mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-10-18 04:49:13 +00:00
CodeRabbit raised six; all six were real. The test double had drifted ahead of production. VisualTestDisplayManager accepted set_scrolling_state(frame_hold=...) while DisplayManager did not, so such a call passed every harness run and would raise TypeError on the panel -- the one failure a safety harness exists to prevent. frame_hold belongs to the change that adds it to DisplayManager (#523), so it moves there and the double matches main again. The harness swallowed exceptions from re-rendered frames. _settle_loop re-renders a mode that came back blank, to give a scroll time to draw; returning silently on a crash meant a mode that renders one good frame and then explodes was reported as passing. Recorded on result.error now, keeping the captured frame so the failure stays inspectable. starlark-apps display() returned True after _display_frame() failed, so the controller held a dead frame for the whole display_duration instead of rotating on. _display_frame now returns bool on all three paths. run_plugin_tests.py used env.setdefault for PYTHONPATH and LEDMATRIX_CORE, so an inherited value won and the subprocess imported a different core than the one under test -- ledmatrix-plugins#467 exactly. Prepends PROJECT_ROOT and sets LEDMATRIX_CORE unconditionally. The on-demand mailbox is polled after every frame, ~125x/second on a scrolling mode, and the read is deliberately uncached, so it was that many disk reads per second to find nothing. Floored at 250ms, which is imperceptible for a web-UI click. Consuming it also deleted whatever was present rather than what had just been processed, so a request posted while the previous one was in flight was thrown away and never ran; the delete is now keyed by request_id. That narrows the window rather than closing it -- a true atomic claim needs a primitive the cache layer does not offer, and the code says so rather than implying otherwise. Codacy's 2 criticals were bandit B404/B603 on the subprocess call added to run_plugin_tests.py. Fixed interpreter, argument list, no shell; annotated with the repo's existing nosec convention. Bandit is clean on the file. Adds test/test_on_demand_mailbox.py (8), test_starlark_display_contract.py (4) and two settle cases in test_harness_empty_claimed.py. 4, 4 and 2 of those fail against the pre-fix code. Full suite: 3961 passed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014RRtqXDCnvnY6EQwhT5CV9
83 lines
2.7 KiB
Python
83 lines
2.7 KiB
Python
"""starlark-apps: display() must report what actually reached the panel.
|
|
|
|
The display controller skips a mode only on a boolean False. Returning True
|
|
after the frame update failed told it the mode had rendered, so it held a dead
|
|
frame for the whole display_duration instead of rotating on -- the same class
|
|
of defect as a display() that returns None.
|
|
"""
|
|
|
|
import sys
|
|
from pathlib import Path
|
|
from unittest.mock import MagicMock
|
|
|
|
import pytest
|
|
|
|
PLUGIN_DIR = Path(__file__).resolve().parent.parent / "plugin-repos" / "starlark-apps"
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def manager_module():
|
|
if not PLUGIN_DIR.exists():
|
|
pytest.skip("starlark-apps plugin is not checked out")
|
|
sys.path.insert(0, str(PLUGIN_DIR))
|
|
try:
|
|
import importlib
|
|
spec = importlib.util.spec_from_file_location(
|
|
"starlark_manager_under_test", PLUGIN_DIR / "manager.py")
|
|
module = importlib.util.module_from_spec(spec)
|
|
spec.loader.exec_module(module)
|
|
return module
|
|
except Exception as e: # noqa: BLE001 - optional deps (pixlet, fcntl) may be absent
|
|
pytest.skip(f"starlark-apps manager is not importable here: {e}")
|
|
finally:
|
|
sys.path.remove(str(PLUGIN_DIR))
|
|
|
|
|
|
def _plugin(manager_module):
|
|
"""A manager with __init__ bypassed -- only display paths are under test."""
|
|
cls = manager_module.StarlarkAppsPlugin
|
|
inst = cls.__new__(cls)
|
|
inst.logger = MagicMock()
|
|
inst.display_manager = MagicMock()
|
|
inst.current_app = None
|
|
return inst
|
|
|
|
|
|
class _App:
|
|
def __init__(self, frames):
|
|
self.frames = frames
|
|
self.current_frame_index = 0
|
|
self.last_frame_time = 0.0
|
|
self.app_id = "app"
|
|
|
|
|
|
class TestDisplayFramePropagates:
|
|
def test_a_failed_update_returns_false(self, manager_module):
|
|
p = _plugin(manager_module)
|
|
p.current_app = _App([("frame", 100)])
|
|
p.display_manager.update_display.side_effect = RuntimeError("panel gone")
|
|
|
|
assert p._display_frame() is False
|
|
|
|
def test_a_good_update_returns_true(self, manager_module):
|
|
p = _plugin(manager_module)
|
|
p.current_app = _App([("frame", 100)])
|
|
|
|
assert p._display_frame() is True
|
|
|
|
def test_no_frames_returns_false(self, manager_module):
|
|
p = _plugin(manager_module)
|
|
p.current_app = _App([])
|
|
|
|
assert p._display_frame() is False
|
|
|
|
def test_display_reports_the_frame_failure(self, manager_module):
|
|
p = _plugin(manager_module)
|
|
p.current_app = _App([("frame", 100)])
|
|
p.display_manager.update_display.side_effect = RuntimeError("panel gone")
|
|
|
|
result = p.display()
|
|
|
|
assert result is False, "display() claimed success over a failed frame update"
|
|
assert isinstance(result, bool), "the controller only skips on a real bool"
|