mirror of https://github.com/Nezreka/SoulSync.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
67 lines
2.4 KiB
67 lines
2.4 KiB
"""The auto-reconcile must run as the FINAL scan phase — inside the worker's
|
|
completion, BEFORE the 'finished' signal — so the scan's status stays
|
|
'running' through it. That ordering is what makes automations (which poll for
|
|
completion), the dashboard card, and the Tools page all treat the reconcile as
|
|
part of the scan and wait for it, rather than seeing 'finished' early and
|
|
missing the tail. These pin that contract on DatabaseUpdateWorker._emit_finished.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from core.database_update_worker import DatabaseUpdateWorker
|
|
|
|
|
|
def _bare_worker():
|
|
# __new__ avoids the full media-client/config init; _emit_finished only
|
|
# touches self.callbacks + self.post_scan_hook.
|
|
w = DatabaseUpdateWorker.__new__(DatabaseUpdateWorker)
|
|
w.callbacks = {'finished': [], 'error': [], 'progress_updated': [],
|
|
'phase_changed': [], 'artist_processed': []}
|
|
w.post_scan_hook = None
|
|
return w
|
|
|
|
|
|
def test_post_scan_hook_runs_before_finished():
|
|
w = _bare_worker()
|
|
order = []
|
|
w.post_scan_hook = lambda worker: order.append('hook')
|
|
w.callbacks['finished'].append(lambda *a: order.append('finished'))
|
|
w._emit_finished(1, 2, 3, 4, 5)
|
|
assert order == ['hook', 'finished'] # reconcile happens inside the running window
|
|
|
|
|
|
def test_finished_receives_original_args():
|
|
w = _bare_worker()
|
|
got = []
|
|
w.callbacks['finished'].append(lambda *a: got.append(a))
|
|
w._emit_finished(1, 2, 3, 4, 5)
|
|
assert got == [(1, 2, 3, 4, 5)]
|
|
|
|
|
|
def test_no_hook_still_emits_finished():
|
|
# Backward-compatible: a worker with no hook signals finished exactly as before.
|
|
w = _bare_worker()
|
|
got = []
|
|
w.callbacks['finished'].append(lambda *a: got.append(a))
|
|
w._emit_finished(0, 0, 0, 0, 0)
|
|
assert got == [(0, 0, 0, 0, 0)]
|
|
|
|
|
|
def test_hook_exception_never_blocks_finished():
|
|
# A reconcile failure must not strand the scan as perpetually 'running'.
|
|
w = _bare_worker()
|
|
fired = []
|
|
w.post_scan_hook = lambda worker: (_ for _ in ()).throw(RuntimeError("boom"))
|
|
w.callbacks['finished'].append(lambda *a: fired.append(a))
|
|
w._emit_finished(1, 1, 1, 1, 1)
|
|
assert fired == [(1, 1, 1, 1, 1)]
|
|
|
|
|
|
def test_hook_receives_the_worker():
|
|
w = _bare_worker()
|
|
seen = []
|
|
w.post_scan_hook = lambda worker: seen.append(worker)
|
|
w.callbacks['finished'].append(lambda *a: None)
|
|
w._emit_finished(0, 0, 0, 0, 0)
|
|
assert seen == [w]
|