Files
minerops/backend/tests/test_system_health.py
T

305 lines
13 KiB
Python

import ast
import unittest
from datetime import datetime, timezone
from pathlib import Path
from uuid import uuid4
import psycopg
from fastapi import FastAPI
from fastapi.testclient import TestClient
from app.config import settings
from app.identity import get_current_user
from app.system_health.application import ApplicationMetadata
from app.system_health.dependencies import get_system_health_service
from app.system_health.frontend import router as frontend_router
from app.system_health.repository import SystemHealthRepository
from app.system_health.router import router as api_router
from app.system_health.service import SystemHealthService
APP_ROOT = Path(__file__).parents[1] / "app"
EXPECTED_HEAD = "0014_repair_parts_tracking"
def database_payload(revision=EXPECTED_HEAD):
return {
"migration": {"current_revision": revision},
"operations": {
"miners": 4, "sites": 1, "rooms": 2, "location_positions": 3,
"repairs": 1, "repair_events": 2, "repair_parts": 1,
"snapshot_count": 5,
"oldest_observed_at": datetime(2026, 8, 18, tzinfo=timezone.utc),
"latest_observed_at": datetime(2026, 8, 19, tzinfo=timezone.utc),
"hourly_present": True, "hourly_rows": 2,
"hourly_latest": datetime(2026, 8, 19, tzinfo=timezone.utc),
"daily_present": True, "daily_rows": 1,
"daily_latest": datetime(2026, 8, 19, tzinfo=timezone.utc).date(),
"retention_mode": "dry_run",
"retention_started_at": datetime(2026, 8, 19, tzinfo=timezone.utc),
"largest_tables": [{"name": "miners", "total_bytes": 8192}],
},
"integrity": {
"miners_without_asset_id": 1, "unmapped_miners": 1,
"miners_in_multiple_positions": 0, "duplicate_current_mac_groups": 0,
"unscoped_legacy_positions": 1, "expected_mac_mismatches": 1,
"occupied_positions": 2, "empty_positions": 1,
"active_modular_repairs": 1, "duplicate_active_repair_groups": 0,
"legacy_repair_only_miners": 0,
"lifecycle_repair_without_active_repair": 0,
"active_repair_lifecycle_mismatches": 0,
"waiting_placement_records": 1,
},
}
class FakeRepository:
def __init__(self, payload=None, error=None):
self.payload = payload or database_payload()
self.error = error
self.calls = 0
def read_overview(self):
self.calls += 1
if self.error:
raise self.error
return self.payload
class FakeRedis:
def __init__(self, available=True):
self.available = available
self.calls = 0
def ping(self):
self.calls += 1
return self.available
def metadata(head=EXPECTED_HEAD):
return ApplicationMetadata(
environment="test", build_commit=None, build_version="0.1-test",
expected_migration_head=head,
)
class SystemHealthServiceTests(unittest.TestCase):
def test_builds_typed_factual_overview_without_health_score(self):
repository, redis = FakeRepository(), FakeRedis()
result = SystemHealthService(repository, redis, metadata()).get_overview()
self.assertEqual(result.data.postgresql.migration.state, "current")
self.assertEqual(result.data.postgresql.telemetry.snapshot_count, 5)
self.assertEqual(result.data.postgresql.fleet.unmapped_miners, 1)
self.assertFalse(result.data.postgresql.retention.raw_retention_enabled)
self.assertEqual(result.data.postgresql.retention.hourly.population, "manual")
self.assertEqual(result.data.postgresql.retention.completeness, "not_guaranteed")
self.assertIsNone(result.data.application.build_commit)
self.assertFalse(result.meta.partial)
self.assertEqual((repository.calls, redis.calls), (1, 1))
self.assertNotIn("score", result.model_dump_json().lower())
def test_migration_mismatch_is_factual(self):
result = SystemHealthService(
FakeRepository(database_payload("0013_control_board_replacement")),
FakeRedis(), metadata(),
).get_overview()
self.assertEqual(result.data.postgresql.migration.state, "mismatch")
self.assertEqual(
result.data.postgresql.migration.current_revision,
"0013_control_board_replacement",
)
def test_postgresql_failure_is_sanitized_and_redis_remains_available(self):
secret = "postgresql://user:password@private-host/minerops"
result = SystemHealthService(
FakeRepository(error=RuntimeError(secret)), FakeRedis(), metadata()
).get_overview()
self.assertTrue(result.meta.partial)
self.assertEqual(result.meta.unavailable_sections, ["postgresql"])
self.assertEqual(result.data.postgresql.status, "unavailable")
self.assertEqual(result.data.redis.status, "available")
self.assertNotIn(secret, result.model_dump_json())
def test_redis_failure_preserves_database_diagnostics(self):
result = SystemHealthService(
FakeRepository(), FakeRedis(False), metadata()
).get_overview()
self.assertEqual(result.data.postgresql.status, "available")
self.assertEqual(result.data.redis.status, "unavailable")
self.assertEqual(result.meta.unavailable_sections, ["redis"])
class StubService:
def get_overview(self):
return SystemHealthService(
FakeRepository(), FakeRedis(), metadata()
).get_overview()
class SystemHealthRouterTests(unittest.TestCase):
def setUp(self):
self.app = FastAPI()
self.app.include_router(api_router)
self.app.dependency_overrides[get_system_health_service] = StubService
self.client = TestClient(self.app)
def tearDown(self):
self.client.close()
def authenticate(self, permissions):
self.app.dependency_overrides[get_current_user] = lambda: {
"id": str(uuid4()), "role": "Custom", "permissions": list(permissions)
}
def test_requires_authentication_and_system_health_permission(self):
self.assertEqual(self.client.get("/api/system/health-summary").status_code, 401)
self.authenticate(("dashboard.view",))
self.assertEqual(self.client.get("/api/system/health-summary").status_code, 403)
def test_returns_typed_no_store_envelope(self):
self.authenticate(("system_health.view",))
response = self.client.get("/api/system/health-summary")
self.assertEqual(response.status_code, 200)
self.assertEqual(response.headers["cache-control"], "no-store")
payload = response.json()
self.assertEqual(payload["data"]["postgresql"]["status"], "available")
self.assertEqual(payload["meta"]["postgresql_statement_count"], 3)
self.assertIsNone(payload["error"])
class CountingCursor(psycopg.Cursor):
statements = 0
def execute(self, query, params=None, *, prepare=None, binary=None):
type(self).statements += 1
return super().execute(
query, params, prepare=prepare, binary=binary
)
class SystemHealthRepositoryIntegrationTests(unittest.TestCase):
def setUp(self):
self.connection = psycopg.connect(
host=settings.postgres_host, port=settings.postgres_port,
dbname=settings.postgres_db, user=settings.postgres_user,
password=settings.postgres_password, cursor_factory=CountingCursor,
)
CountingCursor.statements = 0
self.repository = SystemHealthRepository(connection=self.connection)
def tearDown(self):
self.connection.rollback()
self.connection.close()
def test_real_postgresql_overview_uses_exactly_three_statements(self):
site_id, room_id, mapped_id, unmapped_id = (
uuid4(), uuid4(), uuid4(), uuid4()
)
suffix = uuid4().hex[:10]
with self.connection.cursor() as cur:
cur.execute("INSERT INTO sites (id, name) VALUES (%s, %s)",
(site_id, "Health Site " + suffix))
cur.execute("INSERT INTO rooms (id, site_id, name) VALUES (%s, %s, %s)",
(room_id, site_id, "Health Room " + suffix))
cur.execute(
"INSERT INTO miners (id, asset_tag, lifecycle_status, current_mac) "
"VALUES (%s, %s, 'active', %s), (%s, NULL, 'active', NULL)",
(mapped_id, "HEALTH-" + suffix, "02:00:00:00:00:01", unmapped_id),
)
cur.execute(
"INSERT INTO location_positions "
"(room_id, room_name, rack_name, shelf_name, position_index, "
"miner_id, expected_mac) VALUES (%s, %s, %s, '1', 1, %s, %s), "
"(NULL, %s, %s, '1', 2, NULL, NULL)",
(room_id, "Health Room " + suffix, "Rack " + suffix, mapped_id,
"02:00:00:00:00:02", "Legacy " + suffix, "Rack " + suffix),
)
cur.execute(
"INSERT INTO miner_status_snapshots (miner_id, observed_at, mhs_av) "
"VALUES (%s, %s, 0)",
(mapped_id, datetime(2026, 8, 19, 12, tzinfo=timezone.utc)),
)
CountingCursor.statements = 0
result = self.repository.read_overview()
self.assertEqual(CountingCursor.statements, 3)
self.assertGreaterEqual(result["operations"]["miners"], 2)
self.assertGreaterEqual(result["operations"]["snapshot_count"], 1)
self.assertEqual(result["migration"]["current_revision"], EXPECTED_HEAD)
self.assertGreaterEqual(result["integrity"]["unmapped_miners"], 1)
self.assertGreaterEqual(result["integrity"]["unscoped_legacy_positions"], 1)
self.assertGreaterEqual(result["integrity"]["expected_mac_mismatches"], 1)
self.assertTrue(result["operations"]["hourly_present"])
self.assertTrue(result["operations"]["daily_present"])
def test_existing_role_matrix_preserves_read_only_grant(self):
with self.connection.cursor() as cur:
cur.execute(
"SELECT roles.name FROM role_permissions "
"JOIN roles ON roles.id = role_permissions.role_id "
"JOIN permissions ON permissions.id = role_permissions.permission_id "
"WHERE permissions.key = 'system_health.view' ORDER BY roles.name"
)
roles = [row[0] for row in cur.fetchall()]
self.assertEqual(roles, ["Admin", "Manager", "Read Only"])
class SystemHealthFrontendAndArchitectureTests(unittest.TestCase):
def test_page_is_semantic_safe_and_one_request(self):
app = FastAPI()
app.include_router(frontend_router)
app.dependency_overrides[get_current_user] = lambda: {
"id": str(uuid4()), "display_name": "Health <Operator>",
"role": "Manager", "permissions": ["system_health.view"],
}
client = TestClient(app)
response = client.get("/system-health")
self.assertEqual(response.status_code, 200)
self.assertIn("System Health | MinerOps", response.text)
self.assertNotIn("Health <Operator>", response.text)
self.assertIn("aria-live=\"polite\"", response.text)
client.close()
script = (APP_ROOT / "frontend/static/system-health.js").read_text()
self.assertEqual(script.count('fetch("/api/system/health-summary"'), 1)
self.assertNotIn("setInterval", script)
self.assertNotIn("innerHTML", script)
self.assertIn("textContent", script)
def test_routes_are_unique_and_legacy_source_diagnostics_are_removed(self):
source = (APP_ROOT / "main.py").read_text()
self.assertNotIn("source_lines", source)
self.assertNotIn("recent_patch_markers", source)
from app.main import app
page = [r for r in app.routes if getattr(r, "path", None) == "/system-health"]
api = [r for r in app.routes if getattr(r, "path", None) == "/api/system/health-summary"]
self.assertEqual(len(page), 1)
self.assertEqual(len(api), 1)
self.assertEqual(page[0].methods, {"GET"})
self.assertEqual(api[0].methods, {"GET"})
def test_layers_and_security_boundaries(self):
router_source = (APP_ROOT / "system_health/router.py").read_text()
service_source = (APP_ROOT / "system_health/service.py").read_text()
repository_source = (APP_ROOT / "system_health/repository.py").read_text()
ast.parse(router_source)
ast.parse(service_source)
self.assertNotIn("SELECT ", router_source)
self.assertNotIn("SELECT ", service_source)
self.assertNotIn("fastapi", repository_source.lower())
self.assertNotIn("fastapi", service_source.lower())
static = "\n".join(
(APP_ROOT / path).read_text()
for path in (
"frontend/static/system-health.js",
"frontend/static/system-health.css",
)
).lower()
for forbidden in (
"postgres_password", "redis_url", "jwt_secret", "connection string",
"stack trace", "password hash", "api key",
):
self.assertNotIn(forbidden, static)
if __name__ == "__main__":
unittest.main()