Update FakeChannel.await_result(...) to drive async Rust (Tokio runtime/thread pool)#19879
Conversation
Split off from #19878
FakeChannel.await_result(...) changes on their ownFakeChannel.await_result(...) changes to drive async Rust on their own
Same thing we did in #19871
…Case_new.test_wait_for_sync_token`
| # `notifier.wait_for_stream_token(from_token)` only checks every 500ms so we | ||
| # need to match that in order to make sure we hit the wake-up for sure. | ||
| channel.await_result(timeout_ms=500) |
There was a problem hiding this comment.
Previously, this worked because await_result(...) would advance 0.1s past the specified timeout_ms and I guess that worked out to hit the 500ms notifier.wait_for_stream_token(from_token) check interval every time.
Now await_result(...) can timeout when we exactly hit the timeout_ms so we weren't hitting it.
I've updated the second wait to be 500ms to match notifier.wait_for_stream_token(from_token) so we know that we can always hit the interval regardless of the current Twisted clock time.
FakeChannel.await_result(...) changes to drive async Rust on their ownFakeChannel.await_result(...) and friends to drive async Rust (Tokio runtime/thread pool)
| @@ -0,0 +1 @@ | |||
| Update `HomeserverTestCase.get_success(...)` and friends to drive async Rust (Tokio runtime/thread pool). | |||
There was a problem hiding this comment.
Same changelog as #19871 so they merge
We can consider FakeChannel.await_result(...) one of the "friends" of HomeserverTestCase.get_success(...)
| # TODO: Why? | ||
| self._reactor.run() |
There was a problem hiding this comment.
Prior art. Something to figure out in a future PR. Just noting that I don't know. The reactor should already be running and we can potentially remove it in another PR.
| @@ -301,15 +302,85 @@ def transport(self) -> "FakeChannel": | |||
| def await_result(self, timeout_ms: int = 1000) -> None: | |||
There was a problem hiding this comment.
Similar structure to what we've done in #19871
FakeChannel.await_result(...) and friends to drive async Rust (Tokio runtime/thread pool)FakeChannel.await_result(...) to drive async Rust (Tokio runtime/thread pool)
Based one explanation from #19913 (comment)
```
Error:
Traceback (most recent call last):
File "/home/runner/work/synapse/synapse/tests/test_mau.py", line 74, in test_simple_deny_mau
self.do_sync_for_user(token2)
File "/home/runner/work/synapse/synapse/tests/test_mau.py", line 345, in do_sync_for_user
raise HttpResponseException(
synapse.api.errors.ProxiedRequestError: 403: Monthly Active User Limit Exceeded
tests.test_mau.TestMauLimit.test_simple_deny_mau
```
| if user_id: | ||
| timestamp = await self.store.user_last_seen_monthly_active(user_id) | ||
| if timestamp: | ||
| if timestamp is not None: |
There was a problem hiding this comment.
Fixing a flawed check (0 is falsey) that was exposed by #19879 (comment)
… doesn't care about expiration We don't need to assert exact values. These tests don't care about that
| self.assertEqual(channel.json_body["data"], "foo=bar") | ||
| self.assertEqual(channel.json_body["sequence_token"], sequence_token) | ||
| self.assertEqual(channel.json_body["expires_in_ms"], expires_in_ms - 100) | ||
| self.assertGreater(channel.json_body["expires_in_ms"], 0) |
There was a problem hiding this comment.
Had to touch this because await_result(...) changed the minimum amount of time we advance by. These tests relied on that internal detail.
We don't need to test exact expires_in_ms values. We just care that it's > 0.
And we don't care about testing it on subsequent requests either. This test has nothing to do with expiration.
If we wanted to do this kind of thing, we should do something like the following:
duration_between_requests = Duration(milliseconds=100)
# Advance by some known amount
self.reactor.advance(duration_between_requests.as_secs())
# ...
self.assertGreater(channel.json_body["expires_in_ms"], 0)
self.assertLessEqual(
channel.json_body["expires_in_ms"],
prev_expires_in_ms - duration_between_requests.as_millis(),
)
prev_expires_in_ms = channel.json_body["expires_in_ms"]Related discussion: #19539 (comment)
…elimit`
```
[FAIL]
Traceback (most recent call last):
File "/home/runner/.cache/pypoetry/virtualenvs/matrix-synapse-pswDeSvb-py3.10/lib/python3.10/site-packages/parameterized/parameterized.py", line 620, in standalone_func
return func(*(a + p.args), **p.kwargs, **kw)
File "/home/runner/work/synapse/synapse/tests/rest/client/test_delayed_events.py", line 434, in test_send_delayed_event_ratelimit
self.assertEqual(HTTPStatus.OK, channel.code, channel.result)
File "/home/runner/.cache/pypoetry/virtualenvs/matrix-synapse-pswDeSvb-py3.10/lib/python3.10/site-packages/twisted/trial/_synctest.py", line 444, in assertEqual
super().assertEqual(first, second, msg)
File "/opt/hostedtoolcache/Python/3.10.20/x64/lib/python3.10/unittest/case.py", line 845, in assertEqual
assertion_func(first, second, msg=msg)
File "/opt/hostedtoolcache/Python/3.10.20/x64/lib/python3.10/unittest/case.py", line 838, in _baseAssertEqual
raise self.failureException(msg)
twisted.trial.unittest.FailTest: <HTTPStatus.OK: 200> != 429 : {'version': b'1.1', 'code': b'429', 'reason': b'Unknown Status', 'headers': Headers({b'Server': [b'1'], b'Date': [b'Tue, 07 Jul 2026 00:20:42 GMT'], b'Retry-After': [b'1'], b'Content-Type': [b'application/json'], b'Cache-Control': [b'no-cache, no-store, must-revalidate'], b'Access-Control-Allow-Origin': [b'*'], b'Access-Control-Allow-Methods': [b'GET, HEAD, POST, PUT, DELETE, OPTIONS'], b'Access-Control-Allow-Headers': [b'X-Requested-With, Content-Type, Authorization, Date'], b'Access-Control-Expose-Headers': [b'Synapse-Trace-Id, Server']}), 'body': b'{"errcode":"M_LIMIT_EXCEEDED","error":"Too Many Requests","retry_after_ms":396}', 'done': True}
tests.rest.client.test_delayed_events.DelayedEventsTestCase.test_send_delayed_event_ratelimit_0
tests.rest.client.test_delayed_events.DelayedEventsTestCase.test_send_delayed_event_ratelimit_1
```
…estCases`
```
[FAIL]
Traceback (most recent call last):
File "/home/runner/work/synapse/synapse/tests/federation/test_federation_sender.py", line 790, in test_prune_outbound_device_pokes1
self.assertGreaterEqual(mock_send_txn.call_count, 4)
File "/opt/hostedtoolcache/Python/3.10.20/x64/lib/python3.10/unittest/case.py", line 1250, in assertGreaterEqual
self.fail(self._formatMessage(msg, standardMsg))
twisted.trial.unittest.FailTest: 2 not greater than or equal to 4
tests.federation.test_federation_sender.FederationSenderDevicesTestCases.test_prune_outbound_device_pokes1
===============================================================================
[FAIL]
Traceback (most recent call last):
File "/home/runner/work/synapse/synapse/tests/federation/test_federation_sender.py", line 847, in test_prune_outbound_device_pokes2
self.assertGreaterEqual(mock_send_txn.call_count, 3)
File "/opt/hostedtoolcache/Python/3.10.20/x64/lib/python3.10/unittest/case.py", line 1250, in assertGreaterEqual
self.fail(self._formatMessage(msg, standardMsg))
twisted.trial.unittest.FailTest: 2 not greater than or equal to 3
tests.federation.test_federation_sender.FederationSenderDevicesTestCases.test_prune_outbound_device_pokes2
===============================================================================
[FAIL]
Traceback (most recent call last):
File "/home/runner/work/synapse/synapse/tests/federation/test_federation_sender.py", line 743, in test_unreachable_server
self.assertGreaterEqual(mock_send_txn.call_count, 4)
File "/opt/hostedtoolcache/Python/3.10.20/x64/lib/python3.10/unittest/case.py", line 1250, in assertGreaterEqual
self.fail(self._formatMessage(msg, standardMsg))
twisted.trial.unittest.FailTest: 2 not greater than or equal to 4
tests.federation.test_federation_sender.FederationSenderDevicesTestCases.test_unreachable_server
===============================================================================
[FAIL]
Traceback (most recent call last):
File "/home/runner/work/synapse/synapse/tests/federation/test_federation_sender.py", line 594, in test_upload_signatures
self.assertEqual(len(self.edus), 2)
File "/home/runner/.cache/pypoetry/virtualenvs/matrix-synapse-pswDeSvb-py3.10/lib/python3.10/site-packages/twisted/trial/_synctest.py", line 444, in assertEqual
super().assertEqual(first, second, msg)
File "/opt/hostedtoolcache/Python/3.10.20/x64/lib/python3.10/unittest/case.py", line 845, in assertEqual
assertion_func(first, second, msg=msg)
File "/opt/hostedtoolcache/Python/3.10.20/x64/lib/python3.10/unittest/case.py", line 838, in _baseAssertEqual
raise self.failureException(msg)
twisted.trial.unittest.FailTest: 1 != 2
tests.federation.test_federation_sender.FederationSenderDevicesTestCases.test_upload_signatures
```
| self.edus.extend(data["edus"]) | ||
| return {} | ||
|
|
||
| def wait_for_device_list_updates_to_be_sent(self) -> None: |
There was a problem hiding this comment.
Added wait_for_device_list_updates_to_be_sent to be more precise
| # Wait some time in between each device list update as we want each of them to | ||
| # be attempted to be sent in their own transaction | ||
| self.reactor.advance(Duration(seconds=1).as_secs()) |
There was a problem hiding this comment.
The main fixes to these tests was adding some time in between each device list update so they are sent in their own transaction. Tests assert self.assertGreaterEqual(mock_send_txn.call_count
Previously, we advanced 100ms on every login attempt because of await_result(...). await_result(...) now only advances 1ms and we need to space it out more.
| # Note: The extra 1ms is from `make_request(...)` -> `await_result(...)` | ||
| # | ||
| # FIXME: This test shouldn't care about this internal detail (don't | ||
| # assert exact timing) | ||
| last_seen=123456001, |
There was a problem hiding this comment.
Something for a future PR
|
Thanks for the review @erikjohnston 🐍 |
Update
FakeChannel.await_result(...)to drive async Rust (Tokio runtime/thread pool)Split off from #19878 (needed to drive requests in tests that use async Rust)
Follow-up to #19871
Pull Request Checklist
EventStoretoEventWorkerStore.".code blocks.