Files
intercept/tests/test_wefax_scheduler.py
T
James Smith 96172ca593 style: apply ruff-format to entire codebase
First-time run of ruff-format via pre-commit hook normalises quote
style, trailing commas, and whitespace across 188 Python files.
No logic changes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-05 14:48:11 +01:00

172 lines
5.7 KiB
Python

"""Tests for WeFax auto-scheduler behavior and regressions."""
from __future__ import annotations
from datetime import datetime, timedelta, timezone
from unittest.mock import MagicMock, patch
from utils.wefax_scheduler import ScheduledBroadcast, WeFaxScheduler
class TestWeFaxScheduler:
"""WeFaxScheduler regression tests."""
@patch("threading.Timer")
def test_refresh_reschedules_same_utc_slot_next_day(self, mock_timer):
"""Completed broadcasts must not block the next day's same UTC slot."""
scheduler = WeFaxScheduler()
scheduler._enabled = True
scheduler._station = "USCG Kodiak"
scheduler._callsign = "NOJ"
scheduler._frequency_khz = 4298.0
now = datetime.now(timezone.utc)
utc_time = (now - timedelta(hours=2)).strftime("%H:%M")
today = now.date().isoformat()
prior = ScheduledBroadcast(
station="USCG Kodiak",
callsign="NOJ",
frequency_khz=4298.0,
utc_time=utc_time,
duration_min=20,
content="Chart",
occurrence_date=today,
)
prior.status = "complete"
scheduler._broadcasts = [prior]
mock_timer.return_value = MagicMock()
with patch(
"utils.wefax_scheduler.get_station",
return_value={
"name": "USCG Kodiak",
"schedule": [
{
"utc": utc_time,
"duration_min": 20,
"content": "Chart",
}
],
},
):
scheduler._refresh_schedule()
capture_calls = [
c
for c in mock_timer.call_args_list
if len(c.args) >= 2 and getattr(c.args[1], "__name__", "") == "_execute_capture"
]
assert capture_calls, "Expected a capture timer for the next-day occurrence"
scheduled = [b for b in scheduler._broadcasts if b.status == "scheduled"]
assert len(scheduled) == 1
assert scheduled[0].occurrence_date != today
def test_execute_capture_stops_immediately_if_window_elapsed(self):
"""If stop delay computes to <= 0, capture should close out immediately."""
scheduler = WeFaxScheduler()
scheduler._enabled = True
scheduler._callsign = "NOJ"
scheduler._frequency_khz = 4298.0
scheduler._device = 0
scheduler._gain = 40.0
scheduler._ioc = 576
scheduler._lpm = 120
scheduler._direct_sampling = True
now = datetime.now(timezone.utc)
sb = ScheduledBroadcast(
station="USCG Kodiak",
callsign="NOJ",
frequency_khz=4298.0,
utc_time=now.strftime("%H:%M"),
duration_min=0,
content="Late chart",
occurrence_date=now.date().isoformat(),
)
sb.status = "scheduled"
mock_decoder = MagicMock()
mock_decoder.is_running = False
mock_decoder.start.return_value = True
with (
patch("utils.wefax_scheduler.get_wefax_decoder", return_value=mock_decoder),
patch("utils.wefax_scheduler.WEFAX_CAPTURE_BUFFER_SECONDS", 0),
patch("app.claim_sdr_device", return_value=None),
patch.object(scheduler, "_stop_capture") as mock_stop_capture,
):
scheduler._execute_capture_inner(sb)
mock_stop_capture.assert_called_once()
@patch("threading.Timer")
def test_terminal_progress_releases_scheduler_device_early(self, mock_timer):
"""Scheduler captures must release SDR as soon as terminal progress arrives."""
scheduler = WeFaxScheduler()
scheduler._enabled = True
scheduler._callsign = "NOJ"
scheduler._frequency_khz = 4298.0
scheduler._device = 0
scheduler._gain = 40.0
scheduler._ioc = 576
scheduler._lpm = 120
scheduler._direct_sampling = True
sb = ScheduledBroadcast(
station="USCG Kodiak",
callsign="NOJ",
frequency_khz=4298.0,
utc_time="12:00",
duration_min=20,
content="Chart",
occurrence_date="2026-01-01",
)
sb.status = "scheduled"
mock_decoder = MagicMock()
mock_decoder.is_running = False
mock_decoder.start.return_value = True
mock_timer.return_value = MagicMock()
with (
patch("utils.wefax_scheduler.get_wefax_decoder", return_value=mock_decoder),
patch("app.claim_sdr_device", return_value=None),
patch("app.release_sdr_device") as mock_release,
):
scheduler._execute_capture_inner(sb)
progress_cb = mock_decoder.set_callback.call_args[0][0]
progress_cb(
{
"type": "wefax_progress",
"status": "error",
"message": "rtl_fm failed",
}
)
mock_release.assert_called_once_with(0)
assert sb.status == "skipped"
def test_stop_capture_non_capturing_only_releases(self):
"""_stop_capture should be idempotent when capture already ended."""
scheduler = WeFaxScheduler()
sb = ScheduledBroadcast(
station="USCG Kodiak",
callsign="NOJ",
frequency_khz=4298.0,
utc_time="12:00",
duration_min=20,
content="Chart",
occurrence_date="2026-01-01",
)
sb.status = "complete"
release_fn = MagicMock()
with patch("utils.wefax_scheduler.get_wefax_decoder") as mock_get_decoder:
scheduler._stop_capture(sb, release_fn)
release_fn.assert_called_once()
mock_get_decoder.assert_not_called()