149 lines
4.4 KiB
Python
149 lines
4.4 KiB
Python
import asyncio
|
|
from datetime import datetime, timezone
|
|
from unittest.mock import AsyncMock
|
|
|
|
import pytest
|
|
from fastapi import HTTPException
|
|
|
|
from app.api.v1.endpoints.timeseries import scada as scada_endpoint
|
|
|
|
|
|
def _reading(device_id: str) -> scada_endpoint.ScadaReadingBatchItem:
|
|
return scada_endpoint.ScadaReadingBatchItem(
|
|
time=datetime(2026, 8, 27, tzinfo=timezone.utc),
|
|
device_id=device_id,
|
|
monitored_value=12.5,
|
|
)
|
|
|
|
|
|
def test_scada_batch_rejects_devices_missing_from_bizdb(monkeypatch):
|
|
monkeypatch.setattr(
|
|
scada_endpoint.ScadaInfoRepository,
|
|
"get_existing_device_ids",
|
|
AsyncMock(return_value={"known"}),
|
|
)
|
|
insert = AsyncMock()
|
|
monkeypatch.setattr(scada_endpoint.ScadaRepository, "insert_scada_batch", insert)
|
|
|
|
with pytest.raises(HTTPException, match="missing") as exc_info:
|
|
asyncio.run(
|
|
scada_endpoint.insert_scada_data(
|
|
[_reading("known"), _reading("missing")],
|
|
conn=object(),
|
|
postgres_conn=object(),
|
|
)
|
|
)
|
|
|
|
assert exc_info.value.status_code == 422
|
|
insert.assert_not_awaited()
|
|
|
|
|
|
def test_scada_batch_writes_only_after_bizdb_validation(monkeypatch):
|
|
monkeypatch.setattr(
|
|
scada_endpoint.ScadaInfoRepository,
|
|
"get_existing_device_ids",
|
|
AsyncMock(return_value={"known"}),
|
|
)
|
|
insert = AsyncMock()
|
|
monkeypatch.setattr(scada_endpoint.ScadaRepository, "insert_scada_batch", insert)
|
|
|
|
result = asyncio.run(
|
|
scada_endpoint.insert_scada_data(
|
|
[_reading(" known ")],
|
|
conn=object(),
|
|
postgres_conn=object(),
|
|
)
|
|
)
|
|
|
|
assert result == {"message": "Inserted 1 records"}
|
|
assert insert.await_args.args[1][0]["device_id"] == "known"
|
|
|
|
|
|
def test_latest_scada_readings_join_device_metadata_with_latest_rows(monkeypatch):
|
|
observed_at = datetime(2026, 10, 22, 1, 2, tzinfo=timezone.utc)
|
|
monkeypatch.setattr(
|
|
scada_endpoint.ScadaInfoRepository,
|
|
"get_scadas",
|
|
AsyncMock(return_value=[
|
|
{
|
|
"device_id": "PRESSURE-1",
|
|
"device_type": "pressure",
|
|
"measurement_unit": "MPa",
|
|
"transmission_mode": "realtime",
|
|
"transmission_frequency": "15min",
|
|
},
|
|
{
|
|
"device_id": "FLOW-2",
|
|
"device_type": "pipe_flow",
|
|
"measurement_unit": "m3/h",
|
|
"transmission_mode": "realtime",
|
|
"transmission_frequency": "15min",
|
|
},
|
|
]),
|
|
)
|
|
latest = AsyncMock(return_value={
|
|
"PRESSURE-1": {
|
|
"time": observed_at,
|
|
"device_id": "PRESSURE-1",
|
|
"monitored_value": 0.31,
|
|
"cleaned_value": 0.3,
|
|
}
|
|
})
|
|
monkeypatch.setattr(
|
|
scada_endpoint.ScadaRepository,
|
|
"get_latest_scada_readings",
|
|
latest,
|
|
)
|
|
|
|
result = asyncio.run(
|
|
scada_endpoint.get_latest_scada_readings(
|
|
limit=100,
|
|
offset=0,
|
|
conn=object(),
|
|
postgres_conn=object(),
|
|
)
|
|
)
|
|
|
|
assert result.total == 2
|
|
assert result.observed_count == 1
|
|
assert result.latest_observed_at == observed_at
|
|
assert result.items[0].monitored_value == pytest.approx(0.31)
|
|
assert result.items[1].observed_at is None
|
|
assert latest.await_args.args[1] == ["PRESSURE-1", "FLOW-2"]
|
|
|
|
|
|
def test_latest_scada_readings_applies_device_page_before_timeseries_query(monkeypatch):
|
|
monkeypatch.setattr(
|
|
scada_endpoint.ScadaInfoRepository,
|
|
"get_scadas",
|
|
AsyncMock(return_value=[
|
|
{
|
|
"device_id": f"D-{index}",
|
|
"device_type": "pressure",
|
|
"measurement_unit": "MPa",
|
|
"transmission_mode": "realtime",
|
|
"transmission_frequency": "15min",
|
|
}
|
|
for index in range(4)
|
|
]),
|
|
)
|
|
latest = AsyncMock(return_value={})
|
|
monkeypatch.setattr(
|
|
scada_endpoint.ScadaRepository,
|
|
"get_latest_scada_readings",
|
|
latest,
|
|
)
|
|
|
|
result = asyncio.run(
|
|
scada_endpoint.get_latest_scada_readings(
|
|
limit=2,
|
|
offset=1,
|
|
conn=object(),
|
|
postgres_conn=object(),
|
|
)
|
|
)
|
|
|
|
assert result.total == 4
|
|
assert [item.device_id for item in result.items] == ["D-1", "D-2"]
|
|
assert latest.await_args.args[1] == ["D-1", "D-2"]
|