@@ -128,308 +128,6 @@ def __init__(self, *args, **kwargs):
128128setattr (backend_pkg , "apps" , apps_pkg )
129129setattr (apps_pkg , "config_app" , base_app_mod )
130130
131- # Mock external dependencies before importing backend modules
132- with patch ('backend.database.client.MinioClient' , return_value = minio_client_mock ), \
133- patch ('elasticsearch.Elasticsearch' , return_value = MagicMock ()), \
134- patch ('nexent.vector_database.elasticsearch_core.ElasticSearchCore' , return_value = MagicMock ()):
135- # Mock dotenv before importing config_service
136- with patch ('dotenv.load_dotenv' ):
137- # Mock logging configuration
138- with patch ('utils.logging_utils.configure_logging' ), \
139- patch ('utils.logging_utils.configure_elasticsearch_logging' ):
140- from config_service import startup_initialization
141-
142-
143- class TestMainService :
144- """Test cases for config_service module"""
145-
146- @pytest .mark .asyncio
147- @patch ('config_service.initialize_tools_on_startup' , new_callable = AsyncMock )
148- @patch ('config_service.logger' )
149- async def test_startup_initialization_success (self , mock_logger , mock_initialize_tools ):
150- """
151- Test successful startup initialization.
152-
153- This test verifies that:
154- 1. The function logs the start of initialization
155- 2. It logs the APP version
156- 3. It calls initialize_tools_on_startup
157- 4. It logs successful completion
158- """
159- # Setup
160- mock_initialize_tools .return_value = None
161-
162- # Execute
163- await startup_initialization ()
164-
165- # Assert
166- # Check that appropriate log messages were called
167- mock_logger .info .assert_any_call ("Starting server initialization..." )
168- mock_logger .info .assert_any_call (
169- "Server initialization completed successfully!" )
170-
171- # Verify initialize_tools_on_startup was called
172- mock_initialize_tools .assert_called_once ()
173-
174- @pytest .mark .asyncio
175- @patch ('config_service.initialize_tools_on_startup' , new_callable = AsyncMock )
176- @patch ('config_service.logger' )
177- async def test_startup_initialization_with_version_log (self , mock_logger , mock_initialize_tools ):
178- """
179- Test that startup initialization logs the APP version.
180-
181- This test verifies that:
182- 1. The function logs the APP version from consts.const
183- """
184- # Setup
185- mock_initialize_tools .return_value = None
186-
187- # Execute
188- await startup_initialization ()
189-
190- # Assert
191- # Check that version logging was called (should contain "APP version is:")
192- version_logged = any (
193- call for call in mock_logger .info .call_args_list
194- if len (call .args ) > 0 and "APP version is:" in str (call .args [0 ])
195- )
196- assert version_logged , "APP version should be logged during initialization"
197-
198- @pytest .mark .asyncio
199- @patch ('config_service.initialize_tools_on_startup' , new_callable = AsyncMock )
200- @patch ('config_service.logger' )
201- async def test_startup_initialization_tool_initialization_failure (self , mock_logger , mock_initialize_tools ):
202- """
203- Test startup initialization when tool initialization fails.
204-
205- This test verifies that:
206- 1. When initialize_tools_on_startup raises an exception
207- 2. The function catches the exception and logs an error
208- 3. The function logs a warning about continuing despite issues
209- 4. The function does not re-raise the exception
210- """
211- # Setup
212- mock_initialize_tools .side_effect = Exception (
213- "Tool initialization failed" )
214-
215- # Execute - should not raise exception
216- await startup_initialization ()
217-
218- # Assert
219- mock_logger .error .assert_called_once ()
220- error_call = mock_logger .error .call_args [0 ][0 ]
221- assert "Server initialization failed:" in error_call
222- assert "Tool initialization failed" in error_call
223-
224- mock_logger .warning .assert_called_once_with (
225- "Server will continue to start despite initialization issues"
226- )
227-
228- # Verify initialize_tools_on_startup was called
229- mock_initialize_tools .assert_called_once ()
230-
231- @pytest .mark .asyncio
232- @patch ('config_service.initialize_tools_on_startup' , new_callable = AsyncMock )
233- @patch ('config_service.logger' )
234- async def test_startup_initialization_database_error (self , mock_logger , mock_initialize_tools ):
235- """
236- Test startup initialization when database connection fails.
237-
238- This test verifies that:
239- 1. Database-related exceptions are handled gracefully
240- 2. Appropriate error messages are logged
241- 3. The server startup is not blocked
242- """
243- # Setup
244- mock_initialize_tools .side_effect = ConnectionError (
245- "Database connection failed" )
246-
247- # Execute - should not raise exception
248- await startup_initialization ()
249-
250- # Assert
251- mock_logger .error .assert_called_once ()
252- error_message = mock_logger .error .call_args [0 ][0 ]
253- assert "Server initialization failed:" in error_message
254- assert "Database connection failed" in error_message
255-
256- mock_logger .warning .assert_called_once_with (
257- "Server will continue to start despite initialization issues"
258- )
259-
260- @pytest .mark .asyncio
261- @patch ('config_service.initialize_tools_on_startup' , new_callable = AsyncMock )
262- @patch ('config_service.logger' )
263- async def test_startup_initialization_timeout_error (self , mock_logger , mock_initialize_tools ):
264- """
265- Test startup initialization when tool initialization times out.
266-
267- This test verifies that:
268- 1. Timeout exceptions are handled gracefully
269- 2. Appropriate error messages are logged
270- 3. The function continues execution
271- """
272- # Setup
273- mock_initialize_tools .side_effect = asyncio .TimeoutError (
274- "Tool initialization timed out" )
275-
276- # Execute - should not raise exception
277- await startup_initialization ()
278-
279- # Assert
280- mock_logger .error .assert_called_once ()
281- error_message = mock_logger .error .call_args [0 ][0 ]
282- assert "Server initialization failed:" in error_message
283-
284- mock_logger .warning .assert_called_once_with (
285- "Server will continue to start despite initialization issues"
286- )
287-
288- @pytest .mark .asyncio
289- @patch ('config_service.initialize_tools_on_startup' , new_callable = AsyncMock )
290- @patch ('config_service.logger' )
291- async def test_startup_initialization_multiple_calls_safe (self , mock_logger , mock_initialize_tools ):
292- """
293- Test that multiple calls to startup_initialization are safe.
294-
295- This test verifies that:
296- 1. The function can be called multiple times without issues
297- 2. Each call properly executes the initialization sequence
298- """
299- # Setup
300- mock_initialize_tools .return_value = None
301-
302- # Execute multiple times
303- await startup_initialization ()
304- await startup_initialization ()
305-
306- # Assert
307- assert mock_initialize_tools .call_count == 2
308- # At least 2 calls * 2 info messages per call
309- assert mock_logger .info .call_count >= 4
310-
311- @pytest .mark .asyncio
312- @patch ('config_service.initialize_tools_on_startup' , new_callable = AsyncMock )
313- @patch ('config_service.logger' )
314- async def test_startup_initialization_logging_order (self , mock_logger , mock_initialize_tools ):
315- """
316- Test that logging occurs in the correct order during initialization.
317-
318- This test verifies that:
319- 1. Start message is logged first
320- 2. Version message is logged second
321- 3. Success message is logged last (when successful)
322- """
323- # Setup
324- mock_initialize_tools .return_value = None
325-
326- # Execute
327- await startup_initialization ()
328-
329- # Assert
330- info_calls = [call .args [0 ] for call in mock_logger .info .call_args_list ]
331-
332- # Check order of log messages
333- assert len (info_calls ) >= 3
334- assert "Starting server initialization..." in info_calls [0 ]
335- assert "APP version is:" in info_calls [1 ]
336- assert "Server initialization completed successfully!" in info_calls [- 1 ]
337-
338- @pytest .mark .asyncio
339- @patch ('config_service.initialize_tools_on_startup' , new_callable = AsyncMock )
340- @patch ('config_service.logger' )
341- async def test_startup_initialization_exception_details_logged (self , mock_logger , mock_initialize_tools ):
342- """
343- Test that exception details are properly logged.
344-
345- This test verifies that:
346- 1. The specific exception message is included in error logs
347- 2. Both error and warning messages are logged on failure
348- """
349- # Setup
350- specific_error_message = "Specific tool configuration error occurred"
351- mock_initialize_tools .side_effect = ValueError (specific_error_message )
352-
353- # Execute
354- await startup_initialization ()
355-
356- # Assert
357- mock_logger .error .assert_called_once ()
358- error_call_args = mock_logger .error .call_args [0 ][0 ]
359- assert specific_error_message in error_call_args
360- assert "Server initialization failed:" in error_call_args
361-
362- mock_logger .warning .assert_called_once ()
363-
364- @pytest .mark .asyncio
365- @patch ('config_service.initialize_tools_on_startup' , new_callable = AsyncMock )
366- @patch ('config_service.logger' )
367- async def test_startup_initialization_no_exception_propagation (self , mock_logger , mock_initialize_tools ):
368- """
369- Test that exceptions during initialization do not propagate.
370-
371- This test verifies that:
372- 1. Even when initialize_tools_on_startup fails, no exception is raised
373- 2. This allows the server to continue starting up
374- """
375- # Setup
376- mock_initialize_tools .side_effect = RuntimeError (
377- "Critical initialization error" )
378-
379- # Execute and Assert - should not raise any exception
380- try :
381- await startup_initialization ()
382- except Exception as e :
383- pytest .fail (
384- f"startup_initialization should not raise exceptions, but raised: { e } " )
385-
386- # Verify that error handling occurred
387- mock_logger .error .assert_called_once ()
388- mock_logger .warning .assert_called_once ()
389-
390-
391- class TestMainServiceModuleIntegration :
392- """Integration tests for config_service module dependencies"""
393-
394- @patch ('config_service.configure_logging' )
395- @patch ('config_service.configure_elasticsearch_logging' )
396- def test_logging_configuration_called_on_import (self , mock_configure_es , mock_configure_logging ):
397- """
398- Test that logging configuration functions are called when module is imported.
399-
400- This test verifies that:
401- 1. configure_logging is called with logging.INFO
402- 2. configure_elasticsearch_logging is called
403- """
404- # Note: This test checks that logging configuration happens during module import
405- # The mocks should have been called when the module was imported
406- # In a real scenario, you might need to reload the module to test this properly
407- pass # The actual verification would depend on how the test runner handles imports
408-
409- @patch ('config_service.APP_VERSION' , 'test_version_1.2.3' )
410- @patch ('config_service.initialize_tools_on_startup' , new_callable = AsyncMock )
411- @patch ('config_service.logger' )
412- async def test_startup_initialization_with_custom_version (self , mock_logger , mock_initialize_tools ):
413- """
414- Test startup initialization with a custom APP_VERSION.
415-
416- This test verifies that:
417- 1. The custom version is properly logged
418- """
419- # Setup
420- mock_initialize_tools .return_value = None
421-
422- # Execute
423- await startup_initialization ()
424-
425- # Assert
426- version_logged = any (
427- "test_version_1.2.3" in str (call .args [0 ])
428- for call in mock_logger .info .call_args_list
429- if len (call .args ) > 0
430- )
431- assert version_logged , "Custom APP version should be logged"
432-
433131
434132class TestTenantConfigService :
435133 """Unit tests for tenant_config_service helpers"""
0 commit comments