55import pytest
66import sys
77import os
8- import platform
98from unittest .mock import patch , MagicMock , AsyncMock , Mock
109
11- # Skip on Linux due to platform-specific Mock/issubclass issues
12- skip_on_linux = pytest .mark .skipif (
13- platform .system () == "Linux" ,
14- reason = "Skipping on Linux due to Mock/issubclass compatibility issues"
15- )
16-
1710# Add src to path
1811src_path = os .path .join (os .path .dirname (__file__ ), '..' , '..' , '..' )
1912src_path = os .path .abspath (src_path )
3932os .environ .setdefault ("AZURE_OPENAI_RAI_DEPLOYMENT_NAME" , "test-rai-deployment" )
4033
4134
42- @pytest .fixture (autouse = True )
43- def setup_environment (monkeypatch ):
44- """Set up environment variables and mocks."""
45- # Mock router BEFORE any imports
46- mock_router = MagicMock ()
47- mock_router .routes = []
48- sys .modules ['backend.v4.api.router' ] = MagicMock (app_v4 = mock_router )
35+ @pytest .fixture (scope = "module" , autouse = True )
36+ def setup_mocks ():
37+ """Set up mocks for backend.app imports."""
38+ # Save original modules
39+ original_router = sys .modules .get ('backend.v4.api.router' )
40+ original_agent_registry = sys .modules .get ('backend.v4.config.agent_registry' )
41+
42+ # Create APIRouter mock that doesn't trigger isinstance/issubclass
43+ from fastapi import APIRouter
44+ mock_app_v4 = APIRouter ()
45+ mock_app_v4 .routes = []
46+
47+ # Mock the router module
48+ class MockRouterModule :
49+ app_v4 = mock_app_v4
4950
50- # Mock middleware
51- sys .modules ['backend.middleware.health_check' ] = MagicMock ()
51+ sys .modules ['backend.v4.api.router' ] = MockRouterModule ()
5252
5353 # Mock agent registry
54- mock_agent_registry = MagicMock ()
55- mock_agent_registry .cleanup_all_agents = AsyncMock ()
56- sys .modules ['backend.v4.config.agent_registry' ] = MagicMock (agent_registry = mock_agent_registry )
54+ class MockAgentRegistry :
55+ async def cleanup_all_agents (self ):
56+ pass
57+
58+ class MockAgentRegistryModule :
59+ agent_registry = MockAgentRegistry ()
5760
58- # Mock Azure monitor
61+ sys .modules ['backend.v4.config.agent_registry' ] = MockAgentRegistryModule ()
62+
63+ # Mock Azure monitor and import
5964 with patch ('azure.monitor.opentelemetry.configure_azure_monitor' ):
60- yield
65+ # Now import backend.app
66+ import backend .app
67+ globals ()['app' ] = backend .app .app
68+ globals ()['lifespan' ] = backend .app .lifespan
69+ globals ()['user_browser_language_endpoint' ] = backend .app .user_browser_language_endpoint
70+
71+ yield
72+
73+ # Cleanup - restore original modules
74+ if original_router is not None :
75+ sys .modules ['backend.v4.api.router' ] = original_router
76+ elif 'backend.v4.api.router' in sys .modules :
77+ del sys .modules ['backend.v4.api.router' ]
78+
79+ if original_agent_registry is not None :
80+ sys .modules ['backend.v4.config.agent_registry' ] = original_agent_registry
81+ elif 'backend.v4.config.agent_registry' in sys .modules :
82+ del sys .modules ['backend.v4.config.agent_registry' ]
83+
84+ # Remove backend.app from cache so it can be reimported fresh
85+ if 'backend.app' in sys .modules :
86+ del sys .modules ['backend.app' ]
6187
6288
63- @skip_on_linux
64- def test_app_initialization (setup_environment ):
89+ def test_app_initialization ():
6590 """Test that FastAPI app initializes correctly."""
6691 from backend .app import app
6792 assert app is not None
6893 assert hasattr (app , 'routes' )
6994
7095
71- @skip_on_linux
72- def test_app_has_cors_middleware (setup_environment ):
96+ def test_app_has_cors_middleware ():
7397 """Test that CORS middleware is configured."""
74- from backend .app import app
7598 from starlette .middleware .cors import CORSMiddleware
7699 # Check if CORS middleware is in the middleware stack
77100 has_cors = any (
@@ -81,10 +104,9 @@ def test_app_has_cors_middleware(setup_environment):
81104 assert has_cors , "CORS middleware not found in app.user_middleware"
82105
83106
84- @skip_on_linux
85- def test_user_browser_language_endpoint (setup_environment ):
107+ def test_user_browser_language_endpoint ():
86108 """Test the user browser language endpoint exists."""
87- from backend .app import app , user_browser_language_endpoint
109+ from backend .app import user_browser_language_endpoint
88110 from backend .common .models .messages_af import UserLanguage
89111
90112 # Verify endpoint function exists and is callable
@@ -95,8 +117,7 @@ def test_user_browser_language_endpoint(setup_environment):
95117 assert test_lang .language == "en-US"
96118
97119
98- @skip_on_linux
99- def test_user_browser_language_endpoint_different_languages (setup_environment ):
120+ def test_user_browser_language_endpoint_different_languages ():
100121 """Test UserLanguage model with different languages."""
101122 from backend .common .models .messages_af import UserLanguage
102123
@@ -106,45 +127,37 @@ def test_user_browser_language_endpoint_different_languages(setup_environment):
106127 assert test_lang .language == lang
107128
108129
109- @skip_on_linux
110130@pytest .mark .asyncio
111- async def test_lifespan_context (setup_environment ):
131+ async def test_lifespan_context ():
112132 """Test the lifespan context manager."""
113- from backend .app import lifespan , app
133+ from backend .app import lifespan
114134
115135 async with lifespan (app ):
116136 pass
117137
118138
119- @skip_on_linux
120- def test_app_includes_v4_router (setup_environment ):
139+ def test_app_includes_v4_router ():
121140 """Test that V4 router is included."""
122- from backend .app import app
123141 assert len (app .routes ) > 0
124142
125143
126- @skip_on_linux
127- def test_logging_configured (setup_environment ):
144+ def test_logging_configured ():
128145 """Test that logging is configured."""
129146 import logging
130- from backend .app import app
131147
132148 logger = logging .getLogger ("backend" )
133149 assert logger is not None
134150
135151
136- @skip_on_linux
137- def test_fastapi_app_configuration (setup_environment ):
152+ def test_fastapi_app_configuration ():
138153 """Test FastAPI app is properly configured."""
139- from backend .app import app
140154
141155 # Verify app has lifespan
142156 assert app .router .lifespan_context is not None
143157
144158
145- @skip_on_linux
146159@pytest .mark .asyncio
147- async def test_user_browser_language_endpoint_function (setup_environment ):
160+ async def test_user_browser_language_endpoint_function ():
148161 """Test the user_browser_language_endpoint function directly."""
149162 from backend .app import user_browser_language_endpoint
150163 from backend .common .models .messages_af import UserLanguage
@@ -161,30 +174,36 @@ async def test_user_browser_language_endpoint_function(setup_environment):
161174 assert result == {"status" : "Language received successfully" }
162175
163176
164- @skip_on_linux
165177@pytest .mark .asyncio
166- async def test_lifespan_exception_handling (setup_environment ):
178+ async def test_lifespan_exception_handling ():
167179 """Test lifespan context manager exception handling during cleanup."""
168- from backend .app import lifespan , app
180+ from backend .app import lifespan
169181 from backend .v4 .config .agent_registry import agent_registry
170182
183+ # Save original method
184+ original_cleanup = agent_registry .cleanup_all_agents
185+
171186 # Make cleanup raise an exception
172- agent_registry .cleanup_all_agents .side_effect = Exception ("Test cleanup error" )
187+ async def mock_cleanup ():
188+ raise Exception ("Test cleanup error" )
189+
190+ agent_registry .cleanup_all_agents = mock_cleanup
173191
174192 # Should not raise, exception should be caught
175193 try :
176194 async with lifespan (app ):
177195 pass
178196 except Exception :
179197 pytest .fail ("Lifespan should handle cleanup exceptions gracefully" )
198+ finally :
199+ # Restore original method
200+ agent_registry .cleanup_all_agents = original_cleanup
180201
181202
182- @skip_on_linux
183- def test_applicationinsights_not_configured (setup_environment ):
203+ def test_applicationinsights_not_configured ():
184204 """Test that app handles missing Application Insights gracefully."""
185205 # This test checks that the app can start even without AppInsights
186206 # The warning log on line 59 was already executed during module import
187- from backend .app import app
188207 assert app is not None
189208
190209
0 commit comments