test: the on-demand routes' other callers ack over the socket, not the mailbox

test_api_v3_bool_coercion, test_api_v3_lazy_plugin_discovery and
test_web_api's stop test checked the mailbox write; they now get an ack
from a mocked control socket. The stop route touches no manager any more,
so it leaves the removed-catch-all sample. A request that was sent is
never 'not listening' (pins the sent check the mutation run let through).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Chuck
2026-10-05 09:40:31 -04:00
co-authored by Claude Opus 5.5
parent c461f4efdb
commit fd0a4b50f9
5 changed files with 36 additions and 14 deletions
+4 -1
View File
@@ -54,7 +54,10 @@ class TestOnDemandStart:
def service(self, api_v3_module): def service(self, api_v3_module):
api_v3_module.api_v3.plugin_catalog = None api_v3_module.api_v3.plugin_catalog = None
api_v3_module.api_v3.config_manager = None api_v3_module.api_v3.config_manager = None
with patch("web_interface.blueprints.api_v3.display._get_display_service_status", # The display answers the control socket (the only way in).
with patch("web_interface.blueprints.api_v3.display.control_client.on_demand_start",
side_effect=lambda request_id, *a: {"accepted": True}), \
patch("web_interface.blueprints.api_v3.display._get_display_service_status",
return_value={"active": True}), \ return_value={"active": True}), \
patch("web_interface.blueprints.api_v3.display._stop_display_service") as stop, \ patch("web_interface.blueprints.api_v3.display._stop_display_service") as stop, \
patch("web_interface.blueprints.api_v3.display._ensure_display_service_running", patch("web_interface.blueprints.api_v3.display._ensure_display_service_running",
+15 -4
View File
@@ -77,11 +77,22 @@ def fresh_web_process(api_v3_module, plugins_dir):
@pytest.fixture @pytest.fixture
def display_service(api_v3_module): def display_service(api_v3_module):
"""Keep on-demand start away from systemctl and the real cache.""" """Keep on-demand start away from systemctl and the real cache; the
cache = api_v3_module.api_v3.cache_manager = MagicMock() display's control socket is a mock that acks. What it was sent is
with patch('web_interface.blueprints.api_v3.display._get_display_service_status') as status: recorded as ``.set(cmd, request)`` calls on the yielded mock."""
api_v3_module.api_v3.cache_manager = MagicMock()
sent = MagicMock()
def ack(request_id, plugin_id, mode, *a, **kw):
sent.set('on_demand.start', {'request_id': request_id,
'plugin_id': plugin_id, 'mode': mode})
return {'accepted': True}
with patch('web_interface.blueprints.api_v3.display._get_display_service_status') as status, \
patch('web_interface.blueprints.api_v3.display.control_client.on_demand_start',
side_effect=ack):
status.return_value = {'active': True} status.return_value = {'active': True}
yield cache yield sent
def _start(client, **body): def _start(client, **body):
+6
View File
@@ -144,6 +144,12 @@ class TestSent:
def test_a_client_without_the_socket_is_not_waiting_for_a_display(self, reason): def test_a_client_without_the_socket_is_not_waiting_for_a_display(self, reason):
assert not client.display_not_listening(client.ControlError(reason)) assert not client.display_not_listening(client.ControlError(reason))
@pytest.mark.parametrize('reason', sorted(client.NOT_LISTENING_REASONS))
def test_a_request_that_was_sent_had_a_display(self, reason):
# Only a request that never left can be waited on and sent again: one
# that was sent may have been applied.
assert not client.display_not_listening(client.ControlError(reason, sent=True))
def test_a_client_bug_is_not_a_missing_display(self): def test_a_client_bug_is_not_a_missing_display(self):
assert not client.display_not_listening(RuntimeError('boom')) assert not client.display_not_listening(RuntimeError('boom'))
+8 -5
View File
@@ -529,13 +529,16 @@ class TestDisplayAPI:
mock_cache_manager = api_v3.cache_manager = MagicMock() mock_cache_manager = api_v3.cache_manager = MagicMock()
with patch('web_interface.blueprints.api_v3.display.control_client.on_demand_stop',
side_effect=lambda request_id, **kw: {'accepted': True}) as stop:
response = client.post('/api/v3/display/on-demand/stop') response = client.post('/api/v3/display/on-demand/stop')
# May return 200 if successful or 500 on error assert response.status_code == 200
assert response.status_code in [200, 500] assert response.get_json()['data']['transport'] == 'socket'
# Verify stop request was set in cache if successful stop.assert_called_once()
if response.status_code == 200: # The request goes over the control socket; nothing is written to
assert mock_cache_manager.set.called # the cache (the file mailbox is gone).
mock_cache_manager.set.assert_not_called()
class TestPluginsAPI: class TestPluginsAPI:
@@ -81,7 +81,6 @@ REMOVED_CATCH_ALLS = [
("GET", "/api/v3/config/main", None), ("GET", "/api/v3/config/main", None),
("GET", "/api/v3/config/secrets", None), ("GET", "/api/v3/config/secrets", None),
("GET", "/api/v3/display/modes", None), ("GET", "/api/v3/display/modes", None),
("POST", "/api/v3/display/on-demand/stop", {}),
("GET", "/api/v3/cache/list", None), ("GET", "/api/v3/cache/list", None),
("GET", "/api/v3/plugins/installed", None), ("GET", "/api/v3/plugins/installed", None),
("GET", "/api/v3/plugins/health", None), ("GET", "/api/v3/plugins/health", None),