|
6 | 6 |
|
7 | 7 | from __future__ import annotations |
8 | 8 |
|
| 9 | +from types import SimpleNamespace |
9 | 10 | from typing import Any |
10 | 11 | from unittest.mock import AsyncMock, MagicMock, patch |
11 | 12 |
|
@@ -36,60 +37,63 @@ def user_payload() -> dict[str, Any]: |
36 | 37 | # ---------------------------------- Happy‑path test ---------------------------------- |
37 | 38 |
|
38 | 39 |
|
| 40 | +@patch("assistant.app.logger.instrument_requests", lambda *a, **k: None) |
| 41 | +@patch("assistant.app.logger.instrument_sqlalchemy", lambda *a, **k: None) |
39 | 42 | @patch("assistant.app.init_assistant_service") |
40 | 43 | @patch("assistant.app.init_engine") |
41 | 44 | @patch("assistant.app.init_vdb") |
42 | 45 | def test_invoke_success(mock_vdb, mock_engine, mock_service, user_payload, dummy_usage, patch_configs): |
43 | | - """/invoke returns AgentResponse and disposes engine on shutdown.""" |
44 | | - |
45 | 46 | fake_response = AssistantResponse(output="hi!", usage=dummy_usage, thinking="thinking") |
46 | | - # assistant_service is async, so we need an AsyncMock |
| 47 | + |
| 48 | + # assistant_service — async |
47 | 49 | mock_service_instance = AsyncMock() |
48 | 50 | mock_service_instance.process_request.return_value = fake_response |
49 | 51 | mock_service.return_value = mock_service_instance |
50 | 52 |
|
51 | | - # Mock DB engine + vdb |
52 | | - mock_engine_instance = AsyncMock() |
53 | | - mock_engine_instance.dispose = AsyncMock() |
54 | | - mock_engine.return_value = mock_engine_instance |
| 53 | + # Engine — объект с async dispose() |
| 54 | + engine = MagicMock() |
| 55 | + engine.dispose = AsyncMock() |
| 56 | + mock_engine.return_value = engine |
| 57 | + |
| 58 | + # vdb — любой sync мок |
55 | 59 | mock_vdb_instance = MagicMock() |
56 | 60 | mock_vdb.return_value = mock_vdb_instance |
57 | 61 |
|
58 | 62 | with TestClient(app) as client: |
59 | | - # --- request --- |
60 | 63 | resp = client.post("/invoke", json=user_payload) |
61 | 64 | assert resp.status_code == 200 |
62 | 65 | assert resp.json()["output"] == "hi!" |
63 | 66 |
|
64 | | - # After exiting TestClient, shutdown event has run |
65 | | - mock_engine_instance.dispose.assert_awaited_once() |
| 67 | + engine.dispose.assert_awaited_once() |
66 | 68 | mock_service_instance.process_request.assert_awaited_once() |
67 | 69 |
|
68 | 70 |
|
69 | 71 | # ------------------------ Validation error (missing chat_uid) ------------------------ |
70 | 72 |
|
71 | 73 |
|
| 74 | +@patch("assistant.app.logger.instrument_requests", lambda *a, **k: None) |
| 75 | +@patch("assistant.app.logger.instrument_sqlalchemy", lambda *a, **k: None) |
72 | 76 | @patch("assistant.app.init_assistant_service", lambda *a, **kw: AsyncMock()) |
73 | | -@patch("assistant.app.init_engine", lambda *a, **kw: AsyncMock()) |
| 77 | +@patch("assistant.app.init_engine", lambda *a, **kw: SimpleNamespace(dispose=AsyncMock())) |
74 | 78 | @patch("assistant.app.init_vdb", lambda *a, **kw: MagicMock()) |
75 | 79 | def test_invoke_validation_error(user_payload, patch_configs): |
76 | | - """Test validation error when chat_uid is missing.""" |
77 | 80 | payload = user_payload.copy() |
78 | 81 | payload.pop("chat_uid") |
79 | 82 | with TestClient(app) as client: |
80 | 83 | resp = client.post("/invoke", json=payload) |
81 | | - assert resp.status_code == 422 # FastAPI validation error |
| 84 | + assert resp.status_code == 422 |
82 | 85 |
|
83 | 86 |
|
84 | 87 | # |
85 | 88 | # ---------------------------- Error path: assistant raises ---------------------------- |
86 | 89 |
|
87 | 90 |
|
| 91 | +@patch("assistant.app.logger.instrument_requests", lambda *a, **k: None) |
| 92 | +@patch("assistant.app.logger.instrument_sqlalchemy", lambda *a, **k: None) |
88 | 93 | @patch("assistant.app.init_assistant_service") |
89 | | -@patch("assistant.app.init_engine", lambda *a, **kw: AsyncMock()) |
| 94 | +@patch("assistant.app.init_engine", lambda *a, **kw: SimpleNamespace(dispose=AsyncMock())) |
90 | 95 | @patch("assistant.app.init_vdb", lambda *a, **kw: MagicMock()) |
91 | 96 | def test_invoke_service_error(mock_service, user_payload, patch_configs): |
92 | | - """Test error handling when assistant service raises exception.""" |
93 | 97 | err = RuntimeError("model crashed") |
94 | 98 | mock_service_instance = AsyncMock() |
95 | 99 | mock_service_instance.process_request.side_effect = err |
|
0 commit comments