Skip to content

Commit

Permalink
Add invite tests; RR skipped for now
Browse files Browse the repository at this point in the history
  • Loading branch information
kegsay committed Nov 3, 2023
1 parent 7b91916 commit d90ba3d
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 24 deletions.
2 changes: 2 additions & 0 deletions internal/api/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ type Client interface {
// Wait until an event with the given body is seen. Not all impls expose event IDs
// hence needing to use body as a proxy.
WaitUntilEventInRoom(t *testing.T, roomID, wantBody string) Waiter
// Backpaginate in this room by `count` events.
MustBackpaginate(t *testing.T, roomID string, count int)
Type() ClientType
}

Expand Down
26 changes: 21 additions & 5 deletions internal/api/js.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ func NewJSClient(t *testing.T, opts ClientCreationOpts) (Client, error) {
continue
}
// TODO: debug mode only?
fmt.Printf("[%s] console.log %s\n", opts.UserID, s)
colorify("[%s] console.log %s\n", opts.UserID, s)

if strings.HasPrefix(s, CONSOLE_LOG_CONTROL_STRING) {
val := strings.TrimPrefix(s, CONSOLE_LOG_CONTROL_STRING)
Expand Down Expand Up @@ -186,12 +186,22 @@ func (c *JSClient) SendMessage(t *testing.T, roomID, text string) {
must.NotError(t, "failed to sendMessage", err)
}

func (c *JSClient) MustBackpaginate(t *testing.T, roomID string, count int) {
chrome.MustAwaitExecute(t, c.ctx, fmt.Sprintf(
`window.__client.scrollback(window.__client.getRoom("%s"), %d);`, roomID, count,
))
}

func (c *JSClient) WaitUntilEventInRoom(t *testing.T, roomID, wantBody string) Waiter {
// TODO: check if this event already exists
exists := chrome.MustExecuteInto[bool](t, c.ctx, fmt.Sprintf(
`window.__client.getRoom("%s").getLiveTimeline().getEvents().map((e)=>{return e.getContent().body}).includes("%s");`, roomID, wantBody,
))

return &jsTimelineWaiter{
roomID: roomID,
wantBody: wantBody,
client: c,
exists: exists,
}
}

Expand All @@ -211,9 +221,13 @@ type jsTimelineWaiter struct {
roomID string
wantBody string
client *JSClient
exists bool
}

func (w *jsTimelineWaiter) Wait(t *testing.T, s time.Duration) {
if w.exists {
return
}
updates := make(chan bool, 3)
cancel := w.client.listenForUpdates(func(roomID, gotText string) {
if w.roomID != roomID {
Expand Down Expand Up @@ -241,8 +255,10 @@ func (w *jsTimelineWaiter) Wait(t *testing.T, s time.Duration) {
}
}

func (w *jsTimelineWaiter) callback(gotRoomID, gotText string) {
if w.roomID == gotRoomID && w.wantBody == gotText {
const ansiYellowForeground = "\x1b[33m"
const ansiResetForeground = "\x1b[39m"

}
func colorify(format string, args ...any) {
format = ansiYellowForeground + format + ansiResetForeground
fmt.Printf(format, args...)
}
60 changes: 48 additions & 12 deletions internal/api/rust.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,16 @@ import (
"github.com/matrix-org/complement/must"
)

func init() {
matrix_sdk_ffi.SetupTracing(matrix_sdk_ffi.TracingConfiguration{
WriteToStdoutOrSystem: true,
Filter: "debug",
})
}

type RustRoomInfo struct {
attachedListener bool
room *matrix_sdk_ffi.Room
timeline []*Event
}

Expand Down Expand Up @@ -98,28 +106,43 @@ func (c *RustClient) SendMessage(t *testing.T, roomID, text string) {
r.Send(matrix_sdk_ffi.MessageEventContentFromHtml(text, text))
}

func (c *RustClient) MustBackpaginate(t *testing.T, roomID string, count int) {
t.Helper()
t.Logf("[%s] MustBackpaginate %d %s", c.userID, count, roomID)
r := c.findRoom(roomID)
must.NotEqual(t, r, nil, "unknown room")
must.NotError(t, "failed to backpaginate", r.PaginateBackwards(matrix_sdk_ffi.PaginationOptionsSingleRequest{
EventLimit: uint16(count),
}))
}

func (c *RustClient) findRoom(roomID string) *matrix_sdk_ffi.Room {
rooms := c.FFIClient.Rooms()
for _, r := range rooms {
for i, r := range rooms {
rid := r.Id()
// ensure we only store rooms once
_, exists := c.rooms[rid]
if !exists {
c.rooms[rid] = &RustRoomInfo{
room: rooms[i],
}
}
if r.Id() == roomID {
return r
return c.rooms[rid].room
}
}
return nil
}

func (c *RustClient) ensureListening(t *testing.T, roomID string) *matrix_sdk_ffi.Room {
info, ok := c.rooms[roomID]
if !ok {
info = &RustRoomInfo{}
}
if info.attachedListener {
// TODO: will this work - can you send msgs twice?
return c.findRoom(roomID)
}
r := c.findRoom(roomID)
must.NotEqual(t, r, nil, fmt.Sprintf("room %s does not exist", roomID))
c.rooms[roomID] = info

info := c.rooms[roomID]
if info.attachedListener {
return r
}

t.Logf("[%s]AddTimelineListenerBlocking[%s]", c.userID, roomID)
// we need a timeline listener before we can send messages
r.AddTimelineListenerBlocking(&timelineListener{fn: func(diff []*matrix_sdk_ffi.TimelineDiff) {
Expand All @@ -136,7 +159,15 @@ func (c *RustClient) ensureListening(t *testing.T, roomID string) *matrix_sdk_ff
t.Logf("TimelineListener[%s] INSERT %d out of bounds of events timeline of size %d", roomID, i, len(timeline))
continue
}
timeline[i] = timelineItemToEvent(insertData.Item)
if timeline[i] != nil {
// shift the item in this position right and insert this item
timeline = append(timeline, nil)
copy(timeline[i+1:], timeline[i:])
timeline[i] = timelineItemToEvent(insertData.Item)
} else {
timeline[i] = timelineItemToEvent(insertData.Item)
}
fmt.Printf("[%s]_______ INSERT %+v\n", c.userID, timeline[i])
case matrix_sdk_ffi.TimelineChangeAppend:
appendItems := d.Append()
if appendItems == nil {
Expand All @@ -145,6 +176,7 @@ func (c *RustClient) ensureListening(t *testing.T, roomID string) *matrix_sdk_ff
for _, item := range *appendItems {
ev := timelineItemToEvent(item)
timeline = append(timeline, ev)
fmt.Printf("[%s]_______ APPEND %+v\n", c.userID, ev)
}
case matrix_sdk_ffi.TimelineChangePushBack:
pbData := d.PushBack()
Expand All @@ -153,6 +185,7 @@ func (c *RustClient) ensureListening(t *testing.T, roomID string) *matrix_sdk_ff
}
ev := timelineItemToEvent(*pbData)
timeline = append(timeline, ev)
fmt.Printf("[%s]_______ PUSH BACK %+v\n", c.userID, ev)
case matrix_sdk_ffi.TimelineChangeSet:
setData := d.Set()
if setData == nil {
Expand All @@ -164,6 +197,9 @@ func (c *RustClient) ensureListening(t *testing.T, roomID string) *matrix_sdk_ff
continue
}
timeline[i] = timelineItemToEvent(setData.Item)
fmt.Printf("[%s]_______ SET %+v\n", c.userID, timeline[i])
default:
t.Logf("Unhandled TimelineDiff change %v", d.Change())
}
}
c.rooms[roomID].timeline = timeline
Expand Down
31 changes: 24 additions & 7 deletions tests/invite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,16 @@ import (
// This test checks that Bob can decrypt messages sent before he was joined but after he was invited.
// - Alice creates the room. Alice invites Bob.
// - Alice sends an encrypted message.
// - Bob joins the room.
// - Bob joins the room and backpaginates.
// - Ensure Bob can see the decrypted content.
func TestCanSeeMessagesAfterInviteButBeforeJoin(t *testing.T) {
ClientTypeMatrix(t, testCanSeeMessagesAfterInviteButBeforeJoin)
func TestCanDecryptMessagesAfterInviteButBeforeJoin(t *testing.T) {
ClientTypeMatrix(t, testCanDecryptMessagesAfterInviteButBeforeJoin)
}

func testCanSeeMessagesAfterInviteButBeforeJoin(t *testing.T, clientTypeA, clientTypeB api.ClientType) {
func testCanDecryptMessagesAfterInviteButBeforeJoin(t *testing.T, clientTypeA, clientTypeB api.ClientType) {
if clientTypeA == api.ClientTypeRust && clientTypeB == api.ClientTypeRust {
t.Skip("Skipping rust/rust as SS proxy sends invite/join in timeline, omitting the invite msg")
}
// Setup Code
// ----------
deployment := Deploy(t)
Expand Down Expand Up @@ -77,6 +80,10 @@ func testCanSeeMessagesAfterInviteButBeforeJoin(t *testing.T, clientTypeA, clien

// Alice sends the message whilst Bob is still invited.
alice.SendMessage(t, roomID, wantMsgBody)
// wait for SS proxy to get it. Only needed when testing Rust TODO FIXME
// Without this, the join will race with sending the msg and you could end up with the
// message being sent POST join, which breaks the point of this test.
time.Sleep(time.Second)

// Bob joins the room (via Complement, but it shouldn't matter)
csapiBob.MustJoinRoom(t, roomID, []string{"hs1"})
Expand All @@ -86,8 +93,18 @@ func testCanSeeMessagesAfterInviteButBeforeJoin(t *testing.T, clientTypeA, clien
must.Equal(t, isEncrypted, true, "room is not encrypted")
t.Logf("bob room encrypted = %v", isEncrypted)

// TODO: this is sensitive to the timeline limit used on the SDK. If 1, then the message won't
// be here (and will need to be fetched via /messages).
waiter := bob.WaitUntilEventInRoom(t, roomID, wantMsgBody)
// send a sentinel message and wait for it to ensure we are joined and syncing
sentinelBody := "Sentinel"
waiter := bob.WaitUntilEventInRoom(t, roomID, sentinelBody)
alice.SendMessage(t, roomID, sentinelBody)
waiter.Wait(t, 2*time.Second)

// Explicitly ask for a pagination, rather than assuming the SDK will return events
// earlier than the join by default. This is important because:
// - sync v2 (JS SDK) it depends on the timeline limit, which is 20 by default but we don't want to assume.
// - sliding sync (FFI) it won't return events before the join by default, relying on clients using the prev_batch token.
waiter = bob.WaitUntilEventInRoom(t, roomID, wantMsgBody)
bob.MustBackpaginate(t, roomID, 5) // number is arbitrary, just needs to be >=2
waiter.Wait(t, 2*time.Second)
// time.Sleep(time.Hour)
}

0 comments on commit d90ba3d

Please sign in to comment.