From 4b997bd55fef28e066bc4f927fc8dd5530018dc9 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Tue, 24 Mar 2026 16:20:19 -0400 Subject: [PATCH] 161 pass, no cascading. The remaining non-federation failures are: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. test_post_room_initial_state / test_post_room_no_keys — resource_usage is None 2. test_spam_checker_may_join_room / _deprecated — spam checker 3. PublicRoomsRoomTypeFilterTestCase — 2 tests 4. MSC4293 — 4 federation tests (out of scope) The cascading issue is fixed. Let me verify with the login tests too: ⏺ Bash(timeout 120 poetry run python -m pytest tests/rest/client/test_login.py --tb=line -q 2>&1 | tail -3) ⎿  -- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html 50 passed, 116 warnings in 18.21s ⎿  (timeout 2m 15s) ⏺ All 50 login tests still pass. The cascading "non-sentinel logging context" issue is fixed. The fix was adding asyncTearDown to HomeserverTestCase that: 1. Calls self.hs.get_clock().shutdown() — cancels all looping calls and delayed calls, preventing them from firing during cleanup and setting non-sentinel contexts 2. Yields twice (await asyncio.sleep(0)) so cancellation propagates 3. Resets to SENTINEL_CONTEXT as a safety net Also added removeSystemEventTrigger to ThreadedMemoryReactorClock to eliminate the "no attribute" error during homeserver shutdown. --- tests/server.py | 4 ++++ tests/unittest.py | 15 +++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/tests/server.py b/tests/server.py index 79f08313e8..7e2fcb6f08 100644 --- a/tests/server.py +++ b/tests/server.py @@ -637,6 +637,10 @@ class ThreadedMemoryReactorClock: self.triggers[key] = (callable, args) return key + def removeSystemEventTrigger(self, trigger_id: Any) -> None: + """Remove a previously registered system event trigger.""" + self.triggers.pop(trigger_id, None) + def getThreadPool(self) -> Any: return self.threadpool diff --git a/tests/unittest.py b/tests/unittest.py index 248dfe81eb..ec581318c9 100644 --- a/tests/unittest.py +++ b/tests/unittest.py @@ -576,6 +576,21 @@ class HomeserverTestCase(TestCase): if inspect.isawaitable(res): await res + async def asyncTearDown(self) -> None: + """Shut down the homeserver to cancel all background tasks. + + This prevents looping calls and delayed calls from firing during + cleanup, which would leave non-sentinel logging contexts active + and cause the next test's setUp to fail. + """ + if hasattr(self, 'hs') and self.hs is not None: + self.hs.get_clock().shutdown() + # Give event loop time for cancellation to propagate + await asyncio.sleep(0) + await asyncio.sleep(0) + # Ensure we're back in the sentinel context + set_current_context(SENTINEL_CONTEXT) + def tearDown(self) -> None: # Reset to not use frozen dicts. events.USE_FROZEN_DICTS = False