Skip to content

Commit

Permalink
Outlier/rejected tests for /state and /state_ids
Browse files Browse the repository at this point in the history
Extend the tests for `/state` and `/state_ids` to check the behaviour on
outliers and rejected events.

The rejected-event behaviour has always been to return a 404, but we add a test
to make sure it stays that way.

The outlier behaviour is changed by
matrix-org/synapse#12087.
  • Loading branch information
richvdh committed Mar 12, 2022
1 parent 2780655 commit 819a330
Show file tree
Hide file tree
Showing 2 changed files with 208 additions and 3 deletions.
131 changes: 130 additions & 1 deletion tests/50federation/00prepare.pl
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ =head2 send_and_await_event
I<$room> should be the L<SyTest::Federation::Room> in which to send the event.
I<$user> should be a L<User> which will poll for receiving the event.
I<$server_user> should be a L<User> which will poll for receiving the event.
The remainder of the arguments (I<%fields>) are passed into
L<SyTest::Federation::Room/create_and_insert_event>. They should include at
Expand Down Expand Up @@ -169,6 +169,135 @@ sub send_and_await_event {
push @EXPORT, qw( send_and_await_event );


=head2 send_and_await_outlier
send_and_await_outlier(
$inbound_server, $outbound_client, $room, $sending_user_id, $receiving_user,
)->then( sub {
my ( $outlier_event ) = @_;
});
Arranges for an outlier event to be sent over federation.
I<$inbound_server> should be a L<SyTest::Federation:Server>, likely
I<$main::INBOUND_SERVER>, which will handle the incoming federation requests
involved.
I<$outbound_client> should be a L<SyTest::Federation::Client>, most likely
I<$main::OUTBOUND_CLIENT>, which is used to send the event.
I<$room> should be the L<SyTest::Federation::Room> in which to send the event.
I<$sending_user_id> is a user on the Sytest federation server, and should be a
member of the room.
I<$receiving_user> should be a L<User> on the server under test, which will
poll for receiving the event. Must also be a member of the room.
The created outlier is returned.
=cut

sub send_and_await_outlier {
my ( $inbound_server, $outbound_client, $room, $sending_user_id, $receiving_user ) = @_;

# to construct an outlier, we create three events, Q, R, S.
#
# We send S over federation, and allow the server to backfill R, leaving
# the server with a gap in the dag. It therefore requests the state at Q,
# which leads to Q being persisted as an outlier.

my $first_home_server = $receiving_user->server_name;
my $room_id = $room->room_id;
my %initial_room_state = %{ $room->{current_state} };

my ( $outlier_event_Q, $outlier_event_id_Q ) = $room->create_and_insert_event(
type => 'm.room.member',
sender => $sending_user_id,
state_key => $sending_user_id,
content => { membership => 'join' },
auth_events => $room->make_event_refs(
$room->get_current_state_event( "m.room.create" ),
$room->get_current_state_event( "m.room.power_levels" ),
$room->get_current_state_event( "m.room.member", $sending_user_id ),
),
);

my ( $backfilled_event_R, $backfilled_event_id_R ) = $room->create_and_insert_event(
type => "m.room.message",
sender => $sending_user_id,
content => { body => "backfilled event R" },
);

my ( $sent_event_S, $sent_event_id_S ) = $room->create_and_insert_event(
type => "m.room.message",
sender => $sending_user_id,
content => { body => "sent event S" },
);

log_if_fail "create_outlier_event: events Q, R, S", [ $outlier_event_id_Q, $backfilled_event_id_R, $sent_event_id_S ];

Future->needs_all(
# send S
$outbound_client->send_event(
event => $sent_event_S,
destination => $first_home_server,
),

# we expect to get a missing_events request
$inbound_server->await_request_get_missing_events( $room_id )
->then( sub {
my ( $req ) = @_;
my $body = $req->body_from_json;
log_if_fail "create_outlier_event: /get_missing_events request", $body;

assert_deeply_eq(
$body->{latest_events},
[ $sent_event_id_S ],
"create_outlier_event: latest_events in /get_missing_events request",
);

# just return R
my $resp = { events => [ $backfilled_event_R ] };

log_if_fail "create_outlier_event: /get_missing_events response", $resp;
$req->respond_json( $resp );
Future->done(1);
}),

# there will still be a gap, so then we expect a state_ids request
$inbound_server->await_request_state_ids(
$room_id, $outlier_event_id_Q,
)->then( sub {
my ( $req, @params ) = @_;
log_if_fail "create_outlier_event: /state_ids request", \@params;

my $resp = {
pdu_ids => [
map { $room->id_for_event( $_ ) } values( %initial_room_state ),
],
auth_chain_ids => $room->event_ids_from_refs( $outlier_event_Q->{auth_events} ),
};

log_if_fail "create_outlier_event: /state_ids response", $resp;
$req->respond_json( $resp );
Future->done(1);
}),
)->then( sub {
# wait for S to turn up in /sync
await_sync_timeline_contains(
$receiving_user, $room_id, check => sub {
my ( $event ) = @_;
log_if_fail "create_outlier_event: Got event", $event;
my $event_id = $event->{event_id};
return $event_id eq $sent_event_id_S;
},
);
})->then_done( $outlier_event_Q, $backfilled_event_R, $sent_event_S );
}
push @EXPORT, qw( send_and_await_outlier );


my $next_user_id = 0;

=head2 federation_user_id_fixture
Expand Down
80 changes: 78 additions & 2 deletions tests/50federation/36state.pl
Original file line number Diff line number Diff line change
Expand Up @@ -243,8 +243,84 @@ sub get_state_ids_from_server {
};


foreach my $endpoint( qw( state state_ids ) ) {
test "/$endpoint returns M_NOT_FOUND for an outlier",
requires => [
$main::INBOUND_SERVER,
$main::OUTBOUND_CLIENT,
federated_rooms_fixture(),
],

do => sub {
my ( $inbound_server, $outbound_client, $creator, $user_id, $room ) = @_;

send_and_await_outlier(
$inbound_server, $outbound_client, $room, $user_id, $creator,
)->then( sub {
my ( $outlier_event ) = @_;
my $event_id = $room->id_for_event( $outlier_event );

my $uri = "/v1/$endpoint/".$room->room_id;
log_if_fail "Making request /_matrix/federation/$uri for outlier event $event_id";

$outbound_client->do_request_json(
method => "GET",
hostname => $creator->server_name,
uri => "/v1/state/".$room->room_id,
params => { event_id => $event_id },
);
})->main::expect_m_not_found();
};
}

foreach my $type ( qw( message state ) ) {
test "Room state at a rejected $type event is the same as its predecessor",
foreach my $endpoint( qw( state state_ids ) ) {
test "/$endpoint returns M_NOT_FOUND for a rejected $type event",
requires => [
$main::OUTBOUND_CLIENT,
federated_rooms_fixture(),
],

do => sub {
my ( $outbound_client, $creator_user, $sytest_user_id, $room ) = @_;
my $first_home_server = $creator_user->server_name;

# we send an event which will be rejected (due to having a sender not in the room)
my ( $rejected_event, $rejected_event_id ) = $room->create_and_insert_event(
type => "m.room.$type",
$type eq 'state' ? ( state_key => "" ) : (),

sender => '@fake_sender:' . $outbound_client->server_name,
content => { body => "Rejected" },
auth_events => $room->make_event_refs(
$room->get_current_state_event( "m.room.create" ),
$room->get_current_state_event( "m.room.power_levels" ),
),
);

log_if_fail "sending rejected event $rejected_event_id", $rejected_event;

$outbound_client->send_event(
event => $rejected_event,
destination => $first_home_server,
)->then( sub {
# follow up with a regular event, to make sure the rejected event got through
send_and_await_event( $outbound_client, $room, $creator_user, sender => $sytest_user_id );
})->then( sub {
# now request the state at the rejected event
my $uri = "/v1/$endpoint/".$room->room_id;
log_if_fail "Making request /_matrix/federation/$uri for event $rejected_event_id";
$outbound_client->do_request_json(
method => "GET",
hostname => $first_home_server,
uri => $uri,
params => { event_id => $rejected_event_id },
);
})->main::expect_m_not_found();
};
}

test "Room state after a rejected $type event is the same as before",
requires => [
$main::OUTBOUND_CLIENT,
federated_rooms_fixture(),
Expand Down Expand Up @@ -309,7 +385,7 @@ sub get_state_ids_from_server {
);
})->then( sub {
my ( $body ) = @_;
log_if_fail "state_ids response", $body;
log_if_fail "state_ids response after regular event $regular_event_id", $body;

my @sorted_state = sort @{ $body->{pdu_ids} };
assert_deeply_eq( \@sorted_state, \@initial_state_events );
Expand Down

0 comments on commit 819a330

Please sign in to comment.