This repository has been archived by the owner on Nov 14, 2024. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 676
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add unit tests for history visibility boundaries
- Loading branch information
Showing
2 changed files
with
227 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,214 @@ | ||
package internal | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"math" | ||
"testing" | ||
|
||
rsapi "github.com/matrix-org/dendrite/roomserver/api" | ||
"github.com/matrix-org/dendrite/roomserver/types" | ||
"github.com/matrix-org/dendrite/syncapi/storage" | ||
"github.com/matrix-org/gomatrixserverlib" | ||
"github.com/matrix-org/gomatrixserverlib/spec" | ||
"gotest.tools/v3/assert" | ||
) | ||
|
||
type mockHisVisRoomserverAPI struct { | ||
rsapi.RoomserverInternalAPI | ||
events []*types.HeaderedEvent | ||
roomID string | ||
} | ||
|
||
func (s *mockHisVisRoomserverAPI) QueryMembershipAtEvent(ctx context.Context, roomID spec.RoomID, eventIDs []string, senderID spec.SenderID) (map[string]*types.HeaderedEvent, error) { | ||
if roomID.String() == s.roomID { | ||
membershipMap := map[string]*types.HeaderedEvent{} | ||
|
||
for _, queriedEventID := range eventIDs { | ||
for _, event := range s.events { | ||
if event.EventID() == queriedEventID { | ||
membershipMap[queriedEventID] = event | ||
} | ||
} | ||
} | ||
|
||
return membershipMap, nil | ||
} else { | ||
return nil, fmt.Errorf("room not found: \"%v\"", roomID) | ||
} | ||
} | ||
|
||
func (s *mockHisVisRoomserverAPI) QuerySenderIDForUser(ctx context.Context, roomID spec.RoomID, userID spec.UserID) (*spec.SenderID, error) { | ||
senderID := spec.SenderIDFromUserID(userID) | ||
return &senderID, nil | ||
} | ||
|
||
func (s *mockHisVisRoomserverAPI) QueryUserIDForSender(ctx context.Context, roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) { | ||
userID := senderID.ToUserID() | ||
if userID == nil { | ||
return nil, fmt.Errorf("sender ID not user ID") | ||
} | ||
return userID, nil | ||
} | ||
|
||
type mockDB struct { | ||
storage.DatabaseTransaction | ||
// user ID -> membership (i.e. 'join', 'leave', etc.) | ||
currentMembership map[string]string | ||
roomID string | ||
} | ||
|
||
func (s *mockDB) SelectMembershipForUser(ctx context.Context, roomID string, userID string, pos int64) (string, int, error) { | ||
if roomID == s.roomID { | ||
membership, ok := s.currentMembership[userID] | ||
if !ok { | ||
return spec.Leave, math.MaxInt64, nil | ||
} | ||
return membership, math.MaxInt64, nil | ||
} | ||
|
||
return "", 0, fmt.Errorf("room not found: \"%v\"", roomID) | ||
} | ||
|
||
// Tests logic around history visibility boundaries | ||
// | ||
// Specifically that if a room's history visibility before or after a particular history visibility event | ||
// allows them to see events (a boundary), then the history visibility event itself should be shown | ||
// ( spec: https://spec.matrix.org/v1.8/client-server-api/#server-behaviour-5 ) | ||
// | ||
// This also aims to emulate "Only see history_visibility changes on bounadries" in sytest/tests/30rooms/30history-visibility.pl | ||
func Test_ApplyHistoryVisbility_Boundaries(t *testing.T) { | ||
ctx := context.Background() | ||
|
||
roomID := "!roomid:domain" | ||
|
||
creatorUserID := spec.NewUserIDOrPanic("@creator:domain", false) | ||
otherUserID := spec.NewUserIDOrPanic("@other:domain", false) | ||
roomVersion := gomatrixserverlib.RoomVersionV10 | ||
roomVerImpl := gomatrixserverlib.MustGetRoomVersion(roomVersion) | ||
|
||
eventsJSON := []struct { | ||
id string | ||
json string | ||
}{ | ||
{id: "$create-event", json: fmt.Sprintf(`{ | ||
"type": "m.room.create", "state_key": "", | ||
"room_id": "%v", "sender": "%v", | ||
"content": {"creator": "%v", "room_version": "%v"} | ||
}`, roomID, creatorUserID.String(), creatorUserID.String(), roomVersion)}, | ||
{id: "$creator-joined", json: fmt.Sprintf(`{ | ||
"type": "m.room.member", "state_key": "%v", | ||
"room_id": "%v", "sender": "%v", | ||
"content": {"membership": "join"} | ||
}`, creatorUserID.String(), roomID, creatorUserID.String())}, | ||
{id: "$hisvis-1", json: fmt.Sprintf(`{ | ||
"type": "m.room.history_visibility", "state_key": "", | ||
"room_id": "%v", "sender": "%v", | ||
"content": {"history_visibility": "shared"} | ||
}`, roomID, creatorUserID.String())}, | ||
{id: "$msg-1", json: fmt.Sprintf(`{ | ||
"type": "m.room.message", | ||
"room_id": "%v", "sender": "%v", | ||
"content": {"body": "1"} | ||
}`, roomID, creatorUserID.String())}, | ||
{id: "$hisvis-2", json: fmt.Sprintf(`{ | ||
"type": "m.room.history_visibility", "state_key": "", | ||
"room_id": "%v", "sender": "%v", | ||
"content": {"history_visibility": "joined"}, | ||
"unsigned": {"prev_content": {"history_visibility": "shared"}} | ||
}`, roomID, creatorUserID.String())}, | ||
{id: "$msg-2", json: fmt.Sprintf(`{ | ||
"type": "m.room.message", | ||
"room_id": "%v", "sender": "%v", | ||
"content": {"body": "1"} | ||
}`, roomID, creatorUserID.String())}, | ||
{id: "$hisvis-3", json: fmt.Sprintf(`{ | ||
"type": "m.room.history_visibility", "state_key": "", | ||
"room_id": "%v", "sender": "%v", | ||
"content": {"history_visibility": "invited"}, | ||
"unsigned": {"prev_content": {"history_visibility": "joined"}} | ||
}`, roomID, creatorUserID.String())}, | ||
{id: "$msg-3", json: fmt.Sprintf(`{ | ||
"type": "m.room.message", | ||
"room_id": "%v", "sender": "%v", | ||
"content": {"body": "2"} | ||
}`, roomID, creatorUserID.String())}, | ||
{id: "$hisvis-4", json: fmt.Sprintf(`{ | ||
"type": "m.room.history_visibility", "state_key": "", | ||
"room_id": "%v", "sender": "%v", | ||
"content": {"history_visibility": "shared"}, | ||
"unsigned": {"prev_content": {"history_visibility": "invited"}} | ||
}`, roomID, creatorUserID.String())}, | ||
{id: "$msg-4", json: fmt.Sprintf(`{ | ||
"type": "m.room.message", | ||
"room_id": "%v", "sender": "%v", | ||
"content": {"body": "3"} | ||
}`, roomID, creatorUserID.String())}, | ||
{id: "$other-joined", json: fmt.Sprintf(`{ | ||
"type": "m.room.member", "state_key": "%v", | ||
"room_id": "%v", "sender": "%v", | ||
"content": {"membership": "join"} | ||
}`, otherUserID.String(), roomID, otherUserID.String())}, | ||
} | ||
|
||
events := make([]*types.HeaderedEvent, len(eventsJSON)) | ||
|
||
hisVis := gomatrixserverlib.HistoryVisibilityShared | ||
|
||
for i, eventJSON := range eventsJSON { | ||
pdu, err := roomVerImpl.NewEventFromTrustedJSONWithEventID(eventJSON.id, []byte(eventJSON.json), false) | ||
if err != nil { | ||
t.Fatalf("failed to prepare event %s for test: %s", eventJSON.id, err.Error()) | ||
} | ||
events[i] = &types.HeaderedEvent{PDU: pdu} | ||
|
||
// 'Visibility' should be the visibility of the room just before this event was sent | ||
// (according to processRoomEvent in roomserver/internal/input/input_events.go) | ||
events[i].Visibility = hisVis | ||
if pdu.Type() == spec.MRoomHistoryVisibility { | ||
newHisVis, err := pdu.HistoryVisibility() | ||
if err != nil { | ||
t.Fatalf("failed to prepare history visibility event: %s", err.Error()) | ||
} | ||
hisVis = newHisVis | ||
} | ||
} | ||
|
||
rsAPI := &mockHisVisRoomserverAPI{ | ||
events: events, | ||
roomID: roomID, | ||
} | ||
syncDB := &mockDB{ | ||
roomID: roomID, | ||
currentMembership: map[string]string{ | ||
creatorUserID.String(): spec.Join, | ||
otherUserID.String(): spec.Join, | ||
}, | ||
} | ||
|
||
filteredEvents, err := ApplyHistoryVisibilityFilter(ctx, syncDB, rsAPI, events, nil, otherUserID, "hisVisTest") | ||
if err != nil { | ||
t.Fatalf("ApplyHistoryVisibility returned non-nil error: %s", err.Error()) | ||
} | ||
|
||
filteredEventIDs := make([]string, len(filteredEvents)) | ||
for i, event := range filteredEvents { | ||
filteredEventIDs[i] = event.EventID() | ||
} | ||
|
||
assert.DeepEqual(t, | ||
[]string{ | ||
"$create-event", // Always see m.room.create | ||
"$creator-joined", // Always see membership | ||
"$hisvis-1", // Sets room to shared (technically the room is already shared since shared is default) | ||
"$msg-1", // Room currently 'shared' | ||
"$hisvis-2", // Room changed from 'shared' to 'joined', so boundary event and should be shared | ||
// Other events hidden, as other is not joined yet | ||
// hisvis-3 is also hidden, as it changes from joined to invited, neither of which is visible to other | ||
"$hisvis-4", // Changes from 'invited' to 'shared', so is a boundary event and visible | ||
"$msg-4", // Room is 'shared', so visible | ||
"$other-joined", // other's membership | ||
}, | ||
filteredEventIDs, | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters