2021-11-02 17:21:09 +00:00
|
|
|
package syncv3
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
2022-12-15 11:08:50 +00:00
|
|
|
"github.com/matrix-org/sliding-sync/sync2"
|
|
|
|
"github.com/matrix-org/sliding-sync/sync3"
|
|
|
|
"github.com/matrix-org/sliding-sync/testutils"
|
|
|
|
"github.com/matrix-org/sliding-sync/testutils/m"
|
2021-11-02 17:21:09 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// Test that room names come through sanely. Additional testing to ensure we copy hero slices correctly.
|
|
|
|
func TestRoomNames(t *testing.T) {
|
2021-11-09 10:15:48 +00:00
|
|
|
pqString := testutils.PrepareDBConnectionString()
|
2021-11-02 17:21:09 +00:00
|
|
|
// setup code
|
|
|
|
v2 := runTestV2Server(t)
|
|
|
|
v3 := runTestServer(t, v2, pqString)
|
|
|
|
defer v2.close()
|
|
|
|
defer v3.close()
|
|
|
|
bob := "@TestRoomNames_bob:localhost"
|
2023-04-04 20:03:47 +01:00
|
|
|
// make 4 rooms, last room is most recent, and send A,B,C into each room
|
2021-11-02 17:21:09 +00:00
|
|
|
latestTimestamp := time.Now()
|
|
|
|
allRooms := []roomEvents{
|
|
|
|
{
|
|
|
|
roomID: "!TestRoomNames_dm:localhost",
|
|
|
|
name: "Bob",
|
|
|
|
events: append(createRoomState(t, alice, latestTimestamp), []json.RawMessage{
|
|
|
|
testutils.NewStateEvent(t, "m.room.member", bob, bob, map[string]interface{}{"membership": "join", "displayname": "Bob"}, testutils.WithTimestamp(latestTimestamp.Add(3*time.Second))),
|
|
|
|
}...),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
roomID: "!TestRoomNames_named:localhost",
|
|
|
|
name: "My Room Name",
|
|
|
|
events: append(createRoomState(t, alice, latestTimestamp), []json.RawMessage{
|
|
|
|
testutils.NewStateEvent(t, "m.room.name", "", alice, map[string]interface{}{"name": "My Room Name"}, testutils.WithTimestamp(latestTimestamp.Add(2*time.Second))),
|
|
|
|
}...),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
roomID: "!TestRoomNames_empty:localhost",
|
|
|
|
name: "Empty Room",
|
2021-11-02 17:55:31 +00:00
|
|
|
events: createRoomState(t, alice, latestTimestamp.Add(time.Second)),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
roomID: "!TestRoomNames_dm_name_set_after_join:localhost",
|
|
|
|
name: "Bob",
|
|
|
|
state: append(createRoomState(t, alice, latestTimestamp), []json.RawMessage{
|
2022-07-12 15:12:02 +01:00
|
|
|
testutils.NewJoinEvent(t, bob, testutils.WithTimestamp(latestTimestamp)),
|
2021-11-02 17:55:31 +00:00
|
|
|
}...),
|
|
|
|
events: []json.RawMessage{
|
|
|
|
testutils.NewStateEvent(
|
|
|
|
t, "m.room.member", bob, bob, map[string]interface{}{"membership": "join", "displayname": "Bob"}, testutils.WithTimestamp(latestTimestamp),
|
|
|
|
testutils.WithUnsigned(map[string]interface{}{
|
|
|
|
"prev_content": map[string]interface{}{
|
|
|
|
"membership": "join",
|
|
|
|
},
|
|
|
|
})),
|
|
|
|
},
|
2021-11-02 17:21:09 +00:00
|
|
|
},
|
|
|
|
}
|
2023-05-15 19:11:48 +01:00
|
|
|
v2.addAccount(t, alice, aliceToken)
|
2021-11-02 17:21:09 +00:00
|
|
|
v2.queueResponse(alice, sync2.SyncResponse{
|
|
|
|
Rooms: sync2.SyncRoomsResponse{
|
|
|
|
Join: v2JoinTimeline(allRooms...),
|
|
|
|
},
|
|
|
|
})
|
|
|
|
|
|
|
|
checkRoomNames := func(sessionID string) {
|
2021-11-02 17:55:31 +00:00
|
|
|
t.Helper()
|
2021-11-02 17:21:09 +00:00
|
|
|
// do a sync, make sure room names are sensible
|
|
|
|
res := v3.mustDoV3Request(t, aliceToken, sync3.Request{
|
2022-12-20 13:32:39 +00:00
|
|
|
Lists: map[string]sync3.RequestList{
|
|
|
|
"a": {
|
|
|
|
Ranges: sync3.SliceRanges{
|
|
|
|
[2]int64{0, int64(len(allRooms) - 1)}, // all rooms
|
|
|
|
},
|
|
|
|
RoomSubscription: sync3.RoomSubscription{
|
|
|
|
TimelineLimit: int64(100),
|
|
|
|
},
|
|
|
|
}},
|
2021-11-02 17:21:09 +00:00
|
|
|
})
|
2022-12-20 13:32:39 +00:00
|
|
|
m.MatchResponse(t, res, m.MatchList("a", m.MatchV3Count(len(allRooms)), m.MatchV3Ops(
|
2022-07-26 10:11:06 +01:00
|
|
|
m.MatchV3SyncOpFn(func(op *sync3.ResponseOpRange) error {
|
2022-05-27 09:54:17 +01:00
|
|
|
if len(op.RoomIDs) != len(allRooms) {
|
|
|
|
return fmt.Errorf("want %d rooms, got %d", len(allRooms), len(op.RoomIDs))
|
2021-11-02 17:21:09 +00:00
|
|
|
}
|
|
|
|
for i := range allRooms {
|
2022-05-27 15:23:31 +01:00
|
|
|
err := allRooms[i].MatchRoom(op.RoomIDs[i],
|
2022-05-27 09:54:17 +01:00
|
|
|
res.Rooms[op.RoomIDs[i]],
|
2022-07-26 10:11:06 +01:00
|
|
|
m.MatchRoomName(allRooms[i].name),
|
2021-11-02 17:21:09 +00:00
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}),
|
2022-07-12 17:12:01 +01:00
|
|
|
)))
|
2021-11-02 17:21:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
checkRoomNames("a")
|
|
|
|
// restart the server and repeat the tests, should still be the same when reading from the database
|
|
|
|
v3.restart(t, v2, pqString)
|
|
|
|
checkRoomNames("b")
|
2022-02-18 16:49:26 +00:00
|
|
|
|
|
|
|
// now check that we can filter the rooms by name
|
|
|
|
checkRoomNameFilter := func(searchTerm string, wantRooms []roomEvents) {
|
|
|
|
t.Helper()
|
|
|
|
// do a sync, make sure room names are sensible
|
|
|
|
res := v3.mustDoV3Request(t, aliceToken, sync3.Request{
|
2022-12-20 13:32:39 +00:00
|
|
|
Lists: map[string]sync3.RequestList{
|
|
|
|
"a": {
|
|
|
|
Ranges: sync3.SliceRanges{
|
2023-04-04 20:03:47 +01:00
|
|
|
[2]int64{0, (int64(len(allRooms)) - 1)}, // all rooms
|
2022-12-20 13:32:39 +00:00
|
|
|
},
|
|
|
|
Filters: &sync3.RequestFilters{
|
|
|
|
RoomNameFilter: searchTerm,
|
|
|
|
},
|
|
|
|
}},
|
2022-02-18 16:49:26 +00:00
|
|
|
})
|
2022-07-26 10:11:06 +01:00
|
|
|
matchers := make(map[string][]m.RoomMatcher, len(wantRooms))
|
2022-05-27 09:54:17 +01:00
|
|
|
wantRoomIDs := make([]string, len(wantRooms))
|
2022-02-18 16:49:26 +00:00
|
|
|
for i := range wantRooms {
|
2022-05-27 09:54:17 +01:00
|
|
|
wantRoomIDs[i] = wantRooms[i].roomID
|
2022-07-26 10:11:06 +01:00
|
|
|
matchers[wantRooms[i].roomID] = []m.RoomMatcher{
|
|
|
|
m.MatchRoomName(wantRooms[i].name),
|
2022-02-18 16:49:26 +00:00
|
|
|
}
|
|
|
|
}
|
2022-12-20 13:32:39 +00:00
|
|
|
m.MatchResponse(t, res, m.MatchList("a", m.MatchV3Count(len(wantRooms)), m.MatchV3Ops(
|
2023-04-04 20:03:47 +01:00
|
|
|
m.MatchV3SyncOp(0, int64(len(wantRooms)-1), wantRoomIDs),
|
2022-07-26 10:11:06 +01:00
|
|
|
)), m.MatchRoomSubscriptions(matchers))
|
2022-02-18 16:49:26 +00:00
|
|
|
}
|
|
|
|
// case-insensitive matching
|
|
|
|
checkRoomNameFilter("my room name", []roomEvents{allRooms[1]})
|
|
|
|
// partial matching
|
|
|
|
checkRoomNameFilter("room na", []roomEvents{allRooms[1]})
|
|
|
|
// multiple matches
|
|
|
|
checkRoomNameFilter("bob", []roomEvents{allRooms[0], allRooms[3]})
|
2021-11-02 17:21:09 +00:00
|
|
|
}
|
2022-09-07 15:26:46 +01:00
|
|
|
|
|
|
|
// Tests that rooms have their names updated when events come in
|
|
|
|
func TestRoomNameUpdates(t *testing.T) {
|
|
|
|
rig := NewTestRig(t)
|
|
|
|
defer rig.Finish()
|
|
|
|
roomID := "!a:localhost"
|
|
|
|
rig.SetupV2RoomsForUser(t, alice, NoFlush, map[string]RoomDescriptor{
|
|
|
|
roomID: {},
|
|
|
|
})
|
|
|
|
aliceToken := rig.Token(alice)
|
|
|
|
|
|
|
|
res := rig.V3.mustDoV3Request(t, aliceToken, sync3.Request{
|
|
|
|
RoomSubscriptions: map[string]sync3.RoomSubscription{
|
|
|
|
roomID: {
|
|
|
|
TimelineLimit: 0,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
m.MatchResponse(t, res, m.MatchRoomSubscriptionsStrict(map[string][]m.RoomMatcher{
|
|
|
|
roomID: {
|
|
|
|
m.MatchJoinCount(1),
|
|
|
|
m.MatchRoomName("Empty Room"),
|
|
|
|
},
|
|
|
|
}))
|
|
|
|
// Test hero calculation
|
|
|
|
rig.FlushEvent(t, alice, roomID, testutils.NewStateEvent(t, "m.room.member", bob, bob, map[string]interface{}{
|
|
|
|
"membership": "join",
|
|
|
|
"displayname": "Bob",
|
|
|
|
}))
|
|
|
|
res = rig.V3.mustDoV3RequestWithPos(t, aliceToken, res.Pos, sync3.Request{})
|
|
|
|
m.MatchResponse(t, res, m.MatchRoomSubscriptionsStrict(map[string][]m.RoomMatcher{
|
|
|
|
roomID: {
|
|
|
|
m.MatchJoinCount(2),
|
|
|
|
m.MatchRoomName("Bob"),
|
|
|
|
},
|
|
|
|
}))
|
|
|
|
|
|
|
|
// Test canonical alias
|
|
|
|
rig.FlushEvent(t, alice, roomID, testutils.NewStateEvent(t, "m.room.canonical_alias", "", alice, map[string]interface{}{
|
|
|
|
"alias": "#alias:example.com",
|
|
|
|
}))
|
|
|
|
res = rig.V3.mustDoV3RequestWithPos(t, aliceToken, res.Pos, sync3.Request{})
|
|
|
|
m.MatchResponse(t, res, m.MatchRoomSubscriptionsStrict(map[string][]m.RoomMatcher{
|
|
|
|
roomID: {
|
|
|
|
m.MatchRoomName("#alias:example.com"),
|
|
|
|
},
|
|
|
|
}))
|
|
|
|
|
|
|
|
// Test room name
|
|
|
|
rig.FlushEvent(t, alice, roomID, testutils.NewStateEvent(t, "m.room.name", "", alice, map[string]interface{}{
|
|
|
|
"name": "My Room Name",
|
|
|
|
}))
|
|
|
|
res = rig.V3.mustDoV3RequestWithPos(t, aliceToken, res.Pos, sync3.Request{})
|
|
|
|
m.MatchResponse(t, res, m.MatchRoomSubscriptionsStrict(map[string][]m.RoomMatcher{
|
|
|
|
roomID: {
|
|
|
|
m.MatchRoomName("My Room Name"),
|
|
|
|
},
|
|
|
|
}))
|
|
|
|
}
|