import unittest from types import SimpleNamespace from unittest.mock import AsyncMock, patch from app import main as main_module from app.core.settings import Settings from app.db import bootstrap as bootstrap_module from app.db import init_db as init_db_module from app.db import tool_seed as tool_seed_module class SettingsParsingTests(unittest.TestCase): def test_debug_accepts_release_alias(self): settings = Settings( google_project_id="test-project", debug="release", ) self.assertFalse(settings.debug) def test_normalizes_environment_and_backend_values(self): settings = Settings( google_project_id="test-project", environment=" Production ", conversation_state_backend=" Redis ", ) self.assertEqual(settings.environment, "production") self.assertEqual(settings.conversation_state_backend, "redis") class BootstrapRuntimeTests(unittest.TestCase): @patch.object(bootstrap_module, "seed_tools") @patch.object(bootstrap_module, "seed_mock_data") @patch.object(bootstrap_module, "_ensure_mock_schema_evolution") @patch.object(bootstrap_module.MockBase.metadata, "create_all") @patch.object(bootstrap_module.Base.metadata, "create_all") def test_bootstrap_databases_respects_seed_flags( self, tools_create_all, mock_create_all, ensure_mock_schema_evolution, seed_mock_data, seed_tools, ): with patch.object(bootstrap_module.settings, "auto_seed_tools", False), patch.object( bootstrap_module.settings, "auto_seed_mock", False, ), patch.object(bootstrap_module.settings, "mock_seed_enabled", True): bootstrap_module.bootstrap_databases() tools_create_all.assert_called_once() mock_create_all.assert_called_once() seed_tools.assert_not_called() seed_mock_data.assert_not_called() @patch.object(bootstrap_module, "seed_tools") @patch.object(bootstrap_module, "seed_mock_data") @patch.object(bootstrap_module, "_ensure_mock_schema_evolution") @patch.object(bootstrap_module.MockBase.metadata, "create_all") @patch.object(bootstrap_module.Base.metadata, "create_all", side_effect=RuntimeError("tools db down")) def test_bootstrap_databases_raises_when_any_backend_fails( self, tools_create_all, mock_create_all, ensure_mock_schema_evolution, seed_mock_data, seed_tools, ): with self.assertRaisesRegex(RuntimeError, "tools=tools db down"): bootstrap_module.bootstrap_databases() tools_create_all.assert_called_once() mock_create_all.assert_called_once() seed_mock_data.assert_called_once() seed_tools.assert_not_called() @patch.object(init_db_module, "bootstrap_databases") def test_init_db_wrapper_delegates_to_bootstrap_databases(self, bootstrap_databases): init_db_module.init_db() bootstrap_databases.assert_called_once_with() class ToolSeedTests(unittest.TestCase): def test_seed_tools_remove_tool_legada_de_multa(self): class FakeToolRepo: def __init__(self, tools): self.tools = list(tools) self.deleted_ids = [] def get_all(self): return list(self.tools) def delete(self, tool_id): self.deleted_ids.append(tool_id) self.tools = [tool for tool in self.tools if tool.id != tool_id] def update_by_name(self, **kwargs): return kwargs def create(self, **kwargs): return kwargs repo = FakeToolRepo( [ SimpleNamespace(id=1, name="registrar_multa_aluguel"), SimpleNamespace(id=2, name="consultar_estoque"), ] ) fake_db = SimpleNamespace(close=lambda: None) with patch.object(tool_seed_module, "SessionLocal", return_value=fake_db), patch.object( tool_seed_module, "ToolRepository", return_value=repo, ): tool_seed_module.seed_tools() self.assertEqual(repo.deleted_ids, [1]) self.assertFalse(any(tool.name == "registrar_multa_aluguel" for tool in repo.get_all())) class HttpStartupTests(unittest.IsolatedAsyncioTestCase): async def test_startup_event_warms_llm_without_running_bootstrap(self): with patch("app.main.LLMService") as llm_cls, patch( "app.db.bootstrap.bootstrap_databases" ) as bootstrap_databases: llm_cls.return_value.warmup = AsyncMock() await main_module.startup_event() llm_cls.return_value.warmup.assert_awaited_once() bootstrap_databases.assert_not_called() if __name__ == "__main__": unittest.main()