"""Tests for ISS SSTV route behavior.""" from __future__ import annotations import json from unittest.mock import MagicMock, patch import pytest from utils.sstv import ISS_SSTV_FREQ def _login_session(client) -> None: """Mark the Flask test session as authenticated.""" with client.session_transaction() as sess: sess["logged_in"] = True sess["username"] = "test" sess["role"] = "admin" class TestSSTVRoutes: """ISS SSTV route tests.""" def test_status_reports_fm_modulation(self, client): """GET /sstv/status should report the fixed ISS modulation.""" _login_session(client) mock_decoder = MagicMock() mock_decoder.decoder_available = "python-sstv" mock_decoder.is_running = False mock_decoder.get_images.return_value = [] mock_decoder.doppler_enabled = False mock_decoder.last_doppler_info = None with ( patch("routes.sstv.is_sstv_available", return_value=True), patch("routes.sstv.get_sstv_decoder", return_value=mock_decoder), ): response = client.get("/sstv/status") assert response.status_code == 200 data = response.get_json() assert data["available"] is True assert data["modulation"] == "fm" assert data["iss_frequency"] == ISS_SSTV_FREQ def test_start_uses_fm_and_normalizes_supported_iss_frequency(self, client): """POST /sstv/start should enforce FM and snap near ISS values.""" _login_session(client) mock_decoder = MagicMock() mock_decoder.is_running = False mock_decoder.start.return_value = True mock_decoder.doppler_enabled = False mock_decoder.last_doppler_info = None payload = { "frequency": ISS_SSTV_FREQ + 0.02, # Within tolerance; should normalize. "modulation": "FM", "device": 0, } with ( patch("routes.sstv.is_sstv_available", return_value=True), patch("routes.sstv.get_sstv_decoder", return_value=mock_decoder), patch("routes.sstv.app_module.claim_sdr_device", return_value=None), ): response = client.post( "/sstv/start", data=json.dumps(payload), content_type="application/json", ) assert response.status_code == 200 data = response.get_json() assert data["status"] == "started" assert data["modulation"] == "fm" assert data["frequency"] == pytest.approx(ISS_SSTV_FREQ) mock_decoder.start.assert_called_once() call_kwargs = mock_decoder.start.call_args.kwargs assert call_kwargs["modulation"] == "fm" assert call_kwargs["frequency"] == pytest.approx(ISS_SSTV_FREQ) def test_start_rejects_non_fm_modulation(self, client): """POST /sstv/start should reject non-FM modulation requests.""" _login_session(client) mock_decoder = MagicMock() mock_decoder.is_running = False payload = { "frequency": ISS_SSTV_FREQ, "modulation": "usb", "device": 0, } with ( patch("routes.sstv.is_sstv_available", return_value=True), patch("routes.sstv.get_sstv_decoder", return_value=mock_decoder), ): response = client.post( "/sstv/start", data=json.dumps(payload), content_type="application/json", ) assert response.status_code == 400 data = response.get_json() assert data["status"] == "error" assert "Modulation must be fm" in data["message"] mock_decoder.start.assert_not_called() def test_start_rejects_non_iss_frequency(self, client): """POST /sstv/start should reject unsupported non-ISS frequencies.""" _login_session(client) mock_decoder = MagicMock() mock_decoder.is_running = False payload = { "frequency": 14.230, "modulation": "fm", "device": 0, } with ( patch("routes.sstv.is_sstv_available", return_value=True), patch("routes.sstv.get_sstv_decoder", return_value=mock_decoder), ): response = client.post( "/sstv/start", data=json.dumps(payload), content_type="application/json", ) assert response.status_code == 400 data = response.get_json() assert data["status"] == "error" assert "Supported ISS SSTV frequency" in data["message"] mock_decoder.start.assert_not_called()