mirror of
https://github.com/matrix-org/sliding-sync.git
synced 2025-03-10 13:37:11 +00:00
137 lines
4.3 KiB
Go
137 lines
4.3 KiB
Go
package syncv3_test
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"testing"
|
|
|
|
"github.com/matrix-org/complement/client"
|
|
"github.com/matrix-org/sliding-sync/sync3"
|
|
"github.com/matrix-org/sliding-sync/testutils/m"
|
|
)
|
|
|
|
func TestTransactionIDsAppear(t *testing.T) {
|
|
c := registerNewUser(t)
|
|
roomID := c.MustCreateRoom(t, map[string]interface{}{})
|
|
sendRes := c.MustDo(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "send", "m.room.message", "foobar"},
|
|
client.WithJSONBody(t, map[string]interface{}{
|
|
"msgtype": "m.text",
|
|
"body": "Hello World!",
|
|
}))
|
|
body := client.ParseJSON(t, sendRes)
|
|
eventID := client.GetJSONFieldStr(t, body, "event_id")
|
|
|
|
// ensure initial syncs include the txn id
|
|
res := c.SlidingSync(t, sync3.Request{
|
|
Lists: map[string]sync3.RequestList{
|
|
"a": {
|
|
Ranges: [][2]int64{{0, 10}},
|
|
RoomSubscription: sync3.RoomSubscription{TimelineLimit: 1},
|
|
},
|
|
},
|
|
})
|
|
|
|
// we cannot use MatchTimeline here because the Unsigned section contains 'age' which is not
|
|
// deterministic and MatchTimeline does not do partial matches.
|
|
|
|
m.MatchResponse(t, res, m.MatchRoomSubscriptionsStrict(map[string][]m.RoomMatcher{
|
|
roomID: {
|
|
matchTransactionID(t, eventID, "foobar"),
|
|
},
|
|
}))
|
|
|
|
// now live stream another event and ensure that too has a txn ID
|
|
sendRes = c.MustDo(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "send", "m.room.message", "foobar2"},
|
|
client.WithJSONBody(t, map[string]interface{}{
|
|
"msgtype": "m.text",
|
|
"body": "Hello World 2!",
|
|
}))
|
|
body = client.ParseJSON(t, sendRes)
|
|
eventID = client.GetJSONFieldStr(t, body, "event_id")
|
|
|
|
res = c.SlidingSyncUntilEvent(t, res.Pos, sync3.Request{}, roomID, Event{ID: eventID})
|
|
m.MatchResponse(t, res, m.MatchRoomSubscriptionsStrict(map[string][]m.RoomMatcher{
|
|
roomID: {
|
|
matchTransactionID(t, eventID, "foobar2"),
|
|
},
|
|
}))
|
|
|
|
}
|
|
|
|
// This test has 1 poller expecting a txn ID and 10 others that won't see one.
|
|
// We test that sending device sees a txnID. Without the TxnIDWaiter logic in place,
|
|
// this test is likely (but not guaranteed) to fail.
|
|
func TestTransactionIDsAppearWithMultiplePollers(t *testing.T) {
|
|
alice := registerNamedUser(t, "alice")
|
|
|
|
t.Log("Alice creates a room and syncs until she sees it.")
|
|
roomID := alice.MustCreateRoom(t, map[string]interface{}{})
|
|
res := alice.SlidingSync(t, sync3.Request{
|
|
Lists: map[string]sync3.RequestList{
|
|
"a": {
|
|
RoomSubscription: sync3.RoomSubscription{
|
|
TimelineLimit: 10,
|
|
},
|
|
Ranges: sync3.SliceRanges{{0, 20}},
|
|
},
|
|
},
|
|
})
|
|
m.MatchResponse(t, res, m.MatchRoomSubscription(roomID))
|
|
|
|
t.Log("Alice makes other devices and starts them syncing.")
|
|
for i := 0; i < 10; i++ {
|
|
device := *alice
|
|
device.Login(t, "password", fmt.Sprintf("device_%d", i))
|
|
device.SlidingSync(t, sync3.Request{
|
|
Lists: map[string]sync3.RequestList{
|
|
"a": {
|
|
RoomSubscription: sync3.RoomSubscription{
|
|
TimelineLimit: 10,
|
|
},
|
|
Ranges: sync3.SliceRanges{{0, 20}},
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
t.Log("Alice sends a message with a transaction ID.")
|
|
const txnID = "foobar"
|
|
sendRes := alice.MustDo(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "send", "m.room.message", txnID},
|
|
client.WithJSONBody(t, map[string]interface{}{
|
|
"msgtype": "m.text",
|
|
"body": "Hello, world!",
|
|
}))
|
|
body := client.ParseJSON(t, sendRes)
|
|
eventID := client.GetJSONFieldStr(t, body, "event_id")
|
|
|
|
t.Log("Alice syncs on her main devices until she sees her message.")
|
|
res = alice.SlidingSyncUntilEventID(t, res.Pos, roomID, eventID)
|
|
|
|
m.MatchResponse(t, res, m.MatchRoomSubscription(roomID, matchTransactionID(t, eventID, txnID)))
|
|
}
|
|
|
|
func matchTransactionID(t *testing.T, eventID, txnID string) m.RoomMatcher {
|
|
return func(r sync3.Room) error {
|
|
for _, ev := range r.Timeline {
|
|
var got Event
|
|
if err := json.Unmarshal(ev, &got); err != nil {
|
|
return fmt.Errorf("failed to unmarshal event: %s", err)
|
|
}
|
|
if got.ID != eventID {
|
|
continue
|
|
}
|
|
tx, ok := got.Unsigned["transaction_id"]
|
|
if !ok {
|
|
return fmt.Errorf("unsigned block for %s has no transaction_id", eventID)
|
|
}
|
|
gotTxnID := tx.(string)
|
|
if gotTxnID != txnID {
|
|
return fmt.Errorf("wrong transaction_id, got %s want %s", gotTxnID, txnID)
|
|
}
|
|
t.Logf("%s has txn ID %s", eventID, gotTxnID)
|
|
return nil
|
|
}
|
|
return fmt.Errorf("not found event %s", eventID)
|
|
}
|
|
}
|