mirror of
https://github.com/jkingsman/Remote-Terminal-for-MeshCore.git
synced 2026-08-07 17:23:05 +02:00
Rework radio lock handling
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
"""Tests for shared radio operation locking behavior."""
|
||||
|
||||
import asyncio
|
||||
from unittest.mock import AsyncMock, MagicMock
|
||||
|
||||
import pytest
|
||||
|
||||
from app.radio import RadioOperationBusyError, radio_manager
|
||||
from app.radio_sync import is_polling_paused
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def reset_radio_operation_state():
|
||||
"""Reset shared radio operation lock state before/after each test."""
|
||||
prev_meshcore = radio_manager._meshcore
|
||||
radio_manager._operation_lock = None
|
||||
radio_manager._meshcore = None
|
||||
|
||||
import app.radio_sync as radio_sync
|
||||
|
||||
radio_sync._polling_pause_count = 0
|
||||
yield
|
||||
radio_manager._operation_lock = None
|
||||
radio_manager._meshcore = prev_meshcore
|
||||
radio_sync._polling_pause_count = 0
|
||||
|
||||
|
||||
class TestRadioOperationLock:
|
||||
"""Validate shared radio operation lock semantics."""
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_non_blocking_fails_when_lock_held_by_other_task(self):
|
||||
started = asyncio.Event()
|
||||
release = asyncio.Event()
|
||||
|
||||
async def holder():
|
||||
async with radio_manager.radio_operation("holder"):
|
||||
started.set()
|
||||
await release.wait()
|
||||
|
||||
holder_task = asyncio.create_task(holder())
|
||||
await started.wait()
|
||||
|
||||
with pytest.raises(RadioOperationBusyError):
|
||||
async with radio_manager.radio_operation("contender", blocking=False):
|
||||
pass
|
||||
|
||||
release.set()
|
||||
await holder_task
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_suspend_auto_fetch_stops_and_restarts(self):
|
||||
mc = MagicMock()
|
||||
mc.stop_auto_message_fetching = AsyncMock()
|
||||
mc.start_auto_message_fetching = AsyncMock()
|
||||
radio_manager._meshcore = mc
|
||||
|
||||
async with radio_manager.radio_operation(
|
||||
"auto_fetch_toggle",
|
||||
suspend_auto_fetch=True,
|
||||
):
|
||||
pass
|
||||
|
||||
mc.stop_auto_message_fetching.assert_awaited_once()
|
||||
mc.start_auto_message_fetching.assert_awaited_once()
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_lock_released_when_auto_fetch_restart_is_cancelled(self):
|
||||
mc = MagicMock()
|
||||
mc.stop_auto_message_fetching = AsyncMock()
|
||||
mc.start_auto_message_fetching = AsyncMock(side_effect=asyncio.CancelledError())
|
||||
radio_manager._meshcore = mc
|
||||
|
||||
with pytest.raises(asyncio.CancelledError):
|
||||
async with radio_manager.radio_operation(
|
||||
"cancelled_restart",
|
||||
suspend_auto_fetch=True,
|
||||
):
|
||||
pass
|
||||
|
||||
async with radio_manager.radio_operation("after_cancel", blocking=False):
|
||||
pass
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_pause_polling_toggles_state(self):
|
||||
assert not is_polling_paused()
|
||||
|
||||
async with radio_manager.radio_operation("pause_polling", pause_polling=True):
|
||||
assert is_polling_paused()
|
||||
|
||||
assert not is_polling_paused()
|
||||
@@ -156,7 +156,7 @@ class TestRebootAndReconnect:
|
||||
mock_rm.meshcore = MagicMock()
|
||||
mock_rm.meshcore.commands.reboot = AsyncMock()
|
||||
|
||||
with patch("app.radio.radio_manager", mock_rm):
|
||||
with patch("app.routers.radio.radio_manager", mock_rm):
|
||||
result = await reboot_radio()
|
||||
|
||||
assert result["status"] == "ok"
|
||||
@@ -169,7 +169,7 @@ class TestRebootAndReconnect:
|
||||
mock_rm.meshcore = None
|
||||
mock_rm.is_reconnecting = True
|
||||
|
||||
with patch("app.radio.radio_manager", mock_rm):
|
||||
with patch("app.routers.radio.radio_manager", mock_rm):
|
||||
result = await reboot_radio()
|
||||
|
||||
assert result["status"] == "pending"
|
||||
@@ -184,7 +184,7 @@ class TestRebootAndReconnect:
|
||||
mock_rm.reconnect = AsyncMock(return_value=True)
|
||||
mock_rm.post_connect_setup = AsyncMock()
|
||||
|
||||
with patch("app.radio.radio_manager", mock_rm):
|
||||
with patch("app.routers.radio.radio_manager", mock_rm):
|
||||
result = await reboot_radio()
|
||||
|
||||
assert result["status"] == "ok"
|
||||
@@ -197,7 +197,7 @@ class TestRebootAndReconnect:
|
||||
mock_rm = MagicMock()
|
||||
mock_rm.is_connected = True
|
||||
|
||||
with patch("app.radio.radio_manager", mock_rm):
|
||||
with patch("app.routers.radio.radio_manager", mock_rm):
|
||||
result = await reconnect_radio()
|
||||
|
||||
assert result["status"] == "ok"
|
||||
@@ -210,7 +210,7 @@ class TestRebootAndReconnect:
|
||||
mock_rm.is_reconnecting = False
|
||||
mock_rm.reconnect = AsyncMock(return_value=False)
|
||||
|
||||
with patch("app.radio.radio_manager", mock_rm):
|
||||
with patch("app.routers.radio.radio_manager", mock_rm):
|
||||
with pytest.raises(HTTPException) as exc:
|
||||
await reconnect_radio()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user