305 lines
13 KiB
Python
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 = "0017_agent_enrollment"
|
|
|
|
|
|
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()
|