mirror of
https://github.com/matrix-org/sliding-sync.git
synced 2025-03-10 13:37:11 +00:00
390 lines
10 KiB
Go
390 lines
10 KiB
Go
package sync3
|
|
|
|
import (
|
|
"reflect"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/matrix-org/sliding-sync/internal"
|
|
"github.com/matrix-org/sliding-sync/sync3/caches"
|
|
)
|
|
|
|
type finder struct {
|
|
rooms map[string]*RoomConnMetadata
|
|
roomIDs []string
|
|
}
|
|
|
|
func (f finder) ReadOnlyRoom(roomID string) *RoomConnMetadata {
|
|
return f.rooms[roomID]
|
|
}
|
|
|
|
func newFinder(rooms []*RoomConnMetadata) finder {
|
|
m := make(map[string]*RoomConnMetadata)
|
|
ids := make([]string, len(rooms))
|
|
for i := range rooms {
|
|
ids[i] = rooms[i].RoomID
|
|
m[ids[i]] = rooms[i]
|
|
}
|
|
return finder{
|
|
rooms: m,
|
|
roomIDs: ids,
|
|
}
|
|
}
|
|
|
|
func TestSortBySingleOperation(t *testing.T) {
|
|
const listKey = "my_list"
|
|
room1 := "!1:localhost"
|
|
room2 := "!2:localhost"
|
|
room3 := "!3:localhost"
|
|
room4 := "!4:localhost"
|
|
rooms := []*RoomConnMetadata{
|
|
{
|
|
RoomMetadata: internal.RoomMetadata{
|
|
RoomID: room1,
|
|
},
|
|
UserRoomData: caches.UserRoomData{
|
|
HighlightCount: 3,
|
|
NotificationCount: 12,
|
|
CanonicalisedName: "foo",
|
|
},
|
|
LastInterestedEventTimestamps: map[string]uint64{listKey: 600},
|
|
},
|
|
{
|
|
RoomMetadata: internal.RoomMetadata{
|
|
RoomID: room2,
|
|
},
|
|
UserRoomData: caches.UserRoomData{
|
|
HighlightCount: 0,
|
|
NotificationCount: 3,
|
|
CanonicalisedName: "koo",
|
|
},
|
|
LastInterestedEventTimestamps: map[string]uint64{listKey: 700},
|
|
},
|
|
{
|
|
RoomMetadata: internal.RoomMetadata{
|
|
RoomID: room3,
|
|
},
|
|
UserRoomData: caches.UserRoomData{
|
|
HighlightCount: 2,
|
|
NotificationCount: 7,
|
|
CanonicalisedName: "yoo",
|
|
},
|
|
LastInterestedEventTimestamps: map[string]uint64{listKey: 900},
|
|
},
|
|
{
|
|
RoomMetadata: internal.RoomMetadata{
|
|
RoomID: room4,
|
|
},
|
|
UserRoomData: caches.UserRoomData{
|
|
HighlightCount: 1,
|
|
NotificationCount: 1,
|
|
CanonicalisedName: "boo",
|
|
},
|
|
LastInterestedEventTimestamps: map[string]uint64{listKey: 800},
|
|
},
|
|
}
|
|
// name: 4,1,2,3
|
|
// recency: 3,4,2,1
|
|
// highlight: 1,3,4,2
|
|
// notif: 1,3,2,4
|
|
// level+recency: 3,4,1,2 as 3,4,1 have highlights then sorted by recency
|
|
wantMap := map[string][]string{
|
|
SortByName: {room4, room1, room2, room3},
|
|
SortByRecency: {room3, room4, room2, room1},
|
|
SortByHighlightCount: {room1, room3, room4, room2},
|
|
SortByNotificationCount: {room1, room3, room2, room4},
|
|
SortByNotificationLevel + " " + SortByRecency: {room3, room4, room1, room2},
|
|
}
|
|
f := newFinder(rooms)
|
|
sr := NewSortableRooms(f, listKey, f.roomIDs)
|
|
for sortBy, wantOrder := range wantMap {
|
|
sr.Sort(strings.Split(sortBy, " "))
|
|
var gotRoomIDs []string
|
|
for i := range sr.roomIDs {
|
|
gotRoomIDs = append(gotRoomIDs, sr.roomIDs[i])
|
|
}
|
|
for i := range wantOrder {
|
|
if wantOrder[i] != gotRoomIDs[i] {
|
|
t.Errorf("Sort: %s got %v want %v", sortBy, gotRoomIDs, wantOrder)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestSortByMultipleOperations(t *testing.T) {
|
|
const listKey = "my_list"
|
|
room1 := "!1:localhost"
|
|
room2 := "!2:localhost"
|
|
room3 := "!3:localhost"
|
|
room4 := "!4:localhost"
|
|
rooms := []*RoomConnMetadata{
|
|
{
|
|
RoomMetadata: internal.RoomMetadata{
|
|
RoomID: room1,
|
|
},
|
|
UserRoomData: caches.UserRoomData{
|
|
HighlightCount: 1,
|
|
NotificationCount: 1,
|
|
CanonicalisedName: "foo",
|
|
},
|
|
LastInterestedEventTimestamps: map[string]uint64{listKey: 600},
|
|
},
|
|
{
|
|
RoomMetadata: internal.RoomMetadata{
|
|
RoomID: room2,
|
|
},
|
|
UserRoomData: caches.UserRoomData{
|
|
HighlightCount: 1,
|
|
NotificationCount: 5,
|
|
CanonicalisedName: "koo",
|
|
},
|
|
LastInterestedEventTimestamps: map[string]uint64{listKey: 700},
|
|
},
|
|
{
|
|
RoomMetadata: internal.RoomMetadata{
|
|
RoomID: room3,
|
|
},
|
|
UserRoomData: caches.UserRoomData{
|
|
HighlightCount: 0,
|
|
NotificationCount: 0,
|
|
CanonicalisedName: "yoo",
|
|
},
|
|
LastInterestedEventTimestamps: map[string]uint64{listKey: 800},
|
|
},
|
|
{
|
|
RoomMetadata: internal.RoomMetadata{
|
|
RoomID: room4,
|
|
},
|
|
UserRoomData: caches.UserRoomData{
|
|
HighlightCount: 0,
|
|
NotificationCount: 0,
|
|
CanonicalisedName: "boo",
|
|
},
|
|
LastInterestedEventTimestamps: map[string]uint64{listKey: 900},
|
|
},
|
|
}
|
|
testCases := []struct {
|
|
SortBy []string
|
|
WantRooms []string
|
|
}{
|
|
{
|
|
SortBy: []string{SortByHighlightCount, SortByNotificationCount, SortByRecency, SortByName},
|
|
WantRooms: []string{room2, room1, room4, room3},
|
|
},
|
|
{
|
|
SortBy: []string{SortByHighlightCount, SortByName},
|
|
WantRooms: []string{room1, room2, room4, room3},
|
|
},
|
|
{
|
|
SortBy: []string{SortByNotificationLevel, SortByName},
|
|
WantRooms: []string{room1, room2, room4, room3},
|
|
},
|
|
{
|
|
SortBy: []string{SortByNotificationLevel, SortByRecency},
|
|
WantRooms: []string{room2, room1, room4, room3},
|
|
},
|
|
}
|
|
f := newFinder(rooms)
|
|
sr := NewSortableRooms(f, listKey, f.roomIDs)
|
|
for _, tc := range testCases {
|
|
sr.Sort(tc.SortBy)
|
|
var gotRoomIDs []string
|
|
for i := range sr.roomIDs {
|
|
gotRoomIDs = append(gotRoomIDs, sr.roomIDs[i])
|
|
}
|
|
for i := range tc.WantRooms {
|
|
if tc.WantRooms[i] != gotRoomIDs[i] {
|
|
t.Errorf("Sort: %v got %v want %v", tc.SortBy, gotRoomIDs, tc.WantRooms)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Test that if you remove a room, it updates the lookup map.
|
|
func TestSortableRoomsRemove(t *testing.T) {
|
|
const listKey = "my_list"
|
|
room1 := "!1:localhost"
|
|
room2 := "!2:localhost"
|
|
rooms := []*RoomConnMetadata{
|
|
{
|
|
RoomMetadata: internal.RoomMetadata{
|
|
RoomID: room1,
|
|
},
|
|
UserRoomData: caches.UserRoomData{
|
|
HighlightCount: 1,
|
|
NotificationCount: 1,
|
|
CanonicalisedName: "foo",
|
|
},
|
|
LastInterestedEventTimestamps: map[string]uint64{listKey: 700},
|
|
},
|
|
{
|
|
RoomMetadata: internal.RoomMetadata{
|
|
RoomID: room2,
|
|
},
|
|
UserRoomData: caches.UserRoomData{
|
|
HighlightCount: 2,
|
|
NotificationCount: 2,
|
|
CanonicalisedName: "foo2",
|
|
},
|
|
LastInterestedEventTimestamps: map[string]uint64{listKey: 600},
|
|
},
|
|
}
|
|
f := newFinder(rooms)
|
|
sr := NewSortableRooms(f, listKey, f.roomIDs)
|
|
if err := sr.Sort([]string{SortByRecency}); err != nil { // room 1 is first, then room 2
|
|
t.Fatalf("Sort: %s", err)
|
|
}
|
|
if i, ok := sr.IndexOf(room1); i != 0 || !ok {
|
|
t.Errorf("IndexOf room 1 returned %v %v", i, ok)
|
|
}
|
|
if i, ok := sr.IndexOf(room2); i != 1 || !ok {
|
|
t.Errorf("IndexOf room 2 returned %v %v", i, ok)
|
|
}
|
|
// Remove room 1, so room 2 should take its place.
|
|
rmIndex := sr.Remove(room1)
|
|
if rmIndex != 0 {
|
|
t.Fatalf("Remove: return removed index %v want 0", rmIndex)
|
|
}
|
|
// check
|
|
if i, ok := sr.IndexOf(room1); ok { // should be !ok
|
|
t.Errorf("IndexOf room 1 returned %v %v", i, ok)
|
|
}
|
|
if i, ok := sr.IndexOf(room2); i != 0 || !ok {
|
|
t.Errorf("IndexOf room 2 returned %v %v", i, ok)
|
|
}
|
|
}
|
|
|
|
// dedicated test as it relies on multiple fields
|
|
func TestSortByNotificationLevel(t *testing.T) {
|
|
const listKey = "my_list"
|
|
// create the full set of possible sort variables, most recent message last
|
|
roomUnencHC := "!unencrypted-highlight-count:localhost"
|
|
roomUnencHCNC := "!unencrypted-highlight-and-notif-count:localhost"
|
|
roomUnencNC := "!unencrypted-notif-count:localhost"
|
|
roomUnenc := "!unencrypted:localhost"
|
|
roomEncHC := "!encrypted-highlight-count:localhost"
|
|
roomEncHCNC := "!encrypted-highlight-and-notif-count:localhost"
|
|
roomEncNC := "!encrypted-notif-count:localhost"
|
|
roomEnc := "!encrypted:localhost"
|
|
roomsMap := map[string]*RoomConnMetadata{
|
|
roomUnencHC: {
|
|
RoomMetadata: internal.RoomMetadata{
|
|
Encrypted: false,
|
|
},
|
|
UserRoomData: caches.UserRoomData{
|
|
HighlightCount: 1,
|
|
NotificationCount: 0,
|
|
},
|
|
LastInterestedEventTimestamps: map[string]uint64{listKey: 1},
|
|
},
|
|
roomUnencHCNC: {
|
|
RoomMetadata: internal.RoomMetadata{
|
|
Encrypted: false,
|
|
},
|
|
UserRoomData: caches.UserRoomData{
|
|
HighlightCount: 1,
|
|
NotificationCount: 1,
|
|
},
|
|
LastInterestedEventTimestamps: map[string]uint64{listKey: 2},
|
|
},
|
|
roomUnencNC: {
|
|
RoomMetadata: internal.RoomMetadata{
|
|
Encrypted: false,
|
|
},
|
|
UserRoomData: caches.UserRoomData{
|
|
HighlightCount: 0,
|
|
NotificationCount: 1,
|
|
},
|
|
LastInterestedEventTimestamps: map[string]uint64{listKey: 3},
|
|
},
|
|
roomUnenc: {
|
|
RoomMetadata: internal.RoomMetadata{
|
|
Encrypted: false,
|
|
},
|
|
UserRoomData: caches.UserRoomData{
|
|
HighlightCount: 0,
|
|
NotificationCount: 0,
|
|
},
|
|
LastInterestedEventTimestamps: map[string]uint64{listKey: 4},
|
|
},
|
|
roomEncHC: {
|
|
RoomMetadata: internal.RoomMetadata{
|
|
Encrypted: true,
|
|
},
|
|
UserRoomData: caches.UserRoomData{
|
|
HighlightCount: 1,
|
|
NotificationCount: 0,
|
|
},
|
|
LastInterestedEventTimestamps: map[string]uint64{listKey: 5},
|
|
},
|
|
roomEncHCNC: {
|
|
RoomMetadata: internal.RoomMetadata{
|
|
Encrypted: true,
|
|
},
|
|
UserRoomData: caches.UserRoomData{
|
|
HighlightCount: 1,
|
|
NotificationCount: 1,
|
|
},
|
|
LastInterestedEventTimestamps: map[string]uint64{listKey: 6},
|
|
},
|
|
roomEncNC: {
|
|
RoomMetadata: internal.RoomMetadata{
|
|
RoomID: roomEncNC,
|
|
Encrypted: true,
|
|
},
|
|
UserRoomData: caches.UserRoomData{
|
|
HighlightCount: 0,
|
|
NotificationCount: 1,
|
|
},
|
|
LastInterestedEventTimestamps: map[string]uint64{listKey: 7},
|
|
},
|
|
roomEnc: {
|
|
RoomMetadata: internal.RoomMetadata{
|
|
RoomID: roomEnc,
|
|
Encrypted: true,
|
|
},
|
|
UserRoomData: caches.UserRoomData{
|
|
HighlightCount: 0,
|
|
NotificationCount: 0,
|
|
},
|
|
LastInterestedEventTimestamps: map[string]uint64{listKey: 8},
|
|
},
|
|
}
|
|
roomIDs := make([]string, len(roomsMap))
|
|
rooms := make([]*RoomConnMetadata, len(roomsMap))
|
|
i := 0
|
|
for roomID, room := range roomsMap {
|
|
room.RoomMetadata.RoomID = roomID
|
|
roomIDs[i] = roomID
|
|
rooms[i] = room
|
|
i++
|
|
}
|
|
t.Logf("%v", roomIDs)
|
|
f := newFinder(rooms)
|
|
sr := NewSortableRooms(f, listKey, roomIDs)
|
|
if err := sr.Sort([]string{SortByNotificationLevel, SortByRecency}); err != nil {
|
|
t.Fatalf("Sort: %s", err)
|
|
}
|
|
var gotRoomIDs []string
|
|
for i := range sr.roomIDs {
|
|
gotRoomIDs = append(gotRoomIDs, sr.roomIDs[i])
|
|
}
|
|
// we expect the rooms to be grouped in this order:
|
|
// HIGHLIGHT COUNT > 0
|
|
// ENCRYPTED, NOTIF COUNT > 0
|
|
// UNENCRYPTED, NOTIF COUNT > 0
|
|
// REST
|
|
// Within each group, we expect recency sorting due to SortByRecency
|
|
wantRoomIDs := []string{
|
|
roomEncHCNC, roomEncHC, roomUnencHCNC, roomUnencHC, // in practice we don't expect to see this as encrypted rooms won't have highlight counts > 0
|
|
roomEncNC,
|
|
roomUnencNC,
|
|
roomEnc, roomUnenc,
|
|
}
|
|
|
|
if !reflect.DeepEqual(gotRoomIDs, wantRoomIDs) {
|
|
t.Errorf("got: %v", gotRoomIDs)
|
|
t.Errorf("want: %v", wantRoomIDs)
|
|
}
|
|
}
|