test: stop the suite reinstalling plugins into the real plugin-repos/ (#679)

Any test that imported web_interface.app and sent a request fired the app's
startup reconciliation, which runs against the checkout's real config.json
and plugin-repos/ and reinstalls every configured-but-missing plugin from the
live store. A full Windows run left basketball-scoreboard, calendar,
football-scoreboard, leaderboard and ledmatrix-stocks untracked in
plugin-repos/ (not gitignored) from that daemon thread.

test/conftest.py now installs an import hook that sets the app's run-once
_reconciliation_started latch as the module finishes executing, so lazy
imports, module-level imports and reloads all start disarmed.
StateReconciliation's own tests are unaffected. A regression test pins that
a request to the imported app launches no reconciliation thread.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Chuck
2026-09-29 17:47:32 -04:00
committed by GitHub
co-authored by Claude Opus 5.5
parent c4c46d3ba7
commit 6047eb5e4e
2 changed files with 73 additions and 1 deletions
@@ -0,0 +1,23 @@
"""
No test may start the real app's startup reconciliation.
web_interface/app.py reads the checkout's real config/config.json and
plugin-repos/ at import, and its first request launches a reconciliation
thread that reinstalls every configured-but-missing plugin from the live
store. A full suite run on a dev checkout used to leave whole plugins
untracked in plugin-repos/ that way. test/conftest.py disarms the run-once
latch on every import of the module; this pins that.
"""
from unittest.mock import MagicMock, patch
def test_a_request_to_the_imported_app_launches_no_reconciliation():
import web_interface.app as web_app
assert web_app._reconciliation_started is True
with patch.object(web_app, "threading", MagicMock()) as threading_mock:
web_app.app.test_client().get("/favicon.ico")
threading_mock.Thread.assert_not_called()