mirror of
https://github.com/got-feedBack/feedBack.git
synced 2026-08-11 03:09:57 +00:00
fix(tests): join background scan/enrich workers before closing the DB (#735)
Root cause of the flaky pytest segfault (exit 139): the background scan and enrichment daemon threads (_scan_runner/_enrich_runner) use the shared MetadataDB connection, but test fixtures closed that connection in teardown without stopping them. A daemon thread mid-query on a freed SQLite conn is a native use-after-free → SIGSEGV. The app's startup kicks a scan, so almost any app-booting fixture was vulnerable. It only surfaced now because got-feedback/feedBack#728 added a push trigger, so ci/test runs on every push to main. Fix: server.py retains the scan/enrich thread handles and adds _join_background_db_threads(); every test fixture now joins the workers before conn.close(). Verified: the full suite runs to completion (no segfault) where it previously crashed at ~25%. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
9d6fdfe232
commit
97a941c45d
@@ -5824,6 +5824,27 @@ def _background_scan():
|
|||||||
_scan_kick_lock = threading.Lock()
|
_scan_kick_lock = threading.Lock()
|
||||||
_scan_rescan_pending = False
|
_scan_rescan_pending = False
|
||||||
|
|
||||||
|
# Handles to the running scan / enrichment worker threads. Both use the shared
|
||||||
|
# MetadataDB connection, so teardown/shutdown MUST join them before closing that
|
||||||
|
# connection — a daemon thread mid-query on a closed SQLite conn is a native
|
||||||
|
# use-after-free that segfaults the process (seen flaky in CI). Set by
|
||||||
|
# _kick_scan / _kick_enrich; joined by _join_background_db_threads().
|
||||||
|
_scan_thread: threading.Thread | None = None
|
||||||
|
_enrich_thread: threading.Thread | None = None
|
||||||
|
|
||||||
|
|
||||||
|
def _join_background_db_threads(timeout: float = 30.0) -> None:
|
||||||
|
"""Block until the background scan + enrichment workers finish (or timeout).
|
||||||
|
|
||||||
|
A scan kicks enrichment on completion, so join the scan first — by the time
|
||||||
|
it returns, _kick_enrich() has set _enrich_thread — then join enrichment."""
|
||||||
|
st = _scan_thread
|
||||||
|
if st is not None and st.is_alive():
|
||||||
|
st.join(timeout)
|
||||||
|
et = _enrich_thread
|
||||||
|
if et is not None and et.is_alive():
|
||||||
|
et.join(timeout)
|
||||||
|
|
||||||
|
|
||||||
def _kick_scan() -> bool:
|
def _kick_scan() -> bool:
|
||||||
"""Request a library rescan, single-flight + coalescing.
|
"""Request a library rescan, single-flight + coalescing.
|
||||||
@@ -5835,7 +5856,7 @@ def _kick_scan() -> bool:
|
|||||||
until the next periodic pass. Multiple late-arriving requests coalesce
|
until the next periodic pass. Multiple late-arriving requests coalesce
|
||||||
into a single follow-up.
|
into a single follow-up.
|
||||||
"""
|
"""
|
||||||
global _scan_rescan_pending
|
global _scan_rescan_pending, _scan_thread
|
||||||
with _scan_kick_lock:
|
with _scan_kick_lock:
|
||||||
if _scan_status["running"]:
|
if _scan_status["running"]:
|
||||||
_scan_rescan_pending = True
|
_scan_rescan_pending = True
|
||||||
@@ -5843,7 +5864,8 @@ def _kick_scan() -> bool:
|
|||||||
# Mark running synchronously so a parallel _kick_scan() observes it
|
# Mark running synchronously so a parallel _kick_scan() observes it
|
||||||
# before the worker thread has a chance to reassign _scan_status.
|
# before the worker thread has a chance to reassign _scan_status.
|
||||||
_scan_status["running"] = True
|
_scan_status["running"] = True
|
||||||
threading.Thread(target=_scan_runner, daemon=True).start()
|
_scan_thread = threading.Thread(target=_scan_runner, daemon=True)
|
||||||
|
_scan_thread.start()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
@@ -6538,13 +6560,14 @@ def _kick_enrich() -> bool:
|
|||||||
"""Request an enrichment pass, single-flight + coalescing (the _kick_scan
|
"""Request an enrichment pass, single-flight + coalescing (the _kick_scan
|
||||||
contract): True = a worker thread was started, False = one is running and
|
contract): True = a worker thread was started, False = one is running and
|
||||||
a follow-up pass was queued."""
|
a follow-up pass was queued."""
|
||||||
global _enrich_pending_pass
|
global _enrich_pending_pass, _enrich_thread
|
||||||
with _enrich_kick_lock:
|
with _enrich_kick_lock:
|
||||||
if _enrich_status["running"]:
|
if _enrich_status["running"]:
|
||||||
_enrich_pending_pass = True
|
_enrich_pending_pass = True
|
||||||
return False
|
return False
|
||||||
_enrich_status["running"] = True
|
_enrich_status["running"] = True
|
||||||
threading.Thread(target=_enrich_runner, daemon=True).start()
|
_enrich_thread = threading.Thread(target=_enrich_runner, daemon=True)
|
||||||
|
_enrich_thread.start()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ def server(tmp_path, monkeypatch, isolate_logging):
|
|||||||
finally:
|
finally:
|
||||||
conn = getattr(getattr(srv, "meta_db", None), "conn", None)
|
conn = getattr(getattr(srv, "meta_db", None), "conn", None)
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
sys.modules.pop("server", None)
|
sys.modules.pop("server", None)
|
||||||
|
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ def server(tmp_path, monkeypatch, isolate_logging):
|
|||||||
finally:
|
finally:
|
||||||
conn = getattr(getattr(srv, "meta_db", None), "conn", None)
|
conn = getattr(getattr(srv, "meta_db", None), "conn", None)
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
sys.modules.pop("server", None)
|
sys.modules.pop("server", None)
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ def server(tmp_path, monkeypatch, isolate_logging):
|
|||||||
finally:
|
finally:
|
||||||
conn = getattr(getattr(srv, "meta_db", None), "conn", None)
|
conn = getattr(getattr(srv, "meta_db", None), "conn", None)
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
sys.modules.pop("server", None)
|
sys.modules.pop("server", None)
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ def server(tmp_path, monkeypatch, isolate_logging):
|
|||||||
finally:
|
finally:
|
||||||
conn = getattr(getattr(srv, "meta_db", None), "conn", None)
|
conn = getattr(getattr(srv, "meta_db", None), "conn", None)
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
sys.modules.pop("server", None)
|
sys.modules.pop("server", None)
|
||||||
|
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ def server(tmp_path, monkeypatch, isolate_logging):
|
|||||||
finally:
|
finally:
|
||||||
conn = getattr(getattr(srv, "meta_db", None), "conn", None)
|
conn = getattr(getattr(srv, "meta_db", None), "conn", None)
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
sys.modules.pop("server", None)
|
sys.modules.pop("server", None)
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ def server(tmp_path, monkeypatch, isolate_logging):
|
|||||||
finally:
|
finally:
|
||||||
conn = getattr(getattr(srv, "meta_db", None), "conn", None)
|
conn = getattr(getattr(srv, "meta_db", None), "conn", None)
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
sys.modules.pop("server", None)
|
sys.modules.pop("server", None)
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ def client(tmp_path, monkeypatch):
|
|||||||
for attr in ("meta_db", "audio_effect_mappings"):
|
for attr in ("meta_db", "audio_effect_mappings"):
|
||||||
conn = getattr(getattr(server, attr, None), "conn", None)
|
conn = getattr(getattr(server, attr, None), "conn", None)
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ def client_and_server(tmp_path, monkeypatch):
|
|||||||
meta_db = getattr(server, "meta_db", None)
|
meta_db = getattr(server, "meta_db", None)
|
||||||
conn = getattr(meta_db, "conn", None)
|
conn = getattr(meta_db, "conn", None)
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
@@ -60,6 +61,7 @@ def non_loopback_client(tmp_path, monkeypatch):
|
|||||||
meta_db = getattr(server, "meta_db", None)
|
meta_db = getattr(server, "meta_db", None)
|
||||||
conn = getattr(meta_db, "conn", None)
|
conn = getattr(meta_db, "conn", None)
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ def server(tmp_path, monkeypatch, isolate_logging):
|
|||||||
finally:
|
finally:
|
||||||
conn = getattr(getattr(srv, "meta_db", None), "conn", None)
|
conn = getattr(getattr(srv, "meta_db", None), "conn", None)
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
sys.modules.pop("server", None)
|
sys.modules.pop("server", None)
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ def server_mod(tmp_path, monkeypatch):
|
|||||||
yield mod
|
yield mod
|
||||||
conn = getattr(getattr(mod, "meta_db", None), "conn", None)
|
conn = getattr(getattr(mod, "meta_db", None), "conn", None)
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ def server(tmp_path, monkeypatch, isolate_logging):
|
|||||||
finally:
|
finally:
|
||||||
conn = getattr(getattr(srv, "meta_db", None), "conn", None)
|
conn = getattr(getattr(srv, "meta_db", None), "conn", None)
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
sys.modules.pop("server", None)
|
sys.modules.pop("server", None)
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ def client(tmp_path, monkeypatch):
|
|||||||
finally:
|
finally:
|
||||||
conn = getattr(getattr(server, "meta_db", None), "conn", None)
|
conn = getattr(getattr(server, "meta_db", None), "conn", None)
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
@@ -169,6 +170,7 @@ def test_server_app_request_id_propagated_to_logs(monkeypatch, tmp_path):
|
|||||||
]
|
]
|
||||||
conn = getattr(getattr(server_mod, "meta_db", None), "conn", None)
|
conn = getattr(getattr(server_mod, "meta_db", None), "conn", None)
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
lines = [ln for ln in buf.getvalue().splitlines() if "server_probe_event" in ln]
|
lines = [ln for ln in buf.getvalue().splitlines() if "server_probe_event" in ln]
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ def server(tmp_path, monkeypatch, isolate_logging):
|
|||||||
finally:
|
finally:
|
||||||
conn = getattr(getattr(srv, "meta_db", None), "conn", None)
|
conn = getattr(getattr(srv, "meta_db", None), "conn", None)
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
sys.modules.pop("server", None)
|
sys.modules.pop("server", None)
|
||||||
|
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ def _cleanup(server, client):
|
|||||||
server._DEMO_JANITOR_HOOKS.clear()
|
server._DEMO_JANITOR_HOOKS.clear()
|
||||||
conn = getattr(getattr(server, "meta_db", None), "conn", None)
|
conn = getattr(getattr(server, "meta_db", None), "conn", None)
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
@@ -311,6 +312,7 @@ def test_register_demo_janitor_hook_in_plugin_context(tmp_path, monkeypatch):
|
|||||||
|
|
||||||
conn = getattr(getattr(server, "meta_db", None), "conn", None)
|
conn = getattr(getattr(server, "meta_db", None), "conn", None)
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
# Clean up janitor state so it doesn't bleed into other tests.
|
# Clean up janitor state so it doesn't bleed into other tests.
|
||||||
server._DEMO_JANITOR_STOP.set()
|
server._DEMO_JANITOR_STOP.set()
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ def server(tmp_path, monkeypatch, isolate_logging):
|
|||||||
finally:
|
finally:
|
||||||
conn = getattr(getattr(srv, "meta_db", None), "conn", None)
|
conn = getattr(getattr(srv, "meta_db", None), "conn", None)
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
sys.modules.pop("server", None)
|
sys.modules.pop("server", None)
|
||||||
|
|
||||||
|
|||||||
@@ -100,6 +100,7 @@ def scan_server(tmp_path, monkeypatch, isolate_logging):
|
|||||||
yield mod
|
yield mod
|
||||||
conn = getattr(getattr(mod, "meta_db", None), "conn", None)
|
conn = getattr(getattr(mod, "meta_db", None), "conn", None)
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
@@ -161,6 +162,7 @@ def upload_client(tmp_path, monkeypatch):
|
|||||||
tc.close()
|
tc.close()
|
||||||
conn = getattr(getattr(server, "meta_db", None), "conn", None)
|
conn = getattr(getattr(server, "meta_db", None), "conn", None)
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
@@ -228,6 +230,7 @@ def settings_server(tmp_path, monkeypatch):
|
|||||||
finally:
|
finally:
|
||||||
conn = getattr(getattr(server, "meta_db", None), "conn", None)
|
conn = getattr(getattr(server, "meta_db", None), "conn", None)
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ def server(tmp_path, monkeypatch, isolate_logging):
|
|||||||
finally:
|
finally:
|
||||||
conn = getattr(getattr(srv, "meta_db", None), "conn", None)
|
conn = getattr(getattr(srv, "meta_db", None), "conn", None)
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
sys.modules.pop("server", None)
|
sys.modules.pop("server", None)
|
||||||
|
|
||||||
@@ -255,5 +256,6 @@ def test_demo_mode_blocks_write(tmp_path, monkeypatch, isolate_logging):
|
|||||||
finally:
|
finally:
|
||||||
conn = getattr(getattr(srv, "meta_db", None), "conn", None)
|
conn = getattr(getattr(srv, "meta_db", None), "conn", None)
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
sys.modules.pop("server", None)
|
sys.modules.pop("server", None)
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ def server(tmp_path, monkeypatch, isolate_logging):
|
|||||||
finally:
|
finally:
|
||||||
conn = getattr(getattr(srv, "meta_db", None), "conn", None)
|
conn = getattr(getattr(srv, "meta_db", None), "conn", None)
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
sys.modules.pop("server", None)
|
sys.modules.pop("server", None)
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ def server_mod(monkeypatch, tmp_path):
|
|||||||
yield mod
|
yield mod
|
||||||
conn = getattr(getattr(mod, "meta_db", None), "conn", None)
|
conn = getattr(getattr(mod, "meta_db", None), "conn", None)
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
@@ -124,6 +125,7 @@ def make_client(tmp_path, monkeypatch):
|
|||||||
server = sys.modules.get("server")
|
server = sys.modules.get("server")
|
||||||
conn = getattr(getattr(server, "meta_db", None), "conn", None)
|
conn = getattr(getattr(server, "meta_db", None), "conn", None)
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -103,6 +103,7 @@ def make_client(tmp_path, monkeypatch):
|
|||||||
server = sys.modules.get("server")
|
server = sys.modules.get("server")
|
||||||
conn = getattr(getattr(server, "meta_db", None), "conn", None)
|
conn = getattr(getattr(server, "meta_db", None), "conn", None)
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -130,6 +130,7 @@ def make_client(tmp_path, monkeypatch):
|
|||||||
server = sys.modules.get("server")
|
server = sys.modules.get("server")
|
||||||
conn = getattr(getattr(server, "meta_db", None), "conn", None)
|
conn = getattr(getattr(server, "meta_db", None), "conn", None)
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ def server_mod(tmp_path, monkeypatch):
|
|||||||
yield mod
|
yield mod
|
||||||
conn = getattr(getattr(mod, "meta_db", None), "conn", None)
|
conn = getattr(getattr(mod, "meta_db", None), "conn", None)
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ def server_mod(tmp_path, monkeypatch):
|
|||||||
yield mod
|
yield mod
|
||||||
conn = getattr(getattr(mod, "meta_db", None), "conn", None)
|
conn = getattr(getattr(mod, "meta_db", None), "conn", None)
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ def server_mod(tmp_path, monkeypatch):
|
|||||||
yield mod
|
yield mod
|
||||||
conn = getattr(getattr(mod, "meta_db", None), "conn", None)
|
conn = getattr(getattr(mod, "meta_db", None), "conn", None)
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
@@ -298,4 +299,5 @@ def test_library_provider_registration_is_available_to_plugins(tmp_path, monkeyp
|
|||||||
assert captured["unregister_library_provider"] is server.unregister_library_provider
|
assert captured["unregister_library_provider"] is server.unregister_library_provider
|
||||||
finally:
|
finally:
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ def dlc_client(tmp_path, monkeypatch):
|
|||||||
meta_db = getattr(server, "meta_db", None)
|
meta_db = getattr(server, "meta_db", None)
|
||||||
conn = getattr(meta_db, "conn", None)
|
conn = getattr(meta_db, "conn", None)
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ def server(tmp_path, monkeypatch, isolate_logging):
|
|||||||
finally:
|
finally:
|
||||||
conn = getattr(getattr(srv, "meta_db", None), "conn", None)
|
conn = getattr(getattr(srv, "meta_db", None), "conn", None)
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
sys.modules.pop("server", None)
|
sys.modules.pop("server", None)
|
||||||
|
|
||||||
|
|||||||
@@ -409,6 +409,7 @@ def test_db_uses_wal_journal_mode(setup_routes):
|
|||||||
row = conn.execute("PRAGMA journal_mode").fetchone()
|
row = conn.execute("PRAGMA journal_mode").fetchone()
|
||||||
assert row[0] == "wal"
|
assert row[0] == "wal"
|
||||||
finally:
|
finally:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ def server(tmp_path, monkeypatch, isolate_logging):
|
|||||||
finally:
|
finally:
|
||||||
conn = getattr(getattr(srv, "meta_db", None), "conn", None)
|
conn = getattr(getattr(srv, "meta_db", None), "conn", None)
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
sys.modules.pop("server", None)
|
sys.modules.pop("server", None)
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ def server(tmp_path, monkeypatch, isolate_logging):
|
|||||||
finally:
|
finally:
|
||||||
conn = getattr(getattr(srv, "meta_db", None), "conn", None)
|
conn = getattr(getattr(srv, "meta_db", None), "conn", None)
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
sys.modules.pop("server", None)
|
sys.modules.pop("server", None)
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ def server(tmp_path, monkeypatch, isolate_logging):
|
|||||||
finally:
|
finally:
|
||||||
conn = getattr(getattr(srv, "meta_db", None), "conn", None)
|
conn = getattr(getattr(srv, "meta_db", None), "conn", None)
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
sys.modules.pop("server", None)
|
sys.modules.pop("server", None)
|
||||||
|
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ def server(tmp_path, monkeypatch, isolate_logging):
|
|||||||
finally:
|
finally:
|
||||||
conn = getattr(getattr(srv, "meta_db", None), "conn", None)
|
conn = getattr(getattr(srv, "meta_db", None), "conn", None)
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
sys.modules.pop("server", None)
|
sys.modules.pop("server", None)
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ def server(tmp_path, monkeypatch, isolate_logging):
|
|||||||
finally:
|
finally:
|
||||||
conn = getattr(getattr(srv, "meta_db", None), "conn", None)
|
conn = getattr(getattr(srv, "meta_db", None), "conn", None)
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
sys.modules.pop("server", None)
|
sys.modules.pop("server", None)
|
||||||
|
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ def client(tmp_path, monkeypatch):
|
|||||||
meta_db = getattr(server, "meta_db", None)
|
meta_db = getattr(server, "meta_db", None)
|
||||||
conn = getattr(meta_db, "conn", None)
|
conn = getattr(meta_db, "conn", None)
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
@@ -296,6 +297,7 @@ def server_module(tmp_path, monkeypatch):
|
|||||||
meta_db = getattr(mod, "meta_db", None)
|
meta_db = getattr(mod, "meta_db", None)
|
||||||
conn = getattr(meta_db, "conn", None)
|
conn = getattr(meta_db, "conn", None)
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
@@ -324,6 +326,7 @@ def test_get_dlc_dir_uses_config_when_env_empty(tmp_path, monkeypatch):
|
|||||||
finally:
|
finally:
|
||||||
conn = getattr(getattr(mod, "meta_db", None), "conn", None)
|
conn = getattr(getattr(mod, "meta_db", None), "conn", None)
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
@@ -345,6 +348,7 @@ def test_get_dlc_dir_env_takes_precedence(tmp_path, monkeypatch):
|
|||||||
finally:
|
finally:
|
||||||
conn = getattr(getattr(mod, "meta_db", None), "conn", None)
|
conn = getattr(getattr(mod, "meta_db", None), "conn", None)
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
@@ -362,6 +366,7 @@ def test_get_dlc_dir_env_dot_is_valid(tmp_path, monkeypatch):
|
|||||||
finally:
|
finally:
|
||||||
conn = getattr(getattr(mod, "meta_db", None), "conn", None)
|
conn = getattr(getattr(mod, "meta_db", None), "conn", None)
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
@@ -404,6 +409,7 @@ def scan_module(tmp_path, monkeypatch, isolate_logging):
|
|||||||
yield mod
|
yield mod
|
||||||
conn = getattr(getattr(mod, "meta_db", None), "conn", None)
|
conn = getattr(getattr(mod, "meta_db", None), "conn", None)
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
@@ -525,6 +531,7 @@ def api_client(tmp_path, monkeypatch, isolate_logging):
|
|||||||
finally:
|
finally:
|
||||||
conn = getattr(getattr(server, "meta_db", None), "conn", None)
|
conn = getattr(getattr(server, "meta_db", None), "conn", None)
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
_restore_loaded_plugins(plugins_snapshot)
|
_restore_loaded_plugins(plugins_snapshot)
|
||||||
|
|
||||||
@@ -653,6 +660,7 @@ def test_skip_startup_tasks_does_not_call_load_plugins_or_scan(tmp_path, monkeyp
|
|||||||
finally:
|
finally:
|
||||||
conn = getattr(getattr(server, "meta_db", None), "conn", None)
|
conn = getattr(getattr(server, "meta_db", None), "conn", None)
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
_restore_loaded_plugins(plugins_snapshot)
|
_restore_loaded_plugins(plugins_snapshot)
|
||||||
|
|
||||||
@@ -698,6 +706,7 @@ def test_skip_startup_tasks_clears_stale_plugin_registry(tmp_path, monkeypatch,
|
|||||||
finally:
|
finally:
|
||||||
conn = getattr(getattr(server, "meta_db", None), "conn", None) if server else None
|
conn = getattr(getattr(server, "meta_db", None), "conn", None) if server else None
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
_restore_loaded_plugins(plugins_snapshot)
|
_restore_loaded_plugins(plugins_snapshot)
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ def server_mod(tmp_path, monkeypatch):
|
|||||||
yield mod
|
yield mod
|
||||||
conn = getattr(getattr(mod, "meta_db", None), "conn", None)
|
conn = getattr(getattr(mod, "meta_db", None), "conn", None)
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ def server_mod(tmp_path, monkeypatch):
|
|||||||
yield mod
|
yield mod
|
||||||
conn = getattr(getattr(mod, "meta_db", None), "conn", None)
|
conn = getattr(getattr(mod, "meta_db", None), "conn", None)
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
@@ -87,6 +88,7 @@ def test_export_includes_consistent_library_db_snapshot(client, server_mod, tmp_
|
|||||||
"SELECT title FROM songs WHERE filename = ?", ("snap.archive",)
|
"SELECT title FROM songs WHERE filename = ?", ("snap.archive",)
|
||||||
).fetchall()
|
).fetchall()
|
||||||
finally:
|
finally:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
assert rows == [("SnapSong",)]
|
assert rows == [("SnapSong",)]
|
||||||
|
|
||||||
@@ -271,6 +273,7 @@ def test_full_db_backup_restore_round_trip(client, server_mod, tmp_path):
|
|||||||
"SELECT title FROM songs WHERE filename = ?", ("keepme.archive",)
|
"SELECT title FROM songs WHERE filename = ?", ("keepme.archive",)
|
||||||
).fetchall()
|
).fetchall()
|
||||||
finally:
|
finally:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
assert rows == [("KeepMe",)]
|
assert rows == [("KeepMe",)]
|
||||||
assert not (tmp_path / "web_library.db.restore").exists()
|
assert not (tmp_path / "web_library.db.restore").exists()
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ def env(tmp_path, monkeypatch, isolate_logging):
|
|||||||
finally:
|
finally:
|
||||||
conn = getattr(getattr(srv, "meta_db", None), "conn", None)
|
conn = getattr(getattr(srv, "meta_db", None), "conn", None)
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
sys.modules.pop("server", None)
|
sys.modules.pop("server", None)
|
||||||
|
|
||||||
|
|||||||
@@ -116,6 +116,7 @@ def dlc_client(tmp_path, monkeypatch):
|
|||||||
meta_db = getattr(server, "meta_db", None)
|
meta_db = getattr(server, "meta_db", None)
|
||||||
conn = getattr(meta_db, "conn", None)
|
conn = getattr(meta_db, "conn", None)
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ def dlc_client(tmp_path, monkeypatch):
|
|||||||
meta_db = getattr(server, "meta_db", None)
|
meta_db = getattr(server, "meta_db", None)
|
||||||
conn = getattr(meta_db, "conn", None)
|
conn = getattr(meta_db, "conn", None)
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ def server(tmp_path, monkeypatch, isolate_logging):
|
|||||||
finally:
|
finally:
|
||||||
conn = getattr(getattr(srv, "meta_db", None), "conn", None)
|
conn = getattr(getattr(srv, "meta_db", None), "conn", None)
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
sys.modules.pop("server", None)
|
sys.modules.pop("server", None)
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ def server(tmp_path, monkeypatch, isolate_logging):
|
|||||||
finally:
|
finally:
|
||||||
conn = getattr(getattr(srv, "meta_db", None), "conn", None)
|
conn = getattr(getattr(srv, "meta_db", None), "conn", None)
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
sys.modules.pop("server", None)
|
sys.modules.pop("server", None)
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ def server(tmp_path, monkeypatch, isolate_logging):
|
|||||||
finally:
|
finally:
|
||||||
conn = getattr(getattr(srv, "meta_db", None), "conn", None)
|
conn = getattr(getattr(srv, "meta_db", None), "conn", None)
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
sys.modules.pop("server", None)
|
sys.modules.pop("server", None)
|
||||||
|
|
||||||
|
|||||||
@@ -85,6 +85,7 @@ def client(tmp_path, monkeypatch, isolate_logging):
|
|||||||
finally:
|
finally:
|
||||||
conn = getattr(getattr(server, "meta_db", None), "conn", None)
|
conn = getattr(getattr(server, "meta_db", None), "conn", None)
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
@@ -127,6 +128,7 @@ def startup_harness(tmp_path, monkeypatch, isolate_logging):
|
|||||||
server._DEMO_JANITOR_THREAD = None
|
server._DEMO_JANITOR_THREAD = None
|
||||||
conn = getattr(getattr(server, "meta_db", None), "conn", None)
|
conn = getattr(getattr(server, "meta_db", None), "conn", None)
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
@@ -692,6 +694,7 @@ def test_startup_status_e2e_real_plugin_loader(tmp_path, monkeypatch, isolate_lo
|
|||||||
server._DEMO_JANITOR_THREAD = None
|
server._DEMO_JANITOR_THREAD = None
|
||||||
conn = getattr(getattr(server, "meta_db", None), "conn", None)
|
conn = getattr(getattr(server, "meta_db", None), "conn", None)
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
with plugins_mod.PLUGINS_LOCK:
|
with plugins_mod.PLUGINS_LOCK:
|
||||||
plugins_mod.LOADED_PLUGINS.clear()
|
plugins_mod.LOADED_PLUGINS.clear()
|
||||||
@@ -782,6 +785,7 @@ def test_startup_status_endpoint_background_thread_path(tmp_path, monkeypatch, i
|
|||||||
server._DEMO_JANITOR_THREAD = None
|
server._DEMO_JANITOR_THREAD = None
|
||||||
conn = getattr(getattr(server, "meta_db", None), "conn", None)
|
conn = getattr(getattr(server, "meta_db", None), "conn", None)
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
@@ -830,6 +834,7 @@ def test_startup_status_endpoint_background_thread_failure(tmp_path, monkeypatch
|
|||||||
server._DEMO_JANITOR_THREAD = None
|
server._DEMO_JANITOR_THREAD = None
|
||||||
conn = getattr(getattr(server, "meta_db", None), "conn", None)
|
conn = getattr(getattr(server, "meta_db", None), "conn", None)
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ def client(tmp_path, monkeypatch):
|
|||||||
finally:
|
finally:
|
||||||
conn = getattr(getattr(server, "meta_db", None), "conn", None)
|
conn = getattr(getattr(server, "meta_db", None), "conn", None)
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ def server_mod(tmp_path, monkeypatch):
|
|||||||
yield mod
|
yield mod
|
||||||
conn = getattr(getattr(mod, "meta_db", None), "conn", None)
|
conn = getattr(getattr(mod, "meta_db", None), "conn", None)
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ def server(tmp_path, monkeypatch, isolate_logging):
|
|||||||
finally:
|
finally:
|
||||||
conn = getattr(getattr(srv, "meta_db", None), "conn", None)
|
conn = getattr(getattr(srv, "meta_db", None), "conn", None)
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
sys.modules.pop("server", None)
|
sys.modules.pop("server", None)
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ def server(tmp_path, monkeypatch, isolate_logging):
|
|||||||
finally:
|
finally:
|
||||||
conn = getattr(getattr(srv, "meta_db", None), "conn", None)
|
conn = getattr(getattr(srv, "meta_db", None), "conn", None)
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
|
getattr(__import__("sys").modules.get("server"), "_join_background_db_threads", lambda: None)()
|
||||||
conn.close()
|
conn.close()
|
||||||
sys.modules.pop("server", None)
|
sys.modules.pop("server", None)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user