"""Recording integrity work must leave the UI thread free and report failures.""" import threading from PySide6.QtCore import QObject, QTimer, Slot, QCoreApplication, QEvent, QThreadPool from PySide6.QtTest import QTest from orisys_autocal.ui.review_job import ReviewJob def test_review_job_runs_off_thread_and_keeps_qt_responsive(qt_app): started, release = threading.Event(), threading.Event() main_thread = threading.get_ident() results, ticks = [], [] class Receiver(QObject): @Slot(object, object) def receive(self, value, error): results.append((value, error, threading.get_ident())) receiver = Receiver() def action(): started.set() assert release.wait(3) return threading.get_ident() job = ReviewJob(action, receiver.receive) job.start() try: assert started.wait(2) QTimer.singleShot(0, lambda: ticks.append(True)) QTest.qWait(20) assert ticks == [True] and results == [] finally: release.set() for _ in range(100): if results: break QTest.qWait(10) assert len(results) == 1 assert results[0][0] != main_thread assert results[0][1] is None and results[0][2] == main_thread def test_unexpected_review_job_failure_returns_to_receiver(qt_app): results = [] class Receiver(QObject): @Slot(object, object) def receive(self, value, error): results.append((value, error)) receiver = Receiver() def action(): raise RuntimeError("decoder failed") job = ReviewJob(action, receiver.receive) job.start() for _ in range(100): if results: break QTest.qWait(10) assert results == [(None, "decoder failed")] def test_review_job_can_finish_after_its_receiver_is_destroyed(qt_app): started, release, finished = threading.Event(), threading.Event(), threading.Event() results = [] class Receiver(QObject): @Slot(object, object) def receive(self, value, error): results.append((value, error)) receiver = Receiver() def action(): started.set() assert release.wait(3) finished.set() return "done" job = ReviewJob(action, receiver.receive) job.start() try: assert started.wait(2) receiver.deleteLater() QCoreApplication.sendPostedEvents(receiver, QEvent.Type.DeferredDelete) finally: release.set() assert QThreadPool.globalInstance().waitForDone(3000) qt_app.processEvents() assert finished.is_set() and results == []