Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/SyTest/Federation/Server.pm
Original file line number Diff line number Diff line change
Expand Up @@ -504,7 +504,7 @@ __PACKAGE__->mk_await_request_pair(
);

__PACKAGE__->mk_await_request_pair(
"v1", "state", [qw( :room_id )],
"v1", "state", [qw( :room_id ?event_id )],
);

__PACKAGE__->mk_await_request_pair(
Expand Down
52 changes: 40 additions & 12 deletions tests/50federation/33room-get-missing-events.pl
Original file line number Diff line number Diff line change
Expand Up @@ -377,21 +377,49 @@ sub sytest_user_and_room_fixture {
Future->done(1);
}),
)->then( sub {
# wait for S to turn up
await_sync_timeline_contains(
$creator_user, $room2->room_id, check => sub {
my ( $event ) = @_;
log_if_fail "Got event in room2", $event;
# the server may send a /state request; be prepared to answer that.
# (it may, alternatively, send individual /event requests)
my $state_req_fut = $inbound_server->await_request_v1_state(
$room2->{room_id}, $event_id_Q,
)->then( sub {
my ( $req, @params ) = @_;
log_if_fail "/state request", \@params;

my $event_id = $event->{event_id};
my $resp = {
pdus => [ values( %initial_room2_state ) ],
auth_chain => [
map { $inbound_server->datastore->get_event( $_ ) } @{ $room2->event_ids_from_refs( $event_Q->{auth_events} ) },
],
};

# if either Q or R show up, that's a problem
if( $event->{sender} eq $sytest_user_1 ) {
die "Got an event $event_id from a user who shouldn't be a member";
}
log_if_fail "/state response", $resp;
$req->respond_json( $resp );

return $event_id eq $event_id_S;
},
# return a future which never completes, so that wait_any is not
# satisfied.
return Future->new();
});


# wait for either S to turn up in /sync, or $state_req_fut to fail.
Future->wait_any(
$state_req_fut,

await_sync_timeline_contains(
$creator_user, $room2->room_id, check => sub {
my ( $event ) = @_;
log_if_fail "Got event in room2", $event;

my $event_id = $event->{event_id};

# if either Q or R show up, that's a problem
if( $event->{sender} eq $sytest_user_1 ) {
die "Got an event $event_id from a user who shouldn't be a member";
}

return $event_id eq $event_id_S;
},
),
);
})->then( sub {
# finally, check that the state in room 2 looks correct.
Expand Down
120 changes: 78 additions & 42 deletions tests/50federation/34room-backfill.pl
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,34 @@

log_if_fail "events P, Q, R, S", [ $event_id_P, $event_id_Q, $event_id_R, $event_id_S ];

# the server may send a /state request; be prepared to answer that.
# (it may, alternatively, send individual /event requests)
my $state_req_fut = $inbound_server->await_request_v1_state(
$room2->{room_id}, $event_id_Q,
)->then( sub {
my ( $req, @params ) = @_;
log_if_fail "/state request (1)", \@params;

my %state = %{ $room2->{current_state} };
my $resp = {
pdus => [ values( %state ) ],

# XXX we're supposed to return the whole auth chain here,
# not just Q's auth_events. It doesn't matter too much
# here though.
auth_chain => [
map { $inbound_server->datastore->get_event( $_ ) } @{ $room2->event_ids_from_refs( $event_Q->{auth_events} ) },
],
};

log_if_fail "/state response (1)", $resp;
$req->respond_json( $resp );

# return a future which never completes, so that wait_any is not
# satisfied.
return Future->new();
});

Future->needs_all(
# kick things off by sending S over federation
$outbound_client->send_event(
Expand Down Expand Up @@ -338,7 +366,7 @@
$room2_id, $event_id_Q,
)->then( sub {
my ( $req, @params ) = @_;
log_if_fail "/state_ids request", \@params;
log_if_fail "/state_ids request (1)", \@params;

my %state = %{ $room2->{current_state} };
my $resp = {
Expand All @@ -352,7 +380,7 @@
auth_chain_ids => $room2->event_ids_from_refs( $event_Q->{auth_events} ),
};

log_if_fail "/state_ids response", $resp;
log_if_fail "/state_ids response (1)", $resp;
$req->respond_json( $resp );
Future->done(1);
}),
Expand All @@ -363,14 +391,18 @@
destination => $synapse_server_name,
);
})->then( sub {
# wait for S to arrive
log_if_fail "Awating arrival of event S $event_id_S in room $room2_id";

await_sync_timeline_contains(
$creator_user, $room2_id,
check => sub {
$_[0]->{event_id} eq $event_id_S
},
# wait for either S to turn up in /sync, or $state_req_fut to fail.
Future->wait_any(
$state_req_fut,

await_sync_timeline_contains(
$creator_user, $room2_id,
check => sub {
$_[0]->{event_id} eq $event_id_S
},
),
);
})->then( sub {
my $filter = $json->encode( { room => { timeline => { limit => 2 }}} );
Expand All @@ -392,7 +424,7 @@
$room2_id, $event_id_Q,
)->then( sub {
my ( $req, @params ) = @_;
log_if_fail "/state_ids request", \@params;
log_if_fail "/state_ids request (2)", \@params;

my %state = %{ $room2->{current_state} };
my $resp = {
Expand All @@ -402,48 +434,52 @@
auth_chain_ids => $room2->event_ids_from_refs( $event_Q->{auth_events} ),
};

log_if_fail "/state_ids response", $resp;
log_if_fail "/state_ids response (2)", $resp;
$req->respond_json( $resp );
Future->done(1);

# return a future which never completes, so that wait_any is not
# satisfied.
return Future->new();
});

# now back-paginate, and provide event Q when the
# server backfills.
Future->needs_all(
do_request_json_for(
$creator_user,
method => "GET",
uri => "/v3/rooms/$room2_id/messages",
params => {
dir => "b",
from => $prev_batch,
},
)->on_done(sub {
my ( $resp ) = @_;
log_if_fail "Pagination request completed", $resp;
}),

$inbound_server->await_request_backfill( $room2_id )->then( sub {
my ( $req, @params ) = @_;

log_if_fail "Incoming /backfill request", \@params;

$req->respond_json( {
origin => $inbound_server->server_name,
origin_server_ts => $inbound_server->time_ms,
pdus => [
$event_Q,
],
});
Future->done;
}),
Future->wait_any(
$state_ids_fut,

Future->needs_all(
do_request_json_for(
$creator_user,
method => "GET",
uri => "/v3/rooms/$room2_id/messages",
params => {
dir => "b",
from => $prev_batch,
},
)->on_done(sub {
my ( $resp ) = @_;
log_if_fail "Pagination request completed", $resp;
}),

$inbound_server->await_request_backfill( $room2_id )->then( sub {
my ( $req, @params ) = @_;

log_if_fail "Incoming /backfill request", \@params;

$req->respond_json( {
origin => $inbound_server->server_name,
origin_server_ts => $inbound_server->time_ms,
pdus => [
$event_Q,
],
});
Future->done;
}),
),
)->then( sub {
my ( $messages ) = @_;
log_if_fail "/messages result", $messages;

# cancel the state_ids responder, if it didn't get used.
$state_ids_fut->cancel();

# ensure that P does not feature in the list.
die 'too few events' if @{$messages->{chunk}} < 2;
foreach my $ev ( @{$messages->{chunk}} ) {
Expand Down
108 changes: 81 additions & 27 deletions tests/50federation/36state.pl
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,13 @@ sub get_state_ids_from_server {
log_if_fail "Sent events B, C: " . $sent_event_b->{event_id} .
", " . $sent_event_c->{event_id};

# build a state map from the room's current state and our extra events
my %room_state_at_y = %{ $room->{current_state} };
foreach my $event ( $missing_state_s, $missing_state_t ) {
my $k = join "\0", $event->{type}, $event->{state_key};
$room_state_at_y{$k} = $event;
}

Future->needs_all(
$outbound_client->send_event(
event => $sent_event_c,
Expand Down Expand Up @@ -505,20 +512,13 @@ sub get_state_ids_from_server {
my ( $req ) = @_;
log_if_fail "/state_ids request";

# build a state map from the room's current state and our extra events
my %state = %{ $room->{current_state} };
foreach my $event ( $missing_state_s, $missing_state_t ) {
my $k = join "\0", $event->{type}, $event->{state_key};
$state{$k} = $event;
}

my @auth_chain = $inbound_server->{datastore}->get_auth_chain_events(
map { $_->{event_id} } values( %state )
map { $_->{event_id} } values( %room_state_at_y )
);

my $resp = {
pdu_ids => [
map { $_->{event_id} } values( %state ),
map { $_->{event_id} } values( %room_state_at_y ),
],
auth_chain_ids => [
map { $_->{event_id} } @auth_chain,
Expand All @@ -532,17 +532,45 @@ sub get_state_ids_from_server {
Future->done(1);
}),
)->then( sub {
# the server may send a /state request; be prepared to answer that.
# (it may, alternatively, send individual /event requests)
my $state_req_fut = $inbound_server->await_request_v1_state(
$room_id, $missing_event_y->{event_id},
)->then( sub {
my ( $req, @params ) = @_;
log_if_fail "/state request", \@params;

my $resp = {
pdus => [ values( %room_state_at_y ) ],
auth_chain => [
map { $inbound_server->datastore->get_auth_chain_events( $room->id_for_event( $_ )) }
values( %room_state_at_y )
],
};

log_if_fail "/state response", $resp;
$req->respond_json( $resp );

# return a future which never completes, so that wait_any is not
# satisfied.
return Future->new();
});

# creator user should eventually receive the events
Future->needs_all(
await_sync_timeline_contains($creator, $room_id, check => sub {
my ( $event ) = @_;
return $event->{event_id} eq $sent_event_c->{event_id}
}),
await_sync_timeline_contains($creator, $room_id, check => sub {
my ( $event ) = @_;
log_if_fail "/sync event", $event;
return $event->{event_id} eq $missing_event_x->{event_id}
}),
Future->wait_any(
$state_req_fut,

Future->needs_all(
await_sync_timeline_contains($creator, $room_id, check => sub {
my ( $event ) = @_;
return $event->{event_id} eq $sent_event_c->{event_id}
}),
await_sync_timeline_contains($creator, $room_id, check => sub {
my ( $event ) = @_;
log_if_fail "/sync event", $event;
return $event->{event_id} eq $missing_event_x->{event_id}
}),
),
);
})->then( sub {
# check the 'current' state of the room after state resolution
Expand Down Expand Up @@ -745,15 +773,41 @@ sub get_state_ids_from_server {
Future->done(1);
}),
)->then( sub {
# the server may send a /state request; be prepared to answer that.
# (it may, alternatively, send individual /event requests)
my $state_req_fut = $inbound_server->await_request_v1_state(
$room_id, $missing_event_y->{event_id},
)->then( sub {
my ( $req, @params ) = @_;
log_if_fail "/state request", \@params;

my $resp = {
pdus => [ values( %{ $room->{current_state} } ) ],
auth_chain => [],
};

log_if_fail "/state response", $resp;
$req->respond_json( $resp );

# return a future which never completes, so that wait_any is not
# satisfied.
return Future->new();
});


# creator user should eventually receive X and C.
Future->needs_all(
await_sync_timeline_contains( $creator, $room_id, check => sub {
log_if_fail "/sync " , $_;
return $_[0]->{event_id} eq $missing_event_x->{event_id};
}),
await_sync_timeline_contains( $creator, $room_id, check => sub {
return $_[0]->{event_id} eq $sent_event_c->{event_id};
}),
Future->wait_any(
$state_req_fut,

Future->needs_all(
await_sync_timeline_contains( $creator, $room_id, check => sub {
log_if_fail "/sync " , $_;
return $_[0]->{event_id} eq $missing_event_x->{event_id};
}),
await_sync_timeline_contains( $creator, $room_id, check => sub {
return $_[0]->{event_id} eq $sent_event_c->{event_id};
}),
),
);
});
});
Expand Down