Spaces:
Sleeping
Sleeping
| """Tests for deterministic service mesh behavior.""" | |
| from __future__ import annotations | |
| import pytest | |
| from env.services import ( | |
| Alert, | |
| BLAST_RADIUS, | |
| SERVICE_OBSERVABILITY, | |
| ServiceMesh, | |
| ) | |
| # ===================================================================== | |
| # Core mesh behavior | |
| # ===================================================================== | |
| def test_inject_failure_cascades_to_dependents() -> None: | |
| """Root outage should degrade transitive dependents.""" | |
| mesh = ServiceMesh(seed=7) | |
| mesh.inject_failure("database", "oom") | |
| summary = mesh.get_health_summary() | |
| assert summary["database"] == "down" | |
| assert summary["payments"] == "degraded" | |
| assert summary["analytics"] == "degraded" | |
| assert summary["notifications"] == "degraded" | |
| assert summary["auth"] == "healthy" | |
| def test_apply_fix_root_cause_heals_chain() -> None: | |
| """Correct root-cause fix should heal root and dependents.""" | |
| mesh = ServiceMesh(seed=11) | |
| mesh.inject_failure("auth", "config_corruption") | |
| result = mesh.apply_fix("auth", "config_change") | |
| assert result.success is True | |
| assert "auth" in result.healed_services | |
| assert mesh.get_health_summary()["auth"] == "healthy" | |
| assert mesh.get_health_summary()["payments"] == "healthy" | |
| def test_apply_fix_symptom_is_temporary() -> None: | |
| """Fixing a symptom should not resolve root-cause state.""" | |
| mesh = ServiceMesh(seed=3) | |
| mesh.inject_failure("database", "oom") | |
| result = mesh.apply_fix("payments", "restart_service") | |
| assert result.success is False | |
| assert mesh.services["database"].is_root_cause is True | |
| # ===================================================================== | |
| # Advanced features | |
| # ===================================================================== | |
| def test_topology_hidden_on_hard_and_nightmare() -> None: | |
| """Dependency graph must be hidden on hard/nightmare modes.""" | |
| mesh = ServiceMesh(seed=1) | |
| assert mesh.get_dependencies("easy") | |
| assert mesh.get_dependencies("medium") | |
| assert mesh.get_dependencies("hard") == {} | |
| assert mesh.get_dependencies("nightmare") == {} | |
| def test_observability_affects_probe_detail() -> None: | |
| """Low-observability services return minimal probe findings.""" | |
| mesh = ServiceMesh(seed=8) | |
| high = mesh.probe_service("auth", "logs") | |
| low = mesh.probe_service("analytics", "logs") | |
| assert SERVICE_OBSERVABILITY["auth"] == "high" | |
| assert SERVICE_OBSERVABILITY["analytics"] == "low" | |
| assert len(high.findings) > len(low.findings) | |
| def test_flickering_pattern_is_deterministic() -> None: | |
| """Flickering service should follow deterministic repeating pattern.""" | |
| mesh = ServiceMesh(seed=9) | |
| mesh.set_flickering("payments", "connection_flap") | |
| observed = [] | |
| for step in range(4): | |
| mesh.tick_service_health(step + 1) | |
| observed.append(mesh.services["payments"].health) | |
| assert observed == ["degraded", "healthy", "degraded", "healthy"] | |
| def test_time_based_degradation_can_reach_down() -> None: | |
| """Degraded services worsen every 5 steps and eventually fail hard.""" | |
| mesh = ServiceMesh(seed=2) | |
| mesh.inject_failure("database", "oom") | |
| mesh.services["payments"].error_rate = 0.89 | |
| mesh.tick_service_health(5) | |
| assert mesh.services["payments"].health == "down" | |
| def test_apply_wrong_fix_triggers_blast_radius() -> None: | |
| """Wrong fix should apply configured penalty and extra damage.""" | |
| mesh = ServiceMesh(seed=10) | |
| mesh.inject_failure("auth", "rate_limiting") | |
| result = mesh.apply_wrong_fix("database", "schema_migration") | |
| assert result.penalty == pytest.approx(float(BLAST_RADIUS["schema_migration"]["penalty"])) | |
| assert result.cascade is True | |
| assert "database" in result.damaged_services | |
| def test_generate_alerts_is_deterministic() -> None: | |
| """Alert stream should be reproducible for same seed and step.""" | |
| mesh_a = ServiceMesh(seed=5) | |
| mesh_b = ServiceMesh(seed=5) | |
| mesh_a.inject_failure("database", "oom") | |
| mesh_b.inject_failure("database", "oom") | |
| alerts_a = mesh_a.generate_alerts(step=6) | |
| alerts_b = mesh_b.generate_alerts(step=6) | |
| assert [a.model_dump() for a in alerts_a] == [b.model_dump() for b in alerts_b] | |
| assert all(isinstance(alert, Alert) for alert in alerts_a) | |
| def test_generate_red_herrings_is_deterministic() -> None: | |
| """Per-incident red herring generation should be deterministic.""" | |
| mesh = ServiceMesh(seed=4) | |
| first = mesh.generate_red_herrings("HARD-012") | |
| second = mesh.generate_red_herrings("HARD-012") | |
| assert [h.model_dump() for h in first] == [h.model_dump() for h in second] | |