diff --git a/app/routers/radio.py b/app/routers/radio.py index 93d8aec..c68f65d 100644 --- a/app/routers/radio.py +++ b/app/routers/radio.py @@ -43,7 +43,10 @@ class RadioConfigUpdate(BaseModel): tx_power: int | None = Field(default=None, description="Transmit power in dBm") radio: RadioSettings | None = None path_hash_mode: int | None = Field( - default=None, description="Path hash mode (0=1-byte, 1=2-byte, 2=3-byte)" + default=None, + ge=0, + le=2, + description="Path hash mode (0=1-byte, 1=2-byte, 2=3-byte)", ) diff --git a/tests/test_radio_router.py b/tests/test_radio_router.py index b3be54f..0e4b0c0 100644 --- a/tests/test_radio_router.py +++ b/tests/test_radio_router.py @@ -7,6 +7,7 @@ from unittest.mock import AsyncMock, MagicMock, patch import pytest from fastapi import HTTPException from meshcore import EventType +from pydantic import ValidationError from app.radio import RadioManager, radio_manager from app.routers.radio import ( @@ -131,6 +132,35 @@ class TestUpdateRadioConfig: mock_sync_time.assert_awaited_once() assert result == expected + def test_model_rejects_negative_path_hash_mode(self): + with pytest.raises(ValidationError): + RadioConfigUpdate(path_hash_mode=-1) + + def test_model_rejects_too_large_path_hash_mode(self): + with pytest.raises(ValidationError): + RadioConfigUpdate(path_hash_mode=3) + + @pytest.mark.asyncio + @pytest.mark.parametrize("path_hash_mode", [-1, 3, 999]) + async def test_endpoint_rejects_invalid_path_hash_mode(self, client, path_hash_mode): + response = await client.patch("/api/radio/config", json={"path_hash_mode": path_hash_mode}) + + assert response.status_code == 422 + + @pytest.mark.asyncio + async def test_rejects_path_hash_mode_when_firmware_does_not_support_it(self): + mc = _mock_meshcore_with_info() + + with ( + patch("app.routers.radio.require_connected", return_value=mc), + patch.object(radio_manager, "_meshcore", mc), + patch.object(radio_manager, "path_hash_mode_supported", False), + ): + with pytest.raises(HTTPException) as exc: + await update_radio_config(RadioConfigUpdate(path_hash_mode=1)) + + assert exc.value.status_code == 400 + class TestPrivateKeyImport: @pytest.mark.asyncio