Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/single_sdk_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ jobs:
ln -s . complement-crypto

# Setup code we always need
# If you're bumping the image version here, don't forget to bump it in ./tests.yaml and the
# README as well!
- name: Pull synapse service v1.115.0 and mitmproxy
shell: bash
run: |
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ jobs:
./install_uniffi_bindgen_go.sh && ./rebuild_rust_sdk.sh ./rust-sdk

# Temporary: as it takes 3m to build the complement synapse image >:(
# If you're bumping the image version here, don't forget to bump it in ./single_sdk_tests.yml
# and the README as well!
- name: Pull synapse service v1.115.0 and mitmproxy
shell: bash
run: |
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ js-sdk/dist
/internal/api/js/chrome/dist
/internal/api/js/js-sdk/dist/
/internal/api/js/js-sdk/node_modules/
/internal/api/rust/matrix_sdk*
/internal/tests/logs/
__pycache__
/rust-sdk/
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ The [version] is split into the URL and TAG|BRANCH then fed directly into 'git c

### Running

Find a complement-compatible homeserver image. If you don't care which image is used, use `ghcr.io/matrix-org/synapse-service:v1.114.0`
Find a complement-compatible homeserver image. If you don't care which image is used, use `ghcr.io/matrix-org/synapse-service:v1.115.0`
which will Just Work out-of-the-box.

