Skip to content

Commit

Permalink
Merge pull request #351 from matrix-org/dmr/cleanup-dead-invites
Browse files Browse the repository at this point in the history
  • Loading branch information
David Robertson authored Oct 19, 2023
2 parents bc47e18 + 3a9cbaa commit dae2fa3
Show file tree
Hide file tree
Showing 2 changed files with 147 additions and 0 deletions.
22 changes: 22 additions & 0 deletions state/migrations/20231019153023_cleanup_dead_invites.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
-- +goose Up
-- +goose StatementBegin
WITH
dead_invites(user_id, room_id) AS (
SELECT syncv3_invites.user_id, syncv3_invites.room_id
FROM syncv3_invites
JOIN syncv3_rooms USING (room_id)
JOIN syncv3_snapshots ON (syncv3_snapshots.snapshot_id = syncv3_rooms.current_snapshot_id)
JOIN syncv3_events ON (
event_nid = ANY (membership_events)
AND state_key = syncv3_invites.user_id
AND NOT (membership = 'invite' OR membership = '_invite')
)
)
DELETE FROM syncv3_invites
WHERE (user_id, room_id) IN (SELECT * FROM dead_invites);
-- +goose StatementEnd

-- +goose Down
-- +goose StatementBegin
-- no-op
-- +goose StatementEnd
125 changes: 125 additions & 0 deletions state/migrations/20231019153023_cleanup_dead_invites_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package migrations

import (
"embed"
_ "embed"
"encoding/json"
_ "github.com/lib/pq"
"github.com/matrix-org/sliding-sync/state"
"github.com/pressly/goose/v3"
"reflect"
"testing"
)

//go:embed 20231019153023_cleanup_dead_invites.sql
var deadInviteMigration embed.FS

func TestDeadInviteCleanup(t *testing.T) {
db, close := connectToDB(t)
defer close()
store := state.NewStorageWithDB(db, false)

t.Log("Alice and Bob both have invites to rooms X and Y. Chris has an invite to room Z.")
_, err := store.DB.Exec(`
INSERT INTO syncv3_invites(user_id, room_id, invite_state)
VALUES ('@alice:test', '!x', '[]'),
('@alice:test', '!y', '[]'),
('@bob:test' , '!x', '[]'),
('@bob:test' , '!y', '[]'),
('@chris:test', '!z', '[]');
`)
if err != nil {
t.Fatal(err)
}

t.Log("Alice is joined to room X; Bob banned from room Y. Chris isn't joined to any rooms.")
_, err = store.DB.Exec(`
INSERT INTO syncv3_events(
event_nid,
event_id,
before_state_snapshot_id,
event_replaces_nid,
room_id,
event_type,
state_key,
prev_batch,
membership,
is_state,
event,
missing_previous
)
VALUES (1, '$alice-join-x' , 0, 0, '!x', 'm.room.member', '@alice:test', '', 'join' , false, '', false),
(2, '$alice-invite-y', 0, 0, '!y', 'm.room.member', '@alice:test', '', 'invite', false, '', false),
(3, '$bob-invite-x' , 0, 0, '!x', 'm.room.member', '@bob:test' , '', 'invite', false, '', false),
(4, '$bob-ban-y' , 0, 0, '!y', 'm.room.member', '@bob:test' , '', 'ban' , false, '', false),
(5, '$chris-invite-z', 0, 0, '!x', 'm.room.member', '@chris:test', '', 'invite', false, '', false);
`)
if err != nil {
t.Fatal(err)
}
_, err = store.DB.Exec(`
INSERT INTO syncv3_snapshots(snapshot_id, room_id, events, membership_events)
VALUES (10, '!x', '{}', '{1,3}'),
(11, '!y', '{}', '{2,4}'),
(12, '!z', '{}', '{5}');
`)
if err != nil {
t.Fatal(err)
}
_, err = store.DB.Exec(`
INSERT INTO syncv3_rooms(room_id, current_snapshot_id, is_encrypted, upgraded_room_id, predecessor_room_id, latest_nid, type)
VALUES ('!x', '10', false, NULL, NULL, 3, NULL),
('!y', '11', false, NULL, NULL, 4, NULL),
('!z', '12', false, NULL, NULL, 5, NULL);
`)
if err != nil {
t.Fatal(err)
}

t.Log("Run the migration.")
goose.SetBaseFS(deadInviteMigration)
err = goose.SetDialect("postgres")
if err != nil {
t.Fatal(err)
}

err = goose.Up(db.DB, ".")
if err != nil {
t.Fatal(err)
}

emptyInviteState := []json.RawMessage{}

t.Log("Alice's invite to room X, and Bob's invite to room Y should have been deleted.")
aliceInvites, err := store.InvitesTable.SelectAllInvitesForUser("@alice:test")
if err != nil {
t.Error(err)
}
assertInvites(t, "alice", aliceInvites, map[string][]json.RawMessage{
"!y": emptyInviteState,
})

bobInvites, err := store.InvitesTable.SelectAllInvitesForUser("@bob:test")
if err != nil {
t.Error(err)
}
assertInvites(t, "bob", bobInvites, map[string][]json.RawMessage{
"!x": emptyInviteState,
})

chrisInvites, err := store.InvitesTable.SelectAllInvitesForUser("@chris:test")
if err != nil {
t.Error(err)
}
assertInvites(t, "chris", chrisInvites, map[string][]json.RawMessage{
"!z": emptyInviteState,
})

}

func assertInvites(t *testing.T, name string, got, want map[string][]json.RawMessage) {
t.Helper()
if !reflect.DeepEqual(got, want) {
t.Errorf("Mismatched invites for %s: got %v want %v", name, got, want)
}
}

0 comments on commit dae2fa3

Please sign in to comment.