initial commit
This commit is contained in:
140
tests/test_discovery.py
Normal file
140
tests/test_discovery.py
Normal file
@@ -0,0 +1,140 @@
|
||||
"""Unit tests for the hameter.discovery module."""
|
||||
|
||||
import threading
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
from hameter.discovery import run_discovery_for_web
|
||||
from hameter.config import GeneralConfig
|
||||
from hameter.state import AppState, PipelineStatus
|
||||
|
||||
|
||||
VALID_LINE_1 = '{"Time":"2026-03-05T10:00:00Z","Type":"SCM","Message":{"ID":12345,"Consumption":50000}}'
|
||||
VALID_LINE_2 = '{"Time":"2026-03-05T10:00:05Z","Type":"SCM","Message":{"ID":67890,"Consumption":12000}}'
|
||||
VALID_LINE_3 = '{"Time":"2026-03-05T10:00:10Z","Type":"SCM","Message":{"ID":12345,"Consumption":50100}}'
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def config():
|
||||
return GeneralConfig()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def shutdown_event():
|
||||
return threading.Event()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def app_state():
|
||||
return AppState()
|
||||
|
||||
|
||||
@patch("hameter.discovery.SubprocessManager")
|
||||
def test_run_discovery_for_web_records_results(
|
||||
mock_spm_cls, config, shutdown_event, app_state
|
||||
):
|
||||
"""Parsed meter readings are recorded via app_state."""
|
||||
mock_proc = MagicMock()
|
||||
mock_spm_cls.return_value = mock_proc
|
||||
mock_proc.start_discovery_mode.return_value = True
|
||||
|
||||
calls = [0]
|
||||
|
||||
def get_line(timeout=1.0):
|
||||
calls[0] += 1
|
||||
lines = [VALID_LINE_1, VALID_LINE_2, VALID_LINE_3]
|
||||
if calls[0] <= len(lines):
|
||||
return lines[calls[0] - 1]
|
||||
shutdown_event.set()
|
||||
return None
|
||||
|
||||
mock_proc.get_line.side_effect = get_line
|
||||
|
||||
run_discovery_for_web(
|
||||
config, shutdown_event, app_state,
|
||||
duration=300, stop_event=None,
|
||||
)
|
||||
|
||||
results = app_state.get_discovery_results()
|
||||
assert 12345 in results
|
||||
assert 67890 in results
|
||||
assert results[12345]["count"] >= 2
|
||||
mock_proc.stop.assert_called_once()
|
||||
|
||||
|
||||
@patch("hameter.discovery.SubprocessManager")
|
||||
def test_run_discovery_for_web_start_failure(
|
||||
mock_spm_cls, config, shutdown_event, app_state
|
||||
):
|
||||
"""Start failure sets ERROR status."""
|
||||
mock_proc = MagicMock()
|
||||
mock_spm_cls.return_value = mock_proc
|
||||
mock_proc.start_discovery_mode.return_value = False
|
||||
|
||||
run_discovery_for_web(
|
||||
config, shutdown_event, app_state,
|
||||
duration=120, stop_event=None,
|
||||
)
|
||||
|
||||
assert app_state.status == PipelineStatus.ERROR
|
||||
mock_proc.get_line.assert_not_called()
|
||||
|
||||
|
||||
@patch("hameter.discovery.SubprocessManager")
|
||||
def test_run_discovery_for_web_respects_stop_event(
|
||||
mock_spm_cls, config, shutdown_event, app_state
|
||||
):
|
||||
"""stop_event causes early exit."""
|
||||
mock_proc = MagicMock()
|
||||
mock_spm_cls.return_value = mock_proc
|
||||
mock_proc.start_discovery_mode.return_value = True
|
||||
|
||||
stop_event = threading.Event()
|
||||
stop_event.set()
|
||||
|
||||
mock_proc.get_line.return_value = VALID_LINE_1
|
||||
|
||||
run_discovery_for_web(
|
||||
config, shutdown_event, app_state,
|
||||
duration=300, stop_event=stop_event,
|
||||
)
|
||||
|
||||
mock_proc.stop.assert_called_once()
|
||||
|
||||
|
||||
@patch("hameter.discovery.SubprocessManager")
|
||||
def test_run_discovery_for_web_handles_invalid_json(
|
||||
mock_spm_cls, config, shutdown_event, app_state
|
||||
):
|
||||
"""Invalid lines are skipped without crashing."""
|
||||
mock_proc = MagicMock()
|
||||
mock_spm_cls.return_value = mock_proc
|
||||
mock_proc.start_discovery_mode.return_value = True
|
||||
|
||||
calls = [0]
|
||||
lines = [
|
||||
"not json",
|
||||
"{malformed{{",
|
||||
"",
|
||||
VALID_LINE_1,
|
||||
]
|
||||
|
||||
def get_line(timeout=1.0):
|
||||
calls[0] += 1
|
||||
if calls[0] <= len(lines):
|
||||
return lines[calls[0] - 1]
|
||||
shutdown_event.set()
|
||||
return None
|
||||
|
||||
mock_proc.get_line.side_effect = get_line
|
||||
|
||||
run_discovery_for_web(
|
||||
config, shutdown_event, app_state,
|
||||
duration=300, stop_event=None,
|
||||
)
|
||||
|
||||
results = app_state.get_discovery_results()
|
||||
assert 12345 in results
|
||||
assert len(results) == 1
|
||||
mock_proc.stop.assert_called_once()
|
||||
Reference in New Issue
Block a user