Skip to content

Commit aa99279

Browse files
committed
test: fix latent failures + reconcile k8s tests with main; RBAC/e2e/CodeQL coverage
k8s: k8s_exceptions rename, Job-release parallelism contract, extension- registration order-independence, CLI event-loop deadlock (await main not asyncio.run). Telemetry OTel proxy deadlock; env-var pollution; stale env-setup + auth-performance fixtures; SSE-stream 300s-timeout. New get_current_user RBAC tests (viewer-when-disabled, fail-closed); e2e authorized via dependency_overrides + args._container; _StickyOverridesDict __eq__ (CodeQL).
1 parent 7ebe27a commit aa99279

11 files changed

Lines changed: 521 additions & 84 deletions

tests/e2e/test_cli_integration.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,7 @@ def create_config_file(self, config_data):
3131
return self.config_path
3232

3333
@pytest.mark.asyncio
34-
@patch("orb.interface.system_command_handlers.get_container")
35-
async def test_get_provider_config_cli_e2e(self, mock_get_container):
34+
async def test_get_provider_config_cli_e2e(self):
3635
"""Test getProviderConfig CLI operation end-to-end."""
3736
# Setup mocks
3837
mock_container = Mock()
@@ -50,12 +49,13 @@ async def mock_execute(_query):
5049
mock_orchestrator = Mock()
5150
mock_orchestrator.execute = mock_execute
5251
mock_container.get.return_value = mock_orchestrator
53-
mock_get_container.return_value = mock_container
5452

5553
# Test async function-based handler
5654
from orb.interface.command_handlers import handle_provider_config
5755

56+
# Handlers resolve the DI container from args._container.
5857
mock_command = Mock()
58+
mock_command._container = mock_container
5959

6060
result = await handle_provider_config(mock_command)
6161

@@ -96,8 +96,7 @@ async def test_validate_provider_config_cli_e2e(self, mock_register_services):
9696
assert "provider configuration" in result["message"].lower()
9797

9898
@pytest.mark.asyncio
99-
@patch("orb.interface.system_command_handlers.get_container")
100-
async def test_reload_provider_config_cli_e2e(self, mock_get_container):
99+
async def test_reload_provider_config_cli_e2e(self):
101100
"""Test reloadProviderConfig CLI operation end-to-end."""
102101
from orb.application.dto.interface_response import InterfaceResponse
103102
from orb.application.services.provider_registry_service import ProviderRegistryService
@@ -125,12 +124,13 @@ def container_get(cls):
125124
return Mock()
126125

127126
mock_container.get.side_effect = container_get
128-
mock_get_container.return_value = mock_container
129127

130128
# Test async function-based handler
131129
from orb.interface.command_handlers import handle_reload_provider_config
132130

131+
# Handlers resolve the DI container from args._container.
133132
mock_command = Mock()
133+
mock_command._container = mock_container
134134
mock_command.config_path = self.config_path
135135
mock_command.file = None
136136
mock_command.data = None

tests/e2e/test_critical_path_e2e.py

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@
1818
from fastapi.testclient import TestClient
1919

