Files
monlet/server/tests/test_heartbeat.py
2026-05-27 11:01:27 +04:00

72 lines
2.5 KiB
Python

import pytest
from sqlalchemy import select
from monlet_server.models import Agent
from ._helpers import make_heartbeat
@pytest.mark.asyncio
async def test_heartbeat_creates_agent(app_client, auth_headers, session):
r = await app_client.post("/api/v1/heartbeat", json=make_heartbeat(), headers=auth_headers)
assert r.status_code == 202
res = await session.execute(select(Agent).where(Agent.agent_id == "agent-1"))
a = res.scalar_one()
assert a.hostname == "host-1"
assert a.status == "alive"
@pytest.mark.asyncio
async def test_heartbeat_upsert(app_client, auth_headers, session):
await app_client.post("/api/v1/heartbeat", json=make_heartbeat(), headers=auth_headers)
hb = make_heartbeat()
hb["features"] = {"push": True, "metrics": False}
await app_client.post("/api/v1/heartbeat", json=hb, headers=auth_headers)
res = await session.execute(select(Agent).where(Agent.agent_id == "agent-1"))
a = res.scalar_one()
assert a.features == {"push": True, "metrics": False}
@pytest.mark.asyncio
async def test_heartbeat_validation_400(app_client, auth_headers):
r = await app_client.post(
"/api/v1/heartbeat",
json={
"agent_id": "bad id!",
"observed_at": "x",
"hostname": "h",
"features": {"push": True, "metrics": False},
},
headers=auth_headers,
)
assert r.status_code == 400
assert r.json()["error"]["code"] == "validation"
@pytest.mark.asyncio
@pytest.mark.parametrize("observed_at", ["2026-05-27T09:00:00", "2026-05-27T09:00:00+04:00"])
async def test_heartbeat_requires_utc_timestamp(app_client, auth_headers, observed_at):
hb = make_heartbeat()
hb["observed_at"] = observed_at
r = await app_client.post("/api/v1/heartbeat", json=hb, headers=auth_headers)
assert r.status_code == 400
assert r.json()["error"]["code"] == "validation"
@pytest.mark.asyncio
async def test_heartbeat_rejects_extra_fields(app_client, auth_headers):
hb = make_heartbeat()
hb["mode"] = "hybrid"
r = await app_client.post("/api/v1/heartbeat", json=hb, headers=auth_headers)
assert r.status_code == 400
assert r.json()["error"]["code"] == "validation"
@pytest.mark.asyncio
async def test_heartbeat_rejects_sensitive_label_keys(app_client, auth_headers):
hb = make_heartbeat()
hb["labels"] = {"api_key": "secret"}
r = await app_client.post("/api/v1/heartbeat", json=hb, headers=auth_headers)
assert r.status_code == 400
assert r.json()["error"]["code"] == "validation"