286 lines
9.3 KiB
Python
286 lines
9.3 KiB
Python
import pytest
|
|
from datetime import datetime, timedelta
|
|
from unittest.mock import MagicMock, patch
|
|
from src.services.health_service import HealthService
|
|
from src.models.llm import ValidationRecord
|
|
|
|
# [DEF:test_health_service:Module]
|
|
# @TIER: STANDARD
|
|
# @PURPOSE: Unit tests for HealthService aggregation logic.
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_get_health_summary_aggregation():
|
|
"""
|
|
@TEST_SCENARIO: Verify that HealthService correctly aggregates the latest record per dashboard.
|
|
"""
|
|
# Setup: Mock DB session
|
|
db = MagicMock()
|
|
|
|
now = datetime.utcnow()
|
|
|
|
# Dashboard 1: Old FAIL, New PASS
|
|
rec1_old = ValidationRecord(
|
|
id="rec-old",
|
|
dashboard_id="dash_1",
|
|
environment_id="env_1",
|
|
status="FAIL",
|
|
timestamp=now - timedelta(hours=1),
|
|
summary="Old failure",
|
|
issues=[]
|
|
)
|
|
rec1_new = ValidationRecord(
|
|
id="rec-new",
|
|
dashboard_id="dash_1",
|
|
environment_id="env_1",
|
|
status="PASS",
|
|
timestamp=now,
|
|
summary="New pass",
|
|
issues=[]
|
|
)
|
|
|
|
# Dashboard 2: Single WARN
|
|
rec2 = ValidationRecord(
|
|
id="rec-warn",
|
|
dashboard_id="dash_2",
|
|
environment_id="env_1",
|
|
status="WARN",
|
|
timestamp=now,
|
|
summary="Warning",
|
|
issues=[]
|
|
)
|
|
|
|
# Mock the query chain
|
|
# subquery = self.db.query(...).filter(...).group_by(...).subquery()
|
|
# query = self.db.query(ValidationRecord).join(subquery, ...).all()
|
|
|
|
mock_query = db.query.return_value
|
|
mock_query.filter.return_value = mock_query
|
|
mock_query.group_by.return_value = mock_query
|
|
mock_query.subquery.return_value = MagicMock()
|
|
|
|
db.query.return_value.join.return_value.all.return_value = [rec1_new, rec2]
|
|
|
|
service = HealthService(db)
|
|
summary = await service.get_health_summary(environment_id="env_1")
|
|
|
|
assert summary.pass_count == 1
|
|
assert summary.warn_count == 1
|
|
assert summary.fail_count == 0
|
|
assert len(summary.items) == 2
|
|
|
|
# Verify dash_1 has the latest status (PASS)
|
|
dash_1_item = next(item for item in summary.items if item.dashboard_id == "dash_1")
|
|
assert dash_1_item.status == "PASS"
|
|
assert dash_1_item.summary == "New pass"
|
|
assert dash_1_item.record_id == rec1_new.id
|
|
assert dash_1_item.dashboard_slug == "dash_1"
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_get_health_summary_empty():
|
|
"""
|
|
@TEST_SCENARIO: Verify behavior with no records.
|
|
"""
|
|
db = MagicMock()
|
|
db.query.return_value.join.return_value.all.return_value = []
|
|
|
|
service = HealthService(db)
|
|
summary = await service.get_health_summary(environment_id="env_none")
|
|
|
|
assert summary.pass_count == 0
|
|
assert len(summary.items) == 0
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_get_health_summary_resolves_slug_and_title_from_superset():
|
|
db = MagicMock()
|
|
config_manager = MagicMock()
|
|
config_manager.get_environments.return_value = [MagicMock(id="env_1")]
|
|
|
|
record = ValidationRecord(
|
|
id="rec-1",
|
|
dashboard_id="42",
|
|
environment_id="env_1",
|
|
status="PASS",
|
|
timestamp=datetime.utcnow(),
|
|
summary="Healthy",
|
|
issues=[],
|
|
)
|
|
db.query.return_value.join.return_value.all.return_value = [record]
|
|
|
|
with patch("src.services.health_service.SupersetClient") as mock_client_cls:
|
|
mock_client = MagicMock()
|
|
mock_client.get_dashboards_summary.return_value = [
|
|
{"id": 42, "slug": "ops-overview", "title": "Ops Overview"}
|
|
]
|
|
mock_client_cls.return_value = mock_client
|
|
|
|
service = HealthService(db, config_manager=config_manager)
|
|
summary = await service.get_health_summary(environment_id="env_1")
|
|
|
|
assert summary.items[0].dashboard_slug == "ops-overview"
|
|
assert summary.items[0].dashboard_title == "Ops Overview"
|
|
mock_client.get_dashboards_summary.assert_called_once_with()
|
|
|
|
|
|
@pytest.mark.anyio
|
|
async def test_get_health_summary_reuses_dashboard_metadata_cache_across_service_instances():
|
|
HealthService._dashboard_summary_cache.clear()
|
|
|
|
db = MagicMock()
|
|
config_manager = MagicMock()
|
|
config_manager.get_environments.return_value = [MagicMock(id="env_1")]
|
|
record = ValidationRecord(
|
|
id="rec-1",
|
|
dashboard_id="42",
|
|
environment_id="env_1",
|
|
status="PASS",
|
|
timestamp=datetime.utcnow(),
|
|
summary="Healthy",
|
|
issues=[],
|
|
)
|
|
db.query.return_value.join.return_value.all.return_value = [record]
|
|
|
|
with patch("src.services.health_service.SupersetClient") as mock_client_cls:
|
|
mock_client = MagicMock()
|
|
mock_client.get_dashboards_summary.return_value = [
|
|
{"id": 42, "slug": "ops-overview", "title": "Ops Overview"}
|
|
]
|
|
mock_client_cls.return_value = mock_client
|
|
|
|
first_service = HealthService(db, config_manager=config_manager)
|
|
second_service = HealthService(db, config_manager=config_manager)
|
|
|
|
first_summary = await first_service.get_health_summary(environment_id="env_1")
|
|
second_summary = await second_service.get_health_summary(environment_id="env_1")
|
|
|
|
assert first_summary.items[0].dashboard_slug == "ops-overview"
|
|
assert second_summary.items[0].dashboard_slug == "ops-overview"
|
|
mock_client.get_dashboards_summary.assert_called_once_with()
|
|
HealthService._dashboard_summary_cache.clear()
|
|
|
|
|
|
def test_delete_validation_report_deletes_dashboard_scope_and_linked_tasks():
|
|
db = MagicMock()
|
|
config_manager = MagicMock()
|
|
task_manager = MagicMock()
|
|
task_manager.tasks = {"task-1": object(), "task-2": object(), "task-3": object()}
|
|
|
|
target_record = ValidationRecord(
|
|
id="rec-1",
|
|
task_id="task-1",
|
|
dashboard_id="42",
|
|
environment_id="env_1",
|
|
status="PASS",
|
|
timestamp=datetime.utcnow(),
|
|
summary="Healthy",
|
|
issues=[],
|
|
screenshot_path=None,
|
|
)
|
|
older_peer = ValidationRecord(
|
|
id="rec-2",
|
|
task_id="task-2",
|
|
dashboard_id="42",
|
|
environment_id="env_1",
|
|
status="FAIL",
|
|
timestamp=datetime.utcnow() - timedelta(hours=1),
|
|
summary="Older",
|
|
issues=[],
|
|
screenshot_path=None,
|
|
)
|
|
other_environment = ValidationRecord(
|
|
id="rec-3",
|
|
task_id="task-3",
|
|
dashboard_id="42",
|
|
environment_id="env_2",
|
|
status="WARN",
|
|
timestamp=datetime.utcnow(),
|
|
summary="Other environment",
|
|
issues=[],
|
|
screenshot_path=None,
|
|
)
|
|
|
|
first_query = MagicMock()
|
|
first_query.first.return_value = target_record
|
|
|
|
peer_query = MagicMock()
|
|
peer_query.filter.return_value = peer_query
|
|
peer_query.all.return_value = [target_record, older_peer]
|
|
|
|
db.query.side_effect = [first_query, peer_query]
|
|
|
|
with patch("src.services.health_service.TaskCleanupService") as cleanup_cls:
|
|
cleanup_instance = MagicMock()
|
|
cleanup_cls.return_value = cleanup_instance
|
|
|
|
service = HealthService(db, config_manager=config_manager)
|
|
deleted = service.delete_validation_report("rec-1", task_manager=task_manager)
|
|
|
|
assert deleted is True
|
|
assert db.delete.call_count == 2
|
|
db.delete.assert_any_call(target_record)
|
|
db.delete.assert_any_call(older_peer)
|
|
db.commit.assert_called_once()
|
|
cleanup_instance.delete_task_with_logs.assert_any_call("task-1")
|
|
cleanup_instance.delete_task_with_logs.assert_any_call("task-2")
|
|
cleanup_instance.delete_task_with_logs.call_count == 2
|
|
assert "task-1" not in task_manager.tasks
|
|
assert "task-2" not in task_manager.tasks
|
|
assert "task-3" in task_manager.tasks
|
|
|
|
|
|
def test_delete_validation_report_returns_false_for_unknown_record():
|
|
db = MagicMock()
|
|
db.query.return_value.filter.return_value.first.return_value = None
|
|
|
|
service = HealthService(db, config_manager=MagicMock())
|
|
|
|
assert service.delete_validation_report("missing") is False
|
|
|
|
|
|
def test_delete_validation_report_swallows_linked_task_cleanup_failure():
|
|
db = MagicMock()
|
|
config_manager = MagicMock()
|
|
task_manager = MagicMock()
|
|
task_manager.tasks = {"task-1": object()}
|
|
|
|
record = ValidationRecord(
|
|
id="rec-1",
|
|
task_id="task-1",
|
|
dashboard_id="42",
|
|
environment_id="env_1",
|
|
status="PASS",
|
|
timestamp=datetime.utcnow(),
|
|
summary="Healthy",
|
|
issues=[],
|
|
screenshot_path=None,
|
|
)
|
|
|
|
first_query = MagicMock()
|
|
first_query.first.return_value = record
|
|
|
|
peer_query = MagicMock()
|
|
peer_query.filter.return_value = peer_query
|
|
peer_query.all.return_value = [record]
|
|
|
|
db.query.side_effect = [first_query, peer_query]
|
|
|
|
with patch("src.services.health_service.TaskCleanupService") as cleanup_cls, patch(
|
|
"src.services.health_service.logger"
|
|
) as mock_logger:
|
|
cleanup_instance = MagicMock()
|
|
cleanup_instance.delete_task_with_logs.side_effect = RuntimeError("cleanup exploded")
|
|
cleanup_cls.return_value = cleanup_instance
|
|
|
|
service = HealthService(db, config_manager=config_manager)
|
|
deleted = service.delete_validation_report("rec-1", task_manager=task_manager)
|
|
|
|
assert deleted is True
|
|
db.delete.assert_called_once_with(record)
|
|
db.commit.assert_called_once()
|
|
cleanup_instance.delete_task_with_logs.assert_called_once_with("task-1")
|
|
mock_logger.warning.assert_called_once()
|
|
assert "task-1" not in task_manager.tasks
|
|
|
|
|
|
# [/DEF:test_health_service:Module]
|