forked from matrix-org/complement
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This adds two tests, which check the current spec behaviour of transaction IDs, which are that they are scoped to a series of access tokens, and not the device ID. The first test highlight this behaviour, by logging in with refresh token enabled, sending an event, using the refresh token and syncing with the new access token. On the sync, the transaction ID should be there, but currently in Synapse it is not. The second test highlight that the transaction ID is not scoped to the device ID, by logging in twice with the same device ID, sending an event with the first access token, and syncing with the second access token. In that case, the sync should not contain the transaction ID, but I think it's the case in HS implementations which use the device ID to scope the transaction IDs, like Conduit. Related: matrix-org/matrix-spec#1133, matrix-org/matrix-spec#1236, matrix-org/synapse#13064 and matrix-org/synapse#13083
- Loading branch information
Showing
3 changed files
with
196 additions
and
22 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
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
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,96 @@ | ||
package csapi_tests | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/matrix-org/complement/internal/b" | ||
"github.com/matrix-org/complement/internal/client" | ||
"github.com/tidwall/gjson" | ||
) | ||
|
||
// TestTxnAfterRefresh tests that when a client refreshes its access token, | ||
// it still gets back a transaction ID in the sync response. | ||
func TestTxnAfterRefresh(t *testing.T) { | ||
deployment := Deploy(t, b.BlueprintCleanHS) | ||
defer deployment.Destroy(t) | ||
|
||
deployment.RegisterUser(t, "hs1", "alice", "password", false) | ||
|
||
c := deployment.Client(t, "hs1", "") | ||
|
||
var refreshToken string | ||
c.UserID, c.AccessToken, refreshToken, c.DeviceID, _ = c.LoginUserWithRefreshToken(t, "alice", "password") | ||
|
||
// Create a room where we can send events. | ||
roomID := c.CreateRoom(t, map[string]interface{}{}) | ||
|
||
// Let's send an event, and wait for it to appear in the sync. | ||
eventID := c.SendEventUnsynced(t, roomID, b.Event{ | ||
Type: "m.room.message", | ||
Content: map[string]interface{}{ | ||
"msgtype": "m.text", | ||
"body": "first", | ||
}, | ||
}) | ||
|
||
// When syncing, we should find the event and it should have a transaction ID. | ||
c.MustSyncUntil(t, client.SyncReq{}, client.SyncTimelineHas(roomID, func(r gjson.Result) bool { | ||
return r.Get("event_id").Str == eventID && r.Get("unsigned.transaction_id").Exists() | ||
})) | ||
|
||
// Now do the same, but refresh the token before syncing. | ||
eventID = c.SendEventUnsynced(t, roomID, b.Event{ | ||
Type: "m.room.message", | ||
Content: map[string]interface{}{ | ||
"msgtype": "m.text", | ||
"body": "second", | ||
}, | ||
}) | ||
|
||
// Use the refresh token to get a new access token. | ||
c.AccessToken, refreshToken, _ = c.ConsumeRefreshToken(t, refreshToken) | ||
|
||
// When syncing, we should find the event and it should also have a transaction ID. | ||
c.MustSyncUntil(t, client.SyncReq{}, client.SyncTimelineHas(roomID, func(r gjson.Result) bool { | ||
return r.Get("event_id").Str == eventID && r.Get("unsigned.transaction_id").Exists() | ||
})) | ||
} | ||
|
||
// TestTxnScope tests that transaction IDs are scoped to the access token, not the device | ||
func TestTxnScope(t *testing.T) { | ||
deployment := Deploy(t, b.BlueprintCleanHS) | ||
defer deployment.Destroy(t) | ||
|
||
deployment.RegisterUser(t, "hs1", "alice", "password", false) | ||
|
||
// Create a first client, which allocates a device ID. | ||
c1 := deployment.Client(t, "hs1", "") | ||
c1.UserID, c1.AccessToken, c1.DeviceID = c1.LoginUser(t, "alice", "password") | ||
|
||
// Create a second client, inheriting the same device ID. | ||
c2 := deployment.Client(t, "hs1", "") | ||
c2.UserID, c2.AccessToken = c2.LoginUserWithDeviceID(t, "alice", "password", c1.DeviceID) | ||
c2.DeviceID = c1.DeviceID | ||
|
||
// Create a room where we can send events. | ||
roomID := c1.CreateRoom(t, map[string]interface{}{}) | ||
|
||
// Let's send an event, and wait for it to appear in the timeline. | ||
eventID := c1.SendEventUnsynced(t, roomID, b.Event{ | ||
Type: "m.room.message", | ||
Content: map[string]interface{}{ | ||
"msgtype": "m.text", | ||
"body": "first", | ||
}, | ||
}) | ||
|
||
// When syncing, we should find the event and it should have a transaction ID on the first client. | ||
c1.MustSyncUntil(t, client.SyncReq{}, client.SyncTimelineHas(roomID, func(r gjson.Result) bool { | ||
return r.Get("event_id").Str == eventID && r.Get("unsigned.transaction_id").Exists() | ||
})) | ||
|
||
// When syncing, we should find the event and it should *not* have a transaction ID on the second client. | ||
c2.MustSyncUntil(t, client.SyncReq{}, client.SyncTimelineHas(roomID, func(r gjson.Result) bool { | ||
return r.Get("event_id").Str == eventID && !r.Get("unsigned.transaction_id").Exists() | ||
})) | ||
} |