To run only rust tests:
Expand Down
89 changes: 46 additions & 43 deletions internal/api/rust/rust.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,10 @@ const (
const ProcessNameNSE string = "NSE"

type RustRoomInfo struct {
stream *matrix_sdk_ffi.TaskHandle
room *matrix_sdk_ffi.Room
timeline []*api.Event
stream *matrix_sdk_ffi.TaskHandle
room *matrix_sdk_ffi.Room
timeline []*api.Event
ui_timeline *matrix_sdk_ffi.Timeline
}

type RustClient struct {
Expand Down Expand Up @@ -203,7 +204,7 @@ func (c *RustClient) Login(t ct.TestLike, opts api.ClientCreationOpts) error {
if err != nil {
return fmt.Errorf("Client.Login failed: %s", err)
}
// let the client upload device keys and OTKs
// let the client upload device keys and one-time keys
e := c.FFIClient.Encryption()
e.WaitForE2eeInitializationTasks()
e.Destroy()
Expand Down Expand Up @@ -326,8 +327,8 @@ func (c *RustClient) Close(t ct.TestLike) {

func (c *RustClient) GetEvent(t ct.TestLike, roomID, eventID string) (*api.Event, error) {
t.Helper()
room := c.findRoom(t, roomID)
timelineItem, err := mustGetTimeline(t, room).GetEventTimelineItemByEventId(eventID)
_, ui_timeline := c.findRoom(t, roomID)
timelineItem, err := ui_timeline.GetEventTimelineItemByEventId(eventID)
if err != nil {
return nil, fmt.Errorf("failed to GetEventTimelineItemByEventId(%s): %s", eventID, err)
}
Expand Down Expand Up @@ -378,10 +379,10 @@ func (c *RustClient) StartSyncing(t ct.TestLike) (stopSyncing func(), err error)
// track new rooms when they are made
allRoomsListener := newGenericStateListener[[]matrix_sdk_ffi.RoomListEntriesUpdate]()
go func() {
var allRooms DynamicSlice[*matrix_sdk_ffi.RoomListItem]
var allRooms DynamicSlice[*matrix_sdk_ffi.Room]
for !allRoomsListener.isClosed.Load() {
updates := <-allRoomsListener.ch
var newEntries []*matrix_sdk_ffi.RoomListItem
var newEntries []*matrix_sdk_ffi.Room
for _, update := range updates {
switch x := update.(type) {
case matrix_sdk_ffi.RoomListEntriesUpdateAppend:
Expand Down Expand Up @@ -464,14 +465,14 @@ func (c *RustClient) StartSyncing(t ct.TestLike) (stopSyncing func(), err error)
// provide a bogus room ID.
func (c *RustClient) IsRoomEncrypted(t ct.TestLike, roomID string) (bool, error) {
t.Helper()
r := c.findRoom(t, roomID)
r, _ := c.findRoom(t, roomID)
if r == nil {
rooms := c.FFIClient.Rooms()
return false, fmt.Errorf("failed to find room %s, got %d rooms", roomID, len(rooms))
}
encryptionState, err := r.LatestEncryptionState()
if err != nil {
err = fmt.Errorf("IsRoomEncrpted(rust): %s", err)
err = fmt.Errorf("IsRoomEncrypted(rust): %s", err)
return false, err
}
return encryptionState == matrix_sdk_base.EncryptionStateEncrypted, nil
Expand Down Expand Up @@ -541,7 +542,7 @@ func (c *RustClient) SendMessage(t ct.TestLike, roomID, text string) (eventID st
// we need a timeline listener before we can send messages, AND that listener must be attached to the
// same *Room you call .Send on :S
c.ensureListening(t, roomID)
r := c.findRoom(t, roomID)
r, timeline := c.findRoom(t, roomID)
cancel := c.roomsListener.AddListener(func(broadcastRoomID string) bool {
if roomID != broadcastRoomID {
return false
Expand Down Expand Up @@ -573,9 +574,8 @@ func (c *RustClient) SendMessage(t ct.TestLike, roomID, text string) (eventID st
err = fmt.Errorf("SendMessage(rust) %s: failed to find room %s", c.userID, roomID)
return
}
timeline, err := r.Timeline()
if err != nil {
err = fmt.Errorf("SendMessage(rust) %s: %s", c.userID, err)
if timeline == nil {
err = fmt.Errorf("SendMessage(rust) %s: failed to get timeline %s", c.userID, roomID)
return
}
timeline.Send(matrix_sdk_ffi.MessageEventContentFromHtml(text, text))
Expand All @@ -590,17 +590,17 @@ func (c *RustClient) SendMessage(t ct.TestLike, roomID, text string) (eventID st

func (c *RustClient) InviteUser(t ct.TestLike, roomID, userID string) error {
t.Helper()
r := c.findRoom(t, roomID)
r, _ := c.findRoom(t, roomID)
return r.InviteUserById(userID)
}

func (c *RustClient) Backpaginate(t ct.TestLike, roomID string, count int) error {
t.Helper()
r := c.findRoom(t, roomID)
if r == nil {
return fmt.Errorf("Backpaginate: cannot find room %s", roomID)
_, timeline := c.findRoom(t, roomID)
if timeline == nil {
return fmt.Errorf("Backpaginate: cannot find timeline for room %s", roomID)
}
_, err := mustGetTimeline(t, r).PaginateBackwards(uint16(count))
_, err := timeline.PaginateBackwards(uint16(count))
if err != nil {
return fmt.Errorf("cannot PaginateBackwards in %s: %s", roomID, err)
}
Expand All @@ -611,42 +611,39 @@ func (c *RustClient) UserID() string {
return c.userID
}

func (c *RustClient) findRoomInCache(roomID string) *matrix_sdk_ffi.Room {
func (c *RustClient) findRoomInCache(roomID string) (*matrix_sdk_ffi.Room, *matrix_sdk_ffi.Timeline) {
c.roomsMu.RLock()
defer c.roomsMu.RUnlock()
// do we have a reference to it already?
roomInfo := c.rooms[roomID]
if roomInfo != nil {
return roomInfo.room
return roomInfo.room, roomInfo.ui_timeline
}
return nil
return nil, nil
}

// findRoom tries to find the room in the FFI client. Has a cache of already found rooms to ensure
// the same pointer is always returned for the same room.
func (c *RustClient) findRoom(t ct.TestLike, roomID string) *matrix_sdk_ffi.Room {
func (c *RustClient) findRoom(t ct.TestLike, roomID string) (*matrix_sdk_ffi.Room, *matrix_sdk_ffi.Timeline) {
t.Helper()
room := c.findRoomInCache(roomID)
room, ui_timeline := c.findRoomInCache(roomID)
if room != nil {
return room
return room, ui_timeline
}
// try to find it in all_rooms
if c.allRooms != nil {
roomListItem, err := c.allRooms.Room(roomID)
room, err := c.allRooms.Room(roomID)
if err != nil {
c.Logf(t, "allRooms.Room(%s) err: %s", roomID, err)
} else if roomListItem != nil {
room, err := c.FFIClient.GetRoom(roomID)
if err != nil {
c.Logf(t, "allRooms.FullRoom(%s) err: %s", roomID, err)
} else {
c.roomsMu.Lock()
c.rooms[roomID] = &RustRoomInfo{
room: *room,
}
c.roomsMu.Unlock()
return *room
} else if room != nil {
c.roomsMu.Lock()
ui_timeline := mustGetTimeline(t, room)
c.rooms[roomID] = &RustRoomInfo{
room: room,
ui_timeline: ui_timeline,
}
c.roomsMu.Unlock()
return room, ui_timeline
}
}
// try to find it from FFI
Expand All @@ -657,17 +654,20 @@ func (c *RustClient) findRoom(t ct.TestLike, roomID string) *matrix_sdk_ffi.Room
_, exists := c.rooms[rid]
if !exists {
c.roomsMu.Lock()
room := rooms[i]
ui_timeline := mustGetTimeline(t, room)
c.rooms[rid] = &RustRoomInfo{
room: rooms[i],
room: room,
ui_timeline: ui_timeline,
}
c.roomsMu.Unlock()
}
if r.Id() == roomID {
return c.rooms[rid].room
return c.rooms[rid].room, c.rooms[rid].ui_timeline
}
}
// we really don't know about this room yet
return nil
return nil, nil
}

func (c *RustClient) Logf(t ct.TestLike, format string, args ...interface{}) {
Expand All @@ -684,14 +684,14 @@ func (c *RustClient) logToFile(t ct.TestLike, format string, args ...interface{}

func (c *RustClient) ensureListening(t ct.TestLike, roomID string) {
t.Helper()
r := c.findRoom(t, roomID)
r, ui_timeline := c.findRoom(t, roomID)
if r == nil {
// we allow the room to not exist yet. If this happens, wait until we see the room before continuing
c.roomsListener.AddListener(func(broadcastRoomID string) bool {
if broadcastRoomID != roomID {
return false
}
if room := c.findRoom(t, roomID); room != nil {
if room, _ := c.findRoom(t, roomID); room != nil {
// Do this asynchronously because adding a timeline listener is done synchronously
// which will cause "signal arrived during cgo execution" if it happens within
// this rooms listener callback.
Expand All @@ -704,7 +704,9 @@ func (c *RustClient) ensureListening(t ct.TestLike, roomID string) {
})
return
}

must.NotEqual(t, r, nil, fmt.Sprintf("room %s does not exist", roomID))
must.NotEqual(t, ui_timeline, nil, fmt.Sprintf("ui_timeline for room %s does not exist", roomID))

info := c.rooms[roomID]
if info != nil && info.stream != nil {
Expand All @@ -718,7 +720,8 @@ func (c *RustClient) ensureListening(t ct.TestLike, roomID string) {
// as setting the initial entries clears the timeline, which can then result in test flakes.
waiter := helpers.NewWaiter()
c.rooms[roomID].timeline = make([]*api.Event, 0)
result := mustGetTimeline(t, r).AddListener(&timelineListener{fn: func(diff []*matrix_sdk_ffi.TimelineDiff) {

result := ui_timeline.AddListener(&timelineListener{fn: func(diff []*matrix_sdk_ffi.TimelineDiff) {
defer waiter.Finish()
timeline := c.rooms[roomID].timeline
var newEvents []*api.Event
Expand Down
Loading