109 lines
3.4 KiB
Python
109 lines
3.4 KiB
Python
"""
|
|
Tests for the in-memory DeviceStore.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import asyncio
|
|
|
|
import pytest
|
|
|
|
from app.device_store import DeviceStore, SensorReading
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_get_all_devices(store: DeviceStore):
|
|
"""All registered devices are returned."""
|
|
devices = await store.get_all_devices()
|
|
assert len(devices) == 3
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_get_enabled_devices(store: DeviceStore):
|
|
"""Only enabled devices are returned."""
|
|
devices = await store.get_enabled_devices()
|
|
assert len(devices) == 2
|
|
ids = {d.config.id for d in devices}
|
|
assert "test-disabled" not in ids
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_get_device_by_id(store: DeviceStore):
|
|
"""Lookup by device ID."""
|
|
device = await store.get_device("test-plant-01")
|
|
assert device is not None
|
|
assert device.config.name == "Test Plant"
|
|
|
|
missing = await store.get_device("nonexistent")
|
|
assert missing is None
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_get_device_by_ip(store: DeviceStore):
|
|
"""Lookup by IP address."""
|
|
device = await store.get_device_by_ip("192.168.1.100")
|
|
assert device is not None
|
|
assert device.config.id == "test-plant-01"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_update_reading(store: DeviceStore):
|
|
"""Recording a reading updates value and marks device online."""
|
|
await store.update_reading("test-plant-01", "sensors/soil_moisture", 42.5, "percent")
|
|
|
|
device = await store.get_device("test-plant-01")
|
|
assert device.online is True
|
|
assert "sensors/soil_moisture" in device.readings
|
|
assert device.readings["sensors/soil_moisture"].value == 42.5
|
|
assert device.readings["sensors/soil_moisture"].unit == "percent"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_update_reading_unknown_device(store: DeviceStore):
|
|
"""Readings for unknown devices are silently ignored."""
|
|
await store.update_reading("unknown-device", "sensors/x", 99, "unit")
|
|
device = await store.get_device("unknown-device")
|
|
assert device is None
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_mark_offline(store: DeviceStore):
|
|
"""Marking offline sets flag and marks readings stale."""
|
|
await store.update_reading("test-plant-01", "sensors/temperature", 24.0, "celsius")
|
|
await store.mark_offline("test-plant-01")
|
|
|
|
device = await store.get_device("test-plant-01")
|
|
assert device.online is False
|
|
assert device.readings["sensors/temperature"].stale is True
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_mark_online(store: DeviceStore):
|
|
"""Marking online resets the flag."""
|
|
await store.mark_offline("test-plant-01")
|
|
await store.mark_online("test-plant-01")
|
|
|
|
device = await store.get_device("test-plant-01")
|
|
assert device.online is True
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_snapshot(store: DeviceStore):
|
|
"""Snapshot returns a serializable dict of all devices."""
|
|
await store.update_reading("test-plant-01", "sensors/temperature", 23.5, "celsius")
|
|
snap = await store.snapshot()
|
|
|
|
assert "test-plant-01" in snap
|
|
assert snap["test-plant-01"]["readings"]["sensors/temperature"]["value"] == 23.5
|
|
|
|
|
|
def test_sensor_reading_age():
|
|
"""SensorReading.age_seconds returns meaningful values."""
|
|
import time
|
|
|
|
reading = SensorReading(value=42, unit="percent", timestamp=time.time() - 10)
|
|
assert 9.5 < reading.age_seconds() < 11.0
|
|
|
|
stale = SensorReading(value=0, timestamp=0)
|
|
assert stale.age_seconds() == float("inf")
|