Harden live material polling state
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
from datetime import UTC, datetime
|
||||
from unittest.mock import Mock
|
||||
|
||||
import pytest
|
||||
|
||||
from production_analytics.enlyze.gateway import EnlyzeApiGateway
|
||||
|
||||
|
||||
@@ -131,3 +133,72 @@ def test_get_material_samples_uses_column_names_not_fixed_positions() -> None:
|
||||
|
||||
assert samples[0].material_rate_kg_per_hour == 1028.5
|
||||
assert samples[0].gate_value == 2.1
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def timeseries():
|
||||
client = Mock()
|
||||
client.post_json.return_value.body = {"data": {
|
||||
"columns": ["time", "rate", "gate"], "records": [],
|
||||
}}
|
||||
args = dict(machine_id="m", rate_variable_id="rate", gate_variable_id="gate",
|
||||
start=datetime(2026, 9, 3, tzinfo=UTC), end=datetime(2026, 9, 4, tzinfo=UTC))
|
||||
return EnlyzeApiGateway(client), client, args
|
||||
|
||||
|
||||
@pytest.mark.parametrize("name", ["start", "end"])
|
||||
def test_naive_window_rejected(timeseries, name) -> None:
|
||||
gateway, client, args = timeseries
|
||||
args[name] = args[name].replace(tzinfo=None)
|
||||
with pytest.raises(ValueError, match="timezone-aware"):
|
||||
gateway.get_material_samples(**args)
|
||||
client.post_json.assert_not_called()
|
||||
|
||||
|
||||
def test_reversed_window_rejected(timeseries) -> None:
|
||||
gateway, client, args = timeseries
|
||||
args["start"], args["end"] = args["end"], args["start"]
|
||||
with pytest.raises(ValueError, match="precede"):
|
||||
gateway.get_material_samples(**args)
|
||||
client.post_json.assert_not_called()
|
||||
|
||||
|
||||
def test_empty_timeseries(timeseries) -> None:
|
||||
gateway, client, args = timeseries
|
||||
assert gateway.get_material_samples(**args) == []
|
||||
|
||||
|
||||
@pytest.mark.parametrize("column", ["time", "rate", "gate"])
|
||||
def test_missing_required_column(timeseries, column) -> None:
|
||||
gateway, client, args = timeseries
|
||||
client.post_json.return_value.body["data"]["columns"].remove(column)
|
||||
with pytest.raises(ValueError, match="required column"):
|
||||
gateway.get_material_samples(**args)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("record", [[], {}, ["bad", 1, 1], [None, 1, 1],
|
||||
["2026-09-03T00:00:00", 1, 1], ["2026-09-03T00:00:00Z", None, 1],
|
||||
["2026-09-03T00:00:00Z", 1, float("inf")], ["2026-09-03T00:00:00Z", True, 1]])
|
||||
def test_malformed_records_fail_clearly(timeseries, record) -> None:
|
||||
gateway, client, args = timeseries
|
||||
client.post_json.return_value.body["data"]["records"] = [record]
|
||||
with pytest.raises(ValueError, match="malformed record 0"):
|
||||
gateway.get_material_samples(**args)
|
||||
|
||||
|
||||
def test_multiple_open_runs_rejected() -> None:
|
||||
client = Mock()
|
||||
run = dict(uuid="r", machine="m", production_order="o", start="2026-09-03T00:00:00Z",
|
||||
end=None)
|
||||
client.get.return_value.body = {"data": [run, {**run, "uuid": "r2"}]}
|
||||
with pytest.raises(ValueError, match="multiple open Production Runs"):
|
||||
EnlyzeApiGateway(client).get_open_production_run("m")
|
||||
|
||||
|
||||
@pytest.mark.parametrize("item", [{}, None, {"end": None},
|
||||
dict(uuid="r", machine="m", production_order="o", start="bad", end=None)])
|
||||
def test_malformed_run_fails_clearly(item) -> None:
|
||||
client = Mock()
|
||||
client.get.return_value.body = {"data": [item]}
|
||||
with pytest.raises(ValueError, match="Invalid production-run response"):
|
||||
EnlyzeApiGateway(client).get_open_production_run("m")
|
||||
|
||||
Reference in New Issue
Block a user