Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inject state blocks from incremental polls into the room timeline #71

Merged
merged 40 commits into from
Apr 24, 2023
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
38c1bda
Integration test
Apr 13, 2023
1d59167
E2E test case draft
Apr 13, 2023
46059df
WIP: update test cases
Apr 14, 2023
419e1ab
Update test case again
Apr 17, 2023
4b90454
Don't reselect NIDs after initialising a room
Apr 17, 2023
a2cba6e
We don't need `eventIDs` either
Apr 17, 2023
c19b561
Merge branch 'dmr/dont-select-after-insert-returning' into dmr/gappy-…
Apr 17, 2023
666823d
Introduce return struct for Initialise
Apr 17, 2023
4ba80d2
Initialise: handle state blocks from a gappy sync
Apr 17, 2023
9fdb001
TODO comment
Apr 17, 2023
33b174d
Fixup test code
Apr 17, 2023
ac9651c
Propagate err message
Apr 17, 2023
5d8560c
Fix db query
Apr 17, 2023
b7a8e7d
Improve logging
Apr 17, 2023
e3008e6
Fix the logging
Apr 17, 2023
2406da5
TODO note
Apr 17, 2023
f28f7d0
Return set of unknown events from the db
Apr 18, 2023
9d53a87
Simply Initialise to bail out early
Apr 18, 2023
2bae784
Propagate prepend events to poller, and inject
Apr 18, 2023
5621423
Fix tests
Apr 18, 2023
9af0471
Always look for unknown state events
Apr 18, 2023
b5893b1
Better error checking in test
Apr 18, 2023
aa07188
Fixup test
Apr 18, 2023
7f03a3d
Use test helper instead
Apr 19, 2023
e6aac43
SelectUnknownEventIDs expects a txn
Apr 19, 2023
b54ba7c
Poller test description
Apr 19, 2023
5dd4315
Test new events table query
Apr 19, 2023
76066f9
Tidy up accumulator event ID handling
Apr 19, 2023
5a9fae1
Fix capitalisation
Apr 19, 2023
b32e5da
Fix test function args too
Apr 19, 2023
00dd396
Fix MatchRoomTimelineMostRecent
Apr 19, 2023
bea931d
Fix running unit test alongside other tests
Apr 19, 2023
1680952
Tidyup unit test
Apr 19, 2023
6e7d0cb
Test memberships are updated after gappy sync
Apr 19, 2023
aa09d12
Check the new query reports multiple unknown IDs
Apr 21, 2023
8324f6e
SelectByIDs has an ordering guarantee
Apr 21, 2023
6c9aa09
Pass room ID to new query
Apr 24, 2023
2755384
Revert "Pass room ID to new query"
Apr 24, 2023
82d1d58
Update integration test
Apr 24, 2023
3274cf2
typo
Apr 24, 2023
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
6 changes: 6 additions & 0 deletions state/event_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,8 @@ func (t *EventTable) SelectHighestNID() (highest int64, err error) {
}

