From f16b463736976ed01f1ac35c17f4aa98cc2a59fd Mon Sep 17 00:00:00 2001 From: cproudlock Date: Fri, 18 Sep 2026 13:58:43 -0400 Subject: [PATCH] Stop a settings test depending on which tests ran before it CI failed one test that passes here: "no such table: settings", seeding a Setting into a database with no tables. The test was not wrong about the product, it was asking the process-wide plugin_manager to do the work. create_app() re-points that singleton, and eight test modules build their own app, so it belongs to whichever ran last on the xdist worker. _seed_plugin_settings then opens `with self._app.app_context()` on a different app's in-memory SQLite. A sibling symptom is the registry coming back None ("'NoneType' object has no attribute 'get_all'"). Both land on whichever test follows, never on the module that caused them, so they move with the split - green on one machine, red on another. The test now builds a manager for itself, sets _app and _db, and calls _seed_plugin_settings directly. That is the routine `flask plugin upgrade-all` runs, so what is under test has not changed, and the assertion no longer depends on worker order. init_app is deliberately not called: it re-registers the plugin blueprints and a second call on one app raises "The name 'backups' is already registered". This does NOT fix the underlying fragility, and that is a separate decision. Running tests/test_plugins serially today gives 115 failed and 542 errors, from the same cause; under -n auto it is nearly invisible because modules land in separate processes. The repair is to stop create_app mutating a module-level singleton, and it belongs in its own change rather than riding along here. --- .../test_endpoints_settings_declared.py | 27 +++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/tests/test_plugins/test_endpoints_settings_declared.py b/tests/test_plugins/test_endpoints_settings_declared.py index 8bf73036..d8e4d905 100644 --- a/tests/test_plugins/test_endpoints_settings_declared.py +++ b/tests/test_plugins/test_endpoints_settings_declared.py @@ -74,13 +74,30 @@ def test_the_declared_defaults_match_what_the_code_reads_with_no_row(db): def test_the_upgrade_pass_seeds_them_on_a_site_that_installed_earlier(app, db): """install/enable fire only on a state transition, so a fleet already running this plugin gets these rows from `flask plugin upgrade-all`, which - calls sync_all_plugin_settings.""" - pm = app.extensions.get('plugin_manager') - if pm is None: - pytest.skip('no plugin manager in this build') + calls sync_all_plugin_settings -> _seed_plugin_settings. + + This drives _seed_plugin_settings on a manager built for this test rather + than the process-wide plugin_manager singleton, and that is deliberate. + create_app() re-points that singleton, eight test modules build their own + app, and whatever ran last on this xdist worker owns it: the symptoms are + "no such table: settings" (seeding against another app's in-memory SQLite) + and "'NoneType' object has no attribute 'get_all'" (registry left None). + Both land on whichever test follows, so they move with the split - this one + passed locally and failed on CI for exactly that reason. + + init_app is not called here either: it re-registers the plugin blueprints, + and twice on one app raises "The name 'backups' is already registered". + Setting _app and _db is all the seeding routine reads. + """ + from shopdb.plugins import PluginManager + from plugins.endpoints.plugin import EndpointsPlugin + assert Setting.query.filter_by(key=QUERY_KEY).first() is None - pm.sync_all_plugin_settings() + manager = PluginManager() + manager._app = app + manager._db = db + assert manager._seed_plugin_settings(EndpointsPlugin()) is True for key, value in ((REVOKED_KEY, False), (QUERY_KEY, True)): row = Setting.query.filter_by(key=key).one()