Skip to content

Commit

Permalink
Merge pull request #260 from matrix-org/erikj/purge_history
Browse files Browse the repository at this point in the history
Add basic /admin/purge_history tests
  • Loading branch information
erikjohnston authored Jul 11, 2016
2 parents 438d2e0 + b9b9c09 commit f40820c
Show file tree
Hide file tree
Showing 2 changed files with 222 additions and 1 deletion.
2 changes: 1 addition & 1 deletion tests/10apidoc/01register.pl
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ sub local_admin_fixture
setup => sub {
my ( $http, $localpart ) = @_;

matrix_register_user_via_secret( $http, $localpart, admin => 1, %args );
matrix_register_user_via_secret( $http, $localpart, is_admin => 1, %args );
},
);
}
Expand Down
221 changes: 221 additions & 0 deletions tests/48admin.pl
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use Future::Utils qw( repeat );

test "/whois",
requires => [ $main::API_CLIENTS[0] ],

Expand Down Expand Up @@ -36,3 +38,222 @@
Future->done( 1 );
});
};

test "/purge_history",
requires => [ local_admin_fixture(), local_user_and_room_fixtures() ],

do => sub {
my ( $admin, $user, $room_id ) = @_;

my $last_event_id;

matrix_put_room_state( $user, $room_id,
type => "m.room.name",
content => { name => "A room name" },
)->then( sub {
matrix_sync( $user )
})->then( sub {
repeat( sub {
my $msgnum = $_[0];

matrix_send_room_text_message( $user, $room_id,
body => "Message $msgnum",
)
}, foreach => [ 1 .. 10 ])
})->then( sub {
( $last_event_id ) = @_;

await_message_in_room( $user, $room_id, $last_event_id ),
})->then( sub {
do_request_json_for( $user,
method => "POST",
uri => "/r0/admin/purge_history/$room_id/$last_event_id",
content => {}
)->main::expect_http_403; # Must be server admin
})->then( sub {
do_request_json_for( $admin,
method => "POST",
uri => "/r0/admin/purge_history/$room_id/$last_event_id",
content => {}
)
})->then( sub {
# Test that /sync with an existing token still works.
matrix_sync_again( $user )
})->then( sub {
# Test that an initial /sync has the correct data.
matrix_sync( $user )
})->then( sub {
my ( $body ) = @_;

assert_json_keys( $body->{rooms}{join}, $room_id );
my $room = $body->{rooms}{join}{$room_id};

log_if_fail( "Room", $room->{timeline}{events} );

# The only message event should be the last one.
all {
$_->{type} ne "m.room.message" || $_->{event_id} eq $last_event_id
} @{ $room->{timeline}{events} } or die "Expected no message events";

# Ensure we still see the state.
foreach my $expected_type( qw(
m.room.create
m.room.member
m.room.power_levels
m.room.name
) ) {
any { $_->{type} eq $expected_type } @{ $room->{state}{events} }
or die "Expected state event of type $expected_type";
}

Future->done( 1 );
})
};

test "Can backfill purged history",
requires => [ local_admin_fixture(), local_user_and_room_fixtures(),
remote_user_fixture(), qw( can_paginate_room_remotely ) ],

do => sub {
my ( $admin, $user, $room_id, $remote_user ) = @_;

my @event_ids;
my $last_event_id;

matrix_invite_user_to_room( $user, $remote_user, $room_id )
->then( sub {
matrix_join_room( $remote_user, $room_id )
})->then( sub {
matrix_put_room_state( $user, $room_id,
type => "m.room.name",
content => { name => "A room name" },
)
})->then( sub {
Future->needs_all(
matrix_sync( $user ),
matrix_sync( $remote_user )
)
})->then( sub {
# Send half the messages as the local user...
repeat( sub {
my $msgnum = $_[0];

matrix_send_room_text_message( $user, $room_id,
body => "Message $msgnum",
)->on_done( sub { push @event_ids, $_[0]; } )
}, foreach => [ 0 .. 4 ])
})->then( sub {
my ( $last_local_id ) = @_;

# Wait until both users see the last event
Future->needs_all(
await_message_in_room( $user, $room_id, $last_local_id ),
await_message_in_room( $remote_user, $room_id, $last_local_id )
)
})->then( sub {
# ... and half as the remote. This is useful to esnre that both local
# and remote events are handled correctly.
repeat( sub {
my $msgnum = $_[0];

matrix_send_room_text_message( $remote_user, $room_id,
body => "Message $msgnum",
)->on_done( sub { push @event_ids, $_[0]; } )
}, foreach => [ 5 .. 9 ])
})->then( sub {
( $last_event_id ) = @_;

log_if_fail "last_event_id", $last_event_id;

# Wait until both users see the last event
Future->needs_all(
await_message_in_room( $user, $room_id, $last_event_id ),
await_message_in_room( $remote_user, $room_id, $last_event_id )
)
})->then( sub {
do_request_json_for( $admin,
method => "POST",
uri => "/r0/admin/purge_history/$room_id/$last_event_id",
content => {}
)
})->then( sub {
matrix_sync( $user )
})->then( sub {
my ( $body ) = @_;

assert_json_keys( $body->{rooms}{join}, $room_id );
my $room = $body->{rooms}{join}{$room_id};

log_if_fail( "Room timeline", $room->{timeline}{events} );

# The only message event should be the last one.
all {
$_->{type} ne "m.room.message" || $_->{event_id} eq $last_event_id
} @{ $room->{timeline}{events} } or die "Expected no message events";

# Ensure we still see the state.
foreach my $expected_type( qw(
m.room.create
m.room.member
m.room.power_levels
m.room.name
) ) {
any { $_->{type} eq $expected_type } @{ $room->{state}{events} }
or die "Expected state event of type $expected_type";
}

my $prev_batch = $room->{timeline}{prev_batch};

my @missing_event_ids = grep { $_ ne $last_event_id } @event_ids;

# Keep paginating untill we see all the old messages.
repeat( sub {
log_if_fail "prev_batch", $prev_batch;
matrix_get_room_messages( $user, $room_id,
limit => 20,
from => $prev_batch,
)->on_done( sub {
my ( $body ) = @_;

log_if_fail( "Pagination result", $body );

$prev_batch ne $body->{end} or die "Pagination token did not change";

$prev_batch = $body->{end};

foreach my $event ( @{ $body->{chunk} } ) {
@missing_event_ids = grep {
$_ ne $event->{event_id}
} @missing_event_ids;
}

log_if_fail "Missing", \@missing_event_ids;
})
}, while => sub { scalar @missing_event_ids > 0 });
});
};


sub await_message_in_room
{
my ( $user, $room_id, $event_id ) = @_;

my $user_id = $user->user_id;

repeat( sub {
matrix_sync_again( $user, timeout => 500 )
->then( sub {
my ( $body ) = @_;

log_if_fail "Sync for $user_id", $body;

Future->done( any {
$_->{event_id} eq $event_id
} @{ $body->{rooms}{join}{$room_id}{timeline}{events} } )
})
}, until => sub {
$_[0]->failure or $_[0]->get
})->on_done( sub {
log_if_fail "Found event $event_id for $user_id";
})
}

0 comments on commit f40820c

Please sign in to comment.