// Insert events into the event table. Returns a map of event ID to NID for new events only.
// The NIDs assigned to new events will respect the order of the given events, e.g. if
// we insert new events A and B in that order, then NID(A) < NID(B).
func (t *EventTable) Insert(txn *sqlx.Tx, events []Event, checkFields bool) (map[string]int, error) {
if checkFields {
ensureFieldsSet(events)
Expand Down Expand Up @@ -211,6 +213,10 @@ func (t *EventTable) SelectByNIDs(txn *sqlx.Tx, verifyAll bool, nids []int64) (e
WHERE event_nid = ANY ($1) ORDER BY event_nid ASC;`, pq.Int64Array(nids))
}

// SelectByIDs fetches all events with the given event IDs from the DB as Event structs.
// If verifyAll is true, the function will check that each event ID has a matching
// event row in the database. The returned events are ordered by ascending NID; the
// order of the event IDs is irrelevant.
func (t *EventTable) SelectByIDs(txn *sqlx.Tx, verifyAll bool, ids []string) (events []Event, err error) {
wanted := 0
if verifyAll {
Expand Down
19 changes: 10 additions & 9 deletions state/event_table_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -920,28 +920,29 @@ func TestEventTableSelectUnknownEventIDs(t *testing.T) {
if err != nil {
t.Fatalf("failed to select events: %s", err)
}
if (gotEvents[0].ID == eventID1 && gotEvents[1].ID == eventID2) || (gotEvents[0].ID == eventID2 && gotEvents[1].ID == eventID1) {
if gotEvents[0].ID == eventID1 && gotEvents[1].ID == eventID2 {
t.Logf("Got expected event IDs after insert. NIDS: %s=%d, %s=%d", gotEvents[0].ID, gotEvents[0].NID, gotEvents[1].ID, gotEvents[1].NID)
} else {
DMRobertson marked this conversation as resolved.
Show resolved Hide resolved
t.Fatalf("Event ID mismatch: expected $A-SelectUnknownEventIDs and $B-SelectUnknownEventIDs, got %v", gotEvents)
}

// Someone else tells us the state of the room is {A, C}. Query which of those
// event IDs are unknown.
DMRobertson marked this conversation as resolved.
Show resolved Hide resolved
const unknownEventID = "$C-SelectUnknownEventIDs"
stateBlockIDs := []string{eventID1, unknownEventID}
shouldBeUnknownIDs := []string{"$C-SelectUnknownEventIDs", "$D-SelectUnknownEventIDs"}
stateBlockIDs := append(shouldBeUnknownIDs, eventID1)
unknownIDs, err := table.SelectUnknownEventIDs(txn, stateBlockIDs)
t.Logf("unknownIDs=%v", unknownIDs)
if err != nil {
t.Fatalf("failed to select unknown state events: %s", err)
}

// Only event C should be flagged as unknown.
if len(unknownIDs) != 1 {
t.Fatalf("Expected 1 unknown id, got %v", unknownIDs)
// Event C and D should be flagged as unknown.
if len(unknownIDs) != len(shouldBeUnknownIDs) {
t.Fatalf("Expected %d unknown ids, got %v", len(shouldBeUnknownIDs), unknownIDs)
}
_, ok := unknownIDs[unknownEventID]
if !ok {
t.Fatalf("Expected $C-SelectUnknownEventIDs to be unknown to the DB, but it wasn't")
for _, unknownEventID := range shouldBeUnknownIDs {
if _, ok := unknownIDs[unknownEventID]; !ok {
t.Errorf("Expected %s to be unknown to the DB, but it wasn't", unknownEventID)
}
}
}
69 changes: 39 additions & 30 deletions tests-integration/poller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ func TestPollerUpdatesRoomMemberTrackerOnGappySyncStateBlock(t *testing.T) {
v2.addAccount(bob, bobToken)
const roomID = "!unimportant"

t.Log("Alice's poller does an initial sync. It sees that Alice and Bob share a room.")
t.Log("Alice and Bob's pollers initial sync. Both see the same state: that Alice and Bob share a room.")
initialTimeline := createRoomState(t, alice, time.Now())
bobJoin := testutils.NewStateEvent(
t,
Expand All @@ -221,9 +221,12 @@ func TestPollerUpdatesRoomMemberTrackerOnGappySyncStateBlock(t *testing.T) {
v2.queueResponse(aliceToken, sync2.SyncResponse{
Rooms: sync2.SyncRoomsResponse{Join: initialJoinBlock},
})
v2.queueResponse(aliceToken, sync2.SyncResponse{
DMRobertson marked this conversation as resolved.
Show resolved Hide resolved
Rooms: sync2.SyncRoomsResponse{Join: initialJoinBlock},
})

t.Log("Alice makes an initial sliding sync request.")
aliceRes := v3.mustDoV3Request(t, aliceToken, sync3.Request{
syncRequest := sync3.Request{
Lists: map[string]sync3.RequestList{
"a": {
Ranges: [][2]int64{{0, 20}},
Expand All @@ -232,7 +235,35 @@ func TestPollerUpdatesRoomMemberTrackerOnGappySyncStateBlock(t *testing.T) {
},
},
},
})
}
aliceRes := v3.mustDoV3Request(t, aliceToken, syncRequest)

t.Log("Alice sees herself and Bob joined to the room.")
m.MatchResponse(
t,
aliceRes,
m.MatchList(
"a",
m.MatchV3Count(1),
m.MatchV3Ops(m.MatchV3SyncOp(0, 0, []string{roomID})),
),
m.MatchRoomSubscription(roomID, m.MatchRoomTimelineMostRecent(1, []json.RawMessage{bobJoin})),
)

t.Log("Bob makes an initial sliding sync request.")
bobRes := v3.mustDoV3Request(t, bobToken, syncRequest)

t.Log("Bob sees himself and Alice joined to the room.")
m.MatchResponse(
t,
bobRes,
m.MatchList(
"a",
m.MatchV3Count(1),
m.MatchV3Ops(m.MatchV3SyncOp(0, 0, []string{roomID})),
),
m.MatchRoomSubscription(roomID, m.MatchJoinCount(2)),
)

t.Log("Alice's poller receives a gappy incremental sync response. Bob has left in the gap. The timeline includes a message from Alice.")
bobLeave := testutils.NewStateEvent(
Expand Down Expand Up @@ -260,35 +291,13 @@ func TestPollerUpdatesRoomMemberTrackerOnGappySyncStateBlock(t *testing.T) {
},
})

t.Log("Alice makes an incremental sliding sync request.")
aliceRes = v3.mustDoV3RequestWithPos(t, aliceToken, aliceRes.Pos, sync3.Request{})

t.Log("She should see Bob's leave event and her message at the end of the room timeline.")
m.MatchResponse(
t,
aliceRes,
m.MatchRoomSubscription(
roomID,
m.MatchRoomTimelineMostRecent(2, []json.RawMessage{bobLeave, aliceMessage}),
),
)

t.Log("Bob makes an initial sliding sync request.")
bobRes := v3.mustDoV3Request(t, bobToken, sync3.Request{
Lists: map[string]sync3.RequestList{
"a": {
Ranges: [][2]int64{{0, 20}},
RoomSubscription: sync3.RoomSubscription{
TimelineLimit: 10,
},
},
},
})
t.Log("He should not see himself in the room.")
t.Log("Bob makes an incremental sliding sync request.")
bobRes = v3.mustDoV3RequestWithPos(t, bobToken, bobRes.Pos, sync3.Request{})
t.Log("He should see his leave event in the room timeline.")
m.MatchResponse(
DMRobertson marked this conversation as resolved.
Show resolved Hide resolved
t,
bobRes,
m.MatchList("a", m.MatchV3Count(0)),
m.MatchList("a", m.MatchV3Count(1)),
m.MatchRoomSubscription(roomID, m.MatchRoomTimelineMostRecent(1, []json.RawMessage{bobLeave})),
)

}