2020-09-04 14:22:23 +03:00
|
|
|
from mock import Mock
|
|
|
|
|
|
|
|
from synapse.rest import admin
|
|
|
|
from synapse.rest.client.v1 import login, room
|
|
|
|
|
|
|
|
from tests.test_utils import event_injection, make_awaitable
|
|
|
|
from tests.unittest import FederatingHomeserverTestCase, override_config
|
|
|
|
|
|
|
|
|
|
|
|
class FederationCatchUpTestCases(FederatingHomeserverTestCase):
|
|
|
|
servlets = [
|
|
|
|
admin.register_servlets,
|
|
|
|
room.register_servlets,
|
|
|
|
login.register_servlets,
|
|
|
|
]
|
|
|
|
|
|
|
|
def make_homeserver(self, reactor, clock):
|
|
|
|
return self.setup_test_homeserver(
|
|
|
|
federation_transport_client=Mock(spec=["send_transaction"]),
|
|
|
|
)
|
|
|
|
|
|
|
|
def prepare(self, reactor, clock, hs):
|
|
|
|
# stub out get_current_hosts_in_room
|
|
|
|
state_handler = hs.get_state_handler()
|
|
|
|
|
|
|
|
# This mock is crucial for destination_rooms to be populated.
|
|
|
|
state_handler.get_current_hosts_in_room = Mock(
|
|
|
|
return_value=make_awaitable(["test", "host2"])
|
|
|
|
)
|
|
|
|
|
2020-09-07 12:11:38 +03:00
|
|
|
# whenever send_transaction is called, record the pdu data
|
|
|
|
self.pdus = []
|
|
|
|
self.failed_pdus = []
|
|
|
|
self.is_online = True
|
|
|
|
self.hs.get_federation_transport_client().send_transaction.side_effect = (
|
|
|
|
self.record_transaction
|
|
|
|
)
|
|
|
|
|
|
|
|
async def record_transaction(self, txn, json_cb):
|
|
|
|
if self.is_online:
|
|
|
|
data = json_cb()
|
|
|
|
self.pdus.extend(data["pdus"])
|
|
|
|
return {}
|
|
|
|
else:
|
|
|
|
data = json_cb()
|
|
|
|
self.failed_pdus.extend(data["pdus"])
|
|
|
|
raise IOError("Failed to connect because this is a test!")
|
|
|
|
|
2020-09-04 14:22:23 +03:00
|
|
|
def get_destination_room(self, room: str, destination: str = "host2") -> dict:
|
|
|
|
"""
|
|
|
|
Gets the destination_rooms entry for a (destination, room_id) pair.
|
|
|
|
|
|
|
|
Args:
|
|
|
|
room: room ID
|
|
|
|
destination: what destination, default is "host2"
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
Dictionary of { event_id: str, stream_ordering: int }
|
|
|
|
"""
|
|
|
|
event_id, stream_ordering = self.get_success(
|
|
|
|
self.hs.get_datastore().db_pool.execute(
|
|
|
|
"test:get_destination_rooms",
|
|
|
|
None,
|
|
|
|
"""
|
|
|
|
SELECT event_id, stream_ordering
|
|
|
|
FROM destination_rooms dr
|
|
|
|
JOIN events USING (stream_ordering)
|
|
|
|
WHERE dr.destination = ? AND dr.room_id = ?
|
|
|
|
""",
|
|
|
|
destination,
|
|
|
|
room,
|
|
|
|
)
|
|
|
|
)[0]
|
|
|
|
return {"event_id": event_id, "stream_ordering": stream_ordering}
|
|
|
|
|
|
|
|
@override_config({"send_federation": True})
|
|
|
|
def test_catch_up_destination_rooms_tracking(self):
|
|
|
|
"""
|
|
|
|
Tests that we populate the `destination_rooms` table as needed.
|
|
|
|
"""
|
|
|
|
self.register_user("u1", "you the one")
|
|
|
|
u1_token = self.login("u1", "you the one")
|
|
|
|
room = self.helper.create_room_as("u1", tok=u1_token)
|
|
|
|
|
|
|
|
self.get_success(
|
|
|
|
event_injection.inject_member_event(self.hs, room, "@user:host2", "join")
|
|
|
|
)
|
|
|
|
|
|
|
|
event_id_1 = self.helper.send(room, "wombats!", tok=u1_token)["event_id"]
|
|
|
|
|
|
|
|
row_1 = self.get_destination_room(room)
|
|
|
|
|
|
|
|
event_id_2 = self.helper.send(room, "rabbits!", tok=u1_token)["event_id"]
|
|
|
|
|
|
|
|
row_2 = self.get_destination_room(room)
|
|
|
|
|
|
|
|
# check: events correctly registered in order
|
|
|
|
self.assertEqual(row_1["event_id"], event_id_1)
|
|
|
|
self.assertEqual(row_2["event_id"], event_id_2)
|
|
|
|
self.assertEqual(row_1["stream_ordering"], row_2["stream_ordering"] - 1)
|
2020-09-07 12:11:38 +03:00
|
|
|
|
|
|
|
@override_config({"send_federation": True})
|
|
|
|
def test_catch_up_last_successful_stream_ordering_tracking(self):
|
|
|
|
"""
|
|
|
|
Tests that we populate the `destination_rooms` table as needed.
|
|
|
|
"""
|
|
|
|
self.register_user("u1", "you the one")
|
|
|
|
u1_token = self.login("u1", "you the one")
|
|
|
|
room = self.helper.create_room_as("u1", tok=u1_token)
|
|
|
|
|
|
|
|
# take the remote offline
|
|
|
|
self.is_online = False
|
|
|
|
|
|
|
|
self.get_success(
|
|
|
|
event_injection.inject_member_event(self.hs, room, "@user:host2", "join")
|
|
|
|
)
|
|
|
|
|
|
|
|
self.helper.send(room, "wombats!", tok=u1_token)
|
|
|
|
self.pump()
|
|
|
|
|
|
|
|
lsso_1 = self.get_success(
|
|
|
|
self.hs.get_datastore().get_destination_last_successful_stream_ordering(
|
|
|
|
"host2"
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
self.assertIsNone(
|
|
|
|
lsso_1,
|
|
|
|
"There should be no last successful stream ordering for an always-offline destination",
|
|
|
|
)
|
|
|
|
|
|
|
|
# bring the remote online
|
|
|
|
self.is_online = True
|
|
|
|
|
|
|
|
event_id_2 = self.helper.send(room, "rabbits!", tok=u1_token)["event_id"]
|
|
|
|
|
|
|
|
lsso_2 = self.get_success(
|
|
|
|
self.hs.get_datastore().get_destination_last_successful_stream_ordering(
|
|
|
|
"host2"
|
|
|
|
)
|
|
|
|
)
|
|
|
|
row_2 = self.get_destination_room(room)
|
|
|
|
|
|
|
|
self.assertEqual(
|
|
|
|
self.pdus[0]["content"]["body"],
|
|
|
|
"rabbits!",
|
|
|
|
"Test fault: didn't receive the right PDU",
|
|
|
|
)
|
|
|
|
self.assertEqual(
|
|
|
|
row_2["event_id"],
|
|
|
|
event_id_2,
|
|
|
|
"Test fault: destination_rooms not updated correctly",
|
|
|
|
)
|
|
|
|
self.assertEqual(
|
|
|
|
lsso_2,
|
|
|
|
row_2["stream_ordering"],
|
|
|
|
"Send succeeded but not marked as last_successful_stream_ordering",
|
|
|
|
)
|