1818from fastapi .testclient import TestClient
1919
2020from 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 ,
3638from orb .config .schemas .server_schema import AuthConfig , ServerConfig
3739from 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
6198def 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
0 commit comments