"""Per-server metric samples, offline segments, and API.""" from datetime import datetime, timedelta, timezone import pytest from server.utils.server_metrics import ( merge_offline_segments, parse_system_info_metrics, sample_from_redis_heartbeat, ) def test_parse_system_info_metrics(): cpu, mem = parse_system_info_metrics({"cpu_usage": 12.4, "mem_usage": 55.6}) assert cpu == 12 assert mem == 56 def test_sample_from_redis_online(): is_online, cpu, mem = sample_from_redis_heartbeat( {"is_online": "True", "system_info": '{"cpu_usage": 20, "mem_usage": 30}'} ) assert is_online is True assert cpu == 20 assert mem == 30 def test_sample_from_redis_offline(): is_online, cpu, mem = sample_from_redis_heartbeat( {"is_online": "False", "system_info": '{"cpu_usage": 99, "mem_usage": 99}'} ) assert is_online is False assert cpu is None assert mem is None def test_merge_offline_segments(): points = [ {"recorded_at": "2026-06-09 10:00:00", "is_online": True}, {"recorded_at": "2026-06-09 10:10:00", "is_online": False}, {"recorded_at": "2026-06-09 10:20:00", "is_online": False}, {"recorded_at": "2026-06-09 10:30:00", "is_online": True}, ] segs = merge_offline_segments(points) assert len(segs) == 1 assert segs[0]["from"] == "2026-06-09 10:10:00" assert segs[0]["to"] == "2026-06-09 10:20:00" def test_merge_offline_segments_trailing_offline(): points = [ {"recorded_at": "2026-06-09 10:00:00", "is_online": True}, {"recorded_at": "2026-06-09 10:10:00", "is_online": False}, ] segs = merge_offline_segments(points) assert len(segs) == 1 assert segs[0]["to"] == "2026-06-09 10:10:00" @pytest.mark.asyncio async def test_server_metrics_api(db_session, test_admin): from server.api.servers import get_server_metrics from server.application.services.server_service import ServerService from server.infrastructure.database.server_metric_repo import ServerMetricRepositoryImpl from server.infrastructure.database.server_repo import ServerRepositoryImpl from server.infrastructure.database.sync_log_repo import SyncLogRepositoryImpl from server.domain.models import Server server = Server( name="metric-test", domain="metric.example.com", port=22, agent_version="1.0.0", ) db_session.add(server) await db_session.flush() repo = ServerMetricRepositoryImpl(db_session) now = datetime.now(timezone.utc) await repo.insert_sample( server_id=server.id, recorded_at=now - timedelta(minutes=20), is_online=True, cpu_pct=10, mem_pct=20, ) await repo.insert_sample( server_id=server.id, recorded_at=now - timedelta(minutes=10), is_online=False, cpu_pct=None, mem_pct=None, ) await db_session.commit() service = ServerService( ServerRepositoryImpl(db_session), SyncLogRepositoryImpl(db_session), ) body = await get_server_metrics( id=server.id, hours=24, admin=test_admin["admin"], service=service, db=db_session, ) assert body["server_id"] == server.id assert body["hours"] == 24 assert body["interval_minutes"] == 10 assert len(body["points"]) >= 2 assert len(body["offline_segments"]) >= 1 @pytest.mark.asyncio async def test_server_metrics_api_not_found(db_session, test_admin): from server.api.servers import get_server_metrics from server.application.services.server_service import ServerService from server.infrastructure.database.server_repo import ServerRepositoryImpl from server.infrastructure.database.sync_log_repo import SyncLogRepositoryImpl from fastapi import HTTPException service = ServerService( ServerRepositoryImpl(db_session), SyncLogRepositoryImpl(db_session), ) with pytest.raises(HTTPException) as exc: await get_server_metrics( id=999999, hours=24, admin=test_admin["admin"], service=service, db=db_session, ) assert exc.value.status_code == 404