Skip to content

Commit 46fa9f0

Browse files
Update to upstream Complement v1.141
2 parents ba7b6e5 + 071d7d8 commit 46fa9f0

File tree

8 files changed

+132
-16
lines changed

8 files changed

+132
-16
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,6 @@ complement
1010
# For direnv users
1111
/.envrc
1212
.direnv/
13+
14+
# devenv users
15+
.devenv/

client/client.go

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"net/url"
1616
"strconv"
1717
"strings"
18+
"sync"
1819
"sync/atomic"
1920
"time"
2021

@@ -48,6 +49,19 @@ type retryUntilParams struct {
4849
// See functions starting with `With...` in this package for more info.
4950
type RequestOpt func(req *http.Request)
5051

52+
type CSAPIOpts struct {
53+
UserID string
54+
AccessToken string
55+
DeviceID string
56+
Password string // if provided
57+
BaseURL string
58+
Client *http.Client
59+
// how long are we willing to wait for MustSyncUntil.... calls
60+
SyncUntilTimeout time.Duration
61+
// True to enable verbose logging
62+
Debug bool
63+
}
64+
5165
type CSAPI struct {
5266
UserID string
5367
AccessToken string
@@ -60,7 +74,22 @@ type CSAPI struct {
6074
// True to enable verbose logging
6175
Debug bool
6276

63-
txnID int64
77+
txnID int64
78+
createRoomMutex *sync.Mutex
79+
}
80+
81+
func NewCSAPI(opts CSAPIOpts) *CSAPI {
82+
return &CSAPI{
83+
UserID: opts.UserID,
84+
AccessToken: opts.AccessToken,
85+
DeviceID: opts.DeviceID,
86+
Password: opts.Password,
87+
BaseURL: opts.BaseURL,
88+
Client: opts.Client,
89+
SyncUntilTimeout: opts.SyncUntilTimeout,
90+
Debug: opts.Debug,
91+
createRoomMutex: &sync.Mutex{},
92+
}
6493
}
6594

6695
// CreateMedia creates an MXC URI for asynchronous media uploads.
@@ -172,6 +201,10 @@ func (c *CSAPI) MustCreateRoom(t ct.TestLike, reqBody map[string]interface{}) st
172201
// CreateRoom creates a room with an optional HTTP request body.
173202
func (c *CSAPI) CreateRoom(t ct.TestLike, body map[string]interface{}) *http.Response {
174203
t.Helper()
204+
// Ensure we don't call /createRoom from the same user in parallel, else we might try to make
205+
// 2 rooms in the same millisecond (same `origin_server_ts`), causing v12 rooms to get the same room ID thus failing the test.
206+
c.createRoomMutex.Lock()
207+
defer c.createRoomMutex.Unlock()
175208
return c.Do(t, "POST", []string{"_matrix", "client", "v3", "createRoom"}, WithJSONBody(t, body))
176209
}
177210

internal/docker/deployment.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -105,13 +105,13 @@ func (d *Deployment) Register(t ct.TestLike, hsName string, opts helpers.Registr
105105
ct.Fatalf(t, "Deployment.Register - HS name '%s' not found", hsName)
106106
return nil
107107
}
108-
client := &client.CSAPI{
108+
client := client.NewCSAPI(client.CSAPIOpts{
109109
BaseURL: dep.BaseURL,
110110
Client: client.NewLoggedClient(t, hsName, nil),
111111
SyncUntilTimeout: 5 * time.Second,
112112
Debug: d.Deployer.debugLogging,
113113
Password: opts.Password,
114-
}
114+
})
115115
// Appending a slice is not thread-safe. Protect the write with a mutex.
116116
dep.CSAPIClientsMutex.Lock()
117117
dep.CSAPIClients = append(dep.CSAPIClients, client)
@@ -155,13 +155,13 @@ func (d *Deployment) Login(t ct.TestLike, hsName string, existing *client.CSAPI,
155155
if err != nil {
156156
ct.Fatalf(t, "Deployment.Login: existing CSAPI client has invalid user ID '%s', cannot login as this user: %s", existing.UserID, err)
157157
}
158-
c := &client.CSAPI{
158+
c := client.NewCSAPI(client.CSAPIOpts{
159159
BaseURL: dep.BaseURL,
160160
Client: client.NewLoggedClient(t, hsName, nil),
161161
SyncUntilTimeout: 5 * time.Second,
162162
Debug: d.Deployer.debugLogging,
163163
Password: existing.Password,
164-
}
164+
})
165165
if opts.Password != "" {
166166
c.Password = opts.Password
167167
}
@@ -197,12 +197,12 @@ func (d *Deployment) UnauthenticatedClient(t ct.TestLike, hsName string) *client
197197
ct.Fatalf(t, "Deployment.Client - HS name '%s' not found", hsName)
198198
return nil
199199
}
200-
client := &client.CSAPI{
200+
client := client.NewCSAPI(client.CSAPIOpts{
201201
BaseURL: dep.BaseURL,
202202
Client: client.NewLoggedClient(t, hsName, nil),
203203
SyncUntilTimeout: 5 * time.Second,
204204
Debug: d.Deployer.debugLogging,
205-
}
205+
})
206206
// Appending a slice is not thread-safe. Protect the write with a mutex.
207207
dep.CSAPIClientsMutex.Lock()
208208
dep.CSAPIClients = append(dep.CSAPIClients, client)
@@ -230,15 +230,15 @@ func (d *Deployment) AppServiceUser(t ct.TestLike, hsName, appServiceUserID stri
230230
if deviceID == "" && appServiceUserID != "" {
231231
t.Logf("WARNING: Deployment.Client - HS name '%s' - user ID '%s' - deviceID not found", hsName, appServiceUserID)
232232
}
233-
client := &client.CSAPI{
233+
client := client.NewCSAPI(client.CSAPIOpts{
234234
UserID: appServiceUserID,
235235
AccessToken: token,
236236
DeviceID: deviceID,
237237
BaseURL: dep.BaseURL,
238238
Client: client.NewLoggedClient(t, hsName, nil),
239239
SyncUntilTimeout: 5 * time.Second,
240240
Debug: d.Deployer.debugLogging,
241-
}
241+
})
242242
// Appending a slice is not thread-safe. Protect the write with a mutex.
243243
dep.CSAPIClientsMutex.Lock()
244244
dep.CSAPIClients = append(dep.CSAPIClients, client)

tests/csapi/apidoc_room_receipts_test.go

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,19 @@ func createRoomForReadReceipts(t *testing.T, c *client.CSAPI) (string, string) {
1717

1818
c.MustSyncUntil(t, client.SyncReq{}, client.SyncJoinedTo(c.UserID, roomID))
1919

20-
eventID := c.SendEventSynced(t, roomID, b.Event{
20+
eventID := sendMessageIntoRoom(t, c, roomID)
21+
22+
return roomID, eventID
23+
}
24+
25+
func sendMessageIntoRoom(t *testing.T, c *client.CSAPI, roomID string) string {
26+
return c.SendEventSynced(t, roomID, b.Event{
2127
Type: "m.room.message",
2228
Content: map[string]interface{}{
2329
"msgtype": "m.text",
2430
"body": "Hello world!",
2531
},
2632
})
27-
28-
return roomID, eventID
2933
}
3034

3135
func syncHasReadReceipt(roomID, userID, eventID string) client.SyncCheckOpt {
@@ -45,7 +49,41 @@ func TestRoomReceipts(t *testing.T) {
4549
alice.MustDo(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "receipt", "m.read", eventID}, client.WithJSONBody(t, struct{}{}))
4650

4751
// Make sure the read receipt shows up in sync.
48-
alice.MustSyncUntil(t, client.SyncReq{}, syncHasReadReceipt(roomID, alice.UserID, eventID))
52+
sinceToken := alice.MustSyncUntil(t, client.SyncReq{}, syncHasReadReceipt(roomID, alice.UserID, eventID))
53+
54+
// Receipt events include a `room_id` field over federation, but they should
55+
// not do so down `/sync` to clients. Ensure homeservers strip that field out.
56+
t.Run("Receipts DO NOT include a `room_id` field", func(t *testing.T) {
57+
// Send another event to read.
58+
eventID2 := sendMessageIntoRoom(t, alice, roomID)
59+
60+
// Send a read receipt for the event.
61+
alice.MustDo(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "receipt", "m.read", eventID2}, client.WithJSONBody(t, struct{}{}))
62+
63+
alice.MustSyncUntil(
64+
t,
65+
client.SyncReq{Since: sinceToken},
66+
client.SyncEphemeralHas(roomID, func(r gjson.Result) bool {
67+
// Check that this is a m.receipt ephemeral event.
68+
if r.Get("type").Str != "m.receipt" {
69+
return false
70+
}
71+
72+
// Check that the receipt type is "m.read".
73+
if !r.Get(`content.*.m\.read`).Exists() {
74+
t.Fatalf("Receipt was not of type 'm.read'")
75+
}
76+
77+
// Ensure that the `room_id` field does NOT exist.
78+
if r.Get("room_id").Exists() {
79+
t.Fatalf("Read receipt should not contain 'room_id' field when syncing but saw: %s", r.Raw)
80+
}
81+
82+
// Exit the /sync loop.
83+
return true;
84+
}),
85+
)
86+
})
4987
}
5088

5189
// sytest: POST /rooms/:room_id/read_markers can create read marker

tests/csapi/device_lists_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ func TestDeviceListUpdates(t *testing.T) {
4949
ed25519KeyID: ed25519Key,
5050
curve25519KeyID: curve25519Key,
5151
},
52+
"signatures": map[string]interface{}{},
5253
},
5354
}),
5455
)

