From 02f8155acb0a19a7ebddba67ce7bb2c5da78e90a Mon Sep 17 00:00:00 2001 From: Loren Eteval Date: Wed, 7 Oct 2026 13:24:48 +0800 Subject: [PATCH] Improve lifetime code readability Signed-off-by: Loren Eteval --- Furious/Controllers/ConnectionController.py | 1 + Furious/Service/ConnectivityManager.py | 1 + Furious/Service/TrafficStatsManager.py | 1 + tests/fixtures/editor_lifetime_probe.py | 6 ++++++ tests/test_architecture_refactors.py | 4 ++++ tests/test_profile_test_jobs.py | 7 +++++++ tests/test_service_runtime.py | 16 ++++++++++++++++ 7 files changed, 36 insertions(+) diff --git a/Furious/Controllers/ConnectionController.py b/Furious/Controllers/ConnectionController.py index af03043c..d8203d91 100644 --- a/Furious/Controllers/ConnectionController.py +++ b/Furious/Controllers/ConnectionController.py @@ -104,6 +104,7 @@ class ConnectionController(QtCore.QObject): self._actionQueue = queue.Queue() self._coreManager = coreManager or ConnectionManager() self._updatesManager = updatesManager or UpdateManager(self) + self._state = ConnectionState.Disconnected self._activeProfile = None self._lastError = None diff --git a/Furious/Service/ConnectivityManager.py b/Furious/Service/ConnectivityManager.py index f92e7935..b3d9490a 100644 --- a/Furious/Service/ConnectivityManager.py +++ b/Furious/Service/ConnectivityManager.py @@ -75,6 +75,7 @@ class ConnectivityManager(Mixins.ConnectionAware, HttpGetManager): # A completed reply may be deleted after another probe has started. # Only the invalid active reply owns this timeout and admission slot. self._activeReply = None + self.jobTimeoutTimer.stop() if self._testingEnabled: diff --git a/Furious/Service/TrafficStatsManager.py b/Furious/Service/TrafficStatsManager.py index 08f9868e..81c1e702 100644 --- a/Furious/Service/TrafficStatsManager.py +++ b/Furious/Service/TrafficStatsManager.py @@ -210,6 +210,7 @@ def _closeDestroyedStatisticsManager(managerReference, *_args): manager._generation += 1 manager._connected = False manager._monitor = None + manager._closeExecutor() diff --git a/tests/fixtures/editor_lifetime_probe.py b/tests/fixtures/editor_lifetime_probe.py index b0f687f3..b3bb65c5 100644 --- a/tests/fixtures/editor_lifetime_probe.py +++ b/tests/fixtures/editor_lifetime_probe.py @@ -928,6 +928,7 @@ def runServiceTeardownProbe(iterations=100): try: assert started.wait(2) + threads = tuple(executor._threads) deleteQObject(parent) @@ -974,14 +975,18 @@ def runServiceTeardownProbe(iterations=100): DownloadSpeedTestOptions(5000, 'https://invalid.test'), parent=scheduler, ) + lease = Lease() worker._runtimeLease = lease + job = SimpleNamespace(state=ProfileTestJobState.Running) scheduler.activeJobs[id(worker)] = (worker, job, worker.port) scheduler.activePorts.add(worker.port) + connectWeakly( worker.finished, scheduler, 'handleWorkerFinished', sender=worker ) + workers.append(worker) leases.append(lease) @@ -992,6 +997,7 @@ def runServiceTeardownProbe(iterations=100): assert all(not isValid(worker) for worker in workers) assert not tests._serialDownloadScheduler.activePorts assert not tests._concurrentDownloadScheduler.activePorts + runtimeReleases += len(leases) return { diff --git a/tests/test_architecture_refactors.py b/tests/test_architecture_refactors.py index d3e4b5d4..6bfb656b 100644 --- a/tests/test_architecture_refactors.py +++ b/tests/test_architecture_refactors.py @@ -1424,6 +1424,7 @@ class ApplicationLifecycleTransactionTest(TestCase): def testCoreLogDrainStopsWhenItsCallbackDisposesTheQueue(self): """A runtime shutdown during delivery retires the rest of this drain turn.""" application() + received = [] messageQueue = None @@ -1432,6 +1433,7 @@ class ApplicationLifecycleTransactionTest(TestCase): messageQueue.dispose() messageQueue = ProcessOutputModule.MsgQueue(msgCallback=receive) + timerDestroyed = [] messageQueue.timer.destroyed.connect(lambda *_args: timerDestroyed.append(True)) @@ -1443,12 +1445,14 @@ class ApplicationLifecycleTransactionTest(TestCase): self.assertEqual(received, ['first']) self.assertEqual(get.call_count, 1) + self.assertIsNone(messageQueue.callback) self.assertIsNone(messageQueue._timerConnection) processQtEvents() self.assertEqual(timerDestroyed, [True]) + messageQueue.processMsg() finally: messageQueue.dispose() diff --git a/tests/test_profile_test_jobs.py b/tests/test_profile_test_jobs.py index 2e7e42ca..70466c3e 100644 --- a/tests/test_profile_test_jobs.py +++ b/tests/test_profile_test_jobs.py @@ -429,6 +429,7 @@ class ProfileTestServiceTest(unittest.TestCase): ): manager.testDownloadSpeed((profile,), concurrent=False) processQtEvents() + worker, runtime = workers[0], runtimes[0] reply = _PendingDownloadReply(worker) @@ -595,12 +596,14 @@ class ProfileTestServiceTest(unittest.TestCase): profilesProvider=lambda: (profile,), downloadConcurrency=1, ) + workers, runtimes, routers, destroyed = [], [], [], [] results, errors = [], [] def workerFactory(*args, **kwargs): worker = _DownloadSpeedWorker(*args, **kwargs) worker.CoreStartupGraceMilliseconds = 60_000 + worker.destroyed.connect(lambda *_args: destroyed.append(True)) workers.append(worker) @@ -626,6 +629,7 @@ class ProfileTestServiceTest(unittest.TestCase): prepareDownloadTest=lambda profile, _port: profile, createCoreRuntime=createRuntime, ) + manager.resultApplied.connect(lambda *_args: results.append(True)) try: @@ -676,11 +680,13 @@ class ProfileTestServiceTest(unittest.TestCase): runtime.failure = None results.clear() + deleteQObject(parent) processQtEvents() self.assertFalse(errors) self.assertFalse(results) + self.assertTrue( all(not runtime.isRunning() for runtime in runtimes) ) @@ -688,6 +694,7 @@ class ProfileTestServiceTest(unittest.TestCase): all(not runtime.resourceOwned for runtime in runtimes) ) self.assertTrue(manager._shuttingDown) + self.assertTrue(all(not isValid(worker) for worker in workers)) self.assertTrue(all(not isValid(router) for router in routers)) self.assertEqual(len(destroyed), 2) diff --git a/tests/test_service_runtime.py b/tests/test_service_runtime.py index 80e82abc..bc1042cc 100644 --- a/tests/test_service_runtime.py +++ b/tests/test_service_runtime.py @@ -128,6 +128,7 @@ class UpdateManagerTest(unittest.TestCase): controller = ConnectionController(coreManager=SimpleNamespace(runtimes=[])) manager = controller._updatesManager reply = _ManagedReply(manager) + payload = _ResponseBody(b'fixture') reference = weakref.ref(payload) @@ -136,6 +137,7 @@ class UpdateManagerTest(unittest.TestCase): manager.webGET('https://invalid.test', payload=payload) del payload + deleteQObject(controller) self.assertFalse(isValid(manager)) @@ -199,6 +201,7 @@ class HttpGetManagerLifetimeTest(unittest.TestCase): def testDnsOperationOwnerDestructionAbortsItsRequest(self): """A resolver outliving a request must not outlive that request's owner.""" application() + resolver = DnsResolver() self.addCleanup(resolver.dispose) @@ -206,6 +209,7 @@ class HttpGetManagerLifetimeTest(unittest.TestCase): parent = QtCore.QObject() reply = _ManagedReply(resolver) operation = resolver.resolveAsync('example.test', parent=parent) + results, errors = [], [] operation.finished.connect(lambda *_args: results.append(True)) @@ -214,6 +218,7 @@ class HttpGetManagerLifetimeTest(unittest.TestCase): QNetworkReply.NetworkError.OperationCanceledError, 'cancelled' ) reply.setFinished(True) + reply.finished.emit() reply.abort = abort @@ -225,12 +230,15 @@ class HttpGetManagerLifetimeTest(unittest.TestCase): patch('sys.excepthook', lambda *args: errors.append(args)), ): operation.start() + deleteQObject(parent) self.assertFalse(isValid(operation)) self.assertFalse(isValid(operation._timer)) + self.assertTrue(reply.isFinished()) self.assertFalse(resolver._replyContexts) + self.assertFalse(results) self.assertFalse(errors) @@ -714,7 +722,9 @@ class ConnectivityManagerTest(unittest.TestCase): ): manager.startSingleTest() oldReply.finished.emit() + manager.startSingleTest() + deleteQObject(oldReply) self.assertIs(manager._activeReply, currentReply) @@ -826,6 +836,7 @@ class TrafficStatsManagerTest(unittest.TestCase): for _ in range(20): parent = QtCore.QObject() manager = TrafficStatsManager(parent) + started = threading.Event() release = threading.Event() updates = [] @@ -840,13 +851,16 @@ class TrafficStatsManagerTest(unittest.TestCase): return TrafficCounters(1, 2) manager.sampleChanged.connect(updates.append) + manager._activateMonitor( TrafficStatsMonitor(query=query, target=None) ) + executor = manager._executor try: self.assertTrue(started.wait(1)) + threads = tuple(executor._threads) updates.clear() @@ -857,6 +871,7 @@ class TrafficStatsManagerTest(unittest.TestCase): self.assertFalse(isValid(manager)) self.assertFalse(isValid(manager._sampleTimer)) + self.assertIsNone(manager._executor) self.assertIsNone(manager._future) self.assertIsNone(manager._monitor) @@ -871,6 +886,7 @@ class TrafficStatsManagerTest(unittest.TestCase): self.assertFalse(callbackErrors) self.assertFalse(updates) + self.assertTrue( all(not thread.is_alive() for thread in threads) )