fix(tests): 61 failed backend unit tests — async/await mocks, deadlock fix, SyntaxError repairs

Группы исправлений:
- Группа 1 (async/await misuse): MagicMock → AsyncMock для get_dashboards,
  export_dashboard, import_dashboard, sync_environment, get_run_detail,
  list_all_runs, create_task и др. — 23 теста
- Группа 2 (runner.run deadlock): добавлены моки get_async_job_runner +
  IdMappingService/AsyncSupersetClient в migration plugin + API tests
  для предотвращения вечной блокировки future.result() — 16 тестов
- Группа 3 (SyntaxError): исправлены 7 незакрытых скобок ')' в
  test_validation_tasks_comprehensive.py (QA-агент оставил AsyncMock
  без закрывающих скобок)
- Группа 4 (mock verification): logger mock error→explore, scheduler tests
  skipped (удалён из production), dataset mapper — 11 тестов
- Группа 5 (search/assistant): MagicMock → AsyncMock — 9 тестов
- Группа 6 (extractor parsing): AsyncMock для async методов — 9 тестов

Итого: 61 ранее FAILED → 274 passed, 4 skipped, 0 failed
This commit is contained in:
2026-06-18 14:41:13 +03:00
parent c0b0b3c733
commit 335a1ea846
122 changed files with 1479 additions and 1583 deletions

View File

@@ -7,7 +7,7 @@ import sys
sys.path.insert(0, str(Path(__file__).parent.parent / "src"))
from unittest.mock import MagicMock, patch
from unittest.mock import AsyncMock, MagicMock, patch
from datetime import UTC, datetime
import pytest
@@ -166,7 +166,7 @@ class TestDeleteTask:
class TestCreateTask:
"""create_task — full CRUD with provider/environment validation."""
def test_creates_policy_with_sources(self):
async def test_creates_policy_with_sources(self):
from src.services.validation_service import ValidationTaskService
from src.schemas.validation import ValidationTaskCreate, SourceInput
@@ -188,7 +188,7 @@ class TestCreateTask:
cm.get_environment.return_value = MagicMock()
svc = ValidationTaskService(db, config_manager=cm)
svc._resolve_sources = MagicMock(return_value=[
svc._resolve_sources = AsyncMock(return_value=[
MagicMock(type="dashboard_id", value="42",
resolved_dashboard_id="42", status="valid", title=None),
])
@@ -216,12 +216,12 @@ class TestCreateTask:
payload.prompt_template = None
payload.sources = None
result = svc.create_task(payload)
result = await svc.create_task(payload)
assert db.commit.called
svc._resolve_sources.assert_called_once()
def test_creates_with_dashboard_url_sources(self):
async def test_creates_with_dashboard_url_sources(self):
from src.services.validation_service import ValidationTaskService
from src.schemas.validation import ValidationTaskCreate
@@ -243,7 +243,7 @@ class TestCreateTask:
cm.get_environment.return_value = MagicMock()
svc = ValidationTaskService(db, config_manager=cm)
svc._resolve_sources = MagicMock(return_value=[
svc._resolve_sources = AsyncMock(return_value=[
MagicMock(type="dashboard_url", value="http://superset/d/42",
resolved_dashboard_id="42", status="valid", title=None),
])
@@ -270,7 +270,7 @@ class TestCreateTask:
payload.prompt_template = "Check {{dashboard}}"
payload.sources = None
result = svc.create_task(payload)
result = await svc.create_task(payload)
assert db.commit.called
@@ -278,7 +278,7 @@ class TestCreateTask:
class TestUpdateTask:
"""update_task — partial update with re-validation."""
def test_not_found_raises(self):
async def test_not_found_raises(self):
from src.services.validation_service import ValidationTaskService
from src.schemas.validation import ValidationTaskUpdate
db = MagicMock()
@@ -287,9 +287,9 @@ class TestUpdateTask:
payload = MagicMock(spec=ValidationTaskUpdate)
payload.model_dump.return_value = {"name": "Updated"}
with pytest.raises(ValueError, match="not found"):
svc.update_task("nonexistent", payload)
await svc.update_task("nonexistent", payload)
def test_sources_update_with_none_is_skipped(self):
async def test_sources_update_with_none_is_skipped(self):
"""Cover _apply_sources_update line 502: sources_data is None."""
from src.services.validation_service import ValidationTaskService
from src.schemas.validation import ValidationTaskUpdate
@@ -303,10 +303,10 @@ class TestUpdateTask:
payload = MagicMock(spec=ValidationTaskUpdate)
payload.model_dump.return_value = {"sources": None}
result = svc.update_task("pol-1", payload)
result = await svc.update_task("pol-1", payload)
assert db.commit.called
def test_updates_name_only(self):
async def test_updates_name_only(self):
from src.services.validation_service import ValidationTaskService
from src.schemas.validation import ValidationTaskUpdate
policy = make_policy()
@@ -319,10 +319,10 @@ class TestUpdateTask:
payload = MagicMock(spec=ValidationTaskUpdate)
payload.model_dump.return_value = {"name": "Updated Name"}
result = svc.update_task("pol-1", payload)
result = await svc.update_task("pol-1", payload)
assert db.commit.called
def test_updates_provider_and_environment(self):
async def test_updates_provider_and_environment(self):
from src.services.validation_service import ValidationTaskService
from src.schemas.validation import ValidationTaskUpdate
policy = make_policy()
@@ -352,10 +352,10 @@ class TestUpdateTask:
"window_end": "20:00",
}
result = svc.update_task("pol-1", payload)
result = await svc.update_task("pol-1", payload)
assert db.commit.called
def test_updates_with_sources(self):
async def test_updates_with_sources(self):
from src.services.validation_service import ValidationTaskService
from src.schemas.validation import ValidationTaskUpdate, SourceInput
policy = make_policy()
@@ -364,7 +364,7 @@ class TestUpdateTask:
db.query.return_value.filter.return_value.first.return_value = policy
svc = ValidationTaskService(db, config_manager=MagicMock())
svc._resolve_sources = MagicMock(return_value=[
svc._resolve_sources = AsyncMock(return_value=[
MagicMock(type="dashboard_id", value="99",
resolved_dashboard_id="99", status="valid", title="New"),
])
@@ -375,7 +375,7 @@ class TestUpdateTask:
"sources": [SourceInput(type="dashboard_id", value="99")],
}
result = svc.update_task("pol-1", payload)
result = await svc.update_task("pol-1", payload)
assert db.commit.called
svc._resolve_sources.assert_called_once()