|
1 | | -from typing import Callable, List, Optional, Tuple |
| 1 | +from typing import Callable, Collection, List, Optional, Tuple |
| 2 | +from unittest import mock |
2 | 3 | from unittest.mock import Mock |
3 | 4 |
|
4 | 5 | from twisted.test.proto_helpers import MemoryReactor |
@@ -500,3 +501,87 @@ def test_not_latest_event(self) -> None: |
500 | 501 | self.assertEqual(len(sent_pdus), 1) |
501 | 502 | self.assertEqual(sent_pdus[0].event_id, event_2.event_id) |
502 | 503 | self.assertFalse(per_dest_queue._catching_up) |
| 504 | + |
| 505 | + def test_catch_up_is_not_blocked_by_remote_event_in_partial_state_room( |
| 506 | + self, |
| 507 | + ) -> None: |
| 508 | + """Detects (part of?) https://github.com/matrix-org/synapse/issues/15220.""" |
| 509 | + # ARRANGE: |
| 510 | + # - a local user (u1) |
| 511 | + # - a room which contains u1 and two remote users, @u2:host2 and @u3:other |
| 512 | + # - events in that room such that |
| 513 | + # - history visibility is restricted |
| 514 | + # - u1 sent message events e1 and e2 |
| 515 | + # - afterwards, u3 sent a remote event e3 |
| 516 | + # - catchup to begin for host2; last successfully sent event was e1 |
| 517 | + per_dest_queue, sent_pdus = self.make_fake_destination_queue() |
| 518 | + |
| 519 | + self.register_user("u1", "you the one") |
| 520 | + u1_token = self.login("u1", "you the one") |
| 521 | + room = self.helper.create_room_as("u1", tok=u1_token) |
| 522 | + self.helper.send_state( |
| 523 | + room_id=room, |
| 524 | + event_type="m.room.history_visibility", |
| 525 | + body={"history_visibility": "joined"}, |
| 526 | + tok=u1_token, |
| 527 | + ) |
| 528 | + self.get_success( |
| 529 | + event_injection.inject_member_event(self.hs, room, "@u2:host2", "join") |
| 530 | + ) |
| 531 | + self.get_success( |
| 532 | + event_injection.inject_member_event(self.hs, room, "@u3:other", "join") |
| 533 | + ) |
| 534 | + |
| 535 | + # create some events |
| 536 | + event_id_1 = self.helper.send(room, "hello", tok=u1_token)["event_id"] |
| 537 | + event_id_2 = self.helper.send(room, "world", tok=u1_token)["event_id"] |
| 538 | + # pretend that u3 changes their displayname |
| 539 | + event_id_3 = self.get_success( |
| 540 | + event_injection.inject_member_event(self.hs, room, "@u3:other", "join") |
| 541 | + ).event_id |
| 542 | + |
| 543 | + # destination_rooms should already be populated, but let us pretend that we already |
| 544 | + # sent (successfully) up to and including event id 1 |
| 545 | + event_1 = self.get_success(self.hs.get_datastores().main.get_event(event_id_1)) |
| 546 | + assert event_1.internal_metadata.stream_ordering is not None |
| 547 | + self.get_success( |
| 548 | + self.hs.get_datastores().main.set_destination_last_successful_stream_ordering( |
| 549 | + "host2", event_1.internal_metadata.stream_ordering |
| 550 | + ) |
| 551 | + ) |
| 552 | + |
| 553 | + # also fetch event 2 so we can compare its stream ordering to the sender's |
| 554 | + # last_successful_stream_ordering later |
| 555 | + event_2 = self.get_success(self.hs.get_datastores().main.get_event(event_id_2)) |
| 556 | + |
| 557 | + # Mock event 3 as having partial state |
| 558 | + self.get_success( |
| 559 | + event_injection.mark_event_as_partial_state(self.hs, event_id_3, room) |
| 560 | + ) |
| 561 | + |
| 562 | + # Fail the test if we block on full state for event 3. |
| 563 | + async def mock_await_full_state(event_ids: Collection[str]) -> None: |
| 564 | + if event_id_3 in event_ids: |
| 565 | + raise AssertionError("Tried to await full state for event_id_3") |
| 566 | + |
| 567 | + # ACT |
| 568 | + with mock.patch.object( |
| 569 | + self.hs.get_storage_controllers().state._partial_state_events_tracker, |
| 570 | + "await_full_state", |
| 571 | + mock_await_full_state, |
| 572 | + ): |
| 573 | + self.get_success(per_dest_queue._catch_up_transmission_loop()) |
| 574 | + |
| 575 | + # ASSERT |
| 576 | + # We should have: |
| 577 | + # - not sent event 3: it's not ours, and the room is partial stated |
| 578 | + # - fallen back to sending event 2: it's the most recent event in the room |
| 579 | + # we tried to send to host2 |
| 580 | + # - completed catch-up |
| 581 | + self.assertEqual(len(sent_pdus), 1) |
| 582 | + self.assertEqual(sent_pdus[0].event_id, event_id_2) |
| 583 | + self.assertFalse(per_dest_queue._catching_up) |
| 584 | + self.assertEqual( |
| 585 | + per_dest_queue._last_successful_stream_ordering, |
| 586 | + event_2.internal_metadata.stream_ordering, |
| 587 | + ) |
0 commit comments