{ "verdict": "APPROVED", "rejection_reason": "NONE", "audit_details": { "target_invoked": true, "pre_conditions_tested": true, "post_conditions_tested": true, "test_data_used": true }, "feedback": "Both test files have successfully passed the audit. The 'task_log_viewer.test.js' suite now correctly imports and mounts the real Svelte component using Test Library, fully eliminating the logic mirror/tautology issue. The 'test_logger.py' suite now properly implements negative tests for the @PRE constraint in 'belief_scope' and fully verifies all @POST effects triggered by 'configure_logger'." }

This commit is contained in:
2026-02-24 21:55:13 +03:00
parent 95ae9c6af1
commit 1c362f4092
13 changed files with 2170 additions and 270 deletions

View File

@@ -0,0 +1,181 @@
# [DEF:test_report_service:Module]
# @TIER: CRITICAL
# @PURPOSE: Unit tests for ReportsService list/detail operations
# @LAYER: Domain
# @RELATION: TESTS -> backend.src.services.reports.report_service.ReportsService
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent.parent / "src"))
import pytest
from unittest.mock import MagicMock, patch
from datetime import datetime, timezone, timedelta
def _make_task(task_id="task-1", plugin_id="superset-backup", status_value="SUCCESS",
started_at=None, finished_at=None, result=None, params=None, logs=None):
"""Create a mock Task object matching the Task model interface."""
from src.core.task_manager.models import Task, TaskStatus
task = Task(plugin_id=plugin_id, params=params or {})
task.id = task_id
task.status = TaskStatus(status_value)
task.started_at = started_at or datetime(2024, 1, 15, 10, 0, 0)
task.finished_at = finished_at or datetime(2024, 1, 15, 10, 5, 0)
task.result = result
if logs is not None:
task.logs = logs
return task
class TestReportsServiceList:
"""Tests for ReportsService.list_reports."""
def _make_service(self, tasks):
from src.services.reports.report_service import ReportsService
mock_tm = MagicMock()
mock_tm.get_all_tasks.return_value = tasks
return ReportsService(task_manager=mock_tm)
def test_empty_tasks_returns_empty_collection(self):
from src.models.report import ReportQuery
svc = self._make_service([])
result = svc.list_reports(ReportQuery())
assert result.total == 0
assert result.items == []
assert result.has_next is False
def test_single_task_normalized(self):
from src.models.report import ReportQuery
task = _make_task(result={"summary": "Backup completed"})
svc = self._make_service([task])
result = svc.list_reports(ReportQuery())
assert result.total == 1
assert result.items[0].task_id == "task-1"
assert result.items[0].summary == "Backup completed"
def test_pagination_first_page(self):
from src.models.report import ReportQuery
tasks = [
_make_task(task_id=f"task-{i}",
finished_at=datetime(2024, 1, 15, 10, i, 0))
for i in range(5)
]
svc = self._make_service(tasks)
result = svc.list_reports(ReportQuery(page=1, page_size=2))
assert len(result.items) == 2
assert result.total == 5
assert result.has_next is True
def test_pagination_last_page(self):
from src.models.report import ReportQuery
tasks = [
_make_task(task_id=f"task-{i}",
finished_at=datetime(2024, 1, 15, 10, i, 0))
for i in range(5)
]
svc = self._make_service(tasks)
result = svc.list_reports(ReportQuery(page=3, page_size=2))
assert len(result.items) == 1
assert result.has_next is False
def test_filter_by_status(self):
from src.models.report import ReportQuery, ReportStatus
tasks = [
_make_task(task_id="ok", status_value="SUCCESS"),
_make_task(task_id="fail", status_value="FAILED"),
]
svc = self._make_service(tasks)
result = svc.list_reports(ReportQuery(statuses=[ReportStatus.SUCCESS]))
assert result.total == 1
assert result.items[0].task_id == "ok"
def test_filter_by_task_type(self):
from src.models.report import ReportQuery, TaskType
tasks = [
_make_task(task_id="backup", plugin_id="superset-backup"),
_make_task(task_id="migrate", plugin_id="superset-migration"),
]
svc = self._make_service(tasks)
result = svc.list_reports(ReportQuery(task_types=[TaskType.BACKUP]))
assert result.total == 1
assert result.items[0].task_id == "backup"
def test_search_filter(self):
from src.models.report import ReportQuery
tasks = [
_make_task(task_id="t1", plugin_id="superset-migration",
result={"summary": "Migration complete"}),
_make_task(task_id="t2", plugin_id="documentation",
result={"summary": "Docs generated"}),
]
svc = self._make_service(tasks)
result = svc.list_reports(ReportQuery(search="migration"))
assert result.total == 1
assert result.items[0].task_id == "t1"
def test_sort_by_status(self):
from src.models.report import ReportQuery
tasks = [
_make_task(task_id="t1", status_value="SUCCESS"),
_make_task(task_id="t2", status_value="FAILED"),
]
svc = self._make_service(tasks)
result = svc.list_reports(ReportQuery(sort_by="status", sort_order="asc"))
statuses = [item.status.value for item in result.items]
assert statuses == sorted(statuses)
def test_applied_filters_echoed(self):
from src.models.report import ReportQuery
query = ReportQuery(page=2, page_size=5)
svc = self._make_service([])
result = svc.list_reports(query)
assert result.applied_filters.page == 2
assert result.applied_filters.page_size == 5
class TestReportsServiceDetail:
"""Tests for ReportsService.get_report_detail."""
def _make_service(self, tasks):
from src.services.reports.report_service import ReportsService
mock_tm = MagicMock()
mock_tm.get_all_tasks.return_value = tasks
return ReportsService(task_manager=mock_tm)
def test_detail_found(self):
task = _make_task(task_id="detail-task", result={"summary": "Done"})
svc = self._make_service([task])
detail = svc.get_report_detail("detail-task")
assert detail is not None
assert detail.report.task_id == "detail-task"
def test_detail_not_found(self):
svc = self._make_service([])
detail = svc.get_report_detail("nonexistent")
assert detail is None
def test_detail_includes_timeline(self):
task = _make_task(task_id="tl-task",
started_at=datetime(2024, 1, 15, 10, 0, 0),
finished_at=datetime(2024, 1, 15, 10, 5, 0))
svc = self._make_service([task])
detail = svc.get_report_detail("tl-task")
events = [e["event"] for e in detail.timeline]
assert "started" in events
assert "updated" in events
def test_detail_failed_task_has_next_actions(self):
task = _make_task(task_id="fail-task", status_value="FAILED")
svc = self._make_service([task])
detail = svc.get_report_detail("fail-task")
assert len(detail.next_actions) > 0
def test_detail_success_task_no_error_next_actions(self):
task = _make_task(task_id="ok-task", status_value="SUCCESS",
result={"summary": "All good"})
svc = self._make_service([task])
detail = svc.get_report_detail("ok-task")
assert detail.next_actions == []
# [/DEF:test_report_service:Module]