openenv-customer-support / tests /test_cascading.py
Anuj2209's picture
updated EICC v2 environment, APIs, and training pipeline
ca51294
Raw
History Blame Contribute Delete
5.71 kB
"""Additional cascading-failure tests for service dependency propagation."""
from __future__ import annotations
from env.services import ServiceMesh
def test_database_failure_reaches_notifications_transitively() -> None:
"""Database outage should propagate through payments to notifications."""
mesh = ServiceMesh(seed=101)
mesh.inject_failure("database", "oom")
summary = mesh.get_health_summary()
assert summary["database"] == "down"
assert summary["payments"] == "degraded"
assert summary["notifications"] == "degraded"
def test_root_fix_heals_transitive_chain() -> None:
"""Fixing the root service should recover all cascade-only dependents."""
mesh = ServiceMesh(seed=202)
mesh.inject_failure("database", "oom")
result = mesh.apply_fix("database", "memory_increase")
assert result.success is True
assert set(result.healed_services) >= {"database", "payments", "analytics", "notifications"}
assert mesh.get_health_summary()["payments"] == "healthy"
assert mesh.get_health_summary()["notifications"] == "healthy"
def test_wrong_fix_on_root_damages_dependents_when_cascade_enabled() -> None:
"""Blast radius should degrade dependents for cascade-enabled wrong fixes."""
mesh = ServiceMesh(seed=303)
mesh.inject_failure("database", "oom")
blast = mesh.apply_wrong_fix("database", "config_change")
assert blast.cascade is True
assert "database" in blast.damaged_services
assert "payments" in blast.damaged_services
assert mesh.get_health_summary()["database"] == "down"
assert mesh.get_health_summary()["payments"] == "degraded"
def test_symptom_fix_does_not_clear_root_cause_flag() -> None:
"""Fixing a downstream symptom must not clear the actual root-cause marker."""
mesh = ServiceMesh(seed=404)
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
def test_deterministic_cascade_state_for_same_seed() -> None:
"""Same seed and same failure should produce identical cascade snapshots."""
first = ServiceMesh(seed=505)
second = ServiceMesh(seed=505)
first.inject_failure("database", "oom")
second.inject_failure("database", "oom")
assert first.get_health_summary() == second.get_health_summary()
def test_auth_failure_cascades_to_payments_and_notifications() -> None:
"""Auth outage should degrade payments which degrades notifications."""
mesh = ServiceMesh(seed=606)
mesh.inject_failure("auth", "token_expiry")
summary = mesh.get_health_summary()
assert summary["auth"] == "down"
assert summary["payments"] == "degraded"
assert summary["notifications"] == "degraded"
def test_analytics_failure_does_not_cascade_upstream() -> None:
"""Analytics has no downstream dependents."""
mesh = ServiceMesh(seed=707)
mesh.inject_failure("analytics", "batch_job_runaway")
summary = mesh.get_health_summary()
assert summary["analytics"] == "down"
assert summary["database"] == "healthy"
assert summary["payments"] == "healthy"
def test_notifications_failure_is_isolated() -> None:
"""Notifications is a leaf node with no dependents."""
mesh = ServiceMesh(seed=808)
mesh.inject_failure("notifications", "queue_overflow")
summary = mesh.get_health_summary()
assert summary["notifications"] == "down"
assert summary["payments"] == "healthy"
assert summary["auth"] == "healthy"
def test_fix_wrong_service_does_not_clear_root() -> None:
"""Fixing a non-root service should not clear the root-cause outage."""
mesh = ServiceMesh(seed=909)
mesh.inject_failure("database", "oom")
mesh.apply_fix("analytics", "restart_service")
assert mesh.services["database"].is_root_cause is True
assert mesh.services["database"].health == "down"
def test_monitoring_snapshot_after_failure() -> None:
"""Monitoring data should reflect injected failures."""
mesh = ServiceMesh(seed=1010)
mesh.inject_failure("database", "oom")
snapshot = mesh.get_monitoring_data()
db_record = next(r for r in snapshot.services if r.service == "database")
assert db_record.health == "down"
assert db_record.error_rate > 0.5
def test_blast_radius_non_cascade_fix() -> None:
"""Restart has cascade=False, so only the targeted service is damaged."""
mesh = ServiceMesh(seed=1111)
mesh.inject_failure("auth", "rate_limiting")
result = mesh.apply_wrong_fix("database", "restart_service")
assert result.cascade is False
assert result.damaged_services == ["database"]
def test_double_failure_both_roots_marked() -> None:
"""Two independent failures should both be root causes."""
mesh = ServiceMesh(seed=1212)
mesh.inject_failure("auth", "config_corruption")
mesh.inject_failure("analytics", "query_timeout")
assert mesh.services["auth"].is_root_cause is True
assert mesh.services["analytics"].is_root_cause is True
def test_heal_does_not_affect_independent_root() -> None:
"""Fixing one root cause should not heal another independent outage."""
mesh = ServiceMesh(seed=1313)
mesh.inject_failure("auth", "config_corruption")
mesh.inject_failure("analytics", "query_timeout")
mesh.apply_fix("auth", "config_change")
assert mesh.services["auth"].health == "healthy"
assert mesh.services["analytics"].health == "down"
def test_get_health_summary_returns_all_services() -> None:
mesh = ServiceMesh(seed=1414)
summary = mesh.get_health_summary()
assert set(summary.keys()) == {"auth", "database", "payments", "analytics", "notifications"}