2021-11-02 11:09:26 +00:00
|
|
|
package sync3
|
|
|
|
|
|
|
|
import (
|
2022-12-14 18:53:55 +00:00
|
|
|
"reflect"
|
|
|
|
"strings"
|
2021-11-02 11:09:26 +00:00
|
|
|
"testing"
|
|
|
|
|
2022-12-15 11:08:50 +00:00
|
|
|
"github.com/matrix-org/sliding-sync/internal"
|
|
|
|
"github.com/matrix-org/sliding-sync/sync3/caches"
|
2021-11-02 11:09:26 +00:00
|
|
|
)
|
|
|
|
|
refactor: add RoomFinder and use it in InternalRequestLists
This is part of a series of refactors aimed to improve the performance
and complexity of calculating list deltas, which up until now exists in
its current form due to organic growth of the codebase.
This specific refactor introduces a new interface `RoomFinder` which
can map room IDs to `*RoomConnMetadata` which is used by `ConnState`.
All the sliding sync lists now use the `RoomFinder` instead of keeping
their own copies of `RoomConnMetadata`, meaning per-connection, rooms
just have 1 copy in-memory. This cuts down on memory usage as well as
cuts down on GC churn as we would constantly be replacing N rooms for
each update, where N is the total number of lists on that connection.
For Element-Web, N=7 currently to handle Favourites, Low Priority, DMs,
Rooms, Spaces, Invites, Search. This also has the benefit of creating
a single source of truth in `InternalRequestLists.allRooms` which can
be updated once and then a list of list deltas can be calculated off
the back of that. Previously, `allRooms` was _only_ used to seed new
lists, which created a weird imbalance as we would need to update both
`allRooms` _and_ each `FilteredSortableRooms` to keep things in-sync.
This refactor is incomplete in its present form, as we need to make
use of the new `RoomDelta` struct to efficiently package list updates.
2022-08-26 10:09:41 +01:00
|
|
|
type finder struct {
|
|
|
|
rooms map[string]*RoomConnMetadata
|
|
|
|
roomIDs []string
|
|
|
|
}
|
|
|
|
|
2023-02-02 11:26:08 +00:00
|
|
|
func (f finder) ReadOnlyRoom(roomID string) *RoomConnMetadata {
|
refactor: add RoomFinder and use it in InternalRequestLists
This is part of a series of refactors aimed to improve the performance
and complexity of calculating list deltas, which up until now exists in
its current form due to organic growth of the codebase.
This specific refactor introduces a new interface `RoomFinder` which
can map room IDs to `*RoomConnMetadata` which is used by `ConnState`.
All the sliding sync lists now use the `RoomFinder` instead of keeping
their own copies of `RoomConnMetadata`, meaning per-connection, rooms
just have 1 copy in-memory. This cuts down on memory usage as well as
cuts down on GC churn as we would constantly be replacing N rooms for
each update, where N is the total number of lists on that connection.
For Element-Web, N=7 currently to handle Favourites, Low Priority, DMs,
Rooms, Spaces, Invites, Search. This also has the benefit of creating
a single source of truth in `InternalRequestLists.allRooms` which can
be updated once and then a list of list deltas can be calculated off
the back of that. Previously, `allRooms` was _only_ used to seed new
lists, which created a weird imbalance as we would need to update both
`allRooms` _and_ each `FilteredSortableRooms` to keep things in-sync.
This refactor is incomplete in its present form, as we need to make
use of the new `RoomDelta` struct to efficiently package list updates.
2022-08-26 10:09:41 +01:00
|
|
|
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,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-02 11:09:26 +00:00
|
|
|
func TestSortBySingleOperation(t *testing.T) {
|
2023-05-24 15:50:53 +01:00
|
|
|
const listKey = "my_list"
|
2021-11-02 11:09:26 +00:00
|
|
|
room1 := "!1:localhost"
|
|
|
|
room2 := "!2:localhost"
|
|
|
|
room3 := "!3:localhost"
|
|
|
|
room4 := "!4:localhost"
|
2022-08-25 15:30:07 +01:00
|
|
|
rooms := []*RoomConnMetadata{
|
2021-11-02 11:09:26 +00:00
|
|
|
{
|
|
|
|
RoomMetadata: internal.RoomMetadata{
|
2023-05-23 17:25:35 +01:00
|
|
|
RoomID: room1,
|
2021-11-02 11:09:26 +00:00
|
|
|
},
|
2022-03-23 16:34:43 +00:00
|
|
|
UserRoomData: caches.UserRoomData{
|
2021-11-09 10:36:29 +00:00
|
|
|
HighlightCount: 3,
|
|
|
|
NotificationCount: 12,
|
2022-08-18 13:11:05 +01:00
|
|
|
CanonicalisedName: "foo",
|
2021-11-09 10:36:29 +00:00
|
|
|
},
|
2023-05-24 15:50:53 +01:00
|
|
|
LastInterestedEventTimestamps: map[string]uint64{listKey: 600},
|
2021-11-02 11:09:26 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
RoomMetadata: internal.RoomMetadata{
|
2023-05-23 17:25:35 +01:00
|
|
|
RoomID: room2,
|
2021-11-02 11:09:26 +00:00
|
|
|
},
|
2022-03-23 16:34:43 +00:00
|
|
|
UserRoomData: caches.UserRoomData{
|
2021-11-09 10:36:29 +00:00
|
|
|
HighlightCount: 0,
|
|
|
|
NotificationCount: 3,
|
2022-08-18 13:11:05 +01:00
|
|
|
CanonicalisedName: "koo",
|
2021-11-09 10:36:29 +00:00
|
|
|
},
|
2023-05-24 15:50:53 +01:00
|
|
|
LastInterestedEventTimestamps: map[string]uint64{listKey: 700},
|
2021-11-02 11:09:26 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
RoomMetadata: internal.RoomMetadata{
|
2023-05-23 17:25:35 +01:00
|
|
|
RoomID: room3,
|
2021-11-02 11:09:26 +00:00
|
|
|
},
|
2022-03-23 16:34:43 +00:00
|
|
|
UserRoomData: caches.UserRoomData{
|
2021-11-09 10:36:29 +00:00
|
|
|
HighlightCount: 2,
|
|
|
|
NotificationCount: 7,
|
2022-08-18 13:11:05 +01:00
|
|
|
CanonicalisedName: "yoo",
|
2021-11-09 10:36:29 +00:00
|
|
|
},
|
2023-05-24 15:50:53 +01:00
|
|
|
LastInterestedEventTimestamps: map[string]uint64{listKey: 900},
|
2021-11-02 11:09:26 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
RoomMetadata: internal.RoomMetadata{
|
2023-05-23 17:25:35 +01:00
|
|
|
RoomID: room4,
|
2021-11-02 11:09:26 +00:00
|
|
|
},
|
2022-03-23 16:34:43 +00:00
|
|
|
UserRoomData: caches.UserRoomData{
|
2021-11-09 10:36:29 +00:00
|
|
|
HighlightCount: 1,
|
|
|
|
NotificationCount: 1,
|
2022-08-18 13:11:05 +01:00
|
|
|
CanonicalisedName: "boo",
|
2021-11-09 10:36:29 +00:00
|
|
|
},
|
2023-05-24 15:50:53 +01:00
|
|
|
LastInterestedEventTimestamps: map[string]uint64{listKey: 800},
|
2021-11-02 11:09:26 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
// name: 4,1,2,3
|
|
|
|
// recency: 3,4,2,1
|
|
|
|
// highlight: 1,3,4,2
|
|
|
|
// notif: 1,3,2,4
|
2022-12-14 18:53:55 +00:00
|
|
|
// level+recency: 3,4,1,2 as 3,4,1 have highlights then sorted by recency
|
2021-11-02 11:09:26 +00:00
|
|
|
wantMap := map[string][]string{
|
|
|
|
SortByName: {room4, room1, room2, room3},
|
|
|
|
SortByRecency: {room3, room4, room2, room1},
|
|
|
|
SortByHighlightCount: {room1, room3, room4, room2},
|
|
|
|
SortByNotificationCount: {room1, room3, room2, room4},
|
2022-12-14 18:53:55 +00:00
|
|
|
SortByNotificationLevel + " " + SortByRecency: {room3, room4, room1, room2},
|
2021-11-02 11:09:26 +00:00
|
|
|
}
|
refactor: add RoomFinder and use it in InternalRequestLists
This is part of a series of refactors aimed to improve the performance
and complexity of calculating list deltas, which up until now exists in
its current form due to organic growth of the codebase.
This specific refactor introduces a new interface `RoomFinder` which
can map room IDs to `*RoomConnMetadata` which is used by `ConnState`.
All the sliding sync lists now use the `RoomFinder` instead of keeping
their own copies of `RoomConnMetadata`, meaning per-connection, rooms
just have 1 copy in-memory. This cuts down on memory usage as well as
cuts down on GC churn as we would constantly be replacing N rooms for
each update, where N is the total number of lists on that connection.
For Element-Web, N=7 currently to handle Favourites, Low Priority, DMs,
Rooms, Spaces, Invites, Search. This also has the benefit of creating
a single source of truth in `InternalRequestLists.allRooms` which can
be updated once and then a list of list deltas can be calculated off
the back of that. Previously, `allRooms` was _only_ used to seed new
lists, which created a weird imbalance as we would need to update both
`allRooms` _and_ each `FilteredSortableRooms` to keep things in-sync.
This refactor is incomplete in its present form, as we need to make
use of the new `RoomDelta` struct to efficiently package list updates.
2022-08-26 10:09:41 +01:00
|
|
|
f := newFinder(rooms)
|
2023-05-24 15:50:53 +01:00
|
|
|
sr := NewSortableRooms(f, listKey, f.roomIDs)
|
2021-11-02 11:09:26 +00:00
|
|
|
for sortBy, wantOrder := range wantMap {
|
2022-12-14 18:53:55 +00:00
|
|
|
sr.Sort(strings.Split(sortBy, " "))
|
2021-11-02 11:09:26 +00:00
|
|
|
var gotRoomIDs []string
|
refactor: add RoomFinder and use it in InternalRequestLists
This is part of a series of refactors aimed to improve the performance
and complexity of calculating list deltas, which up until now exists in
its current form due to organic growth of the codebase.
This specific refactor introduces a new interface `RoomFinder` which
can map room IDs to `*RoomConnMetadata` which is used by `ConnState`.
All the sliding sync lists now use the `RoomFinder` instead of keeping
their own copies of `RoomConnMetadata`, meaning per-connection, rooms
just have 1 copy in-memory. This cuts down on memory usage as well as
cuts down on GC churn as we would constantly be replacing N rooms for
each update, where N is the total number of lists on that connection.
For Element-Web, N=7 currently to handle Favourites, Low Priority, DMs,
Rooms, Spaces, Invites, Search. This also has the benefit of creating
a single source of truth in `InternalRequestLists.allRooms` which can
be updated once and then a list of list deltas can be calculated off
the back of that. Previously, `allRooms` was _only_ used to seed new
lists, which created a weird imbalance as we would need to update both
`allRooms` _and_ each `FilteredSortableRooms` to keep things in-sync.
This refactor is incomplete in its present form, as we need to make
use of the new `RoomDelta` struct to efficiently package list updates.
2022-08-26 10:09:41 +01:00
|
|
|
for i := range sr.roomIDs {
|
|
|
|
gotRoomIDs = append(gotRoomIDs, sr.roomIDs[i])
|
2021-11-02 11:09:26 +00:00
|
|
|
}
|
|
|
|
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) {
|
2023-05-24 15:50:53 +01:00
|
|
|
const listKey = "my_list"
|
2021-11-02 11:09:26 +00:00
|
|
|
room1 := "!1:localhost"
|
|
|
|
room2 := "!2:localhost"
|
|
|
|
room3 := "!3:localhost"
|
|
|
|
room4 := "!4:localhost"
|
2022-08-25 15:30:07 +01:00
|
|
|
rooms := []*RoomConnMetadata{
|
2021-11-02 11:09:26 +00:00
|
|
|
{
|
|
|
|
RoomMetadata: internal.RoomMetadata{
|
2023-05-23 17:25:35 +01:00
|
|
|
RoomID: room1,
|
2021-11-02 11:09:26 +00:00
|
|
|
},
|
2022-03-23 16:34:43 +00:00
|
|
|
UserRoomData: caches.UserRoomData{
|
2021-11-09 10:36:29 +00:00
|
|
|
HighlightCount: 1,
|
|
|
|
NotificationCount: 1,
|
2022-08-18 13:11:05 +01:00
|
|
|
CanonicalisedName: "foo",
|
2021-11-09 10:36:29 +00:00
|
|
|
},
|
2023-05-24 15:50:53 +01:00
|
|
|
LastInterestedEventTimestamps: map[string]uint64{listKey: 600},
|
2021-11-02 11:09:26 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
RoomMetadata: internal.RoomMetadata{
|
2023-05-23 17:25:35 +01:00
|
|
|
RoomID: room2,
|
2021-11-02 11:09:26 +00:00
|
|
|
},
|
2022-03-23 16:34:43 +00:00
|
|
|
UserRoomData: caches.UserRoomData{
|
2021-11-09 10:36:29 +00:00
|
|
|
HighlightCount: 1,
|
|
|
|
NotificationCount: 5,
|
2022-08-18 13:11:05 +01:00
|
|
|
CanonicalisedName: "koo",
|
2021-11-09 10:36:29 +00:00
|
|
|
},
|
2023-05-24 15:50:53 +01:00
|
|
|
LastInterestedEventTimestamps: map[string]uint64{listKey: 700},
|
2021-11-02 11:09:26 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
RoomMetadata: internal.RoomMetadata{
|
2023-05-23 17:25:35 +01:00
|
|
|
RoomID: room3,
|
2021-11-02 11:09:26 +00:00
|
|
|
},
|
2022-03-23 16:34:43 +00:00
|
|
|
UserRoomData: caches.UserRoomData{
|
2021-11-09 10:36:29 +00:00
|
|
|
HighlightCount: 0,
|
|
|
|
NotificationCount: 0,
|
2022-08-18 13:11:05 +01:00
|
|
|
CanonicalisedName: "yoo",
|
2021-11-09 10:36:29 +00:00
|
|
|
},
|
2023-05-24 15:50:53 +01:00
|
|
|
LastInterestedEventTimestamps: map[string]uint64{listKey: 800},
|
2021-11-02 11:09:26 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
RoomMetadata: internal.RoomMetadata{
|
2023-05-23 17:25:35 +01:00
|
|
|
RoomID: room4,
|
2021-11-02 11:09:26 +00:00
|
|
|
},
|
2022-03-23 16:34:43 +00:00
|
|
|
UserRoomData: caches.UserRoomData{
|
2021-11-09 10:36:29 +00:00
|
|
|
HighlightCount: 0,
|
|
|
|
NotificationCount: 0,
|
2022-08-18 13:11:05 +01:00
|
|
|
CanonicalisedName: "boo",
|
2021-11-09 10:36:29 +00:00
|
|
|
},
|
2023-05-24 15:50:53 +01:00
|
|
|
LastInterestedEventTimestamps: map[string]uint64{listKey: 900},
|
2021-11-02 11:09:26 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
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},
|
|
|
|
},
|
2022-12-14 18:53:55 +00:00
|
|
|
{
|
|
|
|
SortBy: []string{SortByNotificationLevel, SortByName},
|
|
|
|
WantRooms: []string{room1, room2, room4, room3},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
SortBy: []string{SortByNotificationLevel, SortByRecency},
|
|
|
|
WantRooms: []string{room2, room1, room4, room3},
|
|
|
|
},
|
2021-11-02 11:09:26 +00:00
|
|
|
}
|
refactor: add RoomFinder and use it in InternalRequestLists
This is part of a series of refactors aimed to improve the performance
and complexity of calculating list deltas, which up until now exists in
its current form due to organic growth of the codebase.
This specific refactor introduces a new interface `RoomFinder` which
can map room IDs to `*RoomConnMetadata` which is used by `ConnState`.
All the sliding sync lists now use the `RoomFinder` instead of keeping
their own copies of `RoomConnMetadata`, meaning per-connection, rooms
just have 1 copy in-memory. This cuts down on memory usage as well as
cuts down on GC churn as we would constantly be replacing N rooms for
each update, where N is the total number of lists on that connection.
For Element-Web, N=7 currently to handle Favourites, Low Priority, DMs,
Rooms, Spaces, Invites, Search. This also has the benefit of creating
a single source of truth in `InternalRequestLists.allRooms` which can
be updated once and then a list of list deltas can be calculated off
the back of that. Previously, `allRooms` was _only_ used to seed new
lists, which created a weird imbalance as we would need to update both
`allRooms` _and_ each `FilteredSortableRooms` to keep things in-sync.
This refactor is incomplete in its present form, as we need to make
use of the new `RoomDelta` struct to efficiently package list updates.
2022-08-26 10:09:41 +01:00
|
|
|
f := newFinder(rooms)
|
2023-05-24 15:50:53 +01:00
|
|
|
sr := NewSortableRooms(f, listKey, f.roomIDs)
|
2021-11-02 11:09:26 +00:00
|
|
|
for _, tc := range testCases {
|
|
|
|
sr.Sort(tc.SortBy)
|
|
|
|
var gotRoomIDs []string
|
refactor: add RoomFinder and use it in InternalRequestLists
This is part of a series of refactors aimed to improve the performance
and complexity of calculating list deltas, which up until now exists in
its current form due to organic growth of the codebase.
This specific refactor introduces a new interface `RoomFinder` which
can map room IDs to `*RoomConnMetadata` which is used by `ConnState`.
All the sliding sync lists now use the `RoomFinder` instead of keeping
their own copies of `RoomConnMetadata`, meaning per-connection, rooms
just have 1 copy in-memory. This cuts down on memory usage as well as
cuts down on GC churn as we would constantly be replacing N rooms for
each update, where N is the total number of lists on that connection.
For Element-Web, N=7 currently to handle Favourites, Low Priority, DMs,
Rooms, Spaces, Invites, Search. This also has the benefit of creating
a single source of truth in `InternalRequestLists.allRooms` which can
be updated once and then a list of list deltas can be calculated off
the back of that. Previously, `allRooms` was _only_ used to seed new
lists, which created a weird imbalance as we would need to update both
`allRooms` _and_ each `FilteredSortableRooms` to keep things in-sync.
This refactor is incomplete in its present form, as we need to make
use of the new `RoomDelta` struct to efficiently package list updates.
2022-08-26 10:09:41 +01:00
|
|
|
for i := range sr.roomIDs {
|
|
|
|
gotRoomIDs = append(gotRoomIDs, sr.roomIDs[i])
|
2021-11-02 11:09:26 +00:00
|
|
|
}
|
|
|
|
for i := range tc.WantRooms {
|
|
|
|
if tc.WantRooms[i] != gotRoomIDs[i] {
|
|
|
|
t.Errorf("Sort: %v got %v want %v", tc.SortBy, gotRoomIDs, tc.WantRooms)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-08-16 15:56:16 +01:00
|
|
|
|
|
|
|
// Test that if you remove a room, it updates the lookup map.
|
|
|
|
func TestSortableRoomsRemove(t *testing.T) {
|
2023-05-24 15:50:53 +01:00
|
|
|
const listKey = "my_list"
|
2022-08-16 15:56:16 +01:00
|
|
|
room1 := "!1:localhost"
|
|
|
|
room2 := "!2:localhost"
|
2022-08-25 15:30:07 +01:00
|
|
|
rooms := []*RoomConnMetadata{
|
2022-08-16 15:56:16 +01:00
|
|
|
{
|
|
|
|
RoomMetadata: internal.RoomMetadata{
|
2023-05-23 17:25:35 +01:00
|
|
|
RoomID: room1,
|
2022-08-16 15:56:16 +01:00
|
|
|
},
|
|
|
|
UserRoomData: caches.UserRoomData{
|
|
|
|
HighlightCount: 1,
|
|
|
|
NotificationCount: 1,
|
2022-08-18 13:11:05 +01:00
|
|
|
CanonicalisedName: "foo",
|
2022-08-16 15:56:16 +01:00
|
|
|
},
|
2023-05-24 15:50:53 +01:00
|
|
|
LastInterestedEventTimestamps: map[string]uint64{listKey: 700},
|
2022-08-16 15:56:16 +01:00
|
|
|
},
|
|
|
|
{
|
|
|
|
RoomMetadata: internal.RoomMetadata{
|
2023-05-23 17:25:35 +01:00
|
|
|
RoomID: room2,
|
2022-08-16 15:56:16 +01:00
|
|
|
},
|
|
|
|
UserRoomData: caches.UserRoomData{
|
|
|
|
HighlightCount: 2,
|
|
|
|
NotificationCount: 2,
|
2022-08-18 13:11:05 +01:00
|
|
|
CanonicalisedName: "foo2",
|
2022-08-16 15:56:16 +01:00
|
|
|
},
|
2023-05-24 15:50:53 +01:00
|
|
|
LastInterestedEventTimestamps: map[string]uint64{listKey: 600},
|
2022-08-16 15:56:16 +01:00
|
|
|
},
|
|
|
|
}
|
refactor: add RoomFinder and use it in InternalRequestLists
This is part of a series of refactors aimed to improve the performance
and complexity of calculating list deltas, which up until now exists in
its current form due to organic growth of the codebase.
This specific refactor introduces a new interface `RoomFinder` which
can map room IDs to `*RoomConnMetadata` which is used by `ConnState`.
All the sliding sync lists now use the `RoomFinder` instead of keeping
their own copies of `RoomConnMetadata`, meaning per-connection, rooms
just have 1 copy in-memory. This cuts down on memory usage as well as
cuts down on GC churn as we would constantly be replacing N rooms for
each update, where N is the total number of lists on that connection.
For Element-Web, N=7 currently to handle Favourites, Low Priority, DMs,
Rooms, Spaces, Invites, Search. This also has the benefit of creating
a single source of truth in `InternalRequestLists.allRooms` which can
be updated once and then a list of list deltas can be calculated off
the back of that. Previously, `allRooms` was _only_ used to seed new
lists, which created a weird imbalance as we would need to update both
`allRooms` _and_ each `FilteredSortableRooms` to keep things in-sync.
This refactor is incomplete in its present form, as we need to make
use of the new `RoomDelta` struct to efficiently package list updates.
2022-08-26 10:09:41 +01:00
|
|
|
f := newFinder(rooms)
|
2023-05-24 15:50:53 +01:00
|
|
|
sr := NewSortableRooms(f, listKey, f.roomIDs)
|
2022-08-16 15:56:16 +01:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|
2022-12-14 18:53:55 +00:00
|
|
|
|
|
|
|
// dedicated test as it relies on multiple fields
|
|
|
|
func TestSortByNotificationLevel(t *testing.T) {
|
2023-05-24 15:50:53 +01:00
|
|
|
const listKey = "my_list"
|
2022-12-14 18:53:55 +00:00
|
|
|
// 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{
|
2023-05-23 17:25:35 +01:00
|
|
|
Encrypted: false,
|
2022-12-14 18:53:55 +00:00
|
|
|
},
|
|
|
|
UserRoomData: caches.UserRoomData{
|
|
|
|
HighlightCount: 1,
|
|
|
|
NotificationCount: 0,
|
|
|
|
},
|
2023-05-24 15:50:53 +01:00
|
|
|
LastInterestedEventTimestamps: map[string]uint64{listKey: 1},
|
2022-12-14 18:53:55 +00:00
|
|
|
},
|
|
|
|
roomUnencHCNC: {
|
|
|
|
RoomMetadata: internal.RoomMetadata{
|
2023-05-23 17:25:35 +01:00
|
|
|
Encrypted: false,
|
2022-12-14 18:53:55 +00:00
|
|
|
},
|
|
|
|
UserRoomData: caches.UserRoomData{
|
|
|
|
HighlightCount: 1,
|
|
|
|
NotificationCount: 1,
|
|
|
|
},
|
2023-05-24 15:50:53 +01:00
|
|
|
LastInterestedEventTimestamps: map[string]uint64{listKey: 2},
|
2022-12-14 18:53:55 +00:00
|
|
|
},
|
|
|
|
roomUnencNC: {
|
|
|
|
RoomMetadata: internal.RoomMetadata{
|
2023-05-23 17:25:35 +01:00
|
|
|
Encrypted: false,
|
2022-12-14 18:53:55 +00:00
|
|
|
},
|
|
|
|
UserRoomData: caches.UserRoomData{
|
|
|
|
HighlightCount: 0,
|
|
|
|
NotificationCount: 1,
|
|
|
|
},
|
2023-05-24 15:50:53 +01:00
|
|
|
LastInterestedEventTimestamps: map[string]uint64{listKey: 3},
|
2022-12-14 18:53:55 +00:00
|
|
|
},
|
|
|
|
roomUnenc: {
|
|
|
|
RoomMetadata: internal.RoomMetadata{
|
2023-05-23 17:25:35 +01:00
|
|
|
Encrypted: false,
|
2022-12-14 18:53:55 +00:00
|
|
|
},
|
|
|
|
UserRoomData: caches.UserRoomData{
|
|
|
|
HighlightCount: 0,
|
|
|
|
NotificationCount: 0,
|
|
|
|
},
|
2023-05-24 15:50:53 +01:00
|
|
|
LastInterestedEventTimestamps: map[string]uint64{listKey: 4},
|
2022-12-14 18:53:55 +00:00
|
|
|
},
|
|
|
|
roomEncHC: {
|
|
|
|
RoomMetadata: internal.RoomMetadata{
|
2023-05-23 17:25:35 +01:00
|
|
|
Encrypted: true,
|
2022-12-14 18:53:55 +00:00
|
|
|
},
|
|
|
|
UserRoomData: caches.UserRoomData{
|
|
|
|
HighlightCount: 1,
|
|
|
|
NotificationCount: 0,
|
|
|
|
},
|
2023-05-24 15:50:53 +01:00
|
|
|
LastInterestedEventTimestamps: map[string]uint64{listKey: 5},
|
2022-12-14 18:53:55 +00:00
|
|
|
},
|
|
|
|
roomEncHCNC: {
|
|
|
|
RoomMetadata: internal.RoomMetadata{
|
2023-05-23 17:25:35 +01:00
|
|
|
Encrypted: true,
|
2022-12-14 18:53:55 +00:00
|
|
|
},
|
|
|
|
UserRoomData: caches.UserRoomData{
|
|
|
|
HighlightCount: 1,
|
|
|
|
NotificationCount: 1,
|
|
|
|
},
|
2023-05-24 15:50:53 +01:00
|
|
|
LastInterestedEventTimestamps: map[string]uint64{listKey: 6},
|
2022-12-14 18:53:55 +00:00
|
|
|
},
|
|
|
|
roomEncNC: {
|
|
|
|
RoomMetadata: internal.RoomMetadata{
|
2023-05-23 17:25:35 +01:00
|
|
|
RoomID: roomEncNC,
|
|
|
|
Encrypted: true,
|
2022-12-14 18:53:55 +00:00
|
|
|
},
|
|
|
|
UserRoomData: caches.UserRoomData{
|
|
|
|
HighlightCount: 0,
|
|
|
|
NotificationCount: 1,
|
|
|
|
},
|
2023-05-24 15:50:53 +01:00
|
|
|
LastInterestedEventTimestamps: map[string]uint64{listKey: 7},
|
2022-12-14 18:53:55 +00:00
|
|
|
},
|
|
|
|
roomEnc: {
|
|
|
|
RoomMetadata: internal.RoomMetadata{
|
2023-05-23 17:25:35 +01:00
|
|
|
RoomID: roomEnc,
|
|
|
|
Encrypted: true,
|
2022-12-14 18:53:55 +00:00
|
|
|
},
|
|
|
|
UserRoomData: caches.UserRoomData{
|
|
|
|
HighlightCount: 0,
|
|
|
|
NotificationCount: 0,
|
|
|
|
},
|
2023-05-24 15:50:53 +01:00
|
|
|
LastInterestedEventTimestamps: map[string]uint64{listKey: 8},
|
2022-12-14 18:53:55 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
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)
|
2023-05-24 15:50:53 +01:00
|
|
|
sr := NewSortableRooms(f, listKey, roomIDs)
|
2022-12-14 18:53:55 +00:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|