From e2ddf5f79fb94f1fa20ead9a3706e4ab7e9d6110 Mon Sep 17 00:00:00 2001 From: Jack Kingsman Date: Fri, 3 Apr 2026 17:37:30 -0700 Subject: [PATCH] Move require connected down into the manager --- app/dependencies.py | 8 --- app/routers/contacts.py | 5 +- app/routers/messages.py | 7 +-- app/routers/radio.py | 13 ++--- app/routers/repeaters.py | 21 ++++--- app/routers/rooms.py | 9 ++- tests/test_ack_tracking_wiring.py | 8 +-- tests/test_api.py | 4 +- tests/test_contacts_router.py | 4 +- tests/test_radio_operation.py | 23 +++----- tests/test_radio_router.py | 54 +++++++++--------- tests/test_repeater_routes.py | 82 +++++++++++++-------------- tests/test_room_routes.py | 10 ++-- tests/test_send_messages.py | 94 +++++++++++++++---------------- 14 files changed, 162 insertions(+), 180 deletions(-) delete mode 100644 app/dependencies.py diff --git a/app/dependencies.py b/app/dependencies.py deleted file mode 100644 index d0f6cc2..0000000 --- a/app/dependencies.py +++ /dev/null @@ -1,8 +0,0 @@ -"""Shared dependencies for FastAPI routers.""" - -from app.services.radio_runtime import radio_runtime as radio_manager - - -def require_connected(): - """Dependency that ensures radio is connected and returns meshcore instance.""" - return radio_manager.require_connected() diff --git a/app/routers/contacts.py b/app/routers/contacts.py index 0ef2a97..e9609fd 100644 --- a/app/routers/contacts.py +++ b/app/routers/contacts.py @@ -8,7 +8,6 @@ from fastapi import APIRouter, BackgroundTasks, HTTPException, Query from meshcore import EventType from pydantic import BaseModel, Field -from app.dependencies import require_connected from app.models import ( Contact, ContactActiveRoom, @@ -428,7 +427,7 @@ async def request_trace(public_key: str) -> TraceResponse: (no intermediate repeaters). This uses TRACE's dedicated width flags rather than the radio's normal path_hash_mode setting. """ - require_connected() + radio_manager.require_connected() contact = await _resolve_contact_or_404(public_key) @@ -487,7 +486,7 @@ async def request_trace(public_key: str) -> TraceResponse: @router.post("/{public_key}/path-discovery", response_model=PathDiscoveryResponse) async def request_path_discovery(public_key: str) -> PathDiscoveryResponse: """Discover the current forward and return paths to a known contact.""" - require_connected() + radio_manager.require_connected() contact = await _resolve_contact_or_404(public_key) pubkey_prefix = contact.public_key[:12] diff --git a/app/routers/messages.py b/app/routers/messages.py index 32aa3dd..99b6fd9 100644 --- a/app/routers/messages.py +++ b/app/routers/messages.py @@ -3,7 +3,6 @@ import time from fastapi import APIRouter, HTTPException, Query -from app.dependencies import require_connected from app.event_handlers import track_pending_ack from app.models import ( Message, @@ -89,7 +88,7 @@ async def list_messages( @router.post("/direct", response_model=Message) async def send_direct_message(request: SendDirectMessageRequest) -> Message: """Send a direct message to a contact.""" - require_connected() + radio_manager.require_connected() # First check our database for the contact from app.repository import ContactRepository @@ -136,7 +135,7 @@ TEMP_RADIO_SLOT = 0 @router.post("/channel", response_model=Message) async def send_channel_message(request: SendChannelMessageRequest) -> Message: """Send a message to a channel.""" - require_connected() + radio_manager.require_connected() # Get channel info from our database from app.repository import ChannelRepository @@ -189,7 +188,7 @@ async def resend_channel_message( When new_timestamp=True: resend with a fresh timestamp so repeaters treat it as a new packet. Creates a new message row in the database. No time window restriction. """ - require_connected() + radio_manager.require_connected() from app.repository import ChannelRepository diff --git a/app/routers/radio.py b/app/routers/radio.py index 097c426..906500b 100644 --- a/app/routers/radio.py +++ b/app/routers/radio.py @@ -9,7 +9,6 @@ from fastapi import APIRouter, HTTPException from meshcore import EventType from pydantic import BaseModel, Field -from app.dependencies import require_connected from app.models import ( CONTACT_TYPE_REPEATER, ContactUpsert, @@ -338,7 +337,7 @@ async def _resolve_trace_hops( @router.get("/config", response_model=RadioConfigResponse) async def get_radio_config() -> RadioConfigResponse: """Get the current radio configuration.""" - mc = require_connected() + mc = radio_manager.require_connected() info = mc.self_info if not info: @@ -370,7 +369,7 @@ async def get_radio_config() -> RadioConfigResponse: @router.patch("/config", response_model=RadioConfigResponse) async def update_radio_config(update: RadioConfigUpdate) -> RadioConfigResponse: """Update radio configuration. Only provided fields will be updated.""" - require_connected() + radio_manager.require_connected() async with radio_manager.radio_operation("update_radio_config") as mc: try: @@ -392,7 +391,7 @@ async def update_radio_config(update: RadioConfigUpdate) -> RadioConfigResponse: @router.put("/private-key") async def set_private_key(update: PrivateKeyUpdate) -> dict: """Set the radio's private key. This is write-only.""" - require_connected() + radio_manager.require_connected() try: key_bytes = bytes.fromhex(update.private_key) @@ -426,7 +425,7 @@ async def send_advertisement(request: RadioAdvertiseRequest | None = None) -> di Returns: status: "ok" if sent successfully """ - require_connected() + radio_manager.require_connected() mode: RadioAdvertMode = request.mode if request is not None else "flood" logger.info("Sending %s advertisement", mode.replace("_", "-")) @@ -442,7 +441,7 @@ async def send_advertisement(request: RadioAdvertiseRequest | None = None) -> di @router.post("/discover", response_model=RadioDiscoveryResponse) async def discover_mesh(request: RadioDiscoveryRequest) -> RadioDiscoveryResponse: """Run a short node-discovery sweep from the local radio.""" - require_connected() + radio_manager.require_connected() target_bits = _DISCOVERY_TARGET_BITS[request.target] tag = random.randint(1, 0xFFFFFFFF) @@ -509,7 +508,7 @@ async def discover_mesh(request: RadioDiscoveryRequest) -> RadioDiscoveryRespons @router.post("/trace", response_model=RadioTraceResponse) async def trace_path(request: RadioTraceRequest) -> RadioTraceResponse: """Send a multi-hop trace loop through known repeaters and back to the local radio.""" - require_connected() + radio_manager.require_connected() trace_nodes, requested_hashes = await _resolve_trace_hops(request.hops, request.hop_hash_bytes) tag = random.randint(1, 0xFFFFFFFF) diff --git a/app/routers/repeaters.py b/app/routers/repeaters.py index 72ca330..1bf7c3a 100644 --- a/app/routers/repeaters.py +++ b/app/routers/repeaters.py @@ -3,7 +3,6 @@ import time from fastapi import APIRouter, HTTPException -from app.dependencies import require_connected from app.models import ( CONTACT_TYPE_REPEATER, AclEntry, @@ -75,7 +74,7 @@ def _require_repeater(contact: Contact) -> None: @router.post("/{public_key}/repeater/login", response_model=RepeaterLoginResponse) async def repeater_login(public_key: str, request: RepeaterLoginRequest) -> RepeaterLoginResponse: """Attempt repeater login and report whether auth was confirmed.""" - require_connected() + radio_manager.require_connected() contact = await _resolve_contact_or_404(public_key) _require_repeater(contact) @@ -90,7 +89,7 @@ async def repeater_login(public_key: str, request: RepeaterLoginRequest) -> Repe @router.post("/{public_key}/repeater/status", response_model=RepeaterStatusResponse) async def repeater_status(public_key: str) -> RepeaterStatusResponse: """Fetch status telemetry from a repeater (single attempt, 10s timeout).""" - require_connected() + radio_manager.require_connected() contact = await _resolve_contact_or_404(public_key) _require_repeater(contact) @@ -165,7 +164,7 @@ async def repeater_telemetry_history(public_key: str) -> list[TelemetryHistoryEn @router.post("/{public_key}/repeater/lpp-telemetry", response_model=RepeaterLppTelemetryResponse) async def repeater_lpp_telemetry(public_key: str) -> RepeaterLppTelemetryResponse: """Fetch CayenneLPP sensor telemetry from a repeater (single attempt, 10s timeout).""" - require_connected() + radio_manager.require_connected() contact = await _resolve_contact_or_404(public_key) _require_repeater(contact) @@ -194,7 +193,7 @@ async def repeater_lpp_telemetry(public_key: str) -> RepeaterLppTelemetryRespons @router.post("/{public_key}/repeater/neighbors", response_model=RepeaterNeighborsResponse) async def repeater_neighbors(public_key: str) -> RepeaterNeighborsResponse: """Fetch neighbors from a repeater (single attempt, 10s timeout).""" - require_connected() + radio_manager.require_connected() contact = await _resolve_contact_or_404(public_key) _require_repeater(contact) @@ -228,7 +227,7 @@ async def repeater_neighbors(public_key: str) -> RepeaterNeighborsResponse: @router.post("/{public_key}/repeater/acl", response_model=RepeaterAclResponse) async def repeater_acl(public_key: str) -> RepeaterAclResponse: """Fetch ACL from a repeater (single attempt, 10s timeout).""" - require_connected() + radio_manager.require_connected() contact = await _resolve_contact_or_404(public_key) _require_repeater(contact) @@ -269,7 +268,7 @@ async def _batch_cli_fetch( @router.post("/{public_key}/repeater/node-info", response_model=RepeaterNodeInfoResponse) async def repeater_node_info(public_key: str) -> RepeaterNodeInfoResponse: """Fetch repeater identity/location info via a small CLI batch.""" - require_connected() + radio_manager.require_connected() contact = await _resolve_contact_or_404(public_key) _require_repeater(contact) @@ -289,7 +288,7 @@ async def repeater_node_info(public_key: str) -> RepeaterNodeInfoResponse: @router.post("/{public_key}/repeater/radio-settings", response_model=RepeaterRadioSettingsResponse) async def repeater_radio_settings(public_key: str) -> RepeaterRadioSettingsResponse: """Fetch radio settings from a repeater via radio/config CLI commands.""" - require_connected() + radio_manager.require_connected() contact = await _resolve_contact_or_404(public_key) _require_repeater(contact) @@ -313,7 +312,7 @@ async def repeater_radio_settings(public_key: str) -> RepeaterRadioSettingsRespo ) async def repeater_advert_intervals(public_key: str) -> RepeaterAdvertIntervalsResponse: """Fetch advertisement intervals from a repeater via CLI commands.""" - require_connected() + radio_manager.require_connected() contact = await _resolve_contact_or_404(public_key) _require_repeater(contact) @@ -331,7 +330,7 @@ async def repeater_advert_intervals(public_key: str) -> RepeaterAdvertIntervalsR @router.post("/{public_key}/repeater/owner-info", response_model=RepeaterOwnerInfoResponse) async def repeater_owner_info(public_key: str) -> RepeaterOwnerInfoResponse: """Fetch owner info and guest password from a repeater via CLI commands.""" - require_connected() + radio_manager.require_connected() contact = await _resolve_contact_or_404(public_key) _require_repeater(contact) @@ -349,7 +348,7 @@ async def repeater_owner_info(public_key: str) -> RepeaterOwnerInfoResponse: @router.post("/{public_key}/command", response_model=CommandResponse) async def send_repeater_command(public_key: str, request: CommandRequest) -> CommandResponse: """Send a CLI command to a repeater or room server.""" - require_connected() + radio_manager.require_connected() contact = await _resolve_contact_or_404(public_key) require_server_capable_contact(contact) diff --git a/app/routers/rooms.py b/app/routers/rooms.py index fa1afae..f075089 100644 --- a/app/routers/rooms.py +++ b/app/routers/rooms.py @@ -1,6 +1,5 @@ from fastapi import APIRouter, HTTPException -from app.dependencies import require_connected from app.models import ( CONTACT_TYPE_ROOM, AclEntry, @@ -28,7 +27,7 @@ def _require_room(contact) -> None: @router.post("/{public_key}/room/login", response_model=RepeaterLoginResponse) async def room_login(public_key: str, request: RepeaterLoginRequest) -> RepeaterLoginResponse: """Attempt room-server login and report whether auth was confirmed.""" - require_connected() + radio_manager.require_connected() contact = await _resolve_contact_or_404(public_key) _require_room(contact) @@ -48,7 +47,7 @@ async def room_login(public_key: str, request: RepeaterLoginRequest) -> Repeater @router.post("/{public_key}/room/status", response_model=RepeaterStatusResponse) async def room_status(public_key: str) -> RepeaterStatusResponse: """Fetch status telemetry from a room server.""" - require_connected() + radio_manager.require_connected() contact = await _resolve_contact_or_404(public_key) _require_room(contact) @@ -85,7 +84,7 @@ async def room_status(public_key: str) -> RepeaterStatusResponse: @router.post("/{public_key}/room/lpp-telemetry", response_model=RepeaterLppTelemetryResponse) async def room_lpp_telemetry(public_key: str) -> RepeaterLppTelemetryResponse: """Fetch CayenneLPP telemetry from a room server.""" - require_connected() + radio_manager.require_connected() contact = await _resolve_contact_or_404(public_key) _require_room(contact) @@ -114,7 +113,7 @@ async def room_lpp_telemetry(public_key: str) -> RepeaterLppTelemetryResponse: @router.post("/{public_key}/room/acl", response_model=RepeaterAclResponse) async def room_acl(public_key: str) -> RepeaterAclResponse: """Fetch ACL entries from a room server.""" - require_connected() + radio_manager.require_connected() contact = await _resolve_contact_or_404(public_key) _require_room(contact) diff --git a/tests/test_ack_tracking_wiring.py b/tests/test_ack_tracking_wiring.py index 4f8ee49..d863fdc 100644 --- a/tests/test_ack_tracking_wiring.py +++ b/tests/test_ack_tracking_wiring.py @@ -83,7 +83,7 @@ class TestDMAckTrackingWiring: await _insert_contact(pub_key) with ( - patch("app.routers.messages.require_connected", return_value=mc), + patch("app.routers.messages.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch("app.routers.messages.track_pending_ack") as mock_track, patch("app.routers.messages.broadcast_event"), @@ -115,7 +115,7 @@ class TestDMAckTrackingWiring: await _insert_contact(pub_key) with ( - patch("app.routers.messages.require_connected", return_value=mc), + patch("app.routers.messages.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch("app.routers.messages.track_pending_ack") as mock_track, patch("app.routers.messages.broadcast_event"), @@ -144,7 +144,7 @@ class TestDMAckTrackingWiring: await _insert_contact(pub_key) with ( - patch("app.routers.messages.require_connected", return_value=mc), + patch("app.routers.messages.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch("app.routers.messages.track_pending_ack") as mock_track, patch("app.routers.messages.broadcast_event"), @@ -172,7 +172,7 @@ class TestDMAckTrackingWiring: await _insert_contact(pub_key) with ( - patch("app.routers.messages.require_connected", return_value=mc), + patch("app.routers.messages.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch("app.routers.messages.track_pending_ack") as mock_track, patch("app.routers.messages.broadcast_event"), diff --git a/tests/test_api.py b/tests/test_api.py index cc8aeaf..db88b4a 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -49,10 +49,10 @@ def _disable_background_dm_retries(monkeypatch): def _patch_require_connected(mc=None, *, detail="Radio not connected"): if mc is None: return patch( - "app.dependencies.radio_manager.require_connected", + "app.services.radio_runtime.radio_runtime.require_connected", side_effect=HTTPException(status_code=503, detail=detail), ) - return patch("app.dependencies.radio_manager.require_connected", return_value=mc) + return patch("app.services.radio_runtime.radio_runtime.require_connected", return_value=mc) async def _insert_contact(public_key, name="Alice", **overrides): diff --git a/tests/test_contacts_router.py b/tests/test_contacts_router.py index 2351a7c..09a9a30 100644 --- a/tests/test_contacts_router.py +++ b/tests/test_contacts_router.py @@ -286,7 +286,7 @@ class TestPathDiscovery: ) with ( - patch("app.routers.contacts.require_connected", return_value=mc), + patch("app.routers.contacts.radio_manager.require_connected", return_value=mc), patch("app.routers.contacts.radio_manager") as mock_rm, patch("app.websocket.broadcast_event") as mock_broadcast, ): @@ -324,7 +324,7 @@ class TestPathDiscovery: mc.wait_for_event = AsyncMock(return_value=None) with ( - patch("app.routers.contacts.require_connected", return_value=mc), + patch("app.routers.contacts.radio_manager.require_connected", return_value=mc), patch("app.routers.contacts.radio_manager") as mock_rm, ): mock_rm.radio_operation = _noop_radio_operation(mc) diff --git a/tests/test_radio_operation.py b/tests/test_radio_operation.py index db415da..69ff57d 100644 --- a/tests/test_radio_operation.py +++ b/tests/test_radio_operation.py @@ -7,11 +7,6 @@ import pytest from app.radio import RadioDisconnectedError, RadioOperationBusyError, radio_manager from app.radio_sync import is_polling_paused -from app.services.radio_runtime import RadioRuntime - - -def _runtime(manager): - return RadioRuntime(lambda: manager) @pytest.fixture(autouse=True) @@ -183,15 +178,15 @@ class TestRequireConnected: """HTTPException 503 is raised when radio is connected but setup is still in progress.""" from fastapi import HTTPException - from app.dependencies import require_connected + from app.services.radio_runtime import radio_runtime manager = MagicMock() manager.is_connected = True manager.meshcore = MagicMock() manager.is_setup_in_progress = True - with patch("app.dependencies.radio_manager", _runtime(manager)): + with patch.object(radio_runtime, "_manager_getter", return_value=manager): with pytest.raises(HTTPException) as exc_info: - require_connected() + radio_runtime.require_connected() assert exc_info.value.status_code == 503 assert "initializing" in exc_info.value.detail.lower() @@ -200,28 +195,28 @@ class TestRequireConnected: """HTTPException 503 is raised when radio is not connected.""" from fastapi import HTTPException - from app.dependencies import require_connected + from app.services.radio_runtime import radio_runtime manager = MagicMock() manager.is_setup_in_progress = False manager.is_connected = False manager.meshcore = None - with patch("app.dependencies.radio_manager", _runtime(manager)): + with patch.object(radio_runtime, "_manager_getter", return_value=manager): with pytest.raises(HTTPException) as exc_info: - require_connected() + radio_runtime.require_connected() assert exc_info.value.status_code == 503 def test_returns_meshcore_when_connected_and_setup_complete(self): """Returns meshcore instance when radio is connected and setup is complete.""" - from app.dependencies import require_connected + from app.services.radio_runtime import radio_runtime mock_mc = MagicMock() manager = MagicMock() manager.is_setup_in_progress = False manager.is_connected = True manager.meshcore = mock_mc - with patch("app.dependencies.radio_manager", _runtime(manager)): - result = require_connected() + with patch.object(radio_runtime, "_manager_getter", return_value=manager): + result = radio_runtime.require_connected() assert result is mock_mc diff --git a/tests/test_radio_router.py b/tests/test_radio_router.py index 3774654..92d4135 100644 --- a/tests/test_radio_router.py +++ b/tests/test_radio_router.py @@ -97,7 +97,7 @@ class TestGetRadioConfig: @pytest.mark.asyncio async def test_maps_self_info_to_response(self): mc = _mock_meshcore_with_info() - with patch("app.routers.radio.require_connected", return_value=mc): + with patch("app.routers.radio.radio_manager.require_connected", return_value=mc): response = await get_radio_config() assert response.public_key == "aa" * 32 @@ -114,7 +114,7 @@ class TestGetRadioConfig: mc = _mock_meshcore_with_info() mc.self_info["multi_acks"] = 1 - with patch("app.routers.radio.require_connected", return_value=mc): + with patch("app.routers.radio.radio_manager.require_connected", return_value=mc): response = await get_radio_config() assert response.multi_acks_enabled is True @@ -124,7 +124,7 @@ class TestGetRadioConfig: mc = _mock_meshcore_with_info() mc.self_info["adv_loc_policy"] = 1 - with patch("app.routers.radio.require_connected", return_value=mc): + with patch("app.routers.radio.radio_manager.require_connected", return_value=mc): response = await get_radio_config() assert response.advert_location_source == "current" @@ -133,7 +133,7 @@ class TestGetRadioConfig: async def test_returns_503_when_self_info_missing(self): mc = MagicMock() mc.self_info = None - with patch("app.routers.radio.require_connected", return_value=mc): + with patch("app.routers.radio.radio_manager.require_connected", return_value=mc): with pytest.raises(HTTPException) as exc: await get_radio_config() @@ -155,7 +155,7 @@ class TestUpdateRadioConfig: ) with ( - patch("app.routers.radio.require_connected", return_value=mc), + patch("app.routers.radio.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch("app.routers.radio.sync_radio_time", new_callable=AsyncMock) as mock_sync_time, patch( @@ -190,7 +190,7 @@ class TestUpdateRadioConfig: ) with ( - patch("app.routers.radio.require_connected", return_value=mc), + patch("app.routers.radio.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch("app.routers.radio.sync_radio_time", new_callable=AsyncMock), patch( @@ -220,7 +220,7 @@ class TestUpdateRadioConfig: ) with ( - patch("app.routers.radio.require_connected", return_value=mc), + patch("app.routers.radio.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch("app.routers.radio.sync_radio_time", new_callable=AsyncMock), patch( @@ -252,7 +252,7 @@ class TestUpdateRadioConfig: mc = _mock_meshcore_with_info() with ( - patch("app.routers.radio.require_connected", return_value=mc), + patch("app.routers.radio.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch.object(radio_manager, "path_hash_mode_supported", False), ): @@ -269,7 +269,7 @@ class TestUpdateRadioConfig: ) with ( - patch("app.routers.radio.require_connected", return_value=mc), + patch("app.routers.radio.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch.object(radio_manager, "path_hash_mode_supported", True), patch.object(radio_manager, "path_hash_mode", 0), @@ -287,7 +287,7 @@ class TestPrivateKeyImport: @pytest.mark.asyncio async def test_rejects_invalid_hex(self): mc = _mock_meshcore_with_info() - with patch("app.routers.radio.require_connected", return_value=mc): + with patch("app.routers.radio.radio_manager.require_connected", return_value=mc): with pytest.raises(HTTPException) as exc: await set_private_key(PrivateKeyUpdate(private_key="not-hex")) @@ -300,7 +300,7 @@ class TestPrivateKeyImport: return_value=_radio_result(EventType.ERROR, {"error": "failed"}) ) with ( - patch("app.routers.radio.require_connected", return_value=mc), + patch("app.routers.radio.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), ): with pytest.raises(HTTPException) as exc: @@ -367,7 +367,7 @@ class TestDiscoverMesh: mc.commands.send_node_discover_req = AsyncMock(side_effect=_send_node_discover_req) with ( - patch("app.routers.radio.require_connected", return_value=mc), + patch("app.routers.radio.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch("app.routers.radio.DISCOVERY_WINDOW_SECONDS", 0.01), patch( @@ -441,7 +441,7 @@ class TestDiscoverMesh: mc.subscribe = MagicMock(side_effect=_subscribe) with ( - patch("app.routers.radio.require_connected", return_value=mc), + patch("app.routers.radio.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch("app.routers.radio.DISCOVERY_WINDOW_SECONDS", 0.01), patch( @@ -517,7 +517,7 @@ class TestDiscoverMesh: mc.subscribe = MagicMock(side_effect=_subscribe) with ( - patch("app.routers.radio.require_connected", return_value=mc), + patch("app.routers.radio.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch("app.routers.radio.DISCOVERY_WINDOW_SECONDS", 0.01), patch( @@ -591,7 +591,7 @@ class TestTracePath: ) with ( - patch("app.routers.radio.require_connected", return_value=mc), + patch("app.routers.radio.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch( "app.routers.radio.ContactRepository.get_by_key", new_callable=AsyncMock @@ -648,7 +648,7 @@ class TestTracePath: ) with ( - patch("app.routers.radio.require_connected", return_value=mc), + patch("app.routers.radio.radio_manager.require_connected", return_value=mc), patch( "app.routers.radio.ContactRepository.get_by_key", new_callable=AsyncMock ) as mock_get, @@ -691,7 +691,7 @@ class TestTracePath: mc.wait_for_event = AsyncMock(return_value=None) with ( - patch("app.routers.radio.require_connected", return_value=mc), + patch("app.routers.radio.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch( "app.routers.radio.ContactRepository.get_by_key", new_callable=AsyncMock @@ -731,7 +731,7 @@ class TestTracePath: ) with ( - patch("app.routers.radio.require_connected", return_value=mc), + patch("app.routers.radio.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch("app.routers.radio.radio_manager") as mock_rm, ): @@ -775,7 +775,7 @@ class TestTracePath: mc.subscribe = MagicMock(side_effect=_subscribe) with ( - patch("app.routers.radio.require_connected", return_value=mc), + patch("app.routers.radio.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch("app.routers.radio.DISCOVERY_WINDOW_SECONDS", 0.01), patch( @@ -811,7 +811,7 @@ class TestTracePath: ) with ( - patch("app.routers.radio.require_connected", return_value=mc), + patch("app.routers.radio.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), ): with pytest.raises(HTTPException) as exc: @@ -825,7 +825,7 @@ class TestTracePath: mc = _mock_meshcore_with_info() mc.commands.import_private_key = AsyncMock(return_value=_radio_result()) with ( - patch("app.routers.radio.require_connected", return_value=mc), + patch("app.routers.radio.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch( "app.keystore.export_and_store_private_key", @@ -843,7 +843,7 @@ class TestTracePath: mc = _mock_meshcore_with_info() mc.commands.import_private_key = AsyncMock(return_value=_radio_result()) with ( - patch("app.routers.radio.require_connected", return_value=mc), + patch("app.routers.radio.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch( "app.keystore.export_and_store_private_key", @@ -864,7 +864,7 @@ class TestTracePath: mc = _mock_meshcore_with_info() mc.commands.import_private_key = AsyncMock(return_value=_radio_result()) with ( - patch("app.routers.radio.require_connected", return_value=mc), + patch("app.routers.radio.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch( "app.keystore.export_and_store_private_key", @@ -883,7 +883,7 @@ class TestAdvertise: async def test_raises_when_send_fails(self): radio_manager._meshcore = MagicMock() with ( - patch("app.routers.radio.require_connected"), + patch("app.routers.radio.radio_manager.require_connected"), patch( "app.routers.radio.do_send_advertisement", new_callable=AsyncMock, @@ -899,7 +899,7 @@ class TestAdvertise: async def test_defaults_to_flood_mode(self): radio_manager._meshcore = MagicMock() with ( - patch("app.routers.radio.require_connected"), + patch("app.routers.radio.radio_manager.require_connected"), patch( "app.routers.radio.do_send_advertisement", new_callable=AsyncMock, @@ -917,7 +917,7 @@ class TestAdvertise: async def test_accepts_zero_hop_mode(self): radio_manager._meshcore = MagicMock() with ( - patch("app.routers.radio.require_connected"), + patch("app.routers.radio.radio_manager.require_connected"), patch( "app.routers.radio.do_send_advertisement", new_callable=AsyncMock, @@ -949,7 +949,7 @@ class TestAdvertise: isolated_manager = RadioManager() isolated_manager._meshcore = MagicMock() with ( - patch("app.routers.radio.require_connected"), + patch("app.routers.radio.radio_manager.require_connected"), patch("app.routers.radio.radio_manager", _runtime(isolated_manager)), patch( "app.routers.radio.do_send_advertisement", diff --git a/tests/test_repeater_routes.py b/tests/test_repeater_routes.py index cb633b1..c66d2f0 100644 --- a/tests/test_repeater_routes.py +++ b/tests/test_repeater_routes.py @@ -296,7 +296,7 @@ class TestRepeaterCommandRoute: ) with ( - patch("app.routers.repeaters.require_connected", return_value=mc), + patch("app.routers.repeaters.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), ): with pytest.raises(HTTPException) as exc: @@ -314,7 +314,7 @@ class TestRepeaterCommandRoute: # Expire the deadline after a couple of ticks with ( - patch("app.routers.repeaters.require_connected", return_value=mc), + patch("app.routers.repeaters.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch(_MONOTONIC, side_effect=[0.0, 5.0, 25.0]), patch("app.routers.server_control.asyncio.sleep", new_callable=AsyncMock), @@ -343,7 +343,7 @@ class TestRepeaterCommandRoute: ) with ( - patch("app.routers.repeaters.require_connected", return_value=mc), + patch("app.routers.repeaters.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch(_MONOTONIC, side_effect=_advancing_clock()), ): @@ -371,7 +371,7 @@ class TestRepeaterCommandRoute: ) with ( - patch("app.routers.repeaters.require_connected", return_value=mc), + patch("app.routers.repeaters.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch(_MONOTONIC, side_effect=_advancing_clock()), ): @@ -397,7 +397,7 @@ class TestRepeaterCommandRoute: ) with ( - patch("app.routers.repeaters.require_connected", return_value=mc), + patch("app.routers.repeaters.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch(_MONOTONIC, side_effect=_advancing_clock()), ): @@ -425,7 +425,7 @@ class TestRepeaterCommandRoute: mc.commands.get_msg = AsyncMock(side_effect=[unrelated, expected]) with ( - patch("app.routers.repeaters.require_connected", return_value=mc), + patch("app.routers.repeaters.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch(_MONOTONIC, side_effect=_advancing_clock()), ): @@ -451,7 +451,7 @@ class TestRepeaterCommandRoute: mc.commands.get_msg = AsyncMock(side_effect=[channel_msg, expected]) with ( - patch("app.routers.repeaters.require_connected", return_value=mc), + patch("app.routers.repeaters.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch(_MONOTONIC, side_effect=_advancing_clock()), ): @@ -474,7 +474,7 @@ class TestRepeaterCommandRoute: mc.commands.get_msg = AsyncMock(side_effect=[no_msgs, expected]) with ( - patch("app.routers.repeaters.require_connected", return_value=mc), + patch("app.routers.repeaters.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch(_MONOTONIC, side_effect=_advancing_clock()), patch("app.routers.server_control.asyncio.sleep", new_callable=AsyncMock), @@ -495,7 +495,7 @@ class TestTraceRoute: ) with ( - patch("app.routers.contacts.require_connected", return_value=mc), + patch("app.routers.contacts.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch("app.routers.contacts.random.randint", return_value=1234), ): @@ -517,7 +517,7 @@ class TestTraceRoute: mc.wait_for_event = AsyncMock(return_value=None) with ( - patch("app.routers.contacts.require_connected", return_value=mc), + patch("app.routers.contacts.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch("app.routers.contacts.random.randint", return_value=1234), ): @@ -541,7 +541,7 @@ class TestTraceRoute: ) with ( - patch("app.routers.contacts.require_connected", return_value=mc), + patch("app.routers.contacts.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch("app.routers.contacts.random.randint", return_value=1234), ): @@ -569,7 +569,7 @@ class TestRepeaterLogin: await _insert_contact(KEY_A, name="Repeater", contact_type=2) with ( - patch("app.routers.repeaters.require_connected", return_value=mc), + patch("app.routers.repeaters.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch( "app.routers.repeaters.prepare_repeater_connection", @@ -592,7 +592,7 @@ class TestRepeaterLogin: async def test_404_missing_contact(self, test_db): mc = _mock_mc() with ( - patch("app.routers.repeaters.require_connected", return_value=mc), + patch("app.routers.repeaters.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), ): with pytest.raises(HTTPException) as exc: @@ -604,7 +604,7 @@ class TestRepeaterLogin: mc = _mock_mc() await _insert_contact(KEY_A, name="Client", contact_type=1) with ( - patch("app.routers.repeaters.require_connected", return_value=mc), + patch("app.routers.repeaters.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), ): with pytest.raises(HTTPException) as exc: @@ -625,7 +625,7 @@ class TestRepeaterLogin: ) with ( - patch("app.routers.repeaters.require_connected", return_value=mc), + patch("app.routers.repeaters.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch("app.routers.repeaters.prepare_repeater_connection", side_effect=_prepare_fail), ): @@ -726,7 +726,7 @@ class TestRepeaterStatus: ) with ( - patch("app.routers.repeaters.require_connected", return_value=mc), + patch("app.routers.repeaters.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), ): response = await repeater_status(KEY_A) @@ -749,7 +749,7 @@ class TestRepeaterStatus: mc.commands.req_status_sync = AsyncMock(return_value=None) with ( - patch("app.routers.repeaters.require_connected", return_value=mc), + patch("app.routers.repeaters.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), ): with pytest.raises(HTTPException) as exc: @@ -761,7 +761,7 @@ class TestRepeaterStatus: mc = _mock_mc() await _insert_contact(KEY_A, name="Client", contact_type=1) with ( - patch("app.routers.repeaters.require_connected", return_value=mc), + patch("app.routers.repeaters.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), ): with pytest.raises(HTTPException) as exc: @@ -787,7 +787,7 @@ class TestRepeaterLppTelemetry: ) with ( - patch("app.routers.repeaters.require_connected", return_value=mc), + patch("app.routers.repeaters.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), ): response = await repeater_lpp_telemetry(KEY_A) @@ -809,7 +809,7 @@ class TestRepeaterLppTelemetry: mc.commands.req_telemetry_sync = AsyncMock(return_value=[]) with ( - patch("app.routers.repeaters.require_connected", return_value=mc), + patch("app.routers.repeaters.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), ): response = await repeater_lpp_telemetry(KEY_A) @@ -823,7 +823,7 @@ class TestRepeaterLppTelemetry: mc.commands.req_telemetry_sync = AsyncMock(return_value=None) with ( - patch("app.routers.repeaters.require_connected", return_value=mc), + patch("app.routers.repeaters.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), ): with pytest.raises(HTTPException) as exc: @@ -835,7 +835,7 @@ class TestRepeaterLppTelemetry: mc = _mock_mc() await _insert_contact(KEY_A, name="Client", contact_type=1) with ( - patch("app.routers.repeaters.require_connected", return_value=mc), + patch("app.routers.repeaters.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), ): with pytest.raises(HTTPException) as exc: @@ -861,7 +861,7 @@ class TestRepeaterNeighbors: ) with ( - patch("app.routers.repeaters.require_connected", return_value=mc), + patch("app.routers.repeaters.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), ): response = await repeater_neighbors(KEY_A) @@ -879,7 +879,7 @@ class TestRepeaterNeighbors: mc.commands.fetch_all_neighbours = AsyncMock(return_value={"neighbours": []}) with ( - patch("app.routers.repeaters.require_connected", return_value=mc), + patch("app.routers.repeaters.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), ): response = await repeater_neighbors(KEY_A) @@ -893,7 +893,7 @@ class TestRepeaterNeighbors: mc.commands.fetch_all_neighbours = AsyncMock(return_value=None) with ( - patch("app.routers.repeaters.require_connected", return_value=mc), + patch("app.routers.repeaters.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), ): response = await repeater_neighbors(KEY_A) @@ -917,7 +917,7 @@ class TestRepeaterAcl: ) with ( - patch("app.routers.repeaters.require_connected", return_value=mc), + patch("app.routers.repeaters.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), ): response = await repeater_acl(KEY_A) @@ -935,7 +935,7 @@ class TestRepeaterAcl: mc.commands.req_acl_sync = AsyncMock(return_value=[]) with ( - patch("app.routers.repeaters.require_connected", return_value=mc), + patch("app.routers.repeaters.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), ): response = await repeater_acl(KEY_A) @@ -949,7 +949,7 @@ class TestRepeaterAcl: mc.commands.req_acl_sync = AsyncMock(return_value=None) with ( - patch("app.routers.repeaters.require_connected", return_value=mc), + patch("app.routers.repeaters.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), ): response = await repeater_acl(KEY_A) @@ -982,7 +982,7 @@ class TestRepeaterRadioSettings: mc.commands.get_msg = AsyncMock(side_effect=get_msg_results) with ( - patch("app.routers.repeaters.require_connected", return_value=mc), + patch("app.routers.repeaters.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch(_MONOTONIC, side_effect=_advancing_clock()), ): @@ -1015,7 +1015,7 @@ class TestRepeaterRadioSettings: clock_ticks.extend([base, base + 5.0, base + 11.0]) with ( - patch("app.routers.repeaters.require_connected", return_value=mc), + patch("app.routers.repeaters.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch(_MONOTONIC, side_effect=clock_ticks), patch("app.routers.server_control.asyncio.sleep", new_callable=AsyncMock), @@ -1031,7 +1031,7 @@ class TestRepeaterRadioSettings: mc = _mock_mc() await _insert_contact(KEY_A, name="Client", contact_type=1) with ( - patch("app.routers.repeaters.require_connected", return_value=mc), + patch("app.routers.repeaters.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), ): with pytest.raises(HTTPException) as exc: @@ -1061,7 +1061,7 @@ class TestRepeaterNodeInfo: mc.commands.get_msg = AsyncMock(side_effect=get_msg_results) with ( - patch("app.routers.repeaters.require_connected", return_value=mc), + patch("app.routers.repeaters.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch(_MONOTONIC, side_effect=_advancing_clock()), ): @@ -1090,7 +1090,7 @@ class TestRepeaterNodeInfo: clock_ticks.extend([base, base + 5.0, base + 11.0]) with ( - patch("app.routers.repeaters.require_connected", return_value=mc), + patch("app.routers.repeaters.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch(_MONOTONIC, side_effect=clock_ticks), patch("app.routers.server_control.asyncio.sleep", new_callable=AsyncMock), @@ -1122,7 +1122,7 @@ class TestRepeaterAdvertIntervals: mc.commands.get_msg = AsyncMock(side_effect=responses) with ( - patch("app.routers.repeaters.require_connected", return_value=mc), + patch("app.routers.repeaters.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch(_MONOTONIC, side_effect=_advancing_clock()), ): @@ -1143,7 +1143,7 @@ class TestRepeaterAdvertIntervals: clock_ticks.extend([base, base + 5.0, base + 11.0]) with ( - patch("app.routers.repeaters.require_connected", return_value=mc), + patch("app.routers.repeaters.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch(_MONOTONIC, side_effect=clock_ticks), patch("app.routers.server_control.asyncio.sleep", new_callable=AsyncMock), @@ -1177,7 +1177,7 @@ class TestRepeaterOwnerInfo: mc.commands.get_msg = AsyncMock(side_effect=responses) with ( - patch("app.routers.repeaters.require_connected", return_value=mc), + patch("app.routers.repeaters.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch(_MONOTONIC, side_effect=_advancing_clock()), ): @@ -1198,7 +1198,7 @@ class TestRepeaterOwnerInfo: clock_ticks.extend([base, base + 5.0, base + 11.0]) with ( - patch("app.routers.repeaters.require_connected", return_value=mc), + patch("app.routers.repeaters.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch(_MONOTONIC, side_effect=clock_ticks), patch("app.routers.server_control.asyncio.sleep", new_callable=AsyncMock), @@ -1299,7 +1299,7 @@ class TestRepeaterAddContactError: ) with ( - patch("app.routers.repeaters.require_connected", return_value=mc), + patch("app.routers.repeaters.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), ): with pytest.raises(HTTPException) as exc: @@ -1317,7 +1317,7 @@ class TestRepeaterAddContactError: ) with ( - patch("app.routers.repeaters.require_connected", return_value=mc), + patch("app.routers.repeaters.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), ): with pytest.raises(HTTPException) as exc: @@ -1335,7 +1335,7 @@ class TestRepeaterAddContactError: ) with ( - patch("app.routers.repeaters.require_connected", return_value=mc), + patch("app.routers.repeaters.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), ): with pytest.raises(HTTPException) as exc: @@ -1353,7 +1353,7 @@ class TestRepeaterAddContactError: ) with ( - patch("app.routers.repeaters.require_connected", return_value=mc), + patch("app.routers.repeaters.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), ): with pytest.raises(HTTPException) as exc: diff --git a/tests/test_room_routes.py b/tests/test_room_routes.py index 461a1ce..6738940 100644 --- a/tests/test_room_routes.py +++ b/tests/test_room_routes.py @@ -88,7 +88,7 @@ class TestRoomLogin: mc.commands.send_login = AsyncMock(side_effect=_send_login) with ( - patch("app.routers.rooms.require_connected", return_value=mc), + patch("app.routers.rooms.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), ): response = await room_login(ROOM_KEY, RepeaterLoginRequest(password="hello")) @@ -102,7 +102,7 @@ class TestRoomLogin: await _insert_contact(ROOM_KEY, name="Client", contact_type=1) with ( - patch("app.routers.rooms.require_connected", return_value=mc), + patch("app.routers.rooms.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), ): with pytest.raises(HTTPException) as exc: @@ -139,7 +139,7 @@ class TestRoomStatus: ) with ( - patch("app.routers.rooms.require_connected", return_value=mc), + patch("app.routers.rooms.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), ): response = await room_status(ROOM_KEY) @@ -156,7 +156,7 @@ class TestRoomStatus: mc.commands.req_acl_sync = AsyncMock(return_value=[{"key": AUTHOR_KEY[:12], "perm": 3}]) with ( - patch("app.routers.rooms.require_connected", return_value=mc), + patch("app.routers.rooms.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), ): response = await room_acl(ROOM_KEY) @@ -179,7 +179,7 @@ class TestRoomCommandReuse: ) with ( - patch("app.routers.repeaters.require_connected", return_value=mc), + patch("app.routers.repeaters.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), ): response = await send_repeater_command(ROOM_KEY, CommandRequest(command="ver")) diff --git a/tests/test_send_messages.py b/tests/test_send_messages.py index 2b53531..8136d4b 100644 --- a/tests/test_send_messages.py +++ b/tests/test_send_messages.py @@ -119,7 +119,7 @@ class TestOutgoingDMBroadcast: broadcasts.append({"type": event_type, "data": data}) with ( - patch("app.routers.messages.require_connected", return_value=mc), + patch("app.routers.messages.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch("app.routers.messages.broadcast_event", side_effect=capture_broadcast), ): @@ -143,7 +143,7 @@ class TestOutgoingDMBroadcast: await _insert_contact("abc123" + "00" * 29, "ContactA") await _insert_contact("abc123" + "ff" * 29, "ContactB") - with patch("app.routers.messages.require_connected", return_value=mc): + with patch("app.routers.messages.radio_manager.require_connected", return_value=mc): with pytest.raises(HTTPException) as exc_info: await send_direct_message( SendDirectMessageRequest(destination="abc123", text="Hello") @@ -166,7 +166,7 @@ class TestOutgoingDMBroadcast: ) with ( - patch("app.routers.messages.require_connected", return_value=mc), + patch("app.routers.messages.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch("app.routers.messages.broadcast_event"), ): @@ -195,7 +195,7 @@ class TestOutgoingDMBroadcast: ) with ( - patch("app.routers.messages.require_connected", return_value=mc), + patch("app.routers.messages.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch("app.routers.messages.broadcast_event"), ): @@ -225,7 +225,7 @@ class TestOutgoingDMBroadcast: assert original_id is not None with ( - patch("app.routers.messages.require_connected", return_value=mc), + patch("app.routers.messages.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch("app.routers.messages.broadcast_event"), patch("app.routers.messages.time") as mock_time, @@ -267,7 +267,7 @@ class TestOutgoingDMBroadcast: with ( patch("app.event_handlers.broadcast_event", side_effect=capture_broadcast), - patch("app.routers.messages.require_connected", return_value=mc), + patch("app.routers.messages.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch("app.routers.messages.broadcast_event", side_effect=capture_broadcast), ): @@ -290,7 +290,7 @@ class TestOutgoingDMBroadcast: mc.commands.send_msg = AsyncMock(return_value=_make_radio_result({})) with ( - patch("app.routers.messages.require_connected", return_value=mc), + patch("app.routers.messages.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch("app.routers.messages.broadcast_event"), patch("app.services.message_send.asyncio.create_task") as mock_create_task, @@ -338,7 +338,7 @@ class TestOutgoingDMBroadcast: with ( patch.object(message_send_service, "DM_SEND_MAX_ATTEMPTS", 3), patch("app.routers.messages.track_pending_ack", return_value=False), - patch("app.routers.messages.require_connected", return_value=mc), + patch("app.routers.messages.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch("app.routers.messages.broadcast_event"), patch("app.services.message_send.asyncio.create_task", side_effect=schedule_retry), @@ -386,7 +386,7 @@ class TestOutgoingDMBroadcast: with ( patch.object(message_send_service, "DM_SEND_MAX_ATTEMPTS", 3), patch("app.event_handlers.broadcast_event"), - patch("app.routers.messages.require_connected", return_value=mc), + patch("app.routers.messages.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch("app.routers.messages.broadcast_event"), patch("app.services.message_send.asyncio.create_task", side_effect=schedule_retry), @@ -443,7 +443,7 @@ class TestOutgoingDMBroadcast: with ( patch.object(message_send_service, "DM_SEND_MAX_ATTEMPTS", 3), patch("app.event_handlers.broadcast_event"), - patch("app.routers.messages.require_connected", return_value=mc), + patch("app.routers.messages.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch("app.routers.messages.broadcast_event"), patch("app.services.message_send.asyncio.create_task", side_effect=schedule_retry), @@ -477,7 +477,7 @@ class TestOutgoingChannelBroadcast: broadcasts.append({"type": event_type, "data": data}) with ( - patch("app.routers.messages.require_connected", return_value=mc), + patch("app.routers.messages.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch("app.routers.messages.broadcast_event", side_effect=capture_broadcast), ): @@ -511,7 +511,7 @@ class TestOutgoingChannelBroadcast: assert original_id is not None with ( - patch("app.routers.messages.require_connected", return_value=mc), + patch("app.routers.messages.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch("app.routers.messages.broadcast_event"), patch("app.routers.messages.time") as mock_time, @@ -537,7 +537,7 @@ class TestOutgoingChannelBroadcast: await ChannelRepository.upsert(key=chan_key, name="#acked") with ( - patch("app.routers.messages.require_connected", return_value=mc), + patch("app.routers.messages.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch("app.routers.messages.broadcast_event"), ): @@ -564,7 +564,7 @@ class TestOutgoingChannelBroadcast: broadcasts.append({"type": event_type, "data": data}) with ( - patch("app.routers.messages.require_connected", return_value=mc), + patch("app.routers.messages.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch("app.routers.messages.broadcast_event", side_effect=capture_broadcast), ): @@ -594,7 +594,7 @@ class TestOutgoingChannelBroadcast: await AppSettingsRepository.update(flood_scope="Baseline") with ( - patch("app.routers.messages.require_connected", return_value=mc), + patch("app.routers.messages.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch("app.routers.messages.broadcast_event"), ): @@ -617,7 +617,7 @@ class TestOutgoingChannelBroadcast: await AppSettingsRepository.update(flood_scope="Esperance") with ( - patch("app.routers.messages.require_connected", return_value=mc), + patch("app.routers.messages.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch("app.routers.messages.broadcast_event"), ): @@ -638,7 +638,7 @@ class TestOutgoingChannelBroadcast: ) with ( - patch("app.routers.messages.require_connected", return_value=mc), + patch("app.routers.messages.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch("app.routers.messages.broadcast_event"), pytest.raises(HTTPException) as exc_info, @@ -660,7 +660,7 @@ class TestOutgoingChannelBroadcast: radio_manager._connection_info = "Serial: /dev/ttyUSB0" with ( - patch("app.routers.messages.require_connected", return_value=mc), + patch("app.routers.messages.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch("app.routers.messages.broadcast_event"), ): @@ -688,7 +688,7 @@ class TestOutgoingChannelBroadcast: radio_manager._connection_info = "Serial: /dev/ttyUSB0" with ( - patch("app.routers.messages.require_connected", return_value=mc), + patch("app.routers.messages.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch("app.routers.messages.broadcast_event"), ): @@ -729,7 +729,7 @@ class TestOutgoingChannelBroadcast: radio_manager._connection_info = "TCP: 127.0.0.1:4000" with ( - patch("app.routers.messages.require_connected", return_value=mc), + patch("app.routers.messages.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch("app.routers.messages.broadcast_event"), ): @@ -753,7 +753,7 @@ class TestOutgoingChannelBroadcast: radio_manager._connection_info = "Serial: /dev/ttyUSB0" with ( - patch("app.routers.messages.require_connected", return_value=mc), + patch("app.routers.messages.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch("app.routers.messages.broadcast_event"), patch("app.radio.settings.force_channel_slot_reconfigure", True), @@ -781,7 +781,7 @@ class TestOutgoingChannelBroadcast: ) with ( - patch("app.routers.messages.require_connected", return_value=mc), + patch("app.routers.messages.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch("app.routers.messages.broadcast_event"), pytest.raises(HTTPException) as exc_info, @@ -816,7 +816,7 @@ class TestResendChannelMessage: assert msg_id is not None with ( - patch("app.routers.messages.require_connected", return_value=mc), + patch("app.routers.messages.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), ): result = await resend_channel_message(msg_id, new_timestamp=False) @@ -849,7 +849,7 @@ class TestResendChannelMessage: assert msg_id is not None with ( - patch("app.routers.messages.require_connected", return_value=mc), + patch("app.routers.messages.radio_manager.require_connected", return_value=mc), pytest.raises(HTTPException) as exc_info, ): await resend_channel_message(msg_id, new_timestamp=False) @@ -877,7 +877,7 @@ class TestResendChannelMessage: assert msg_id is not None with ( - patch("app.routers.messages.require_connected", return_value=mc), + patch("app.routers.messages.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), ): await resend_channel_message(msg_id, new_timestamp=False) @@ -914,7 +914,7 @@ class TestResendChannelMessage: ) with ( - patch("app.routers.messages.require_connected", return_value=mc), + patch("app.routers.messages.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch("app.routers.messages.broadcast_error") as mock_broadcast_error, ): @@ -943,7 +943,7 @@ class TestResendChannelMessage: assert msg_id is not None with ( - patch("app.routers.messages.require_connected", return_value=mc), + patch("app.routers.messages.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch("app.routers.messages.broadcast_event"), patch("app.routers.messages.time") as mock_time, @@ -989,7 +989,7 @@ class TestResendChannelMessage: mc.commands.send_chan_msg = AsyncMock(return_value=None) with ( - patch("app.routers.messages.require_connected", return_value=mc), + patch("app.routers.messages.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), pytest.raises(HTTPException) as exc_info, ): @@ -1022,7 +1022,7 @@ class TestResendChannelMessage: assert msg_id is not None with ( - patch("app.routers.messages.require_connected", return_value=mc), + patch("app.routers.messages.radio_manager.require_connected", return_value=mc), pytest.raises(HTTPException) as exc_info, ): await resend_channel_message(msg_id, new_timestamp=False) @@ -1048,7 +1048,7 @@ class TestResendChannelMessage: assert msg_id is not None with ( - patch("app.routers.messages.require_connected", return_value=mc), + patch("app.routers.messages.radio_manager.require_connected", return_value=mc), pytest.raises(HTTPException) as exc_info, ): await resend_channel_message(msg_id, new_timestamp=False) @@ -1062,7 +1062,7 @@ class TestResendChannelMessage: mc = _make_mc(name="MyNode") with ( - patch("app.routers.messages.require_connected", return_value=mc), + patch("app.routers.messages.radio_manager.require_connected", return_value=mc), pytest.raises(HTTPException) as exc_info, ): await resend_channel_message(999999, new_timestamp=False) @@ -1088,7 +1088,7 @@ class TestResendChannelMessage: assert msg_id is not None with ( - patch("app.routers.messages.require_connected", return_value=mc), + patch("app.routers.messages.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), ): await resend_channel_message(msg_id, new_timestamp=False) @@ -1115,7 +1115,7 @@ class TestResendChannelMessage: assert msg_id is not None with ( - patch("app.routers.messages.require_connected", return_value=mc), + patch("app.routers.messages.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch("app.routers.messages.broadcast_event"), ): @@ -1144,7 +1144,7 @@ class TestResendChannelMessage: assert msg_id is not None with ( - patch("app.routers.messages.require_connected", return_value=mc), + patch("app.routers.messages.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch("app.routers.messages.broadcast_event"), ): @@ -1179,7 +1179,7 @@ class TestResendChannelMessage: assert msg_id is not None with ( - patch("app.routers.messages.require_connected", return_value=mc), + patch("app.routers.messages.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch("app.routers.messages.broadcast_event") as mock_broadcast, ): @@ -1211,7 +1211,7 @@ class TestResendChannelMessage: assert msg_id is not None with ( - patch("app.routers.messages.require_connected", return_value=mc), + patch("app.routers.messages.radio_manager.require_connected", return_value=mc), pytest.raises(HTTPException) as exc_info, ): await resend_channel_message(msg_id, new_timestamp=False) @@ -1234,7 +1234,7 @@ class TestRadioExceptionMidSend: mc.commands.send_msg = AsyncMock(side_effect=ConnectionError("Serial port disconnected")) with ( - patch("app.routers.messages.require_connected", return_value=mc), + patch("app.routers.messages.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), ): with pytest.raises(ConnectionError): @@ -1258,7 +1258,7 @@ class TestRadioExceptionMidSend: mc.commands.send_msg = AsyncMock(return_value=None) with ( - patch("app.routers.messages.require_connected", return_value=mc), + patch("app.routers.messages.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), pytest.raises(HTTPException) as exc_info, ): @@ -1286,7 +1286,7 @@ class TestRadioExceptionMidSend: mc.commands.send_chan_msg = AsyncMock(return_value=None) with ( - patch("app.routers.messages.require_connected", return_value=mc), + patch("app.routers.messages.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), pytest.raises(HTTPException) as exc_info, ): @@ -1316,7 +1316,7 @@ class TestRadioExceptionMidSend: ) with ( - patch("app.routers.messages.require_connected", return_value=mc), + patch("app.routers.messages.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), ): with pytest.raises(ConnectionError): @@ -1341,7 +1341,7 @@ class TestRadioExceptionMidSend: mc.commands.set_channel = AsyncMock(side_effect=TimeoutError("Radio not responding")) with ( - patch("app.routers.messages.require_connected", return_value=mc), + patch("app.routers.messages.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), ): with pytest.raises(TimeoutError): @@ -1377,7 +1377,7 @@ class TestRadioExceptionMidSend: mc.commands.set_channel = AsyncMock(side_effect=TimeoutError("Radio not responding")) with ( - patch("app.routers.messages.require_connected", return_value=mc), + patch("app.routers.messages.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), ): with pytest.raises(TimeoutError): @@ -1407,7 +1407,7 @@ class TestRadioExceptionMidSend: ) with ( - patch("app.routers.messages.require_connected", return_value=mc), + patch("app.routers.messages.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), pytest.raises(HTTPException) as exc_info, ): @@ -1440,7 +1440,7 @@ class TestConcurrentChannelSends: await ChannelRepository.upsert(key=chan_key_b, name="#bravo") with ( - patch("app.routers.messages.require_connected", return_value=mc), + patch("app.routers.messages.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch("app.routers.messages.broadcast_event"), ): @@ -1494,7 +1494,7 @@ class TestConcurrentChannelSends: return original_time() + call_count with ( - patch("app.routers.messages.require_connected", return_value=mc), + patch("app.routers.messages.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch("app.routers.messages.broadcast_event"), patch("app.routers.messages.time") as mock_time, @@ -1537,7 +1537,7 @@ class TestChannelSendLockScope: return await original_create(*args, **kwargs) with ( - patch("app.routers.messages.require_connected", return_value=mc), + patch("app.routers.messages.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch("app.routers.messages.broadcast_event"), patch( @@ -1587,7 +1587,7 @@ class TestChannelSendLockScope: mc.commands.send_chan_msg = AsyncMock(side_effect=send_with_self_observation) with ( - patch("app.routers.messages.require_connected", return_value=mc), + patch("app.routers.messages.radio_manager.require_connected", return_value=mc), patch.object(radio_manager, "_meshcore", mc), patch("app.routers.messages.broadcast_event", side_effect=capture_broadcast), ):