Files
demeter/server/tests/test_devices_api.py

134 lines
4.7 KiB
Python

"""
Tests for the REST API endpoints.
"""
from __future__ import annotations
import asyncio
import pytest
from fastapi.testclient import TestClient
from app.device_store import DeviceStore
class TestDevicesApi:
"""Tests for /api/devices endpoints."""
def test_list_devices(self, client: TestClient):
"""GET /api/devices returns all devices."""
resp = client.get("/api/devices")
assert resp.status_code == 200
data = resp.json()
assert data["count"] == 3
assert len(data["devices"]) == 3
def test_get_device(self, client: TestClient):
"""GET /api/devices/{id} returns device detail."""
resp = client.get("/api/devices/test-plant-01")
assert resp.status_code == 200
data = resp.json()
assert data["id"] == "test-plant-01"
assert data["name"] == "Test Plant"
def test_get_device_not_found(self, client: TestClient):
"""GET /api/devices/{id} returns 404 for missing device."""
resp = client.get("/api/devices/nonexistent")
assert resp.status_code == 404
def test_get_readings_empty(self, client: TestClient):
"""GET /api/devices/{id}/readings returns empty when no data."""
resp = client.get("/api/devices/test-plant-01/readings")
assert resp.status_code == 200
data = resp.json()
assert data["device_id"] == "test-plant-01"
assert data["readings"] == {}
def test_get_readings_with_data(self, client: TestClient, store: DeviceStore):
"""GET /api/devices/{id}/readings returns stored readings."""
# Populate store
loop = asyncio.get_event_loop()
loop.run_until_complete(
store.update_reading("test-plant-01", "sensors/temperature", 25.0, "celsius")
)
resp = client.get("/api/devices/test-plant-01/readings")
assert resp.status_code == 200
data = resp.json()
assert "sensors/temperature" in data["readings"]
assert data["readings"]["sensors/temperature"]["value"] == 25.0
def test_server_status(self, client: TestClient):
"""GET /api/status returns server info."""
resp = client.get("/api/status")
assert resp.status_code == 200
data = resp.json()
assert data["server"] == "demeter"
assert data["devices_total"] == 3
assert "active_subscriptions" in data
class TestCoapBridge:
"""Tests for /api/devices/{id}/coap/ bridge endpoints."""
def test_coap_get(self, client: TestClient):
"""GET bridge proxies CoAP request and returns response."""
resp = client.get("/api/devices/test-plant-01/coap/sensors/temperature")
assert resp.status_code == 200
data = resp.json()
assert data["device_id"] == "test-plant-01"
assert data["method"] == "GET"
assert "response" in data
def test_coap_get_not_found(self, client: TestClient):
"""GET bridge returns 404 for missing device."""
resp = client.get("/api/devices/missing/coap/sensors/temperature")
assert resp.status_code == 404
def test_coap_put(self, client: TestClient):
"""PUT bridge proxies CoAP request."""
resp = client.put(
"/api/devices/test-plant-01/coap/config/interval",
json={"interval": 10},
)
assert resp.status_code == 200
data = resp.json()
assert data["method"] == "PUT"
class TestMetricsEndpoint:
"""Tests for the /metrics Prometheus endpoint."""
def test_metrics_returns_text(self, client: TestClient):
"""GET /metrics returns Prometheus text format."""
resp = client.get("/metrics")
assert resp.status_code == 200
assert "text/plain" in resp.headers["content-type"]
# Should contain our metric names
assert "demeter_server_info" in resp.text
class TestDashboard:
"""Tests for dashboard HTML routes."""
def test_root_redirects(self, client: TestClient):
"""GET / redirects to /dashboard."""
resp = client.get("/", follow_redirects=False)
assert resp.status_code == 307
assert "/dashboard" in resp.headers["location"]
def test_dashboard_renders(self, client: TestClient):
"""GET /dashboard returns HTML."""
resp = client.get("/dashboard")
assert resp.status_code == 200
assert "text/html" in resp.headers["content-type"]
assert "Demeter" in resp.text
def test_dashboard_api_readings(self, client: TestClient):
"""GET /dashboard/api/readings returns JSON."""
resp = client.get("/dashboard/api/readings")
assert resp.status_code == 200
data = resp.json()
assert "devices" in data
assert "timestamp" in data