Files
ServiceMap-Public/backend/tests/test_v160_evidence_changes.py
T

133 lines
4.1 KiB
Python

from datetime import UTC, datetime, timedelta
from app.discovery_store import DiscoveryStore
from app.evidence import resolve_health
from app.models import (
EvidenceProvider,
EvidenceScope,
HealthEvidence,
HealthStatus,
ServiceCreate,
ServiceKind,
)
from app.store import Store
def _evidence(
evidence_id: str,
*,
provider: EvidenceProvider,
status: HealthStatus,
scope: EvidenceScope = EvidenceScope.COMPONENT,
service_id: str | None = "svc",
observed_at: datetime | None = None,
) -> HealthEvidence:
observed = observed_at or datetime.now(UTC)
return HealthEvidence(
id=evidence_id,
subject_type="service" if scope == EvidenceScope.COMPONENT else "application",
subject_id=service_id or "appops:demo",
service_id=service_id,
provider=provider,
provider_ref=provider.value,
status=status,
scope=scope,
confidence=0.8,
observed_at=observed,
valid_until=observed + timedelta(minutes=5),
received_at=observed,
summary="test evidence",
)
def test_application_scope_evidence_never_becomes_component_direct_health(tmp_path) -> None:
store = Store(str(tmp_path / "servicemap.db"))
service = store.create_service(
ServiceCreate(name="API", kind=ServiceKind.HTTP, url="https://api.local")
)
store.record_health_evidence(
_evidence(
"appops-application",
provider=EvidenceProvider.APPOPS,
status=HealthStatus.DOWN,
scope=EvidenceScope.APPLICATION,
service_id=None,
),
service_ids=[service.id],
)
resolution = store.health_resolution(service.id)
assert resolution.selected_evidence_id is None
assert resolution.status == HealthStatus.UNKNOWN
assert "application-scoped" in resolution.explanation
def test_evidence_conflict_and_priority_are_visible(tmp_path) -> None:
store = Store(str(tmp_path / "servicemap.db"))
service = store.create_service(
ServiceCreate(name="API", kind=ServiceKind.HTTP, url="https://api.local")
)
store.record_health_evidence(
_evidence(
"docker-down",
provider=EvidenceProvider.DOCKER,
status=HealthStatus.DOWN,
service_id=service.id,
)
)
store.record_health_evidence(
_evidence(
"probe-healthy",
provider=EvidenceProvider.PROBE,
status=HealthStatus.HEALTHY,
service_id=service.id,
)
)
resolution = store.health_resolution(service.id)
assert resolution.status == HealthStatus.HEALTHY
assert resolution.selected_provider == EvidenceProvider.PROBE
assert resolution.conflict is True
def test_expired_evidence_is_explained_but_not_selected() -> None:
old = datetime.now(UTC) - timedelta(hours=2)
resolution = resolve_health(
[
_evidence(
"expired",
provider=EvidenceProvider.DOCKER,
status=HealthStatus.DOWN,
observed_at=old,
),
]
)
assert resolution.selected_evidence_id is None
assert resolution.evidence[0].freshness.value == "expired"
def test_topology_snapshots_diff_canonical_service_and_dependency_changes(tmp_path) -> None:
store = Store(str(tmp_path / "servicemap.db"))
discovery = DiscoveryStore(store)
database = store.create_service(
ServiceCreate(name="Database", kind=ServiceKind.TCP, host="db.local", port=5432)
)
first = discovery.capture_snapshot(run_id=None)
store.create_service(
ServiceCreate(
name="API",
kind=ServiceKind.HTTP,
url="https://api.local",
depends_on=[database.id],
)
)
second = discovery.capture_snapshot(run_id=None)
diff = discovery.topology_diff(after_snapshot_id=second.id, before_snapshot_id=first.id)
assert diff.summary["added"] == 2 # API service and its canonical dependency
assert {item.entity_type for item in diff.added} == {"service", "relationship"}