Skip to content

Commit 9bd60fe

Browse files
fixed test_router.py unittestcases
1 parent 088978b commit 9bd60fe

2 files changed

Lines changed: 653 additions & 259 deletions

File tree

Lines changed: 287 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,287 @@
1+
"""
2+
Test configuration for v4 API router tests.
3+
Sets up mocks before module imports to enable proper test discovery.
4+
"""
5+
6+
import os
7+
import sys
8+
from enum import Enum
9+
from pathlib import Path
10+
from unittest.mock import AsyncMock, MagicMock, Mock
11+
12+
import pytest
13+
14+
# Add backend to path FIRST
15+
# From src/tests/backend/v4/api/conftest.py, go up to src/ then into backend/
16+
backend_path = Path(__file__).parent.parent.parent.parent.parent / "backend"
17+
sys.path.insert(0, str(backend_path))
18+
19+
# Set up environment variables before any imports
20+
os.environ.update({
21+
'APPLICATIONINSIGHTS_CONNECTION_STRING': 'InstrumentationKey=test-key',
22+
'AZURE_AI_SUBSCRIPTION_ID': 'test-subscription',
23+
'AZURE_AI_RESOURCE_GROUP': 'test-rg',
24+
'AZURE_AI_PROJECT_NAME': 'test-project',
25+
'AZURE_AI_AGENT_ENDPOINT': 'https://test.agent.endpoint.com',
26+
'AZURE_OPENAI_ENDPOINT': 'https://test.openai.azure.com/',
27+
'AZURE_OPENAI_API_KEY': 'test-key',
28+
'AZURE_OPENAI_API_VERSION': '2023-05-15',
29+
'COSMOSDB_ENDPOINT': 'https://mock-endpoint',
30+
'COSMOSDB_KEY': 'mock-key',
31+
'COSMOSDB_DATABASE': 'mock-database',
32+
'COSMOSDB_CONTAINER': 'mock-container',
33+
'USER_LOCAL_BROWSER_LANGUAGE': 'en-US',
34+
})
35+
36+
# Mock Azure dependencies with proper module structure
37+
azure_monitor_mock = MagicMock()
38+
sys.modules["azure.monitor"] = azure_monitor_mock
39+
sys.modules["azure.monitor.events"] = MagicMock()
40+
sys.modules["azure.monitor.events.extension"] = MagicMock()
41+
sys.modules["azure.monitor.opentelemetry"] = MagicMock()
42+
azure_monitor_mock.opentelemetry = sys.modules["azure.monitor.opentelemetry"]
43+
azure_monitor_mock.opentelemetry.configure_azure_monitor = MagicMock()
44+
45+
azure_ai_mock = type(sys)("azure.ai")
46+
azure_ai_agents_mock = type(sys)("azure.ai.agents")
47+
azure_ai_agents_mock.aio = MagicMock()
48+
azure_ai_mock.agents = azure_ai_agents_mock
49+
sys.modules["azure.ai"] = azure_ai_mock
50+
sys.modules["azure.ai.agents"] = azure_ai_agents_mock
51+
sys.modules["azure.ai.agents.aio"] = azure_ai_agents_mock.aio
52+
53+
azure_ai_projects_mock = type(sys)("azure.ai.projects")
54+
azure_ai_projects_mock.models = MagicMock()
55+
azure_ai_projects_mock.aio = MagicMock()
56+
sys.modules["azure.ai.projects"] = azure_ai_projects_mock
57+
sys.modules["azure.ai.projects.models"] = azure_ai_projects_mock.models
58+
sys.modules["azure.ai.projects.aio"] = azure_ai_projects_mock.aio
59+
60+
# Cosmos DB mocks with nested structure
61+
sys.modules["azure.cosmos"] = MagicMock()
62+
cosmos_aio_mock = type(sys)("azure.cosmos.aio") # Create a real module object
63+
cosmos_aio_mock.CosmosClient = MagicMock() # Add CosmosClient
64+
cosmos_aio_mock._database = MagicMock()
65+
cosmos_aio_mock._database.DatabaseProxy = MagicMock()
66+
cosmos_aio_mock._container = MagicMock()
67+
cosmos_aio_mock._container.ContainerProxy = MagicMock()
68+
sys.modules["azure.cosmos.aio"] = cosmos_aio_mock
69+
sys.modules["azure.cosmos.aio._database"] = cosmos_aio_mock._database
70+
sys.modules["azure.cosmos.aio._container"] = cosmos_aio_mock._container
71+
72+
sys.modules["azure.identity"] = MagicMock()
73+
sys.modules["azure.identity.aio"] = MagicMock()
74+
75+
# Create proper enum mocks for agent_framework
76+
class MockRole(str, Enum):
77+
"""Mock Role enum for agent_framework."""
78+
USER = "user"
79+
ASSISTANT = "assistant"
80+
SYSTEM = "system"
81+
TOOL = "tool"
82+
83+
# Create proper base classes for agent_framework
84+
class MockBaseAgent:
85+
"""Mock base agent class."""
86+
__name__ = "BaseAgent"
87+
__module__ = "agent_framework"
88+
__qualname__ = "BaseAgent"
89+
90+
class MockChatAgent:
91+
"""Mock chat agent class."""
92+
__name__ = "ChatAgent"
93+
__module__ = "agent_framework"
94+
__qualname__ = "ChatAgent"
95+
96+
# Mock agent framework dependencies
97+
agent_framework_mock = type(sys)("agent_framework")
98+
agent_framework_mock.azure = type(sys)("agent_framework.azure")
99+
agent_framework_mock.azure.AzureOpenAIChatClient = MagicMock()
100+
agent_framework_mock._workflows = type(sys)("agent_framework._workflows")
101+
agent_framework_mock._workflows._magentic = type(sys)("agent_framework._workflows._magentic")
102+
agent_framework_mock._workflows._magentic.MagenticContext = MagicMock()
103+
agent_framework_mock._workflows._magentic.StandardMagenticManager = MagicMock()
104+
agent_framework_mock._workflows._magentic.ORCHESTRATOR_FINAL_ANSWER_PROMPT = "mock_prompt"
105+
agent_framework_mock._workflows._magentic.ORCHESTRATOR_TASK_LEDGER_PLAN_PROMPT = "mock_prompt"
106+
agent_framework_mock._workflows._magentic.ORCHESTRATOR_TASK_LEDGER_PLAN_UPDATE_PROMPT = "mock_prompt"
107+
agent_framework_mock._workflows._magentic.ORCHESTRATOR_PROGRESS_LEDGER_PROMPT = "mock_prompt"
108+
agent_framework_mock.AgentResponse = MagicMock()
109+
agent_framework_mock.AgentResponseUpdate = MagicMock()
110+
agent_framework_mock.AgentRunUpdateEvent = MagicMock()
111+
agent_framework_mock.AgentThread = MagicMock()
112+
agent_framework_mock.BaseAgent = MockBaseAgent
113+
agent_framework_mock.ChatAgent = MockChatAgent
114+
agent_framework_mock.ChatMessage = MagicMock()
115+
agent_framework_mock.ChatOptions = MagicMock()
116+
agent_framework_mock.Content = MagicMock()
117+
agent_framework_mock.ExecutorCompletedEvent = MagicMock()
118+
agent_framework_mock.GroupChatRequestSentEvent = MagicMock()
119+
agent_framework_mock.GroupChatResponseReceivedEvent = MagicMock()
120+
agent_framework_mock.HostedCodeInterpreterTool = MagicMock()
121+
agent_framework_mock.HostedMCPTool = MagicMock()
122+
agent_framework_mock.ImageContent = MagicMock()
123+
agent_framework_mock.ImageDetail = MagicMock()
124+
agent_framework_mock.ImageUrl = MagicMock()
125+
agent_framework_mock.InMemoryCheckpointStorage = MagicMock()
126+
agent_framework_mock.MagenticBuilder = MagicMock()
127+
agent_framework_mock.MagenticOrchestratorEvent = MagicMock()
128+
agent_framework_mock.MagenticProgressLedger = MagicMock()
129+
agent_framework_mock.MCPStreamableHTTPTool = MagicMock()
130+
agent_framework_mock.Role = MockRole
131+
agent_framework_mock.TemplatedChatAgent = MagicMock()
132+
agent_framework_mock.TextContent = MagicMock()
133+
agent_framework_mock.UsageDetails = MagicMock()
134+
agent_framework_mock.WorkflowOutputEvent = MagicMock()
135+
sys.modules["agent_framework"] = agent_framework_mock
136+
sys.modules["agent_framework.azure"] = agent_framework_mock.azure
137+
sys.modules["agent_framework._workflows"] = agent_framework_mock._workflows
138+
sys.modules["agent_framework._workflows._magentic"] = agent_framework_mock._workflows._magentic
139+
sys.modules["agent_framework_azure_ai"] = MagicMock()
140+
sys.modules["magentic"] = MagicMock()
141+
142+
# OpenTelemetry mocks
143+
otel_mock = type(sys)("opentelemetry")
144+
otel_mock.trace = MagicMock()
145+
sys.modules["opentelemetry"] = otel_mock
146+
sys.modules["opentelemetry.trace"] = otel_mock.trace
147+
sys.modules["opentelemetry.sdk"] = MagicMock()
148+
sys.modules["opentelemetry.sdk.trace"] = MagicMock()
149+
150+
# ---------------------------------------------------------------------------
151+
# Shared Fixtures - Simple approach: create test client and don't pre-patch
152+
# ---------------------------------------------------------------------------
153+
154+
@pytest.fixture
155+
def create_test_client():
156+
"""Create FastAPI TestClient with inline mocks."""
157+
from fastapi.testclient import TestClient
158+
from fastapi import FastAPI
159+
160+
# Import router - all dependencies are stubbed in sys.modules
161+
from v4.api import router as router_module
162+
163+
# Now replace everything in router's namespace with mocks
164+
# Auth
165+
router_module.get_authenticated_user_details = MagicMock(return_value={"user_principal_id": "test-user-123"})
166+
167+
# Database
168+
mock_db = AsyncMock()
169+
mock_db.get_current_team = AsyncMock(return_value=None)
170+
mock_db.get_team_by_id = AsyncMock(return_value=None)
171+
mock_db.get_plan_by_plan_id = AsyncMock(return_value=None)
172+
mock_db.get_all_plans_by_team_id_status = AsyncMock(return_value=[])
173+
mock_db.add_plan = AsyncMock()
174+
mock_db_factory = MagicMock()
175+
mock_db_factory.get_database = AsyncMock(return_value=mock_db)
176+
router_module.DatabaseFactory = mock_db_factory
177+
178+
# Services
179+
router_module.PlanService = MagicMock()
180+
router_module.PlanService.handle_plan_approval = AsyncMock(return_value={"status": "success"})
181+
router_module.PlanService.handle_human_clarification = AsyncMock(return_value={"status": "success"})
182+
router_module.PlanService.handle_agent_messages = AsyncMock(return_value={"status": "success"})
183+
184+
team_svc_instance = AsyncMock()
185+
team_svc_instance.handle_team_selection = AsyncMock(return_value=MagicMock(team_id="team-123"))
186+
team_svc_instance.get_team_configuration = AsyncMock(return_value=None)
187+
team_svc_instance.get_all_team_configurations = AsyncMock(return_value=[])
188+
team_svc_instance.delete_team_configuration = AsyncMock(return_value=True)
189+
team_svc_instance.validate_team_models = AsyncMock(return_value=(True, []))
190+
team_svc_instance.validate_team_search_indexes = AsyncMock(return_value=(True, []))
191+
team_svc_instance.validate_and_parse_team_config = AsyncMock()
192+
team_svc_instance.save_team_configuration = AsyncMock(return_value="team-123")
193+
router_module.TeamService = MagicMock(return_value=team_svc_instance)
194+
195+
orch_mgr_instance = AsyncMock()
196+
orch_mgr_instance.run_orchestration = AsyncMock()
197+
router_module.OrchestrationManager = MagicMock(return_value=orch_mgr_instance)
198+
router_module.OrchestrationManager.get_current_or_new_orchestration = AsyncMock(return_value=orch_mgr_instance)
199+
200+
# Utils
201+
router_module.find_first_available_team = MagicMock(return_value="team-123")
202+
router_module.rai_success = AsyncMock(return_value=True)
203+
router_module.rai_validate_team_config = MagicMock(return_value=(True, None))
204+
router_module.track_event_if_configured = MagicMock(return_value=None)
205+
206+
# Configs
207+
conn_cfg = MagicMock()
208+
conn_cfg.add_connection = AsyncMock()
209+
conn_cfg.close_connection = AsyncMock()
210+
conn_cfg.send_status_update_async = AsyncMock()
211+
router_module.connection_config = conn_cfg
212+
213+
orch_cfg = MagicMock()
214+
orch_cfg.approvals = {}
215+
orch_cfg.clarifications = {}
216+
orch_cfg.set_approval_result = Mock()
217+
orch_cfg.set_clarification_result = Mock()
218+
router_module.orchestration_config = orch_cfg
219+
220+
team_cfg = MagicMock()
221+
team_cfg.set_current_team = Mock()
222+
router_module.team_config = team_cfg
223+
224+
# Create test app with router
225+
app = FastAPI()
226+
app.include_router(router_module.app_v4)
227+
228+
client = TestClient(app)
229+
client.headers = {"Authorization": "Bearer test-token"}
230+
231+
# Store mocks as client attributes for test access
232+
client._mock_db = mock_db
233+
client._mock_team_svc = team_svc_instance
234+
client._mock_auth = router_module.get_authenticated_user_details
235+
client._mock_utils = {
236+
"find_first_available_team": router_module.find_first_available_team,
237+
"rai_success": router_module.rai_success,
238+
"rai_validate_team_config": router_module.rai_validate_team_config,
239+
}
240+
client._mock_configs = {
241+
"connection_config": conn_cfg,
242+
"orchestration_config": orch_cfg,
243+
"team_config": team_cfg,
244+
}
245+
246+
yield client
247+
248+
249+
# ---------------------------------------------------------------------------
250+
# Additional Fixtures for Test Access
251+
# ---------------------------------------------------------------------------
252+
253+
@pytest.fixture
254+
def mock_database(create_test_client):
255+
"""Provide access to the mock database."""
256+
return create_test_client._mock_db
257+
258+
259+
@pytest.fixture
260+
def mock_services(create_test_client):
261+
"""Provide access to mock services."""
262+
# Return a callable that always returns the same instance
263+
class ServiceGetter:
264+
def __call__(self):
265+
return create_test_client._mock_team_svc
266+
267+
return {
268+
"team_service": ServiceGetter()
269+
}
270+
271+
272+
@pytest.fixture
273+
def mock_auth(create_test_client):
274+
"""Provide access to mock authentication."""
275+
return create_test_client._mock_auth
276+
277+
278+
@pytest.fixture
279+
def mock_utils(create_test_client):
280+
"""Provide access to mock utilities."""
281+
return create_test_client._mock_utils
282+
283+
284+
@pytest.fixture
285+
def mock_configs(create_test_client):
286+
"""Provide access to mock configurations."""
287+
return create_test_client._mock_configs

0 commit comments

Comments
 (0)