136 lines
4.1 KiB
Python
136 lines
4.1 KiB
Python
|
|
"""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
|