From b365c738a17c59194e126d21b1bef5b1fc37c290 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Tue, 28 Aug 2018 18:32:42 +0100 Subject: [PATCH 01/10] Initial tests for room version upgrades --- tests/00expect_http_fail.pl | 64 +++++++++-- tests/30rooms/60version_upgrade.pl | 173 +++++++++++++++++++++++++++++ 2 files changed, 230 insertions(+), 7 deletions(-) create mode 100644 tests/30rooms/60version_upgrade.pl diff --git a/tests/00expect_http_fail.pl b/tests/00expect_http_fail.pl index afc26c606..29eb297b9 100644 --- a/tests/00expect_http_fail.pl +++ b/tests/00expect_http_fail.pl @@ -114,18 +114,68 @@ sub check_http_code ); } +=head2 expect_matrix_error -# todo: generalise this to other http errors/matrix errcodes -sub expect_m_not_found + http_request()->main::expect_matrix_error( + 'M_EXPECTED_ERROR', + http_code => 418, + )->then( sub { + my ( $error_body ) = @_; + }); + +A decorator for a Future which we expect to return an HTTP error with a Matrix +error code. Asserts that the HTTP error code and matrix error code were as +expected, and if so returns the JSON-decoded body of the error (so that it can +be checked for additional fields). + +By default, the expected HTTP error code is 400. This can be overridden with an +"http_code" parameter. + +=cut + +sub expect_matrix_error { - my $f = shift; + my ( $f, $expected_errcode, %opts ) = @_; + + my $expected_http_code = $opts{http_code} // 400; + + return $f->then_with_f( + sub { # done + my ( undef, $response ) = @_; + + log_if_fail "Response", $response; + Future->fail( + "Expected to receive an HTTP $expected_http_code failure but it succeeded" + ); + }, + http => sub { # catch http + my ( $f, undef, undef, $response ) = @_; - $f->main::expect_http_404() - ->then( sub { + $response and $response->code == $expected_http_code and + return Future->done( $response ); + + # if the error code doesn't match, return the failure. + return $f; + }, + )->then( sub { my ( $response ) = @_; my $body = decode_json( $response->content ); - assert_eq( $body->{errcode}, "M_NOT_FOUND", 'responsecode' ); - Future->done( 1 ); + + log_if_fail "Error response body", $body; + + assert_eq( $body->{errcode}, $expected_errcode, 'errcode' ); + Future->done( $body ); }); } +push @EXPORT, qw/expect_matrix_error/; + + +sub expect_m_not_found +{ + my $f = shift; + return expect_matrix_error( + $f, 'M_NOT_FOUND', + http_code=>404, + ); +} push @EXPORT, qw/expect_m_not_found/; diff --git a/tests/30rooms/60version_upgrade.pl b/tests/30rooms/60version_upgrade.pl new file mode 100644 index 000000000..87198eb57 --- /dev/null +++ b/tests/30rooms/60version_upgrade.pl @@ -0,0 +1,173 @@ +# Copyright 2018 New Vector Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# TODO: switch this to '2' once that is released +my $TEST_NEW_VERSION = 'vdh-test-version'; + +=head2 upgrade_room + + upgrade_room( $user, $room_id, %opts )->then( sub { + my ( $new_room_id ) = @_; + }) + +Request that the homeserver upgrades the given room. + +%opts may include: + +=over + +=item new_version => STRING + +Defaults to $TEST_NEW_VERSION if unspecified + +=back + +=cut + +sub upgrade_room { + my ( $user, $room_id, %opts ) = @_; + + my $new_version = $opts{new_version} // $TEST_NEW_VERSION; + + do_request_json_for( + $user, + method => "POST", + uri => "/r0/rooms/$room_id/upgrade", + content => { + new_version => $new_version, + }, + )->then( sub { + my ( $body ) = @_; + log_if_fail "upgrade response", $body; + + assert_json_keys( $body, qw( replacement_room ) ); + Future->done( $body->{replacement_room} ); + }); +} + +=head2 upgrade_room_synced + + upgrade_room_synced( $user, $room_id, %opts )->then( sub { + my ( $new_room_id, $sync_body ) = @_; + }) + +Request that the homeserver upgrades the given room, and waits for the +new room to appear in the sync result. + +%opts are as for C. + +=cut + +sub upgrade_room_synced { + my ( $user, $room_id, %opts ) = @_; + + matrix_do_and_wait_for_sync( + $user, + do => sub { + upgrade_room( $user, $room_id, %opts ); + }, + check => sub { + my ( $sync_body, $new_room_id ) = @_; + return 0 if not exists $sync_body->{rooms}{join}{$new_room_id}; + return $sync_body; + }, + ); +} + +test "/upgrade creates a new room", + requires => [ + local_user_and_room_fixtures(), + qw( can_create_versioned_room ), + ], + + proves => [ qw( can_upgrade_room_version ) ], + + do => sub { + my ( $user, $old_room_id ) = @_; + my ( $replacement_room ); + + upgrade_room_synced( + $user, $old_room_id, + new_version => $TEST_NEW_VERSION, + )->then( sub { + my ( $new_room_id, $sync_body ) = @_; + + log_if_fail "sync body", $sync_body; + + # check the new room has the right version + + my $room = $sync_body->{rooms}{join}{$new_room_id}; + my $ev0 = $room->{timeline}{events}[0]; + + assert_eq( $ev0->{type}, 'm.room.create', 'first event in new room' ); + assert_json_keys( $ev0->{content}, qw( room_version )); + assert_eq( $ev0->{content}{room_version}, $TEST_NEW_VERSION, 'room_version' ); + + # the old room should have a tombstone event + my $old_room_timeline = $sync_body->{rooms}{join}{$old_room_id}{timeline}{events}; + assert_eq( $old_room_timeline->[0]{type}, + 'm.room.tombstone', + 'event in old room' ); + + assert_eq( + $old_room_timeline->[0]{content}{replacement_room}, + $new_room_id, + 'room_id in tombstone' + ); + + Future->done(1); + }); + }; + +test "/upgrade to an unknown version is rejected", + requires => [ + local_user_and_room_fixtures(), + local_user_fixture(), + qw( can_create_versioned_room can_upgrade_room_version), + ], + + do => sub { + my ( $user, $room_id ) = @_; + + upgrade_room( + $user, $room_id, + new_version => 'my_bad_version', + )->main::expect_matrix_error( 'M_UNSUPPORTED_ROOM_VERSION' ); + }; + +test "/upgrade is rejected if the user can't send state events", + requires => [ + local_user_and_room_fixtures(), + local_user_fixture(), + qw( can_create_versioned_room can_upgrade_room_version), + ], + + do => sub { + my ( $creator, $room_id, $joiner ) = @_; + my ( $replacement_room ); + + matrix_join_room( $joiner, $room_id )->then( sub { + upgrade_room( + $joiner, $room_id, + )->main::expect_matrix_error( 'M_FORBIDDEN', http_code => 403 ); + }); + }; + + +# upgrade without perms +# upgrade with other local users +# upgrade with remote users +# check names and aliases are copied + + From 5ae96c75877b72123bfd5af194099cd55735ab4e Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Fri, 12 Oct 2018 11:13:46 +0100 Subject: [PATCH 02/10] test room visibility --- tests/30rooms/60version_upgrade.pl | 72 +++++++++++++++++++++++++++--- 1 file changed, 66 insertions(+), 6 deletions(-) diff --git a/tests/30rooms/60version_upgrade.pl b/tests/30rooms/60version_upgrade.pl index 87198eb57..43d1d42ea 100644 --- a/tests/30rooms/60version_upgrade.pl +++ b/tests/30rooms/60version_upgrade.pl @@ -116,9 +116,11 @@ sub upgrade_room_synced { # the old room should have a tombstone event my $old_room_timeline = $sync_body->{rooms}{join}{$old_room_id}{timeline}{events}; - assert_eq( $old_room_timeline->[0]{type}, - 'm.room.tombstone', - 'event in old room' ); + assert_eq( + $old_room_timeline->[0]{type}, + 'm.room.tombstone', + 'event in old room', + ); assert_eq( $old_room_timeline->[0]{content}{replacement_room}, @@ -130,11 +132,56 @@ sub upgrade_room_synced { }); }; +foreach my $vis ( qw( public private ) ) { + test "/upgrade should preserve room visibility for $vis rooms", + requires => [ + local_user_and_room_fixtures(), + qw( can_upgrade_room_version ), + ], + + do => sub { + my ( $creator, $room_id ) = @_; + + # set the visibility on the old room. (The default is 'private', but + # we may as well set it explicitly.) + do_request_json_for( + $creator, + method => "PUT", + uri => "/r0/directory/list/room/$room_id", + content => { + visibility => $vis, + }, + )->then( sub { + upgrade_room_synced( + $creator, $room_id, + new_version => $TEST_NEW_VERSION, + ); + })->then( sub { + my ( $new_room_id, $sync_body ) = @_; + + # check the visibility of the new room + do_request_json_for( + $creator, + method => "GET", + uri => "/r0/directory/list/room/$new_room_id", + ); + })->then( sub { + my ( $response ) = @_; + log_if_fail "room vis", $response; + assert_eq( + $response->{visibility}, + $vis, + "replacement room visibility", + ); + Future->done(1); + }); + }; +} + test "/upgrade to an unknown version is rejected", requires => [ local_user_and_room_fixtures(), - local_user_fixture(), - qw( can_create_versioned_room can_upgrade_room_version), + qw( can_upgrade_room_version ), ], do => sub { @@ -150,7 +197,7 @@ sub upgrade_room_synced { requires => [ local_user_and_room_fixtures(), local_user_fixture(), - qw( can_create_versioned_room can_upgrade_room_version), + qw( can_create_versioned_room ), ], do => sub { @@ -164,6 +211,19 @@ sub upgrade_room_synced { }); }; +test "/upgrade of a bogus room fails gracefully", + requires => [ + local_user_fixture(), + ], + + do => sub { + my ( $user ) = @_; + my ( $replacement_room ); + + upgrade_room( + $user, "!fail:unknown", + )->main::expect_matrix_error( 'M_NOT_FOUND', http_code => 404 ); + }; # upgrade without perms # upgrade with other local users From 5db376a6bc94760805dc4eef2552c28a645f8431 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Fri, 12 Oct 2018 12:05:37 +0100 Subject: [PATCH 03/10] test PL preservation --- lib/SyTest/Assertions.pm | 4 +-- tests/30rooms/60version_upgrade.pl | 41 ++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/lib/SyTest/Assertions.pm b/lib/SyTest/Assertions.pm index d30b7ddaa..9ba16881d 100644 --- a/lib/SyTest/Assertions.pm +++ b/lib/SyTest/Assertions.pm @@ -120,8 +120,8 @@ sub _assert_deeply_eq croak "Got a value for '$key' that was not expected at $outerkeystr for $name"; } } - elsif( $wanttype eq JSON_BOOLEAN_CLASS ) { - ref $got eq JSON_BOOLEAN_CLASS and $got eq $want or + elsif( $wanttype eq JSON_BOOLEAN_CLASS or $wanttype eq "JSON::number" ) { + $got eq $want or croak "Got ${\ pp $got }, expected ${\ pp $want } at $outerkeystr for $name"; } else { diff --git a/tests/30rooms/60version_upgrade.pl b/tests/30rooms/60version_upgrade.pl index 43d1d42ea..0a37662ec 100644 --- a/tests/30rooms/60version_upgrade.pl +++ b/tests/30rooms/60version_upgrade.pl @@ -12,6 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +use List::Util qw( first ); + # TODO: switch this to '2' once that is released my $TEST_NEW_VERSION = 'vdh-test-version'; @@ -178,6 +180,45 @@ sub upgrade_room_synced { }; } +test "/upgrade copies the power levels to the new room", + requires => [ + local_user_and_room_fixtures(), + qw( can_upgrade_room_version can_change_power_levels ), + ], + + do => sub { + my ( $creator, $room_id ) = @_; + + my $pl_content; + + matrix_change_room_power_levels( + $creator, $room_id, sub { + ( $pl_content ) = @_; + $pl_content->{users}->{'@test:xyz'} = 40; + } + )->then( sub { + upgrade_room_synced( + $creator, $room_id, + new_version => $TEST_NEW_VERSION, + ); + })->then( sub { + my ( $new_room_id, $sync_body ) = @_; + my $room = $sync_body->{rooms}{join}{$new_room_id}; + my $pl_event = first { + $_->{type} eq 'm.room.power_levels' + } @{ $room->{timeline}->{events} }; + + log_if_fail "PL content in new room", $pl_event->{content}; + + assert_deeply_eq( + $pl_event->{content}, + $pl_content, + "power levels in replacement room", + ); + Future->done(1); + }); + }; + test "/upgrade to an unknown version is rejected", requires => [ local_user_and_room_fixtures(), From f6ec362ad0df877ed7310b11bc0c34d55dde1902 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Fri, 12 Oct 2018 17:05:55 +0100 Subject: [PATCH 04/10] test state copy --- tests/30rooms/60version_upgrade.pl | 57 ++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/tests/30rooms/60version_upgrade.pl b/tests/30rooms/60version_upgrade.pl index 0a37662ec..bf212ed15 100644 --- a/tests/30rooms/60version_upgrade.pl +++ b/tests/30rooms/60version_upgrade.pl @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +use Future::Utils qw( repeat ); use List::Util qw( first ); # TODO: switch this to '2' once that is released @@ -219,6 +220,62 @@ sub upgrade_room_synced { }); }; + +test "/upgrade copies important state to the new room", + requires => [ + local_user_and_room_fixtures(), + qw( can_upgrade_room_version ), + ], + + do => sub { + my ( $creator, $room_id ) = @_; + + # map from type to content + my %STATE_DICT = ( + "m.room.topic" => { topic => "topic" }, + "m.room.name" => { name => "name" }, + "m.room.join_rules" => { join_rule => "public" }, + "m.room.guest_access" => { guest_access => "forbidden" }, + "m.room.history_visibility" => { history_visibility => "joined" }, + ); + + my $f = Future->done(1); + foreach my $k ( keys %STATE_DICT ) { + $f = $f->then( sub { + matrix_put_room_state( + $creator, $room_id, + type => $k, + content => $STATE_DICT{$k}, + ); + }); + } + + $f->then( sub { + upgrade_room_synced( + $creator, $room_id, + new_version => $TEST_NEW_VERSION, + ); + })->then( sub { + my ( $new_room_id, $sync_body ) = @_; + my $room = $sync_body->{rooms}{join}{$new_room_id}; + + foreach my $k ( keys %STATE_DICT ) { + my $event = first { + $_->{type} eq $k && $_->{state_key} eq '', + } @{ $room->{timeline}->{events} }; + + log_if_fail "State for $k", $event->{content}; + assert_deeply_eq( + $event->{content}, + $STATE_DICT{$k}, + "$k in replacement room", + ); + } + Future->done(1); + }); + }; + + test "/upgrade to an unknown version is rejected", requires => [ local_user_and_room_fixtures(), From 0711d9ace888f42808343fd162faf47c2f15157c Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Wed, 24 Oct 2018 23:14:04 +0100 Subject: [PATCH 05/10] Test setting PLs in old room --- tests/30rooms/60version_upgrade.pl | 65 ++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/tests/30rooms/60version_upgrade.pl b/tests/30rooms/60version_upgrade.pl index bf212ed15..9bab68ca8 100644 --- a/tests/30rooms/60version_upgrade.pl +++ b/tests/30rooms/60version_upgrade.pl @@ -275,6 +275,71 @@ sub upgrade_room_synced { }); }; +test "/upgrade restricts power levels in the old room", + requires => [ + local_user_and_room_fixtures(), + qw( can_upgrade_room_version ), + ], + + do => sub { + my ( $creator, $room_id ) = @_; + + log_if_fail "Old room id", $room_id; + + upgrade_room_synced( + $creator, $room_id, + new_version => $TEST_NEW_VERSION, + )->then( sub { + my ( $new_room_id, $sync_body ) = @_; + + matrix_get_room_state( + $creator, $room_id, type=>'m.room.power_levels', + ); + })->then( sub { + my ( $pl_event ) = @_; + + log_if_fail 'power_levels after upgrade', $pl_event; + assert_eq( $pl_event->{events_default}, 50, "events_default" ); + assert_eq( $pl_event->{invite}, 50, "invite" ); + Future->done(1); + }); + }; + +test "/upgrade restricts power levels in the old room when the old PLs are unusual", + requires => [ + local_user_and_room_fixtures(), + qw( can_upgrade_room_version ), + ], + + do => sub { + my ( $creator, $room_id ) = @_; + + matrix_change_room_power_levels( + $creator, $room_id, sub { + my ( $levels ) = @_; + $levels -> {users_default} = 80; + } + )->then( sub { + upgrade_room_synced( + $creator, $room_id, + new_version => $TEST_NEW_VERSION, + ); + })->then( sub { + my ( $new_room_id, $sync_body ) = @_; + + matrix_get_room_state( + $creator, $room_id, type=>'m.room.power_levels', + ); + })->then( sub { + my ( $pl_event ) = @_; + + log_if_fail 'power_levels after upgrade', $pl_event; + + assert_eq( $pl_event->{events_default}, 81, "events_default" ); + assert_eq( $pl_event->{invite}, 81, "invite" ); + Future->done(1); + }); + }; test "/upgrade to an unknown version is rejected", requires => [ From f969e0d627e96753a68c0cb86b0b13e3c9d5222c Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Thu, 25 Oct 2018 00:30:15 +0100 Subject: [PATCH 06/10] Test backlink from new room to old --- tests/30rooms/60version_upgrade.pl | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/tests/30rooms/60version_upgrade.pl b/tests/30rooms/60version_upgrade.pl index 9bab68ca8..b631048fa 100644 --- a/tests/30rooms/60version_upgrade.pl +++ b/tests/30rooms/60version_upgrade.pl @@ -119,18 +119,24 @@ sub upgrade_room_synced { # the old room should have a tombstone event my $old_room_timeline = $sync_body->{rooms}{join}{$old_room_id}{timeline}{events}; + my $tombstone_event = $old_room_timeline->[0]; assert_eq( - $old_room_timeline->[0]{type}, + $tombstone_event->{type}, 'm.room.tombstone', 'event in old room', ); - assert_eq( - $old_room_timeline->[0]{content}{replacement_room}, + $tombstone_event->{content}{replacement_room}, $new_room_id, 'room_id in tombstone' ); + # the new room should link to the old room + assert_json_keys( $ev0->{content}, qw( predecessor )); + assert_json_keys( $ev0->{content}{predecessor}, qw( room_id event_id )); + assert_eq( $ev0->{content}{predecessor}{room_id}, $old_room_id ); + assert_eq( $ev0->{content}{predecessor}{event_id}, $tombstone_event->{event_id} ); + Future->done(1); }); }; @@ -196,6 +202,7 @@ sub upgrade_room_synced { $creator, $room_id, sub { ( $pl_content ) = @_; $pl_content->{users}->{'@test:xyz'} = 40; + log_if_fail "PL content in old room", $pl_content; } )->then( sub { upgrade_room_synced( @@ -204,12 +211,15 @@ sub upgrade_room_synced { ); })->then( sub { my ( $new_room_id, $sync_body ) = @_; + + log_if_fail "sync body", $sync_body; + my $room = $sync_body->{rooms}{join}{$new_room_id}; my $pl_event = first { $_->{type} eq 'm.room.power_levels' } @{ $room->{timeline}->{events} }; - log_if_fail "PL content in new room", $pl_event->{content}; + log_if_fail "PL event in new room", $pl_event; assert_deeply_eq( $pl_event->{content}, From 41b12b21a05dd558679120e200b7dc60476d0000 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Fri, 26 Oct 2018 23:56:46 +0100 Subject: [PATCH 07/10] Test that we copy the avatar when upgrading rooms --- tests/30rooms/60version_upgrade.pl | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/30rooms/60version_upgrade.pl b/tests/30rooms/60version_upgrade.pl index b631048fa..34e0458f3 100644 --- a/tests/30rooms/60version_upgrade.pl +++ b/tests/30rooms/60version_upgrade.pl @@ -247,6 +247,7 @@ sub upgrade_room_synced { "m.room.join_rules" => { join_rule => "public" }, "m.room.guest_access" => { guest_access => "forbidden" }, "m.room.history_visibility" => { history_visibility => "joined" }, + "m.room.avatar" => { url => "http://something" }, ); my $f = Future->done(1); From 175cfe7692c0fcca0089216449f5abd2bb0df321 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Mon, 29 Oct 2018 14:59:35 +0000 Subject: [PATCH 08/10] s#qw//#qw()# --- tests/00expect_http_fail.pl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/00expect_http_fail.pl b/tests/00expect_http_fail.pl index 29eb297b9..9c15a2280 100644 --- a/tests/00expect_http_fail.pl +++ b/tests/00expect_http_fail.pl @@ -167,7 +167,7 @@ sub expect_matrix_error Future->done( $body ); }); } -push @EXPORT, qw/expect_matrix_error/; +push @EXPORT, qw( expect_matrix_error ); sub expect_m_not_found @@ -178,4 +178,4 @@ sub expect_m_not_found http_code=>404, ); } -push @EXPORT, qw/expect_m_not_found/; +push @EXPORT, qw( expect_m_not_found ); From 2eb2d3c58fe7c153367f737f761c9915c7515107 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Mon, 29 Oct 2018 14:59:43 +0000 Subject: [PATCH 09/10] expect_matrix_error: make http code required --- tests/00expect_http_fail.pl | 15 ++++----------- tests/30rooms/60version_upgrade.pl | 6 +++--- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/tests/00expect_http_fail.pl b/tests/00expect_http_fail.pl index 9c15a2280..2e7ccdf7c 100644 --- a/tests/00expect_http_fail.pl +++ b/tests/00expect_http_fail.pl @@ -117,8 +117,7 @@ sub check_http_code =head2 expect_matrix_error http_request()->main::expect_matrix_error( - 'M_EXPECTED_ERROR', - http_code => 418, + $http_code, $matrix_errcode, )->then( sub { my ( $error_body ) = @_; }); @@ -128,16 +127,11 @@ =head2 expect_matrix_error expected, and if so returns the JSON-decoded body of the error (so that it can be checked for additional fields). -By default, the expected HTTP error code is 400. This can be overridden with an -"http_code" parameter. - =cut sub expect_matrix_error { - my ( $f, $expected_errcode, %opts ) = @_; - - my $expected_http_code = $opts{http_code} // 400; + my ( $f, $expected_http_code, $expected_errcode ) = @_; return $f->then_with_f( sub { # done @@ -174,8 +168,7 @@ sub expect_m_not_found { my $f = shift; return expect_matrix_error( - $f, 'M_NOT_FOUND', - http_code=>404, - ); + $f, 404, 'M_NOT_FOUND', + ); } push @EXPORT, qw( expect_m_not_found ); diff --git a/tests/30rooms/60version_upgrade.pl b/tests/30rooms/60version_upgrade.pl index b631048fa..cf3d112b7 100644 --- a/tests/30rooms/60version_upgrade.pl +++ b/tests/30rooms/60version_upgrade.pl @@ -363,7 +363,7 @@ sub upgrade_room_synced { upgrade_room( $user, $room_id, new_version => 'my_bad_version', - )->main::expect_matrix_error( 'M_UNSUPPORTED_ROOM_VERSION' ); + )->main::expect_matrix_error( 400, 'M_UNSUPPORTED_ROOM_VERSION' ); }; test "/upgrade is rejected if the user can't send state events", @@ -380,7 +380,7 @@ sub upgrade_room_synced { matrix_join_room( $joiner, $room_id )->then( sub { upgrade_room( $joiner, $room_id, - )->main::expect_matrix_error( 'M_FORBIDDEN', http_code => 403 ); + )->main::expect_matrix_error( 403, 'M_FORBIDDEN' ); }); }; @@ -395,7 +395,7 @@ sub upgrade_room_synced { upgrade_room( $user, "!fail:unknown", - )->main::expect_matrix_error( 'M_NOT_FOUND', http_code => 404 ); + )->main::expect_matrix_error( 404, 'M_NOT_FOUND' ); }; # upgrade without perms From 2ee0a21cbd262b59a4f94f0570c0bac571aeb8f3 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Tue, 30 Oct 2018 15:33:27 +0000 Subject: [PATCH 10/10] Make upgrade_room_synced wait for all the events This should mean we can reduce some boilerplate in some of the other tests. --- tests/30rooms/60version_upgrade.pl | 93 +++++++++++++++++++++++++----- 1 file changed, 77 insertions(+), 16 deletions(-) diff --git a/tests/30rooms/60version_upgrade.pl b/tests/30rooms/60version_upgrade.pl index cf3d112b7..ccaa36635 100644 --- a/tests/30rooms/60version_upgrade.pl +++ b/tests/30rooms/60version_upgrade.pl @@ -62,19 +62,41 @@ sub upgrade_room { =head2 upgrade_room_synced upgrade_room_synced( $user, $room_id, %opts )->then( sub { - my ( $new_room_id, $sync_body ) = @_; + my ( $new_room_id ) = @_; }) Request that the homeserver upgrades the given room, and waits for the new room to appear in the sync result. -%opts are as for C. +%opts may include: + +=over + +=item expected_event_counts => HASH + +The number of events of each type we expect to appear in the new room. A map +from event type to count. + +=back + +Other %opts are as for C. =cut sub upgrade_room_synced { my ( $user, $room_id, %opts ) = @_; + my $expected_event_counts = delete $opts{expected_event_counts} // {}; + foreach my $t (qw( + m.room.create m.room.member m.room.guest_access + m.room.history_visibility m.room.join_rules m.room.power_levels + )) { + $expected_event_counts->{$t} //= 1; + } + + # map from event type to count + my %received_event_counts = (); + matrix_do_and_wait_for_sync( $user, do => sub { @@ -83,7 +105,22 @@ sub upgrade_room_synced { check => sub { my ( $sync_body, $new_room_id ) = @_; return 0 if not exists $sync_body->{rooms}{join}{$new_room_id}; - return $sync_body; + my $tl = $sync_body->{rooms}{join}{$new_room_id}{timeline}{events}; + log_if_fail "New room timeline", $tl; + + foreach my $ev ( @$tl ) { + $received_event_counts{$ev->{type}} //= 0; + $received_event_counts{$ev->{type}} += 1; + } + + # check we've got all the events we expect + foreach my $t ( keys %$expected_event_counts ) { + if( $received_event_counts{$t} < $expected_event_counts->{$t} ) { + log_if_fail "Still waiting for a $t event"; + return 0; + } + } + return 1; }, ); } @@ -98,13 +135,19 @@ sub upgrade_room_synced { do => sub { my ( $user, $old_room_id ) = @_; - my ( $replacement_room ); + my ( $new_room_id ); - upgrade_room_synced( - $user, $old_room_id, - new_version => $TEST_NEW_VERSION, - )->then( sub { - my ( $new_room_id, $sync_body ) = @_; + matrix_sync( $user )->then( sub { + upgrade_room_synced( + $user, $old_room_id, + new_version => $TEST_NEW_VERSION, + ); + })->then( sub { + ( $new_room_id, ) = @_; + + matrix_sync_again( $user ); + })->then( sub { + my ( $sync_body ) = @_; log_if_fail "sync body", $sync_body; @@ -166,7 +209,7 @@ sub upgrade_room_synced { new_version => $TEST_NEW_VERSION, ); })->then( sub { - my ( $new_room_id, $sync_body ) = @_; + my ( $new_room_id, ) = @_; # check the visibility of the new room do_request_json_for( @@ -196,7 +239,7 @@ sub upgrade_room_synced { do => sub { my ( $creator, $room_id ) = @_; - my $pl_content; + my ( $pl_content, $new_room_id ); matrix_change_room_power_levels( $creator, $room_id, sub { @@ -205,19 +248,26 @@ sub upgrade_room_synced { log_if_fail "PL content in old room", $pl_content; } )->then( sub { + matrix_sync( $creator ); + })->then( sub { upgrade_room_synced( $creator, $room_id, + expected_event_counts => { 'm.room.power_levels' => 2 }, new_version => $TEST_NEW_VERSION, ); })->then( sub { - my ( $new_room_id, $sync_body ) = @_; + ( $new_room_id, ) = @_; + + matrix_sync_again( $creator ); + })->then( sub { + my ( $sync_body ) = @_; log_if_fail "sync body", $sync_body; my $room = $sync_body->{rooms}{join}{$new_room_id}; my $pl_event = first { $_->{type} eq 'm.room.power_levels' - } @{ $room->{timeline}->{events} }; + } reverse @{ $room->{timeline}->{events} }; log_if_fail "PL event in new room", $pl_event; @@ -239,6 +289,7 @@ sub upgrade_room_synced { do => sub { my ( $creator, $room_id ) = @_; + my ( $new_room_id ); # map from type to content my %STATE_DICT = ( @@ -261,12 +312,21 @@ sub upgrade_room_synced { } $f->then( sub { + matrix_sync( $creator ); + })->then( sub { upgrade_room_synced( $creator, $room_id, new_version => $TEST_NEW_VERSION, ); })->then( sub { - my ( $new_room_id, $sync_body ) = @_; + ( $new_room_id, ) = @_; + + matrix_sync_again( $creator ); + })->then( sub { + my ( $sync_body ) = @_; + + log_if_fail "sync body", $sync_body; + my $room = $sync_body->{rooms}{join}{$new_room_id}; foreach my $k ( keys %STATE_DICT ) { @@ -300,7 +360,7 @@ sub upgrade_room_synced { $creator, $room_id, new_version => $TEST_NEW_VERSION, )->then( sub { - my ( $new_room_id, $sync_body ) = @_; + my ( $new_room_id ) = @_; matrix_get_room_state( $creator, $room_id, type=>'m.room.power_levels', @@ -332,10 +392,11 @@ sub upgrade_room_synced { )->then( sub { upgrade_room_synced( $creator, $room_id, + expected_event_counts => { 'm.room.power_levels' => 2 }, new_version => $TEST_NEW_VERSION, ); })->then( sub { - my ( $new_room_id, $sync_body ) = @_; + my ( $new_room_id ) = @_; matrix_get_room_state( $creator, $room_id, type=>'m.room.power_levels',