tests/csapi/room_typing_test.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"github.com/matrix-org/complement"
77
"github.com/matrix-org/complement/client"
88
"github.com/matrix-org/complement/helpers"
9+
"github.com/tidwall/gjson"
910
)
1011

1112
// sytest: PUT /rooms/:room_id/typing/:user_id sets typing notification
@@ -33,6 +34,30 @@ func TestTyping(t *testing.T) {
3334
alice.SendTyping(t, roomID, false, 0)
3435
bob.MustSyncUntil(t, client.SyncReq{Since: token}, client.SyncUsersTyping(roomID, []string{}))
3536
})
37+
38+
// Typing events include a `room_id` field over federation, but they should
39+
// not do so down `/sync` to clients. Ensure homeservers strip that field out.
40+
t.Run("Typing events DO NOT include a `room_id` field", func(t *testing.T) {
41+
alice.SendTyping(t, roomID, true, 0)
42+
43+
bob.MustSyncUntil(
44+
t,
45+
client.SyncReq{Since: token},
46+
client.SyncEphemeralHas(roomID, func(r gjson.Result) bool {
47+
if r.Get("type").Str != "m.typing" {
48+
return false
49+
}
50+
51+
// Ensure that the `room_id` field does NOT exist.
52+
if r.Get("room_id").Exists() {
53+
t.Fatalf("Typing event should not contain `room_id` field when syncing but saw: %s", r.Raw)
54+
}
55+
56+
// Exit the /sync loop.
57+
return true;
58+
}),
59+
)
60+
})
3661
}
3762

