Passing tests_versions.py: Wait real time for tokio thread pool to work on our async Rust function

Previously, we were running into this problem:
```
SYNAPSE_TEST_LOG_LEVEL=INFO poetry run trial tests.rest.client.test_versions.VersionsTestCase.test_authenticated
tests.rest.client.test_versions
  VersionsTestCase
    test_authenticated ...                                              [ERROR]

===============================================================================
[ERROR]
Traceback (most recent call last):
  File "/home/eric/Documents/github/element/synapse/tests/rest/client/test_versions.py", line 85, in test_authenticated
    channel = self.make_request(
  File "/home/eric/Documents/github/element/synapse/tests/unittest.py", line 619, in make_request
    return make_request(
  File "/home/eric/Documents/github/element/synapse/tests/server.py", line 486, in make_request
    channel.await_result()
  File "/home/eric/Documents/github/element/synapse/tests/server.py", line 310, in await_result
    raise TimedOutException("Timed out waiting for request to finish.")
tests.server.TimedOutException: Timed out waiting for request to finish.

tests.rest.client.test_versions.VersionsTestCase.test_authenticated
-------------------------------------------------------------------------------
Ran 1 tests in 0.182s

FAILED (errors=1)
```
This commit is contained in:
Eric Eastwood
2026-06-17 20:33:02 -05:00
parent 8270087c3b
commit 0b6a9733a1
+37 -27
View File
@@ -11,17 +11,19 @@
# <https://www.gnu.org/licenses/agpl-3.0.html>.
import logging
import time
from twisted.internet.testing import MemoryReactor
from synapse.rest import admin
from synapse.rest.client import login, versions
from synapse.server import HomeServer
from synapse.util.clock import Clock
from synapse.types import JsonDict
from synapse.synapse_rust.http_client import HttpClient
from synapse.types import JsonDict
from synapse.util.clock import Clock
from tests import unittest
from tests.server import FakeChannel, TimedOutException
logger = logging.getLogger(__name__)
@@ -69,12 +71,40 @@ class VersionsTestCase(unittest.HomeserverTestCase):
self.admin_user = self.register_user("admin", "pass", admin=True)
self.admin_user_tok = self.login("admin", "pass")
def test_unauthenticated(self) -> None:
def _request_versions(self, access_token: str | None = None) -> FakeChannel:
"""
Make a `GET /_matrix/client/versions` request and wait for it to finish.
The endpoint is served by a Rust handler that is async and relies on the Tokio
thread pool (posting back via `reactor.callFromThread`). The default
`make_request` pump only advances the reactor's *virtual* clock in a tight loop,
never yielding real wall-clock time, so the Tokio threads never get a chance to
run and the request times out. Instead we pump the reactor while also sleeping a
little real time each iteration, the same way `wait_on_thread` and
`tests.synapse_rust.test_http_client.till_deferred_has_result` do.
"""
channel = self.make_request(
"GET",
"/_matrix/client/versions",
content={},
access_token=access_token,
# We will pump it ourselves just below
await_result=False,
)
deadline = time.time() + 10
while not channel.is_finished():
if time.time() > deadline:
raise TimedOutException("Timed out waiting for request to finish.")
# Drain anything the Tokio threads have posted back...
self.reactor.advance(0.1)
# ...then give them real time to make more progress.
time.sleep(0.01)
return channel
def test_unauthenticated(self) -> None:
channel = self._request_versions()
self.assertEqual(channel.code, 200, channel.result)
self._sanity_check_versions_response(channel.json_body)
@@ -82,12 +112,7 @@ class VersionsTestCase(unittest.HomeserverTestCase):
user1_id = self.register_user("user1", "pass")
user1_tok = self.login(user1_id, "pass")
channel = self.make_request(
"GET",
"/_matrix/client/versions",
content={},
access_token=user1_tok,
)
channel = self._request_versions(access_token=user1_tok)
self.assertEqual(channel.code, 200, channel.result)
self._sanity_check_versions_response(channel.json_body)
@@ -98,12 +123,7 @@ class VersionsTestCase(unittest.HomeserverTestCase):
user2_tok = self.login(user2_id, "pass")
# Sanity check that the experimental feature should not be enabled yet
channel = self.make_request(
"GET",
"/_matrix/client/versions",
content={},
access_token=user1_tok,
)
channel = self._request_versions(access_token=user1_tok)
self.assertEqual(channel.code, 200, channel.result)
self._sanity_check_versions_response(channel.json_body)
self.assertEqual(
@@ -116,12 +136,7 @@ class VersionsTestCase(unittest.HomeserverTestCase):
self._enable_experimental_feature_for_user(target_user_id=user1_id)
# The experimental feature should be enabled for this user
channel = self.make_request(
"GET",
"/_matrix/client/versions",
content={},
access_token=user1_tok,
)
channel = self._request_versions(access_token=user1_tok)
self.assertEqual(channel.code, 200, channel.result)
self._sanity_check_versions_response(channel.json_body)
self.assertEqual(
@@ -131,12 +146,7 @@ class VersionsTestCase(unittest.HomeserverTestCase):
)
# But not for other users
channel = self.make_request(
"GET",
"/_matrix/client/versions",
content={},
access_token=user2_tok,
)
channel = self._request_versions(access_token=user2_tok)
self.assertEqual(channel.code, 200, channel.result)
self._sanity_check_versions_response(channel.json_body)
self.assertEqual(