diff --git a/lib/SyTest/Homeserver/Dendrite.pm b/lib/SyTest/Homeserver/Dendrite.pm index 9c02c2eec..75d2d472a 100644 --- a/lib/SyTest/Homeserver/Dendrite.pm +++ b/lib/SyTest/Homeserver/Dendrite.pm @@ -63,7 +63,8 @@ sub _check_db_config my $self = shift; my ( %config ) = @_; - $config{type} eq "pg" or die "Dendrite can only run against postgres"; + # We're in the business of running sytest against dendrite+sqlite these days + #$config{type} eq "pg" or die "Dendrite can only run against postgres"; return $self->SUPER::_check_db_config( @_ ); } diff --git a/lib/SyTest/Homeserver/ProcessManager.pm b/lib/SyTest/Homeserver/ProcessManager.pm index 00e953439..4aa3c9b0f 100644 --- a/lib/SyTest/Homeserver/ProcessManager.pm +++ b/lib/SyTest/Homeserver/ProcessManager.pm @@ -316,7 +316,7 @@ sub _await_ready_notification # We replace null byte with '@' to allow us to pass it in via env. (This is # as per the sd_notify spec). my $path_env = $path; - $path_env =~ s/\0/\@/rg; + $path_env =~ s/\0/\@/g; $env->{"NOTIFY_SOCKET"} = $path_env; # Create a future that gets resolved when we receive a `READY=1` diff --git a/tests/10apidoc/30room-create.pl b/tests/10apidoc/30room-create.pl index 91c726588..cc7f52f7f 100644 --- a/tests/10apidoc/30room-create.pl +++ b/tests/10apidoc/30room-create.pl @@ -16,7 +16,7 @@ content => { visibility => "public", # This is just the localpart - room_alias_name => "30room-create", + room_alias_name => "30room-create-".time, }, )->then( sub { my ( $body ) = @_; diff --git a/tests/31sync/17peeking.pl b/tests/31sync/17peeking.pl new file mode 100644 index 000000000..2e23ead0e --- /dev/null +++ b/tests/31sync/17peeking.pl @@ -0,0 +1,222 @@ +use Future::Utils qw( repeat ); +use JSON qw( decode_json ); + +# Tests MSC2753 style peeking + +test "Local users can peek into world_readable rooms by room ID", + requires => [ local_user_and_room_fixtures(), local_user_fixture() ], + + check => sub { + my ( $user, $room_id, $peeking_user ) = @_; + + matrix_set_room_history_visibility( $user, $room_id, "world_readable" )->then(sub { + do_request_json_for( $peeking_user, + method => "POST", + uri => "/r0/peek/$room_id", + content => {}, + ) + })->then( sub { + matrix_send_room_text_message_synced( $user, $room_id, body => "something to peek"); + })->then(sub { + await_sync( $peeking_user, + since => $peeking_user->sync_next_batch, + check => sub { + my ( $body ) = @_; + return 0 unless $body->{rooms}{peek}{$room_id}; + return $body; + } + ) + })->then( sub { + my ( $body ) = @_; + $peeking_user->sync_next_batch = $body->{next_batch}; + + log_if_fail "first sync response", $body; + + my $room = $body->{rooms}{peek}{$room_id}; + assert_json_keys( $room, qw( timeline state ephemeral )); + assert_json_keys( $room->{timeline}, qw( events limited prev_batch )); + assert_json_keys( $room->{state}, qw( events )); + assert_json_keys( $room->{ephemeral}, qw( events )); + + assert_ok( $room->{timeline}->{events}->[0]->{type} eq 'm.room.create', "peek has m.room.create" ); + assert_ok( $room->{timeline}->{events}->[-1]->{type} eq 'm.room.message', "peek has message type" ); + assert_ok( $room->{timeline}->{events}->[-1]->{content}->{body} eq 'something to peek', "peek has message body" ); + assert_ok( @{$room->{state}->{events}} == 0 ); + + assert_ok( scalar keys(%{$body->{rooms}{join}}) == 0, "no joined rooms present"); + + matrix_sync_again( $peeking_user ); + })->then( sub { + my ( $body ) = @_; + + log_if_fail "second sync response", $body; + my $room = $body->{rooms}{peek}{$room_id}; + (!defined $room) or die "Unchanged rooms shouldn't be in the sync response"; + })->then( sub { + matrix_send_room_text_message_synced( $user, $room_id, body => "something else to peek"); + })->then( sub { + await_sync( $peeking_user, + since => $peeking_user->sync_next_batch, + check => sub { + my ( $body ) = @_; + return 0 unless $body->{rooms}{peek}{$room_id}; + return $body; + } + ) + })->then( sub { + my ( $body ) = @_; + $peeking_user->sync_next_batch = $body->{next_batch}; + + log_if_fail "third sync response", $body; + my $room = $body->{rooms}{peek}{$room_id}; + + assert_ok( $room->{timeline}->{events}->[-1]->{type} eq 'm.room.message', "second peek has message type" ); + assert_ok( $room->{timeline}->{events}->[-1]->{content}->{body} eq 'something else to peek', "second peek has message body" ); + + Future->done(1) + }) + }; + + +for my $visibility (qw(shared invited joined)) { + test "We can't peek into rooms with $visibility history_visibility", + requires => [ local_user_and_room_fixtures(), local_user_fixture() ], + + check => sub { + my ( $user, $room_id, $peeking_user ) = @_; + + matrix_set_room_history_visibility( $user, $room_id, $visibility )->then(sub { + do_request_json_for( $peeking_user, + method => "POST", + uri => "/r0/peek/$room_id", + content => {}, + ); + })->main::expect_http_403() + ->then( sub { + my ( $response ) = @_; + my $body = decode_json( $response->content ); + log_if_fail "error body", $body; + assert_eq( $body->{errcode}, "M_FORBIDDEN", 'responsecode' ); + Future->done( 1 ); + }); + }; +} + + +my $room_alias_name = sprintf("peektest-%s", $TEST_RUN_ID); +test "Local users can peek by room alias", + requires => [ + local_user_and_room_fixtures(room_opts => { room_alias_name => $room_alias_name }), + local_user_fixture() + ], + + check => sub { + my ( $user, $room_id, $peeking_user ) = @_; + + matrix_set_room_history_visibility( $user, $room_id, "world_readable" )->then(sub { + do_request_json_for( $peeking_user, + method => "POST", + uri => "/r0/peek/#$room_alias_name:".$user->http->server_name, + content => {}, + ) + })->then(sub { + matrix_send_room_text_message_synced( $user, $room_id, body => "something to peek"); + })->then(sub { + await_sync( $peeking_user, + since => $peeking_user->sync_next_batch, + check => sub { + my ( $body ) = @_; + return 0 unless $body->{rooms}{peek}{$room_id}; + return $body; + } + ) + })->then( sub { + my ( $body ) = @_; + $peeking_user->sync_next_batch = $body->{next_batch}; + + log_if_fail "first sync response", $body; + + my $room = $body->{rooms}{peek}{$room_id}; + assert_ok( $room->{timeline}->{events}->[-1]->{content}->{body} eq 'something to peek', "peek has message body" ); + Future->done(1) + }) + }; + +test "Peeked rooms only turn up in the sync for the device who peeked them", + requires => [ local_user_and_room_fixtures(), local_user_fixture() ], + + check => sub { + my ( $user, $room_id, $peeking_user ) = @_; + my ( $peeking_user_device2 ); + + matrix_set_room_history_visibility( $user, $room_id, "world_readable" )->then(sub { + matrix_login_again_with_user($peeking_user); + })->then(sub { + $peeking_user_device2 = $_[0]; + do_request_json_for( $peeking_user, + method => "POST", + uri => "/r0/peek/$room_id", + content => {}, + ) + })->then(sub { + matrix_send_room_text_message_synced( $user, $room_id, body => "something to peek"); + })->then(sub { + await_sync( $peeking_user, + since => $peeking_user->sync_next_batch, + check => sub { + my ( $body ) = @_; + return 0 unless $body->{rooms}{peek}{$room_id}; + return $body; + } + ) + })->then( sub { + my ( $body ) = @_; + $peeking_user->sync_next_batch = $body->{next_batch}; + log_if_fail "device 1 first sync response", $body; + my $room = $body->{rooms}{peek}{$room_id}; + assert_ok( $room->{timeline}->{events}->[-1]->{content}->{body} eq 'something to peek', "peek has message body" ); + })->then(sub { + # FIXME: racey - this may return blank due to the peek not having taken effect yet + matrix_sync( $peeking_user_device2, timeout => 1000 ); + })->then( sub { + my ( $body ) = @_; + log_if_fail "device 2 first sync response", $body; + assert_ok( scalar keys(%{$body->{rooms}{peek}}) == 0, "no peeked rooms present"); + })->then( sub { + matrix_send_room_text_message_synced( $user, $room_id, body => "something else to peek") + })->then( sub { + await_sync( $peeking_user, + since => $peeking_user->sync_next_batch, + check => sub { + my ( $body ) = @_; + return 0 unless $body->{rooms}{peek}{$room_id}; + return $body; + } + ) + })->then( sub { + my ( $body ) = @_; + $peeking_user->sync_next_batch = $body->{next_batch}; + log_if_fail "device 1 second sync response", $body; + my $room = $body->{rooms}{peek}{$room_id}; + assert_ok( $room->{timeline}->{events}->[-1]->{content}->{body} eq 'something else to peek', "second peek has message body" ); + # FIXME: racey - this may return blank due to the peek not having taken effect yet + matrix_sync_again( $peeking_user_device2, timeout => 1000 ); + })->then( sub { + my ( $body ) = @_; + log_if_fail "device 2 second sync response", $body; + assert_ok( scalar keys(%{$body->{rooms}{peek}}) == 0, "still no peeked rooms present"); + Future->done(1) + }) + }; + +# test "Users can unpeek from rooms" + +# test "Users can peek, unpeek and peek again" + +# test "Peeking with full_state=true does the right thing" + +# test "Joining a peeked room moves it atomically from peeked to joined rooms and stops peeking" + +# test "Parting a room which was joined after being peeked doesn't go back to being peeked" + +# test "Changing history visibility to non-world_readable terminates peeks"