3863
// sytest: Typing notifications don't leak

tests/federation_acl_test.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,9 @@ func TestACLs(t *testing.T) {
5959
Content: map[string]interface{}{
6060
"allow": []string{"*"},
6161
"allow_ip_literals": true,
62-
"deny": []string{"hs2"},
62+
"deny": []string{
63+
string(deployment.GetFullyQualifiedHomeserverName(t, "hs2")),
64+
},
6365
},
6466
})
6567
// wait for the ACL to show up on hs2
@@ -111,7 +113,9 @@ func TestACLs(t *testing.T) {
111113
content := user.MustGetStateEventContent(t, roomID, "m.room.server_acl", "")
112114
must.MatchGJSON(t, content,
113115
match.JSONKeyEqual("allow", []string{"*"}),
114-
match.JSONKeyEqual("deny", []string{"hs2"}),
116+
match.JSONKeyEqual("deny", []string{
117+
string(deployment.GetFullyQualifiedHomeserverName(t, "hs2")),
118+
}),
115119
match.JSONKeyEqual("allow_ip_literals", true),
116120
)
117121
}

tests/federation_unreject_rejected_test.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
package tests
22

33
import (
4+
"context"
45
"encoding/json"
56
"testing"
7+
"time"
68

79
"github.com/matrix-org/complement"
810
"github.com/matrix-org/complement/client"
911
"github.com/matrix-org/complement/federation"
1012
"github.com/matrix-org/complement/helpers"
13+
"github.com/matrix-org/gomatrixserverlib"
1114
"github.com/matrix-org/gomatrixserverlib/spec"
1215
)
1316

@@ -65,7 +68,16 @@ func TestUnrejectRejectedEvents(t *testing.T) {
6568
// Send event B into the room. Event A at this point is unknown
6669
// to the homeserver and we're not going to respond to the events
6770
// request for it, so it should get rejected.
68-
srv.MustSendTransaction(t, deployment, deployment.GetFullyQualifiedHomeserverName(t, "hs1"), []json.RawMessage{eventB.JSON()}, nil)
71+
fedClient := srv.FederationClient(deployment)
72+
fedClient.SendTransaction(context.Background(), gomatrixserverlib.Transaction{
73+
TransactionID: "complement1",
74+
Origin: srv.ServerName(),
75+
Destination: deployment.GetFullyQualifiedHomeserverName(t, "hs1"),
76+
OriginServerTS: spec.AsTimestamp(time.Now()),
77+
PDUs: []json.RawMessage{
78+
eventB.JSON(),
79+
},
80+
})
6981

7082
// Now we're going to send Event A into the room, which should give
7183
// the server the prerequisite event to pass Event B later. This one

0 commit comments

Comments
 (0)