diff --git a/changelog.d/20130.misc b/changelog.d/20130.misc new file mode 100644 index 00000000000..82c8faa0159 --- /dev/null +++ b/changelog.d/20130.misc @@ -0,0 +1 @@ +Raise default room version to "12". Contributed by @jason-famedly @famedly. diff --git a/synapse/config/server.py b/synapse/config/server.py index 00b414ea305..4b19b160b8a 100644 --- a/synapse/config/server.py +++ b/synapse/config/server.py @@ -176,7 +176,7 @@ def generate_ip_set( "fec0::/10", ] -DEFAULT_ROOM_VERSION = "11" +DEFAULT_ROOM_VERSION = "12" # Defaults for the presence state machine timers, in milliseconds. Overridden # by the corresponding options in the `presence` config section. diff --git a/synapse/handlers/message.py b/synapse/handlers/message.py index b34ee9d50f7..eb679bbbf8f 100644 --- a/synapse/handlers/message.py +++ b/synapse/handlers/message.py @@ -2404,7 +2404,15 @@ async def _rebuild_event_after_third_party_rules( original_event.room_version, third_party_result ) self.validator.validate_builder(builder) - assert builder.room_id is not None + + # The room_id should only be None for creation events using msc4291 + # rooms(version "12" and newer) + if not ( + builder.room_version.msc4291_room_ids_as_hashes + and builder.type == EventTypes.Create + ): + assert builder.room_id is not None + except SynapseError as e: raise Exception( "Third party rules module created an invalid event: " + e.msg, @@ -2439,12 +2447,21 @@ async def _rebuild_event_after_third_party_rules( for k, v in original_event.internal_metadata.get_dict().items(): setattr(builder.internal_metadata, k, v) - # modules can send new state events, so we re-calculate the auth events just in - # case. - prev_event_ids = await self.store.get_prev_events_for_room(builder.room_id) + # Creation events using msc4291 rooms will not have a room_id, and will + # also not have prev_events nor prev_state_events. + # This was asserted above, so makes an acceptable sign that room_id can not be + # None here(which makes mypy happy) but if it is then the lists should be empty. + prev_event_ids = [] + if builder.room_id is not None: + # modules can send new state events, so we re-calculate the auth events just + # in case. + prev_event_ids = await self.store.get_prev_events_for_room(builder.room_id) prev_state_events = None - if original_event.room_version.msc4242_state_dags: + if ( + original_event.room_version.msc4242_state_dags + and builder.room_id is not None + ): prev_state_events = list( await self.store.get_state_dag_extremities(builder.room_id) ) diff --git a/synapse/handlers/relations.py b/synapse/handlers/relations.py index a8db082febf..eb8eb62c9fd 100644 --- a/synapse/handlers/relations.py +++ b/synapse/handlers/relations.py @@ -44,6 +44,7 @@ BundledAggregations, ThreadAggregation, ) +from synapse.synapse_rust.room_versions import RoomVersion from synapse.types import JsonDict, Requester, UserID from synapse.util.async_helpers import gather_results from synapse.visibility import filter_and_transform_events_for_client @@ -193,6 +194,7 @@ async def redact_events_related_to( event_id: str, initial_redaction_event: EventBase, relation_types: list[str], + room_version: RoomVersion, ) -> None: """Redacts all events related to the given event ID with one of the given relation types. @@ -210,6 +212,8 @@ async def redact_events_related_to( event_id. relation_types: The types of relations to look for. If "*" is in the list, all related events will be redacted regardless of the type. + room_version: The RoomVersion of the room, for deciding where the 'redacts' + key should go in the event dict Raises: ShadowBanError if the requester is shadow-banned @@ -226,16 +230,24 @@ async def redact_events_related_to( ) for related_event_id in related_event_ids: + # Depending on the room version involved, the "redacts" key can go in one of + # two places. If we only use what was provided in the initial event, it will + # only target an event that was already redacted and nothing will happen. + new_redaction_content = dict(initial_redaction_event.content) + event_dict: JsonDict = { + "type": EventTypes.Redaction, + "content": new_redaction_content, + "room_id": initial_redaction_event.room_id, + "sender": requester.user.to_string(), + } + if room_version.updated_redaction_rules: + event_dict["content"].update({"redacts": related_event_id}) + else: + event_dict["redacts"] = related_event_id try: await self._event_creation_handler.create_and_send_nonmember_event( requester, - { - "type": EventTypes.Redaction, - "content": initial_redaction_event.content, - "room_id": initial_redaction_event.room_id, - "sender": requester.user.to_string(), - "redacts": related_event_id, - }, + event_dict, ratelimit=False, ) except SynapseError as e: diff --git a/synapse/rest/client/room.py b/synapse/rest/client/room.py index c3bb82e15c8..1b8774fde3d 100644 --- a/synapse/rest/client/room.py +++ b/synapse/rest/client/room.py @@ -1412,6 +1412,7 @@ async def _do( event_id=event_id, initial_redaction_event=event, relation_types=with_relations, + room_version=room_version, ) event_id = event.event_id diff --git a/synapse/storage/databases/main/events_worker.py b/synapse/storage/databases/main/events_worker.py index 27dab290b39..200e61db7d7 100644 --- a/synapse/storage/databases/main/events_worker.py +++ b/synapse/storage/databases/main/events_worker.py @@ -1468,7 +1468,7 @@ async def _fetch_event_ids_and_get_outstanding_redactions( # if d["type"] != EventTypes.Member: raise InvalidEventError( - "Room %s for event %s is unknown" % (d["room_id"], event_id) + "Room %s for event %s is unknown" % (d.get("room_id"), event_id) ) # so, assuming this is an out-of-band-invite that arrived before @@ -1499,7 +1499,7 @@ async def _fetch_event_ids_and_get_outstanding_redactions( logger.warning( "Event %s in room %s has unknown room version %s", event_id, - d["room_id"], + d.get("room_id"), room_version_id, ) continue @@ -1509,7 +1509,7 @@ async def _fetch_event_ids_and_get_outstanding_redactions( "Event %s in room %s with version %s has wrong format: " "expected %s, was %s", event_id, - d["room_id"], + d.get("room_id"), room_version_id, room_version.event_format, format_version, @@ -1538,7 +1538,7 @@ async def _fetch_event_ids_and_get_outstanding_redactions( # it's difficult to see what to do here. Pretty much all bets are off # if Synapse cannot rely on the consistency of its database. raise DatabaseCorruptionError( - d["room_id"], event_id, original_ev.event_id + d.get("room_id"), event_id, original_ev.event_id ) event_map[event_id] = original_ev diff --git a/tests/federation/test_federation_client.py b/tests/federation/test_federation_client.py index 656665cb424..003ec616dea 100644 --- a/tests/federation/test_federation_client.py +++ b/tests/federation/test_federation_client.py @@ -25,7 +25,6 @@ from twisted.internet import defer from twisted.internet.testing import MemoryReactor -from synapse.api.room_versions import RoomVersions from synapse.events import EventBase from synapse.rest import admin from synapse.rest.client import login, room @@ -33,6 +32,7 @@ from synapse.util.clock import Clock from tests.test_utils import FakeResponse, event_injection +from tests.test_utils.event_builders import make_test_pdu_event from tests.unittest import FederatingHomeserverTestCase @@ -58,28 +58,42 @@ def prepare( self.reactor.advance(1000000000) self.creator = f"@creator:{self.OTHER_SERVER_NAME}" - self.test_room_id = "!room_id" + self.room_version = self.hs.config.server.default_room_version def test_get_room_state(self) -> None: # mock up some events to use in the response. - # In real life, these would have things in `prev_events` and `auth_events`, but that's - # a bit annoying to mock up, and the code under test doesn't care, so we don't bother. + # In real life, these would have things in `prev_events` and `auth_events`, but + # that's a bit annoying to mock up, and the code under test doesn't care, so we + # don't bother. We do bother with the room_id though, since it has to be + # generated by the hash of the creation event. + create_event_source = { + "type": "m.room.create", + "state_key": "", + "sender": self.creator, + "content": {"room_version": self.room_version.identifier}, + "prev_events": [], + "auth_events": [], + "depth": 1, + "origin_server_ts": 500, + } + if not self.room_version.msc4291_room_ids_as_hashes: + # Do not bother saving this now, we will pull it out of the calculated event + # later. + create_event_source["room_id"] = f"!room:{self.OTHER_SERVER_NAME}" + create_event_dict = self.add_hashes_and_signatures_from_other_server( - { - "room_id": self.test_room_id, - "type": "m.room.create", - "state_key": "", - "sender": self.creator, - "content": {"creator": self.creator}, - "prev_events": [], - "auth_events": [], - "depth": 1, - "origin_server_ts": 500, - } + create_event_source, + self.room_version, + ) + create_event = make_test_pdu_event( + create_event_source, + self.room_version, ) + room_id = create_event.room_id + member_event_dict = self.add_hashes_and_signatures_from_other_server( { - "room_id": self.test_room_id, + "room_id": room_id, "type": "m.room.member", "sender": self.creator, "state_key": self.creator, @@ -88,11 +102,12 @@ def test_get_room_state(self) -> None: "auth_events": [], "depth": 2, "origin_server_ts": 600, - } + }, + self.room_version, ) pl_event_dict = self.add_hashes_and_signatures_from_other_server( { - "room_id": self.test_room_id, + "room_id": room_id, "type": "m.room.power_levels", "sender": self.creator, "state_key": "", @@ -101,7 +116,8 @@ def test_get_room_state(self) -> None: "auth_events": [], "depth": 3, "origin_server_ts": 700, - } + }, + self.room_version, ) # mock up the response, and have the agent return it @@ -125,16 +141,19 @@ def test_get_room_state(self) -> None: state_resp, auth_resp = self.get_success( self.hs.get_federation_client().get_room_state( "yet.another.server", - self.test_room_id, + room_id, "event_id", - RoomVersions.V9, + self.room_version, ) ) # check the right call got made to the agent self._mock_agent.request.assert_called_once_with( b"GET", - b"matrix-federation://yet.another.server/_matrix/federation/v1/state/%21room_id?event_id=event_id", + # Please double-check me that ascii encoding is correct thing to do here + f"matrix-federation://yet.another.server/_matrix/federation/v1/state/%21{room_id[1:]}?event_id=event_id".encode( + "ascii" + ), headers=mock.ANY, bodyProducer=None, ) @@ -158,7 +177,7 @@ def test_get_pdu_returns_nothing_when_event_does_not_exist(self) -> None: self.hs.get_federation_client().get_pdu( ["yet.another.server"], "event_should_not_exist", - RoomVersions.V9, + self.room_version, ) ) self.assertEqual(pulled_pdu_info, None) @@ -185,7 +204,7 @@ def test_get_pdu_event_from_cache_is_pristine(self) -> None: self.hs.get_federation_client().get_pdu( ["yet.another.server"], remote_pdu.event_id, - RoomVersions.V9, + self.room_version, ) ) assert pulled_pdu_info2 is not None @@ -204,7 +223,7 @@ def _get_pdu_once(self) -> EventBase: """ message_event_dict = self.add_hashes_and_signatures_from_other_server( { - "room_id": self.test_room_id, + "room_id": f"!bogus_made_up_room_id:{self.OTHER_SERVER_NAME}", "type": "m.room.message", "sender": self.creator, "state_key": "", @@ -213,7 +232,8 @@ def _get_pdu_once(self) -> EventBase: "auth_events": [], "origin_server_ts": 700, "depth": 10, - } + }, + self.room_version, ) # mock up the response, and have the agent return it @@ -233,7 +253,7 @@ def _get_pdu_once(self) -> EventBase: self.hs.get_federation_client().get_pdu( ["yet.another.server"], "event_id", - RoomVersions.V9, + self.room_version, ) ) assert pulled_pdu_info is not None diff --git a/tests/federation/test_federation_out_of_band_membership.py b/tests/federation/test_federation_out_of_band_membership.py index 85e221a64ad..3adbf4e35b1 100644 --- a/tests/federation/test_federation_out_of_band_membership.py +++ b/tests/federation/test_federation_out_of_band_membership.py @@ -32,7 +32,7 @@ from twisted.internet.testing import MemoryReactor from synapse.api.constants import EventContentFields, EventTypes, Membership -from synapse.api.room_versions import RoomVersion, RoomVersions +from synapse.api.room_versions import RoomVersion from synapse.events import EventBase from synapse.events.utils import strip_event from synapse.federation.transport.client import SendJoinResponse @@ -188,13 +188,11 @@ def _invite_local_user_to_remote_room_and_join(self) -> RemoteRoomJoinResult: # Create a remote room room_creator_user_id = f"@remote-user:{self.OTHER_SERVER_NAME}" - remote_room_id = f"!remote-room:{self.OTHER_SERVER_NAME}" - room_version = RoomVersions.V11 + room_version = self.hs.config.server.default_room_version room_create_event = make_test_event( self.add_hashes_and_signatures_from_other_server( { - "room_id": remote_room_id, "sender": room_creator_user_id, "depth": 1, "origin_server_ts": 1, @@ -210,6 +208,8 @@ def _invite_local_user_to_remote_room_and_join(self) -> RemoteRoomJoinResult: room_version=room_version, ) + remote_room_id = room_create_event.room_id + creator_membership_event = make_test_event( self.add_hashes_and_signatures_from_other_server( { @@ -220,7 +220,7 @@ def _invite_local_user_to_remote_room_and_join(self) -> RemoteRoomJoinResult: "type": EventTypes.Member, "state_key": room_creator_user_id, "content": {"membership": Membership.JOIN}, - "auth_events": [room_create_event.event_id], + "auth_events": [], "prev_events": [room_create_event.event_id], } ), @@ -239,7 +239,6 @@ def _invite_local_user_to_remote_room_and_join(self) -> RemoteRoomJoinResult: "state_key": local_user1_id, "content": {"membership": Membership.INVITE}, "auth_events": [ - room_create_event.event_id, creator_membership_event.event_id, ], "prev_events": [creator_membership_event.event_id], @@ -300,7 +299,6 @@ def _invite_local_user_to_remote_room_and_join(self) -> RemoteRoomJoinResult: "state_key": local_user1_id, "content": {"membership": Membership.JOIN}, "auth_events": [ - room_create_event.event_id, user1_invite_membership_event.event_id, ], "prev_events": [user1_invite_membership_event.event_id], @@ -542,9 +540,6 @@ async def put_json( "state_key": local_user2_id, "content": {"membership": Membership.INVITE}, "auth_events": [ - remote_room_join_result.state_map[ - (EventTypes.Create, "") - ].event_id, remote_room_join_result.state_map[ ( EventTypes.Member, diff --git a/tests/handlers/test_device.py b/tests/handlers/test_device.py index cb047d118a7..611a3267a5e 100644 --- a/tests/handlers/test_device.py +++ b/tests/handlers/test_device.py @@ -33,10 +33,9 @@ from synapse.api.constants import EventTypes, JoinRules, RoomEncryptionAlgorithms from synapse.api.errors import NotFoundError, SynapseError -from synapse.api.room_versions import RoomVersions from synapse.appservice import ApplicationService from synapse.crypto.event_signing import add_hashes_and_signatures -from synapse.events import EventBase, make_event_from_dict +from synapse.events import EventBase from synapse.federation.federation_client import SendJoinResult from synapse.federation.transport.client import ( StateRequestResponse, @@ -60,6 +59,7 @@ from synapse.util.task_scheduler import TaskScheduler from tests import unittest +from tests.test_utils.event_builders import make_test_pdu_event from tests.unittest import override_config user1 = "@boris:aaa" @@ -671,8 +671,7 @@ def make_homeserver(self, reactor: MemoryReactor, clock: Clock) -> HomeServer: def _build_public_room(self) -> StateMap[EventBase]: """Build a public room DAG that has REMOTE1 in it""" - room_id = f"!room:{self.REMOTE1_SERVER_NAME}" - room_version = RoomVersions.V10 + room_version = self.hs.config.server.default_room_version events: list[EventBase] = [] @@ -680,13 +679,11 @@ def _build_public_room(self) -> StateMap[EventBase]: create_event_dict: JsonDict = { "auth_events": [], "content": { - "creator": self.REMOTE1_USER, "room_version": room_version.identifier, }, - "depth": 0, + "depth": 1, "origin_server_ts": 0, "prev_events": [], - "room_id": room_id, "sender": self.REMOTE1_USER, "state_key": "", "type": EventTypes.Create, @@ -699,16 +696,15 @@ def _build_public_room(self) -> StateMap[EventBase]: self.REMOTE1_SERVER_SIGNATURE_KEY, ) - create_event = make_event_from_dict(create_event_dict, room_version) + create_event = make_test_pdu_event(create_event_dict, room_version) + # This will always be the correct room_id + room_id = create_event.room_id events.append(create_event) - room_version = self.hs.config.server.default_room_version join_event_dict: JsonDict = { - "auth_events": [ - create_event.event_id, - ], + "auth_events": [], "content": {"membership": "join"}, - "depth": 1, + "depth": 2, "origin_server_ts": 100, "prev_events": [create_event.event_id], "sender": self.REMOTE1_USER, @@ -716,20 +712,21 @@ def _build_public_room(self) -> StateMap[EventBase]: "room_id": room_id, "type": EventTypes.Member, } + add_hashes_and_signatures( room_version, join_event_dict, self.hs.hostname, self.hs.signing_key, ) - join_event = make_event_from_dict(join_event_dict, room_version) + join_event = make_test_pdu_event(join_event_dict, room_version) events.append(join_event) # Then set the join rules to public join_rules_event_dict: JsonDict = { - "auth_events": [create_event.event_id, join_event.event_id], + "auth_events": [join_event.event_id], "content": {"join_rule": JoinRules.PUBLIC}, - "depth": 2, + "depth": 3, "origin_server_ts": 200, "prev_events": [join_event.event_id], "room_id": room_id, @@ -744,7 +741,7 @@ def _build_public_room(self) -> StateMap[EventBase]: self.REMOTE1_SERVER_NAME, self.REMOTE1_SERVER_SIGNATURE_KEY, ) - join_rules_event = make_event_from_dict(join_rules_event_dict, room_version) + join_rules_event = make_test_pdu_event(join_rules_event_dict, room_version) events.append(join_rules_event) return {(event.type, event.state_key): event for event in events} @@ -763,7 +760,6 @@ def _build_signed_join_event( room_version = self.hs.config.server.default_room_version join_event_dict: JsonDict = { "auth_events": [ - state[(EventTypes.Create, "")].event_id, state[(EventTypes.JoinRules, "")].event_id, ], "content": {"membership": "join"}, @@ -781,7 +777,7 @@ def _build_signed_join_event( get_domain_from_id(user), signing_key, ) - return make_event_from_dict(join_event_dict, room_version) + return make_test_pdu_event(join_event_dict, room_version) @parameterized.expand([("not_pruned", False), ("pruned", True)]) @patch( @@ -795,7 +791,7 @@ def test_local_device_changes_sent_to_new_servers_on_un_partial_state( partial state period should be sent to remote servers that were NOT known at the time of the partial join. - We do this by creating a room with one remote server, partialling + We do this by creating a room with one remote server, partially joining it, then receiving a join event from a second remote server. The second remote server should receive a device list update EDU for any local device changes that happened during the partial state period. diff --git a/tests/handlers/test_federation_event.py b/tests/handlers/test_federation_event.py index 9da9f52fb6f..10cd7822e2b 100644 --- a/tests/handlers/test_federation_event.py +++ b/tests/handlers/test_federation_event.py @@ -120,7 +120,6 @@ def _test_process_pulled_event_with_missing_state( ) auth_event_ids = [ - initial_state_map[("m.room.create", "")], initial_state_map[("m.room.power_levels", "")], member_event.event_id, ] @@ -416,7 +415,6 @@ def test_process_pulled_event_clears_backfill_attempts_after_being_successfully_ ) auth_event_ids = [ - initial_state_map[("m.room.create", "")], initial_state_map[("m.room.power_levels", "")], member_event.event_id, ] @@ -517,7 +515,6 @@ def test_backfill_signature_failure_does_not_fetch_same_prev_event_later( ) auth_event_ids = [ - initial_state_map[("m.room.create", "")], initial_state_map[("m.room.power_levels", "")], member_event.event_id, ] @@ -714,7 +711,6 @@ def test_backfill_process_previously_failed_pull_attempt_event_in_the_background ) auth_event_ids = [ - initial_state_map[("m.room.create", "")], initial_state_map[("m.room.power_levels", "")], member_event.event_id, ] @@ -834,6 +830,9 @@ def test_process_pulled_event_with_rejected_missing_state(self) -> None: ) room_version = self.get_success(main_store.get_room_version(room_id)) + ernie_user_id = self.register_user("ernie", "test") + ernie_tok = self.login("ernie", "test") + self.helper.join(room_id, user=ernie_user_id, tok=ernie_tok) # Add another local user to the room. This user is going to be kicked in a # rejected event. bert_user_id = self.register_user("bert", "test") @@ -842,13 +841,13 @@ def test_process_pulled_event_with_rejected_missing_state(self) -> None: # Allow the remote user to kick bert. # The remote user is going to send a rejected power levels event later on and we - # need state resolution to order it before another power levels event kermit is + # need state resolution to order it before another power levels event ernie is # going to send later on. Hence we give both users the same power level, so that # ties are broken by `origin_server_ts`. self.helper.send_state( room_id, "m.room.power_levels", - {"users": {kermit_user_id: 100, OTHER_USER: 100}}, + {"users": {ernie_user_id: 100, OTHER_USER: 100}}, tok=kermit_tok, ) @@ -887,7 +886,6 @@ def test_process_pulled_event_with_rejected_missing_state(self) -> None: "sender": OTHER_USER, "prev_events": [other_member_event.event_id], "auth_events": [ - initial_state_map[("m.room.create", "")], initial_state_map[("m.room.power_levels", "")], # The event will be rejected because of the duplicated auth # event. @@ -936,7 +934,6 @@ def test_process_pulled_event_with_rejected_missing_state(self) -> None: "sender": OTHER_USER, "prev_events": [rejected_power_levels_event.event_id], "auth_events": [ - initial_state_map[("m.room.create", "")], rejected_power_levels_event.event_id, initial_state_map[("m.room.member", bert_user_id)], initial_state_map[("m.room.member", OTHER_USER)], @@ -1014,8 +1011,8 @@ def test_process_pulled_event_with_rejected_missing_state(self) -> None: self.helper.send_state( room_id, "m.room.power_levels", - {"users": {kermit_user_id: 100, OTHER_USER: 100, bert_user_id: 1}}, - tok=kermit_tok, + {"users": {ernie_user_id: 100, OTHER_USER: 100, bert_user_id: 1}}, + tok=ernie_tok, )["event_id"] ) ) @@ -1050,7 +1047,6 @@ def test_process_pulled_event_with_rejected_missing_state(self) -> None: "sender": OTHER_USER, "prev_events": [rejected_kick_event.event_id], "auth_events": [ - initial_state_map[("m.room.create", "")], initial_state_map[("m.room.power_levels", "")], initial_state_map[("m.room.member", OTHER_USER)], ], @@ -1078,7 +1074,6 @@ def test_process_pulled_event_with_rejected_missing_state(self) -> None: missing_event.event_id, ], "auth_events": [ - initial_state_map[("m.room.create", "")], new_power_levels_event.event_id, initial_state_map[("m.room.member", OTHER_USER)], ], diff --git a/tests/handlers/test_message.py b/tests/handlers/test_message.py index 6450a904449..1160a66938e 100644 --- a/tests/handlers/test_message.py +++ b/tests/handlers/test_message.py @@ -234,11 +234,6 @@ def test_reject_event_with_empty_prev_events( ) def test_call_invite_event_creation_fails_in_public_room(self) -> None: - # get prev_events for room - prev_events = self.get_success( - self.store.get_prev_events_for_room(self.room_id) - ) - # the invite in a public room should fail self.get_failure( self.handler.create_event( @@ -248,8 +243,6 @@ def test_call_invite_event_creation_fails_in_public_room(self) -> None: "room_id": self.room_id, "sender": self.requester.user.to_string(), }, - prev_event_ids=prev_events, - auth_event_ids=prev_events, ), SynapseError, ) @@ -263,8 +256,6 @@ def test_call_invite_event_creation_fails_in_public_room(self) -> None: "room_id": self.private_room_id, "sender": self.requester.user.to_string(), }, - prev_event_ids=prev_events, - auth_event_ids=prev_events, ) ) diff --git a/tests/handlers/test_presence.py b/tests/handlers/test_presence.py index a5620508425..61cf78730f5 100644 --- a/tests/handlers/test_presence.py +++ b/tests/handlers/test_presence.py @@ -2382,7 +2382,6 @@ def _add_new_user(self, room_id: str, user_id: str) -> None: "origin_server_ts": 1, "content": {"membership": Membership.JOIN}, "auth_events": [ - state_map[(EventTypes.Create, "")].event_id, state_map[(EventTypes.JoinRules, "")].event_id, ], "prev_events": list(forward_extremity_event_ids), diff --git a/tests/handlers/test_register.py b/tests/handlers/test_register.py index 182ff7a8fc3..46cd2ed83ba 100644 --- a/tests/handlers/test_register.py +++ b/tests/handlers/test_register.py @@ -477,6 +477,7 @@ def test_auto_create_auto_join_room_preset_guest(self) -> None: "auto_join_rooms": ["#room:test"], "autocreate_auto_join_room_preset": "private_chat", "auto_join_mxid_localpart": "support", + "default_room_version": "11", } ) def test_auto_create_auto_join_room_preset_invalid_permissions(self) -> None: @@ -485,6 +486,8 @@ def test_auto_create_auto_join_room_preset_invalid_permissions(self) -> None: registration doesn't completely break if the inviter doesn't have proper permissions. """ + # This test is limited to room version 11, as after that the room creator will + # always have permission to invite users and make any other changes they wish. inviter = "@support:test" # Register an initial user to create the room and such (essentially this @@ -528,7 +531,7 @@ def test_auto_create_auto_join_room_preset_invalid_permissions(self) -> None: ) ) - # Register a second user, which won't be be in the room (or even have an invite) + # Register a second user, which won't be in the room (or even have an invite) # since the inviter no longer has the proper permissions. user_id = self.get_success(self.handler.register_user(localpart="bob")) diff --git a/tests/handlers/test_room_member.py b/tests/handlers/test_room_member.py index 0a7475856a8..9ce0392e040 100644 --- a/tests/handlers/test_room_member.py +++ b/tests/handlers/test_room_member.py @@ -8,10 +8,9 @@ from synapse.api.constants import AccountDataTypes, EventTypes, Membership from synapse.api.errors import Codes, LimitExceededError, SynapseError from synapse.crypto.event_signing import add_hashes_and_signatures -from synapse.events import make_event_from_dict from synapse.federation.federation_client import SendJoinResult from synapse.server import HomeServer -from synapse.types import UserID, create_requester +from synapse.types import JsonDict, UserID, create_requester from synapse.util.clock import Clock from tests.replication._base import BaseMultiWorkerStreamTestCase @@ -43,10 +42,10 @@ def prepare(self, reactor: MemoryReactor, clock: Clock, hs: HomeServer) -> None: self.chris_token = self.login("chris", "pass") # Create a room on this homeserver. Note that this counts as a join: it - # contributes to the rate limter's count of actions + # contributes to the rate limiter's count of actions self.room_id = self.helper.create_room_as(self.alice, tok=self.alice_token) - self.intially_unjoined_room_id = f"!example:{self.OTHER_SERVER_NAME}" + self.room_version = self.hs.config.server.default_room_version @override_config({"rc_joins_per_room": {"per_second": 0.1, "burst_count": 2}}) def test_local_user_local_joins_contribute_to_limit_and_are_limited(self) -> None: @@ -105,60 +104,55 @@ def test_remote_joins_contribute_to_rate_limit(self) -> None: # We also patch out a bunch of event checks on our end. All we're really # trying to check here is that remote joins will bump the rate limter when # they are persisted. - create_event_source = { + create_event_source: JsonDict = { "auth_events": [], "content": { - "creator": f"@creator:{self.OTHER_SERVER_NAME}", - "room_version": self.hs.config.server.default_room_version.identifier, + "room_version": self.room_version.identifier, }, - "depth": 0, + "depth": 1, "origin_server_ts": 0, "prev_events": [], - "room_id": self.intially_unjoined_room_id, "sender": f"@creator:{self.OTHER_SERVER_NAME}", "state_key": "", "type": EventTypes.Create, } - self.add_hashes_and_signatures_from_other_server( - create_event_source, - self.hs.config.server.default_room_version, - ) - create_event = make_event_from_dict( + + self.add_hashes_and_signatures_from_other_server(create_event_source) + create_event = make_test_pdu_event( create_event_source, - self.hs.config.server.default_room_version, - {}, - None, + self.room_version, ) + # Extract the room_id for use below + initially_unjoined_room_id = create_event.room_id + join_event_source = { - "auth_events": [create_event.event_id], + "auth_events": [], "content": {"membership": "join"}, - "depth": 1, + "depth": 2, "origin_server_ts": 100, "prev_events": [create_event.event_id], "sender": self.bob, "state_key": self.bob, - "room_id": self.intially_unjoined_room_id, + "room_id": initially_unjoined_room_id, "type": EventTypes.Member, } add_hashes_and_signatures( - self.hs.config.server.default_room_version, + self.room_version, join_event_source, self.hs.hostname, self.hs.signing_key, ) - join_event = make_event_from_dict( + join_event = make_test_pdu_event( join_event_source, - self.hs.config.server.default_room_version, - {}, - None, + self.room_version, ) mock_make_membership_event = AsyncMock( return_value=( self.OTHER_SERVER_NAME, join_event, - self.hs.config.server.default_room_version, + self.room_version, ) ) mock_send_join = AsyncMock( @@ -196,7 +190,7 @@ def test_remote_joins_contribute_to_rate_limit(self) -> None: self.handler.update_membership( requester=create_requester(self.bob), target=UserID.from_string(self.bob), - room_id=self.intially_unjoined_room_id, + room_id=initially_unjoined_room_id, action=Membership.JOIN, remote_room_hosts=[self.OTHER_SERVER_NAME], ) @@ -207,7 +201,7 @@ def test_remote_joins_contribute_to_rate_limit(self) -> None: self.handler.update_membership( requester=create_requester(self.chris), target=UserID.from_string(self.chris), - room_id=self.intially_unjoined_room_id, + room_id=initially_unjoined_room_id, action=Membership.JOIN, remote_room_hosts=[self.OTHER_SERVER_NAME], ), diff --git a/tests/handlers/test_sliding_sync.py b/tests/handlers/test_sliding_sync.py index 22939880368..f91468db1e1 100644 --- a/tests/handlers/test_sliding_sync.py +++ b/tests/handlers/test_sliding_sync.py @@ -19,7 +19,6 @@ # import logging from typing import AbstractSet -from unittest.mock import patch import attr from parameterized import parameterized, parameterized_class @@ -3018,21 +3017,6 @@ def prepare(self, reactor: MemoryReactor, clock: Clock, hs: HomeServer) -> None: self.store = self.hs.get_datastores().main self.event_sources = hs.get_event_sources() - def _create_room(self, room_id: str, user_id: str, tok: str) -> None: - """ - Create a room with a specific room_id. We use this so that that we have a - consistent room_id across test runs that hashes to the same value and will be - sharded to a known worker in the tests. - """ - - # We control the room ID generation by patching out the - # `_generate_room_id` method - with patch( - "synapse.handlers.room.RoomCreationHandler._generate_room_id" - ) as mock: - mock.side_effect = lambda: room_id - self.helper.create_room_as(user_id, tok=tok) - def test_sharded_event_persisters(self) -> None: """ This test should catch bugs that would come from flawed stream position @@ -3070,19 +3054,15 @@ def test_sharded_event_persisters(self) -> None: {"worker_name": "worker3"}, ) - # Specially crafted room IDs that get persisted on different workers. - # - # Sharded to worker1 - room_id1 = "!fooo:test" - # Sharded to worker2 - room_id2 = "!bar:test" - # Sharded to worker3 - room_id3 = "!quux:test" - - # Create rooms on the different workers. - self._create_room(room_id1, user2_id, user2_tok) - self._create_room(room_id2, user2_id, user2_tok) - self._create_room(room_id3, user2_id, user2_tok) + # 3 different rooms, each on a different worker. Match them up based on the + # trailing number. + room_results = self._generate_rooms_on_worker( + user2_id, user2_tok, ["worker1", "worker2", "worker3"] + ) + room_id1 = room_results["worker1"] + room_id2 = room_results["worker2"] + room_id3 = room_results["worker3"] + join_response1 = self.helper.join(room_id1, user1_id, tok=user1_tok) join_response2 = self.helper.join(room_id2, user1_id, tok=user1_tok) # Leave room2 diff --git a/tests/module_api/test_api.py b/tests/module_api/test_api.py index b4b14c87b9a..79b3d27d119 100644 --- a/tests/module_api/test_api.py +++ b/tests/module_api/test_api.py @@ -282,11 +282,11 @@ def test_sending_events_into_room(self) -> None: # Create and send a state event content = { "events_default": 0, - "users": {user_id: 100}, "state_default": 50, "users_default": 0, "events": {"test.event.type": 25}, } + event_dict = { "room_id": room_id, "type": "m.room.power_levels", @@ -743,6 +743,7 @@ def test_create_room(self) -> None: # Now do the happy path. user_id = self.register_user("user", "password") + access_token = self.login(user_id, "password") room_id, room_alias = self.get_success( self.module_api.create_room( @@ -750,6 +751,18 @@ def test_create_room(self) -> None: ) ) + # Check room creator. + channel = self.make_request( + "GET", + f"/_matrix/client/v3/rooms/{room_id}/state/m.room.create", + access_token=access_token, + ) + self.assertEqual(channel.code, 200, channel.result) + self.assertEqual( + channel.json_body["room_version"], + self.hs.config.server.default_room_version.identifier, + ) + # Check room alias. self.assertEqual(room_alias, f"#foo-bar:{self.module_api.server_name}") @@ -758,6 +771,17 @@ def test_create_room(self) -> None: self.module_api.create_room(user_id=user_id, config={}, ratelimit=False) ) + channel = self.make_request( + "GET", + f"/_matrix/client/v3/rooms/{room_id}/state/m.room.create", + access_token=access_token, + ) + self.assertEqual(channel.code, 200, channel.result) + self.assertEqual( + channel.json_body["room_version"], + self.hs.config.server.default_room_version.identifier, + ) + # Check room alias. self.assertIsNone(room_alias) @@ -825,7 +849,7 @@ def test_event_deprecated_methods(self) -> None: self.assertEqual(create_event.user_id, user_id) # type: ignore[attr-defined] # The event supports looking up keys via `__getitem__` although deprecated - self.assertEqual(create_event["room_id"], room_id) # type: ignore[index] + self.assertEqual(create_event["type"], EventTypes.Create) # type: ignore[index] class ModuleApiWorkerTestCase(BaseModuleApiTestCase, BaseMultiWorkerStreamTestCase): diff --git a/tests/replication/_base.py b/tests/replication/_base.py index b23696668f3..26fbfa8d19f 100644 --- a/tests/replication/_base.py +++ b/tests/replication/_base.py @@ -39,6 +39,7 @@ from synapse.replication.tcp.resource import ReplicationStreamProtocolFactory from synapse.server import HomeServer from synapse.util.clock import Clock +from synapse.util.duration import Duration from tests import unittest from tests.server import FakeTransport @@ -483,6 +484,71 @@ def connect_any_redis_attempts(self) -> None: ) server_protocol.makeConnection(server_to_client_transport) + def _generate_rooms_on_worker( + self, + user_id: str, + user_tok: str, + list_of_worker_names: list[str] | None = None, + try_at_most_count: int | None = None, + ) -> dict[str, str]: + """ + Given a list of worker names, generate rooms until there is at least one on each + of the named workers. + + Args: + user_id: The user_id of the user making the room. + user_tok: The token of the user making the room. + list_of_worker_names: A list of worker names that need to have rooms. By + default, each `events` worker provided in the homeserver config will be used. + try_at_most_count: A given number of iterations to try and produce rooms. If + not provided, use the number of workers multiplied by 3 for the count. + Returns: + A mapping of `worker_name`->`room_id` + """ + # Save a shorter reference to the `RoutableShardedWorkerHandlingConfig` that + # contains the information needed to not only identify the full list of workers + # (in case the default for `list_of_workernames` is used) and provides the + # routing hash function that decides which worker a given room id should go to. + events_writers_config = self.hs.config.worker.events_shard_config + + if list_of_worker_names is None: + _set_of_worker_names = set(events_writers_config.instances) + else: + _set_of_worker_names = set(list_of_worker_names) + + assert len(_set_of_worker_names) > 0 + # Save a copy of this to use now, we can use the original to assert expectations + # before returning. + set_of_workernames = set(_set_of_worker_names) + + results_mapping = {} + + # Maintain a count, in case of a runaway process. + count = try_at_most_count or len(set_of_workernames) * 3 + + while set_of_workernames: + self.reactor.advance(Duration(milliseconds=1).as_secs()) + count -= 1 + _room_id = self.helper.create_room_as(user_id, tok=user_tok) + + _worker_responsible = events_writers_config.get_instance(_room_id) + + if _worker_responsible in set_of_workernames: + results_mapping[_worker_responsible] = _room_id + # Remember to remove the worker now that it is found + set_of_workernames.remove(_worker_responsible) + + if count == 0: + raise AssertionError( + "Count exhausted attempting to generate rooms. Aborting and failing test" + ) + + # Since this *IS* part of a test, lets make sure all worker names requested are + # accounted for + assert results_mapping.keys() == _set_of_worker_names + + return results_mapping + class TestReplicationDataHandler(ReplicationDataHandler): """Drop-in for ReplicationDataHandler which just collects RDATA rows""" diff --git a/tests/replication/test_federation_sender_shard.py b/tests/replication/test_federation_sender_shard.py index 3896e0ce8a0..929b1d028ef 100644 --- a/tests/replication/test_federation_sender_shard.py +++ b/tests/replication/test_federation_sender_shard.py @@ -338,7 +338,6 @@ def create_room_with_remote_server( "origin_server_ts": 1, "content": {"membership": Membership.JOIN}, "auth_events": [ - state_map[(EventTypes.Create, "")].event_id, state_map[(EventTypes.JoinRules, "")].event_id, ], "prev_events": list(prev_event_ids), diff --git a/tests/replication/test_sharded_event_persister.py b/tests/replication/test_sharded_event_persister.py index f37394c1f5c..1b9b9aa6301 100644 --- a/tests/replication/test_sharded_event_persister.py +++ b/tests/replication/test_sharded_event_persister.py @@ -18,8 +18,6 @@ # [This file includes modifications made by New Vector Limited] # # -import logging -from unittest.mock import patch from twisted.internet.testing import MemoryReactor @@ -32,8 +30,6 @@ from tests.replication._base import BaseMultiWorkerStreamTestCase from tests.server import make_request -logger = logging.getLogger(__name__) - class EventPersisterShardTestCase(BaseMultiWorkerStreamTestCase): """Checks event persisting sharding works""" @@ -63,17 +59,6 @@ def default_config(self) -> dict: } return conf - def _create_room(self, room_id: str, user_id: str, tok: str) -> None: - """Create a room with given room_id""" - - # We control the room ID generation by patching out the - # `_generate_room_id` method - with patch( - "synapse.handlers.room.RoomCreationHandler._generate_room_id" - ) as mock: - mock.side_effect = lambda: room_id - self.helper.create_room_as(user_id, tok=tok) - def test_basic(self) -> None: """Simple test to ensure that multiple rooms can be created and joined, and that different rooms get handled by different instances. @@ -145,10 +130,16 @@ def test_vector_clock_token(self) -> None: ) sync_hs_site = self._hs_to_site[sync_hs] - # Specially selected room IDs that get persisted on different workers. - room_id1 = "!foo:test" - room_id2 = "!baz:test" + user_id = self.register_user("user", "pass") + access_token = self.login("user", "pass") + + store = self.hs.get_datastores().main + + room_generation_results = self._generate_rooms_on_worker(user_id, access_token) + room_id1 = room_generation_results["worker1"] + room_id2 = room_generation_results["worker2"] + # Verify that the expected worker is responsible for the specific room self.assertEqual( self.hs.config.worker.events_shard_config.get_instance(room_id1), "worker1" ) @@ -156,15 +147,6 @@ def test_vector_clock_token(self) -> None: self.hs.config.worker.events_shard_config.get_instance(room_id2), "worker2" ) - user_id = self.register_user("user", "pass") - access_token = self.login("user", "pass") - - store = self.hs.get_datastores().main - - # Create two room on the different workers. - self._create_room(room_id1, user_id, access_token) - self._create_room(room_id2, user_id, access_token) - # The other user joins self.helper.join( room=room_id1, user=self.other_user_id, tok=self.other_access_token diff --git a/tests/rest/admin/test_room.py b/tests/rest/admin/test_room.py index 4deb3c29f41..2680358236e 100644 --- a/tests/rest/admin/test_room.py +++ b/tests/rest/admin/test_room.py @@ -3318,15 +3318,25 @@ def test_not_enough_power(self) -> None: self.creator, tok=self.creator_tok, is_public=True ) - # The creator drops admin rights in the room. + # In the case that this is a msc4291 compliant room, we can not use the room + # creator as the "puppeted" user. Join another user to use as a sentinel + # instead. The room's creator will leave the room before the command runs. + self.helper.join(room_id, self.second_user_id, tok=self.second_tok) + + # The creator gives a placeholder of rights in the room. The power level can be + # 0, as long as it is present it will be considered. Having it be missing will + # produce a different error: "No local admin user in room" which is not what + # this test is supposed to check pl = self.helper.get_state( room_id, EventTypes.PowerLevels, tok=self.creator_tok ) - pl["users"][self.creator] = 0 + pl["users"][self.second_user_id] = 0 self.helper.send_state( room_id, EventTypes.PowerLevels, body=pl, tok=self.creator_tok ) + self.helper.leave(room_id, self.creator, tok=self.creator_tok) + channel = self.make_request( "POST", f"/_synapse/admin/v1/rooms/{room_id}/make_room_admin", diff --git a/tests/rest/client/sliding_sync/test_rooms_invites.py b/tests/rest/client/sliding_sync/test_rooms_invites.py index 85628833f51..9be187318ca 100644 --- a/tests/rest/client/sliding_sync/test_rooms_invites.py +++ b/tests/rest/client/sliding_sync/test_rooms_invites.py @@ -21,7 +21,7 @@ from synapse.api.constants import EventTypes, HistoryVisibility from synapse.rest.client import login, room, sync from synapse.server import HomeServer -from synapse.types import UserID +from synapse.types import JsonDict, UserID from synapse.util.clock import Clock from tests.rest.client.sliding_sync.test_sliding_sync import SlidingSyncBase @@ -66,6 +66,31 @@ def prepare(self, reactor: MemoryReactor, clock: Clock, hs: HomeServer) -> None: self.storage_controllers = hs.get_storage_controllers() super().prepare(reactor, clock, hs) + self.room_version = hs.config.server.default_room_version + + def assertHasSubset( + self, + container: list[JsonDict], + contains_these: list[JsonDict], + ) -> None: + assert contains_these, "`contains_these` was empty" + assert container, "`container` was empty" + + for dict_to_search_for in contains_these: + for container_entry in container: + # The <= operator is a subset comparison operator when used on + # 'set-like' containers + if dict_to_search_for.items() <= container_entry.items(): + # The searched for item was found, move on. Break will skip the + # else statement below + break + else: + # Searching the 'container' for this subset yielded nothing, that is + # an error. + raise AssertionError( + "The searched for dict was not present in the container:\n\n" + f"Searched for {dict_to_search_for}\n\nContainer: {container}" + ) def test_rooms_invite_shared_history_initial_sync(self) -> None: """ @@ -73,7 +98,7 @@ def test_rooms_invite_shared_history_initial_sync(self) -> None: initial sync. This is an `invite` room so we should only have `stripped_state` (no `timeline`) - but we also shouldn't see any timeline events because the history visiblity is + but we also shouldn't see any timeline events because the history visibility is `shared` and we haven't joined the room yet. """ user1_id = self.register_user("user1", "pass") @@ -85,7 +110,7 @@ def test_rooms_invite_shared_history_initial_sync(self) -> None: room_id1 = self.helper.create_room_as(user2_id, tok=user2_tok) # Ensure we're testing with a room with `shared` history visibility which means - # history visible until you actually join the room. + # history won't be visible until you actually join the room. history_visibility_response = self.helper.get_state( room_id1, EventTypes.RoomHistoryVisibility, tok=user2_tok ) @@ -138,12 +163,15 @@ def test_rooms_invite_shared_history_initial_sync(self) -> None: response_body["rooms"][room_id1], ) # We should have some `stripped_state` so the potential joiner can identify the - # room (we don't care about the order). - self.assertCountEqual( + # room (we don't care about the order). The exception is the creation event + # which is a full PDU format from room v12 and newer + self.assertHasSubset( response_body["rooms"][room_id1]["invite_state"], [ { - "content": {"room_version": "11"}, + "content": { + "room_version": self.room_version.identifier, + }, "sender": user2_id, "state_key": "", "type": "m.room.create", @@ -167,7 +195,6 @@ def test_rooms_invite_shared_history_initial_sync(self) -> None: "type": "m.room.member", }, ], - response_body["rooms"][room_id1]["invite_state"], ) def test_rooms_invite_shared_history_incremental_sync(self) -> None: @@ -248,12 +275,15 @@ def test_rooms_invite_shared_history_incremental_sync(self) -> None: response_body["rooms"][room_id1], ) # We should have some `stripped_state` so the potential joiner can identify the - # room (we don't care about the order). - self.assertCountEqual( + # room (we don't care about the order). The exception is the creation event + # which is a full PDU format from room v12 and newer + self.assertHasSubset( response_body["rooms"][room_id1]["invite_state"], [ { - "content": {"room_version": "11"}, + "content": { + "room_version": self.room_version.identifier, + }, "sender": user2_id, "state_key": "", "type": "m.room.create", @@ -277,7 +307,6 @@ def test_rooms_invite_shared_history_incremental_sync(self) -> None: "type": "m.room.member", }, ], - response_body["rooms"][room_id1]["invite_state"], ) def test_rooms_invite_world_readable_history_initial_sync(self) -> None: @@ -369,12 +398,15 @@ def test_rooms_invite_world_readable_history_initial_sync(self) -> None: response_body["rooms"][room_id1], ) # We should have some `stripped_state` so the potential joiner can identify the - # room (we don't care about the order). - self.assertCountEqual( + # room (we don't care about the order). The exception is the creation event + # which is a full PDU format from room v12 and newer + self.assertHasSubset( response_body["rooms"][room_id1]["invite_state"], [ { - "content": {"room_version": "11"}, + "content": { + "room_version": self.room_version.identifier, + }, "sender": user2_id, "state_key": "", "type": "m.room.create", @@ -398,7 +430,6 @@ def test_rooms_invite_world_readable_history_initial_sync(self) -> None: "type": "m.room.member", }, ], - response_body["rooms"][room_id1]["invite_state"], ) def test_rooms_invite_world_readable_history_incremental_sync(self) -> None: @@ -495,12 +526,15 @@ def test_rooms_invite_world_readable_history_incremental_sync(self) -> None: response_body["rooms"][room_id1], ) # We should have some `stripped_state` so the potential joiner can identify the - # room (we don't care about the order). - self.assertCountEqual( + # room (we don't care about the order). The exception is the creation event + # which is a full PDU format from room v12 and newer + self.assertHasSubset( response_body["rooms"][room_id1]["invite_state"], [ { - "content": {"room_version": "11"}, + "content": { + "room_version": self.room_version.identifier, + }, "sender": user2_id, "state_key": "", "type": "m.room.create", @@ -524,5 +558,4 @@ def test_rooms_invite_world_readable_history_incremental_sync(self) -> None: "type": "m.room.member", }, ], - response_body["rooms"][room_id1]["invite_state"], ) diff --git a/tests/rest/client/sliding_sync/test_rooms_required_state.py b/tests/rest/client/sliding_sync/test_rooms_required_state.py index 901f22a35d1..5aff19c7fd0 100644 --- a/tests/rest/client/sliding_sync/test_rooms_required_state.py +++ b/tests/rest/client/sliding_sync/test_rooms_required_state.py @@ -1289,7 +1289,7 @@ def test_rooms_required_state_me(self) -> None: self.helper.send_state( room_id1, event_type=EventTypes.PowerLevels, - body={"users": {user1_id: 50, user2_id: 100}}, + body={"users": {user1_id: 50}}, tok=user2_tok, ) self.helper.send_state( diff --git a/tests/rest/client/test_rooms.py b/tests/rest/client/test_rooms.py index 78c960a5372..a0ba76acb5c 100644 --- a/tests/rest/client/test_rooms.py +++ b/tests/rest/client/test_rooms.py @@ -45,7 +45,6 @@ RoomTypes, ) from synapse.api.errors import Codes, HttpResponseException -from synapse.api.room_versions import RoomVersions from synapse.appservice import ApplicationService from synapse.events import EventBase, make_event_from_dict from synapse.events.snapshot import EventContext @@ -4800,6 +4799,9 @@ def prepare(self, reactor: MemoryReactor, clock: Clock, hs: HomeServer) -> None: self.creator = self.register_user("creator", "test") self.creator_tok = self.login("creator", "test") + self.good_admin = self.register_user("good_admin", "test") + self.good_admin_tok = self.login("good_admin", "test") + self.bad_user_id = self.register_user("bad", "test") self.bad_tok = self.login("bad", "test") @@ -4812,6 +4814,8 @@ def prepare(self, reactor: MemoryReactor, clock: Clock, hs: HomeServer) -> None: self.hs.config.experimental.msc4293_enabled = True + self.room_version = self.hs.config.server.default_room_version + def _check_redactions( self, original_events: list[EventBase], @@ -4919,16 +4923,13 @@ def test_banning_remote_member_with_flag_redacts_their_events(self) -> None: bad_user = "@remote_bad_user:" + self.OTHER_SERVER_NAME channel = self.make_signed_federation_request( "GET", - f"/_matrix/federation/v1/make_join/{self.room_id}/{bad_user}?ver=11", + f"/_matrix/federation/v1/make_join/{self.room_id}/{bad_user}?ver={self.room_version.identifier}", ) self.assertEqual(channel.code, HTTPStatus.OK, channel.json_body) join_result = channel.json_body join_event_dict = join_result["event"] - self.add_hashes_and_signatures_from_other_server( - join_event_dict, - RoomVersions.V11, - ) + self.add_hashes_and_signatures_from_other_server(join_event_dict) channel = self.make_signed_federation_request( "PUT", f"/_matrix/federation/v2/send_join/{self.room_id}/x", @@ -4943,7 +4944,6 @@ def test_banning_remote_member_with_flag_redacts_their_events(self) -> None: self.assertEqual(r[("m.room.member", bad_user)].membership, "join") auth_ids = [ - r[("m.room.create", "")].event_id, r[("m.room.power_levels", "")].event_id, r[("m.room.member", "@remote_bad_user:other.example.com")].event_id, ] @@ -4962,7 +4962,7 @@ def test_banning_remote_member_with_flag_redacts_their_events(self) -> None: "prev_events": auth_ids, } ), - room_version=RoomVersions.V11, + room_version=self.room_version, ) self.get_success( @@ -5013,7 +5013,7 @@ def test_banning_remote_member_with_flag_redacts_their_events(self) -> None: "prev_events": auth_ids, } ), - room_version=RoomVersions.V11, + room_version=self.room_version, ) self.get_success( @@ -5038,16 +5038,13 @@ def test_unbanning_remote_user_stops_redaction_action(self) -> None: bad_user = "@remote_bad_user:" + self.OTHER_SERVER_NAME channel = self.make_signed_federation_request( "GET", - f"/_matrix/federation/v1/make_join/{self.room_id}/{bad_user}?ver=11", + f"/_matrix/federation/v1/make_join/{self.room_id}/{bad_user}?ver={self.room_version.identifier}", ) self.assertEqual(channel.code, HTTPStatus.OK, channel.json_body) join_result = channel.json_body join_event_dict = join_result["event"] - self.add_hashes_and_signatures_from_other_server( - join_event_dict, - RoomVersions.V11, - ) + self.add_hashes_and_signatures_from_other_server(join_event_dict) channel = self.make_signed_federation_request( "PUT", f"/_matrix/federation/v2/send_join/{self.room_id}/x", @@ -5062,7 +5059,6 @@ def test_unbanning_remote_user_stops_redaction_action(self) -> None: self.assertEqual(r[("m.room.member", bad_user)].membership, "join") auth_ids = [ - r[("m.room.create", "")].event_id, r[("m.room.power_levels", "")].event_id, r[("m.room.member", "@remote_bad_user:other.example.com")].event_id, ] @@ -5081,7 +5077,7 @@ def test_unbanning_remote_user_stops_redaction_action(self) -> None: "prev_events": auth_ids, } ), - room_version=RoomVersions.V11, + room_version=self.room_version, ) self.get_success( @@ -5122,16 +5118,13 @@ def test_unbanning_remote_user_stops_redaction_action(self) -> None: # user should be able to join again channel = self.make_signed_federation_request( "GET", - f"/_matrix/federation/v1/make_join/{self.room_id}/{bad_user}?ver=11", + f"/_matrix/federation/v1/make_join/{self.room_id}/{bad_user}?ver={self.room_version.identifier}", ) self.assertEqual(channel.code, HTTPStatus.OK, channel.json_body) join_result = channel.json_body join_event_dict = join_result["event"] - self.add_hashes_and_signatures_from_other_server( - join_event_dict, - RoomVersions.V10, - ) + self.add_hashes_and_signatures_from_other_server(join_event_dict) channel = self.make_signed_federation_request( "PUT", f"/_matrix/federation/v2/send_join/{self.room_id}/x", @@ -5149,7 +5142,6 @@ def test_unbanning_remote_user_stops_redaction_action(self) -> None: self._storage_controllers.state.get_current_state(self.room_id) ) auth_ids = [ - new_state[("m.room.create", "")].event_id, new_state[("m.room.power_levels", "")].event_id, new_state[("m.room.member", "@remote_bad_user:other.example.com")].event_id, ] @@ -5170,7 +5162,7 @@ def test_unbanning_remote_user_stops_redaction_action(self) -> None: "prev_events": auth_ids, } ), - room_version=RoomVersions.V11, + room_version=self.room_version, ) self.get_success( @@ -5192,13 +5184,16 @@ def test_unbanning_remote_user_stops_redaction_action(self) -> None: def test_redaction_flag_ignored_for_user_if_banner_lacks_redaction_power( self, ) -> None: - # change power levels so creator can ban but not redact + # change power levels so room admin can ban but not redact. Do not use the + # room's creator, as the power level they hold is not consistently definable + # after msc4289(creator has infinite power level). self.helper.send_state( self.room_id, "m.room.power_levels", - {"events_default": 0, "redact": 100, "users": {self.creator: 75}}, + {"events_default": 0, "redact": 100, "users": {self.good_admin: 75}}, tok=self.creator_tok, ) + self.helper.join(self.room_id, self.good_admin, tok=self.good_admin_tok) self.helper.join(self.room_id, self.bad_user_id, tok=self.bad_tok) # bad user sends some messages @@ -5220,11 +5215,11 @@ def test_redaction_flag_ignored_for_user_if_banner_lacks_redaction_power( } self.helper.change_membership( self.room_id, - self.creator, + self.good_admin, self.bad_user_id, "ban", content, - self.creator_tok, + self.good_admin_tok, ) filter = json.dumps({"types": [EventTypes.Message]}) @@ -5284,16 +5279,13 @@ def test_kicking_remote_member_with_flag_redacts_their_events(self) -> None: bad_user = "@remote_bad_user:" + self.OTHER_SERVER_NAME channel = self.make_signed_federation_request( "GET", - f"/_matrix/federation/v1/make_join/{self.room_id}/{bad_user}?ver=11", + f"/_matrix/federation/v1/make_join/{self.room_id}/{bad_user}?ver={self.room_version.identifier}", ) self.assertEqual(channel.code, HTTPStatus.OK, channel.json_body) join_result = channel.json_body join_event_dict = join_result["event"] - self.add_hashes_and_signatures_from_other_server( - join_event_dict, - RoomVersions.V11, - ) + self.add_hashes_and_signatures_from_other_server(join_event_dict) channel = self.make_signed_federation_request( "PUT", f"/_matrix/federation/v2/send_join/{self.room_id}/x", @@ -5308,7 +5300,6 @@ def test_kicking_remote_member_with_flag_redacts_their_events(self) -> None: self.assertEqual(r[("m.room.member", bad_user)].membership, "join") auth_ids = [ - r[("m.room.create", "")].event_id, r[("m.room.power_levels", "")].event_id, r[("m.room.member", "@remote_bad_user:other.example.com")].event_id, ] @@ -5327,7 +5318,7 @@ def test_kicking_remote_member_with_flag_redacts_their_events(self) -> None: "prev_events": auth_ids, } ), - room_version=RoomVersions.V11, + room_version=self.room_version, ) self.get_success( @@ -5378,7 +5369,7 @@ def test_kicking_remote_member_with_flag_redacts_their_events(self) -> None: "prev_events": auth_ids, } ), - room_version=RoomVersions.V11, + room_version=self.room_version, ) self.get_success( @@ -5400,16 +5391,13 @@ def test_rejoining_kicked_remote_user_stops_redaction_action(self) -> None: bad_user = "@remote_bad_user:" + self.OTHER_SERVER_NAME channel = self.make_signed_federation_request( "GET", - f"/_matrix/federation/v1/make_join/{self.room_id}/{bad_user}?ver=11", + f"/_matrix/federation/v1/make_join/{self.room_id}/{bad_user}?ver={self.room_version.identifier}", ) self.assertEqual(channel.code, HTTPStatus.OK, channel.json_body) join_result = channel.json_body join_event_dict = join_result["event"] - self.add_hashes_and_signatures_from_other_server( - join_event_dict, - RoomVersions.V11, - ) + self.add_hashes_and_signatures_from_other_server(join_event_dict) channel = self.make_signed_federation_request( "PUT", f"/_matrix/federation/v2/send_join/{self.room_id}/x", @@ -5424,7 +5412,6 @@ def test_rejoining_kicked_remote_user_stops_redaction_action(self) -> None: self.assertEqual(r[("m.room.member", bad_user)].membership, "join") auth_ids = [ - r[("m.room.create", "")].event_id, r[("m.room.power_levels", "")].event_id, r[("m.room.member", "@remote_bad_user:other.example.com")].event_id, ] @@ -5443,7 +5430,7 @@ def test_rejoining_kicked_remote_user_stops_redaction_action(self) -> None: "prev_events": auth_ids, } ), - room_version=RoomVersions.V11, + room_version=self.room_version, ) self.get_success( @@ -5479,16 +5466,13 @@ def test_rejoining_kicked_remote_user_stops_redaction_action(self) -> None: # user re-joins after kick channel = self.make_signed_federation_request( "GET", - f"/_matrix/federation/v1/make_join/{self.room_id}/{bad_user}?ver=11", + f"/_matrix/federation/v1/make_join/{self.room_id}/{bad_user}?ver={self.room_version.identifier}", ) self.assertEqual(channel.code, HTTPStatus.OK, channel.json_body) join_result = channel.json_body join_event_dict = join_result["event"] - self.add_hashes_and_signatures_from_other_server( - join_event_dict, - RoomVersions.V11, - ) + self.add_hashes_and_signatures_from_other_server(join_event_dict) channel = self.make_signed_federation_request( "PUT", f"/_matrix/federation/v2/send_join/{self.room_id}/x", @@ -5506,7 +5490,6 @@ def test_rejoining_kicked_remote_user_stops_redaction_action(self) -> None: self._storage_controllers.state.get_current_state(self.room_id) ) auth_ids = [ - new_state[("m.room.create", "")].event_id, new_state[("m.room.power_levels", "")].event_id, new_state[("m.room.member", "@remote_bad_user:other.example.com")].event_id, ] @@ -5527,7 +5510,7 @@ def test_rejoining_kicked_remote_user_stops_redaction_action(self) -> None: "prev_events": auth_ids, } ), - room_version=RoomVersions.V11, + room_version=self.room_version, ) self.get_success( @@ -5549,13 +5532,16 @@ def test_rejoining_kicked_remote_user_stops_redaction_action(self) -> None: def test_redaction_flag_ignored_for_user_if_kicker_lacks_redaction_power( self, ) -> None: - # change power levels so creator can kick but not redact + # change power levels so room admin can kick but not redact. Do not use the + # room's creator, as the power level they hold is not consistently definable + # after msc4289(creator has infinite power level). self.helper.send_state( self.room_id, "m.room.power_levels", - {"events_default": 0, "redact": 100, "users": {self.creator: 75}}, + {"events_default": 0, "redact": 100, "users": {self.good_admin: 75}}, tok=self.creator_tok, ) + self.helper.join(self.room_id, self.good_admin, tok=self.good_admin_tok) self.helper.join(self.room_id, self.bad_user_id, tok=self.bad_tok) # bad user sends some messages @@ -5577,11 +5563,11 @@ def test_redaction_flag_ignored_for_user_if_kicker_lacks_redaction_power( } self.helper.change_membership( self.room_id, - self.creator, + self.good_admin, self.bad_user_id, "kick", content, - self.creator_tok, + self.good_admin_tok, ) filter = json.dumps({"types": [EventTypes.Message]}) diff --git a/tests/rest/client/test_sync.py b/tests/rest/client/test_sync.py index 74a8678ae99..36065b38a3d 100644 --- a/tests/rest/client/test_sync.py +++ b/tests/rest/client/test_sync.py @@ -496,7 +496,7 @@ def prepare(self, reactor: MemoryReactor, clock: Clock, hs: HomeServer) -> None: self.room_id, EventTypes.PowerLevels, { - "users": {self.user_id: 100, self.user2: 100}, + "users": {self.user2: 100}, "users_default": 0, "events": { "m.room.name": 50, diff --git a/tests/rest/client/test_third_party_rules.py b/tests/rest/client/test_third_party_rules.py index 5eaa6f9fb28..0b0fb6c4f72 100644 --- a/tests/rest/client/test_third_party_rules.py +++ b/tests/rest/client/test_third_party_rules.py @@ -576,7 +576,6 @@ def _update_power_levels(self, event_default: int = 0) -> None: "kick": 50, "redact": 50, "state_default": 50, - "users": {self.user_id: 100}, "users_default": 0, }, tok=self.tok, diff --git a/tests/rest/client/test_upgrade_room.py b/tests/rest/client/test_upgrade_room.py index 6cb85c94c42..1fc3475733a 100644 --- a/tests/rest/client/test_upgrade_room.py +++ b/tests/rest/client/test_upgrade_room.py @@ -134,7 +134,9 @@ def test_power_levels(self) -> None: "m.room.power_levels", tok=self.creator_token, ) - power_levels["users"][self.other] = 100 + # In the Matrix Spec v1.16, m.room.tombstone events are MUST explicitly be + # higher than `state_default` per MSC4289. + power_levels["users"][self.other] = 150 self.helper.send_state( self.room_id, "m.room.power_levels", @@ -160,7 +162,9 @@ def test_power_levels_user_default(self) -> None: "m.room.power_levels", tok=self.creator_token, ) - power_levels["users_default"] = 100 + # In the Matrix Spec v1.16, m.room.tombstone events are MUST explicitly be + # higher than `state_default` per MSC4289. + power_levels["users"][self.other] = 150 self.helper.send_state( self.room_id, "m.room.power_levels", @@ -220,8 +224,8 @@ def test_stringy_power_levels(self) -> None: tok=self.creator_token, ) - # Set creator's power level to the string "100" instead of the integer `100`. - power_levels["users"][self.creator] = "100" + # Set other's power level to the string "100" instead of the integer `100`. + power_levels["users"][self.other] = "100" # Synapse refuses to accept new stringy power level events. Bypass this by # neutering the validation. @@ -252,7 +256,7 @@ def test_stringy_power_levels(self) -> None: ) # We should now have an integer power level. - self.assertEqual(new_power_levels["users"][self.creator], 100, new_power_levels) + self.assertEqual(new_power_levels["users"][self.other], 100, new_power_levels) def test_events_field_missing(self) -> None: """Regression test for https://github.com/matrix-org/synapse/issues/16715.""" diff --git a/tests/storage/test_cleanup_extrems.py b/tests/storage/test_cleanup_extrems.py index 054e4a4d0b6..3437b6dd772 100644 --- a/tests/storage/test_cleanup_extrems.py +++ b/tests/storage/test_cleanup_extrems.py @@ -283,52 +283,76 @@ def prepare( self.user = UserID.from_string(self.register_user("user1", "password")) self.token1 = self.login("user1", "password") self.requester = create_requester(self.user) - self.room_id, _, _ = self.get_success( - self.room_creator.create_room(self.requester, {"visibility": "public"}) - ) self.event_creator = homeserver.get_event_creation_handler() homeserver.config.consent.user_consent_version = self.CONSENT_VERSION def test_send_dummy_event(self) -> None: - self._create_extremity_rich_graph() + room_id, _, _ = self.get_success( + self.room_creator.create_room(self.requester, {"visibility": "public"}) + ) + self._create_extremity_rich_graph(room_id, self.user) # Pump the reactor repeatedly so that the background updates have a # chance to run. self.pump(20) latest_event_ids = self.get_success( - self.store.get_latest_event_ids_in_room(self.room_id) + self.store.get_latest_event_ids_in_room(room_id) ) self.assertTrue(len(latest_event_ids) < 10, len(latest_event_ids)) @patch("synapse.handlers.message._DUMMY_EVENT_ROOM_EXCLUSION_EXPIRY", new=0) def test_send_dummy_events_when_insufficient_power(self) -> None: - self._create_extremity_rich_graph() - # Criple power levels + # The Plan: + # create a new room with main user(creator). + # join with second user(user2). + # creator changes power levels of user2 so cannot send any events. + # create extremities graph. + # creators leaves - this should remove the user with potentially infinite power + # level. Side effect: this event will capture 10 extremities. + # move time(pump()), try and resolve with dummy events. Should fail. + # creator rejoins. Side effect: this will take tie up 10 more extremities. + # move time(pump()), try and resolve with dummy events again. Should succeed. + + room_id, _, _ = self.get_success( + self.room_creator.create_room(self.requester, {"visibility": "public"}) + ) + + user2 = self.register_user("user2", "password") + token2 = self.login("user2", "password") + self.helper.join(room_id, user2, tok=token2) + + # Cripple power levels for this new user self.helper.send_state( - self.room_id, + room_id, EventTypes.PowerLevels, - body={"users": {str(self.user): -1}}, + body={"users": {user2: -1}}, tok=self.token1, ) + + self._create_extremity_rich_graph(room_id, self.user) + + # The room creator leaves now. They are the only member of the room with a power + # level that can not be tweaked + self.helper.leave(room_id, self.user.to_string(), tok=self.token1) + # Pump the reactor repeatedly so that the background updates have a # chance to run. self.pump(10 * 60) latest_event_ids = self.get_success( - self.store.get_latest_event_ids_in_room(self.room_id) + self.store.get_latest_event_ids_in_room(room_id) ) # Check that the room has not been pruned self.assertTrue(len(latest_event_ids) > 10) - # New user with regular levels - user2 = self.register_user("user2", "password") - token2 = self.login("user2", "password") - self.helper.join(self.room_id, user2, tok=token2) + # Rejoin the room creator + self.helper.join(room_id, self.user.to_string(), tok=self.token1) + # Running the background updates again should clean up the extremities self.pump(10 * 60) latest_event_ids = self.get_success( - self.store.get_latest_event_ids_in_room(self.room_id) + self.store.get_latest_event_ids_in_room(room_id) ) self.assertTrue(len(latest_event_ids) < 10, len(latest_event_ids)) @@ -373,18 +397,20 @@ def test_expiry_logic(self) -> None: 0, ) - def _create_extremity_rich_graph(self) -> None: + def _create_extremity_rich_graph( + self, room_id: str, user_for_sending: UserID + ) -> None: """Helper method to create bushy graph on demand""" - event_id_start = self.create_and_send_event(self.room_id, self.user) + event_id_start = self.create_and_send_event(room_id, user_for_sending) for _ in range(self.EXTREMITIES_COUNT): self.create_and_send_event( - self.room_id, self.user, prev_event_ids=[event_id_start] + room_id, user_for_sending, prev_event_ids=[event_id_start] ) latest_event_ids = self.get_success( - self.store.get_latest_event_ids_in_room(self.room_id) + self.store.get_latest_event_ids_in_room(room_id) ) self.assertEqual(len(latest_event_ids), 50) diff --git a/tests/storage/test_stream.py b/tests/storage/test_stream.py index de127e3971d..1297d869cb1 100644 --- a/tests/storage/test_stream.py +++ b/tests/storage/test_stream.py @@ -35,7 +35,6 @@ ) from synapse.api.filtering import Filter from synapse.crypto.event_signing import add_hashes_and_signatures -from synapse.events import make_event_from_dict from synapse.federation.federation_client import SendJoinResult from synapse.rest import admin from synapse.rest.client import login, room @@ -50,6 +49,7 @@ ) from synapse.util.clock import Clock +from tests.test_utils.event_builders import make_test_pdu_event from tests.test_utils.event_injection import create_event from tests.unittest import FederatingHomeserverTestCase, HomeserverTestCase @@ -690,7 +690,6 @@ def test_server_left_room_after_us(self) -> None: extra_content={ "power_level_content_override": { "users": { - user2_id: 100, # Allow user1 to send state in the room user1_id: 100, } @@ -861,7 +860,6 @@ def test_we_cause_server_left_room(self) -> None: extra_content={ "power_level_content_override": { "users": { - user2_id: 100, # Allow user1 to send state in the room user1_id: 100, } @@ -1350,6 +1348,7 @@ def prepare(self, reactor: MemoryReactor, clock: Clock, hs: HomeServer) -> None: self.store = self.hs.get_datastores().main self.event_sources = hs.get_event_sources() self.room_member_handler = hs.get_room_member_handler() + self.room_version = self.hs.config.server.default_room_version def test_remote_join(self) -> None: """ @@ -1361,98 +1360,96 @@ def test_remote_join(self) -> None: before_join_token = self.event_sources.get_current_token() - intially_unjoined_room_id = f"!example:{self.OTHER_SERVER_NAME}" - # Remotely join a room on another homeserver. # # To do this we have to mock the responses from the remote homeserver. We also # patch out a bunch of event checks on our end. - create_event_source = { + creation_event_source = { "auth_events": [], "content": { - "creator": f"@creator:{self.OTHER_SERVER_NAME}", - "room_version": self.hs.config.server.default_room_version.identifier, + "room_version": self.room_version.identifier, }, - "depth": 0, + "depth": 1, "origin_server_ts": 0, "prev_events": [], - "room_id": intially_unjoined_room_id, "sender": f"@creator:{self.OTHER_SERVER_NAME}", "state_key": "", "type": EventTypes.Create, } + self.add_hashes_and_signatures_from_other_server( - create_event_source, - self.hs.config.server.default_room_version, + creation_event_source, + self.room_version, ) - create_event = make_event_from_dict( - create_event_source, - self.hs.config.server.default_room_version, - {}, - None, + # This handles FrozenEvent* creation for us, and will create the room_id if this + # is a msc4921 room + creation_event = make_test_pdu_event( + creation_event_source, + self.room_version, ) + + initially_unjoined_room_id = creation_event.room_id + creator_join_event_source = { - "auth_events": [create_event.event_id], + "auth_events": [], "content": { "membership": "join", }, - "depth": 1, + "depth": 2, "origin_server_ts": 1, "prev_events": [], - "room_id": intially_unjoined_room_id, + "room_id": initially_unjoined_room_id, "sender": f"@creator:{self.OTHER_SERVER_NAME}", "state_key": f"@creator:{self.OTHER_SERVER_NAME}", "type": EventTypes.Member, } + self.add_hashes_and_signatures_from_other_server( creator_join_event_source, - self.hs.config.server.default_room_version, + self.room_version, ) - creator_join_event = make_event_from_dict( + creator_join_event = make_test_pdu_event( creator_join_event_source, - self.hs.config.server.default_room_version, - {}, - None, + self.room_version, ) # Our local user is going to remote join the room join_event_source = { - "auth_events": [create_event.event_id], + "auth_events": [], "content": {"membership": "join"}, - "depth": 1, + "depth": 3, "origin_server_ts": 100, "prev_events": [creator_join_event.event_id], "sender": user1_id, "state_key": user1_id, - "room_id": intially_unjoined_room_id, + "room_id": initially_unjoined_room_id, "type": EventTypes.Member, } + add_hashes_and_signatures( - self.hs.config.server.default_room_version, + self.room_version, join_event_source, self.hs.hostname, self.hs.signing_key, ) - join_event = make_event_from_dict( + join_event = make_test_pdu_event( join_event_source, - self.hs.config.server.default_room_version, - {}, - None, + self.room_version, ) mock_make_membership_event = AsyncMock( return_value=( self.OTHER_SERVER_NAME, join_event, - self.hs.config.server.default_room_version, + self.room_version, ) ) mock_send_join = AsyncMock( return_value=SendJoinResult( join_event, self.OTHER_SERVER_NAME, - state=[create_event, creator_join_event], - auth_chain=[create_event, creator_join_event], + state=[creation_event, creator_join_event], + auth_chain=[creation_event, creator_join_event], partial_state=False, servers_in_room=frozenset(), ) @@ -1482,7 +1479,7 @@ def test_remote_join(self) -> None: self.room_member_handler.update_membership( requester=create_requester(user1_id), target=UserID.from_string(user1_id), - room_id=intially_unjoined_room_id, + room_id=initially_unjoined_room_id, action=Membership.JOIN, remote_room_hosts=[self.OTHER_SERVER_NAME], ) @@ -1519,7 +1516,7 @@ def test_remote_join(self) -> None: membership_changes, [ CurrentStateDeltaMembership( - room_id=intially_unjoined_room_id, + room_id=initially_unjoined_room_id, event_id=join_event.event_id, event_pos=join_pos, membership="join", diff --git a/tests/test_utils/event_builders.py b/tests/test_utils/event_builders.py index a5d686801d7..564289376de 100644 --- a/tests/test_utils/event_builders.py +++ b/tests/test_utils/event_builders.py @@ -49,6 +49,11 @@ def default_event_fields(room_version: RoomVersion) -> JsonDict: else: defaults["auth_events"] = [] + # MSC4291 versions do not have a room_id in the create event, so discard this now + # as it needs to be populated later for the actual room + if room_version.msc4291_room_ids_as_hashes: + defaults.pop("room_id") + if room_version == RoomVersions.V1: # V1 requires an event_id field, but later versions don't. defaults["event_id"] = "$test_event_id:matrix.org" diff --git a/tests/unittest.py b/tests/unittest.py index 152fb341cb8..55d3c26c4c0 100644 --- a/tests/unittest.py +++ b/tests/unittest.py @@ -19,6 +19,7 @@ # [This file includes modifications made by New Vector Limited] # # +import copy import functools import gc import hashlib @@ -148,8 +149,14 @@ def deepcopy_config(config: _TConfig) -> _TConfig: if attr_name.startswith("__") or attr_name == "root": continue attr = getattr(config, attr_name) + new_attr: Any if isinstance(attr, Config): new_attr = deepcopy_config(attr) + elif isinstance(attr, (list, dict, set)): + # Copy mutable containers so that tests which modify config values + # in place (e.g. appending to a list) don't leak those changes into + # the cached config object, and thus into every other test. + new_attr = copy.deepcopy(attr) else: new_attr = attr