2020
from orb.api.dependencies import (
21+
CurrentUser,
2122
get_acquire_machines_orchestrator,
2223
get_command_bus,
2324
get_create_template_orchestrator,
25+
get_current_user,
2426
get_get_template_orchestrator,
2527
get_health_check_port,
2628
get_list_machines_orchestrator,
@@ -36,6 +38,41 @@
3638
from orb.config.schemas.server_schema import AuthConfig, ServerConfig
3739
from orb.infrastructure.di.buses import CommandBus, QueryBus
3840

41+
42+
def _admin_user() -> CurrentUser:
43+
"""Return an admin CurrentUser for dependency override in e2e tests."""
44+
return CurrentUser(username="test-admin", role="admin", claims={})
45+
46+
47+
class _StickyOverridesDict(dict):
48+
"""dict subclass that re-inserts a set of 'sticky' entries after every
49+
``clear()``. Used so that auth overrides survive the per-step
50+
``app.dependency_overrides.clear()`` calls in lifecycle tests.
51+
"""
52+
53+
def __init__(self, sticky: dict, *args, **kwargs):
54+
super().__init__(*args, **kwargs)
55+
self._sticky = sticky
56+
self.update(sticky)
57+
58+
def clear(self):
59+
super().clear()
60+
self.update(self._sticky)
61+
62+
def __eq__(self, other: object) -> bool:
63+
# Include _sticky in equality so the added attribute is not ignored
64+
# (CodeQL py/missing-equals). Two sticky dicts are equal when both
65+
# their contents and their sticky sets match; comparison with a plain
66+
# mapping falls back to dict contents for normal interoperability.
67+
if isinstance(other, _StickyOverridesDict):
68+
return dict.__eq__(self, other) and self._sticky == other._sticky
69+
if isinstance(other, dict):
70+
return dict.__eq__(self, other)
71+
return NotImplemented
72+
73+
__hash__ = None # type: ignore[assignment] # mutable mapping is unhashable
74+
75+
3976
# ---------------------------------------------------------------------------
4077
# Shared helpers and fixtures
4178
# ---------------------------------------------------------------------------
@@ -59,7 +96,15 @@ def _make_command_bus(return_value: Any = None) -> AsyncMock:
5996

6097
@pytest.fixture
6198
def app():
62-
return create_fastapi_app(_server_config())
99+
_app = create_fastapi_app(_server_config())
100+
# Auth is disabled in the test server config, so get_current_user would
101+
# resolve to viewer (least privilege). Replace dependency_overrides with a
102+
# sticky-dict subclass that re-inserts the auth override after every
103+
# .clear() call. This lets multi-step lifecycle tests reset their
104+
# orchestrator overrides between steps without losing the admin identity.
105+
sticky = {get_current_user: _admin_user}
106+
_app.dependency_overrides = _StickyOverridesDict(sticky)
107+
return _app
63108

64109

65110
@pytest.fixture
@@ -373,6 +418,8 @@ def test_list_templates_returns_empty_list(self, app, client: TestClient):
373418
"""GET /api/v1/templates/ returns empty list when no templates exist."""
374419
mock_result = Mock()
375420
mock_result.templates = []
421+
mock_result.total_count = None
422+
mock_result.next_cursor = None
376423
mock_orch = AsyncMock()
377424
mock_orch.execute = AsyncMock(return_value=mock_result)
378425

@@ -401,6 +448,8 @@ def test_list_templates_returns_templates(self, app, client: TestClient):
401448
)
402449
mock_result = Mock()
403450
mock_result.templates = [mock_template]
451+
mock_result.total_count = None
452+
mock_result.next_cursor = None
404453
mock_orch = AsyncMock()
405454
mock_orch.execute = AsyncMock(return_value=mock_result)
406455

@@ -647,6 +696,8 @@ def test_list_templates_with_provider_api_filter(self, app, client: TestClient):
647696
)
648697
mock_result = Mock()
649698
mock_result.templates = [mock_template]
699+
mock_result.total_count = None
700+
mock_result.next_cursor = None
650701
mock_orch = AsyncMock()
651702
mock_orch.execute = AsyncMock(return_value=mock_result)
652703

@@ -757,6 +808,8 @@ def test_list_machines_endpoint_exists(self, app, client: TestClient):
757808
"""GET /api/v1/machines/ endpoint is reachable and returns results."""
758809
mock_result = Mock()
759810
mock_result.machines = []
811+
mock_result.total_count = None
812+
mock_result.next_cursor = None
760813
mock_orch = AsyncMock()
761814
mock_orch.execute = AsyncMock(return_value=mock_result)
762815

tests/performance/test_auth_performance.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,12 @@ def no_auth_client(self):
2121
from unittest.mock import MagicMock
2222

2323
from orb.api.dependencies import get_health_check_port
24+
from orb.config.schemas.server_schema import RateLimitConfig
2425

2526
server_config = ServerConfig( # type: ignore[call-arg]
2627
enabled=True,
2728
auth=AuthConfig(enabled=False, strategy="replace"), # type: ignore[call-arg]
29+
rate_limiting=RateLimitConfig(enabled=False),
2830
)
2931
app = create_fastapi_app(server_config)
3032
mock_health_port = MagicMock()
@@ -35,6 +37,11 @@ def no_auth_client(self):
3537
@pytest.fixture
3638
def auth_client_and_token(self):
3739
"""Client with authentication and valid token."""
40+
from unittest.mock import MagicMock
41+
42+
from orb.api.dependencies import get_health_check_port
43+
from orb.config.schemas.server_schema import RateLimitConfig
44+
3845
server_config = ServerConfig( # type: ignore[call-arg]
3946
enabled=True,
4047
auth=AuthConfig( # type: ignore[call-arg]
@@ -45,8 +52,12 @@ def auth_client_and_token(self):
4552
"algorithm": "HS256",
4653
},
4754
),
55+
rate_limiting=RateLimitConfig(enabled=False),
4856
)
4957
app = create_fastapi_app(server_config)
58+
mock_health_port = MagicMock()
59+
mock_health_port.get_status.return_value = {"status": "healthy"}
60+
app.dependency_overrides[get_health_check_port] = lambda: mock_health_port
5061
client = TestClient(app)
5162

5263
# Create valid token

0 commit comments

Comments
 (0)