From 4332b1a10716ac5387bc5e98b678755ea3f5717b Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Tue, 3 Oct 2023 13:22:58 +0100 Subject: [PATCH 1/9] refactor: make client public and rename/reshuffle functions - Remove `Func` from `MustDoFunc` and `DoFunc`. They were called that to differentiate from the old-style `Do` and `MustDo` which are no more. - Move sync functions to a new file. - Move registration/login functions to a new file. - Move `/internal/client` to `/client`. --- client/auth.go | 161 +++ client/client.go | 586 +++++++++ client/sync.go | 392 ++++++ internal/client/client.go | 1117 ----------------- internal/docker/deployment.go | 2 +- .../account_change_password_pushers_test.go | 10 +- tests/csapi/account_change_password_test.go | 18 +- tests/csapi/account_deactivate_test.go | 8 +- tests/csapi/admin_test.go | 10 +- tests/csapi/apidoc_device_management_test.go | 36 +- tests/csapi/apidoc_login_test.go | 18 +- tests/csapi/apidoc_logout_test.go | 20 +- tests/csapi/apidoc_presence_test.go | 13 +- tests/csapi/apidoc_profile_avatar_url_test.go | 6 +- .../csapi/apidoc_profile_displayname_test.go | 6 +- tests/csapi/apidoc_register_test.go | 38 +- tests/csapi/apidoc_request_encoding_test.go | 4 +- tests/csapi/apidoc_room_alias_test.go | 14 +- tests/csapi/apidoc_room_create_test.go | 10 +- tests/csapi/apidoc_room_forget_test.go | 26 +- .../apidoc_room_history_visibility_test.go | 4 +- tests/csapi/apidoc_room_members_test.go | 26 +- tests/csapi/apidoc_room_receipts_test.go | 6 +- tests/csapi/apidoc_room_state_test.go | 34 +- tests/csapi/apidoc_search_test.go | 20 +- .../csapi/apidoc_server_capabilities_test.go | 2 +- tests/csapi/apidoc_version_test.go | 2 +- tests/csapi/device_lists_test.go | 6 +- tests/csapi/e2e_key_backup_test.go | 16 +- tests/csapi/ignored_users_test.go | 10 +- tests/csapi/invalid_test.go | 12 +- tests/csapi/keychanges_test.go | 10 +- tests/csapi/media_misc_test.go | 6 +- tests/csapi/power_levels_test.go | 10 +- tests/csapi/push_test.go | 10 +- tests/csapi/room_ban_test.go | 4 +- tests/csapi/room_kick_test.go | 6 +- tests/csapi/room_leave_test.go | 16 +- tests/csapi/room_members_test.go | 12 +- .../room_messages_relation_filter_test.go | 20 +- tests/csapi/room_messages_test.go | 28 +- tests/csapi/room_profile_test.go | 4 +- tests/csapi/room_relations_test.go | 32 +- tests/csapi/room_threads_test.go | 16 +- tests/csapi/room_typing_test.go | 8 +- tests/csapi/rooms_invite_test.go | 12 +- tests/csapi/rooms_members_local_test.go | 4 +- tests/csapi/rooms_state_test.go | 4 +- tests/csapi/sync_archive_test.go | 8 +- tests/csapi/sync_filter_test.go | 6 +- tests/csapi/sync_test.go | 6 +- tests/csapi/thread_notifications_test.go | 10 +- tests/csapi/to_device_test.go | 2 +- tests/csapi/txnid_test.go | 65 +- tests/csapi/upload_keys_test.go | 18 +- tests/csapi/url_preview_test.go | 4 +- .../user_directory_display_names_test.go | 18 +- tests/csapi/user_query_keys_test.go | 4 +- tests/direct_messaging_test.go | 2 +- tests/federation_acl_test.go | 4 +- tests/federation_presence_test.go | 6 +- tests/federation_query_profile_test.go | 6 +- tests/federation_room_alias_test.go | 6 +- tests/federation_room_ban_test.go | 6 +- tests/federation_room_event_auth_test.go | 8 +- ...federation_room_get_missing_events_test.go | 2 +- ...federation_room_join_partial_state_test.go | 59 +- tests/federation_room_join_test.go | 6 +- tests/federation_room_typing_test.go | 4 +- tests/federation_rooms_invite_test.go | 4 +- tests/federation_unreject_rejected_test.go | 2 +- tests/federation_upload_keys_test.go | 12 +- tests/knocking_test.go | 22 +- tests/media_filename_test.go | 4 +- tests/media_thumbnail_test.go | 4 +- tests/msc2836_test.go | 38 +- tests/msc3391_test.go | 10 +- tests/msc3890_test.go | 10 +- tests/restricted_room_hierarchy_test.go | 4 +- tests/restricted_rooms_test.go | 6 +- tests/room_hierarchy_test.go | 22 +- tests/room_timestamp_to_event_test.go | 18 +- tests/unknown_endpoints_test.go | 6 +- 83 files changed, 1640 insertions(+), 1607 deletions(-) create mode 100644 client/auth.go create mode 100644 client/client.go create mode 100644 client/sync.go delete mode 100644 internal/client/client.go diff --git a/client/auth.go b/client/auth.go new file mode 100644 index 00000000..3284f82c --- /dev/null +++ b/client/auth.go @@ -0,0 +1,161 @@ +package client + +import ( + "crypto/hmac" + "crypto/sha1" + "encoding/hex" + "io" + "testing" + + "github.com/matrix-org/complement/internal/must" + "github.com/tidwall/gjson" +) + +type LoginOpt func(map[string]interface{}) + +func WithDeviceID(deviceID string) LoginOpt { + return func(loginBody map[string]interface{}) { + loginBody["device_id"] = deviceID + } +} + +// LoginUser will log in to a homeserver and create a new device on an existing user. +func (c *CSAPI) LoginUser(t *testing.T, localpart, password string, opts ...LoginOpt) (userID, accessToken, deviceID string) { + t.Helper() + reqBody := map[string]interface{}{ + "identifier": map[string]interface{}{ + "type": "m.id.user", + "user": localpart, + }, + "password": password, + "type": "m.login.password", + } + + for _, opt := range opts { + opt(reqBody) + } + + res := c.MustDo(t, "POST", []string{"_matrix", "client", "v3", "login"}, WithJSONBody(t, reqBody)) + + body, err := io.ReadAll(res.Body) + if err != nil { + t.Fatalf("unable to read response body: %v", err) + } + + userID = gjson.GetBytes(body, "user_id").Str + accessToken = gjson.GetBytes(body, "access_token").Str + deviceID = gjson.GetBytes(body, "device_id").Str + return userID, accessToken, deviceID +} + +// LoginUserWithRefreshToken will log in to a homeserver, with refresh token enabled, +// and create a new device on an existing user. +func (c *CSAPI) LoginUserWithRefreshToken(t *testing.T, localpart, password string) (userID, accessToken, refreshToken, deviceID string, expiresInMs int64) { + t.Helper() + reqBody := map[string]interface{}{ + "identifier": map[string]interface{}{ + "type": "m.id.user", + "user": localpart, + }, + "password": password, + "type": "m.login.password", + "refresh_token": true, + } + res := c.MustDo(t, "POST", []string{"_matrix", "client", "v3", "login"}, WithJSONBody(t, reqBody)) + + body, err := io.ReadAll(res.Body) + if err != nil { + t.Fatalf("unable to read response body: %v", err) + } + + userID = gjson.GetBytes(body, "user_id").Str + accessToken = gjson.GetBytes(body, "access_token").Str + deviceID = gjson.GetBytes(body, "device_id").Str + refreshToken = gjson.GetBytes(body, "refresh_token").Str + expiresInMs = gjson.GetBytes(body, "expires_in_ms").Int() + return userID, accessToken, refreshToken, deviceID, expiresInMs +} + +// RefreshToken will consume a refresh token and return a new access token and refresh token. +func (c *CSAPI) ConsumeRefreshToken(t *testing.T, refreshToken string) (newAccessToken, newRefreshToken string, expiresInMs int64) { + t.Helper() + reqBody := map[string]interface{}{ + "refresh_token": refreshToken, + } + res := c.MustDo(t, "POST", []string{"_matrix", "client", "v3", "refresh"}, WithJSONBody(t, reqBody)) + + body, err := io.ReadAll(res.Body) + if err != nil { + t.Fatalf("unable to read response body: %v", err) + } + + newAccessToken = gjson.GetBytes(body, "access_token").Str + newRefreshToken = gjson.GetBytes(body, "refresh_token").Str + expiresInMs = gjson.GetBytes(body, "expires_in_ms").Int() + return newAccessToken, newRefreshToken, expiresInMs +} + +// RegisterUser will register the user with given parameters and +// return user ID, access token and device ID. It fails the test on network error. +func (c *CSAPI) RegisterUser(t *testing.T, localpart, password string) (userID, accessToken, deviceID string) { + t.Helper() + reqBody := map[string]interface{}{ + "auth": map[string]string{ + "type": "m.login.dummy", + }, + "username": localpart, + "password": password, + } + res := c.MustDo(t, "POST", []string{"_matrix", "client", "v3", "register"}, WithJSONBody(t, reqBody)) + + body, err := io.ReadAll(res.Body) + if err != nil { + t.Fatalf("unable to read response body: %v", err) + } + + userID = gjson.GetBytes(body, "user_id").Str + accessToken = gjson.GetBytes(body, "access_token").Str + deviceID = gjson.GetBytes(body, "device_id").Str + return userID, accessToken, deviceID +} + +// RegisterSharedSecret registers a new account with a shared secret via HMAC +// See https://github.com/matrix-org/synapse/blob/e550ab17adc8dd3c48daf7fedcd09418a73f524b/synapse/_scripts/register_new_matrix_user.py#L40 +func (c *CSAPI) RegisterSharedSecret(t *testing.T, user, pass string, isAdmin bool) (userID, accessToken, deviceID string) { + resp := c.Do(t, "GET", []string{"_synapse", "admin", "v1", "register"}) + if resp.StatusCode != 200 { + t.Skipf("Homeserver image does not support shared secret registration, /_synapse/admin/v1/register returned HTTP %d", resp.StatusCode) + return + } + body := must.ParseJSON(t, resp.Body) + nonce := gjson.GetBytes(body, "nonce") + if !nonce.Exists() { + t.Fatalf("Malformed shared secret GET response: %s", string(body)) + } + mac := hmac.New(sha1.New, []byte(SharedSecret)) + mac.Write([]byte(nonce.Str)) + mac.Write([]byte("\x00")) + mac.Write([]byte(user)) + mac.Write([]byte("\x00")) + mac.Write([]byte(pass)) + mac.Write([]byte("\x00")) + if isAdmin { + mac.Write([]byte("admin")) + } else { + mac.Write([]byte("notadmin")) + } + sig := mac.Sum(nil) + reqBody := map[string]interface{}{ + "nonce": nonce.Str, + "username": user, + "password": pass, + "mac": hex.EncodeToString(sig), + "admin": isAdmin, + } + resp = c.MustDo(t, "POST", []string{"_synapse", "admin", "v1", "register"}, WithJSONBody(t, reqBody)) + body = must.ParseJSON(t, resp.Body) + userID = gjson.GetBytes(body, "user_id").Str + accessToken = gjson.GetBytes(body, "access_token").Str + deviceID = gjson.GetBytes(body, "device_id").Str + return userID, accessToken, deviceID +} diff --git a/client/client.go b/client/client.go new file mode 100644 index 00000000..c4d02e21 --- /dev/null +++ b/client/client.go @@ -0,0 +1,586 @@ +package client + +import ( + "bytes" + "context" // nolint:gosec + "encoding/json" + "fmt" + "io" + "net/http" + "net/http/httputil" + "net/url" + "strconv" + "strings" + "sync/atomic" + "testing" + "time" + + "github.com/matrix-org/gomatrixserverlib" + "github.com/tidwall/gjson" + + "github.com/matrix-org/complement/internal/b" +) + +const ( + SharedSecret = "complement" +) + +type CtxKey string + +const ( + CtxKeyWithRetryUntil CtxKey = "complement_retry_until" // contains *retryUntilParams +) + +type retryUntilParams struct { + timeout time.Duration + untilFn func(*http.Response) bool +} + +// RequestOpt is a functional option which will modify an outgoing HTTP request. +// See functions starting with `With...` in this package for more info. +type RequestOpt func(req *http.Request) + +type CSAPI struct { + UserID string + AccessToken string + DeviceID string + BaseURL string + Client *http.Client + // how long are we willing to wait for MustSyncUntil.... calls + SyncUntilTimeout time.Duration + // True to enable verbose logging + Debug bool + + txnID int64 +} + +// UploadContent uploads the provided content with an optional file name. Fails the test on error. Returns the MXC URI. +func (c *CSAPI) UploadContent(t *testing.T, fileBody []byte, fileName string, contentType string) string { + t.Helper() + query := url.Values{} + if fileName != "" { + query.Set("filename", fileName) + } + res := c.MustDo( + t, "POST", []string{"_matrix", "media", "v3", "upload"}, + WithRawBody(fileBody), WithContentType(contentType), WithQueries(query), + ) + body := ParseJSON(t, res) + return GetJSONFieldStr(t, body, "content_uri") +} + +// DownloadContent downloads media from the server, returning the raw bytes and the Content-Type. Fails the test on error. +func (c *CSAPI) DownloadContent(t *testing.T, mxcUri string) ([]byte, string) { + t.Helper() + origin, mediaId := SplitMxc(mxcUri) + res := c.MustDo(t, "GET", []string{"_matrix", "media", "v3", "download", origin, mediaId}) + contentType := res.Header.Get("Content-Type") + b, err := io.ReadAll(res.Body) + if err != nil { + t.Error(err) + } + return b, contentType +} + +// CreateRoom creates a room with an optional HTTP request body. Fails the test on error. Returns the room ID. +func (c *CSAPI) CreateRoom(t *testing.T, creationContent interface{}) string { + t.Helper() + res := c.MustDo(t, "POST", []string{"_matrix", "client", "v3", "createRoom"}, WithJSONBody(t, creationContent)) + body := ParseJSON(t, res) + return GetJSONFieldStr(t, body, "room_id") +} + +// JoinRoom joins the room ID or alias given, else fails the test. Returns the room ID. +func (c *CSAPI) JoinRoom(t *testing.T, roomIDOrAlias string, serverNames []string) string { + t.Helper() + // construct URL query parameters + query := make(url.Values, len(serverNames)) + for _, serverName := range serverNames { + query.Add("server_name", serverName) + } + // join the room + res := c.MustDo( + t, "POST", []string{"_matrix", "client", "v3", "join", roomIDOrAlias}, + WithQueries(query), WithJSONBody(t, map[string]interface{}{}), + ) + // return the room ID if we joined with it + if roomIDOrAlias[0] == '!' { + return roomIDOrAlias + } + // otherwise we should be told the room ID if we joined via an alias + body := ParseJSON(t, res) + return GetJSONFieldStr(t, body, "room_id") +} + +// LeaveRoom leaves the room ID, else fails the test. +func (c *CSAPI) LeaveRoom(t *testing.T, roomID string) { + t.Helper() + // leave the room + body := map[string]interface{}{} + c.MustDo(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "leave"}, WithJSONBody(t, body)) +} + +// InviteRoom invites userID to the room ID, else fails the test. +func (c *CSAPI) InviteRoom(t *testing.T, roomID string, userID string) { + t.Helper() + // Invite the user to the room + body := map[string]interface{}{ + "user_id": userID, + } + c.MustDo(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "invite"}, WithJSONBody(t, body)) +} + +func (c *CSAPI) GetGlobalAccountData(t *testing.T, eventType string) *http.Response { + return c.MustDo(t, "GET", []string{"_matrix", "client", "v3", "user", c.UserID, "account_data", eventType}) +} + +func (c *CSAPI) SetGlobalAccountData(t *testing.T, eventType string, content map[string]interface{}) *http.Response { + return c.MustDo(t, "PUT", []string{"_matrix", "client", "v3", "user", c.UserID, "account_data", eventType}, WithJSONBody(t, content)) +} + +func (c *CSAPI) GetRoomAccountData(t *testing.T, roomID string, eventType string) *http.Response { + return c.MustDo(t, "GET", []string{"_matrix", "client", "v3", "user", c.UserID, "rooms", roomID, "account_data", eventType}) +} + +func (c *CSAPI) SetRoomAccountData(t *testing.T, roomID string, eventType string, content map[string]interface{}) *http.Response { + return c.MustDo(t, "PUT", []string{"_matrix", "client", "v3", "user", c.UserID, "rooms", roomID, "account_data", eventType}, WithJSONBody(t, content)) +} + +// GetAllPushRules fetches all configured push rules for a user from the homeserver. +// Push rules are returned as a parsed gjson result +// +// Example of printing the IDs of all underride rules of the current user: +// +// allPushRules := c.GetAllPushRules(t) +// globalUnderridePushRules := allPushRules.Get("global").Get("underride").Array() +// +// for index, rule := range globalUnderridePushRules { +// fmt.Printf("This rule's ID is: %s\n", rule.Get("rule_id").Str) +// } +// +// Push rules are returned in the same order received from the homeserver. +func (c *CSAPI) GetAllPushRules(t *testing.T) gjson.Result { + t.Helper() + + // We have to supply an empty string to the end of this path in order to generate a trailing slash. + // See https://github.com/matrix-org/matrix-spec/issues/457 + res := c.MustDo(t, "GET", []string{"_matrix", "client", "v3", "pushrules", ""}) + pushRulesBytes := ParseJSON(t, res) + return gjson.ParseBytes(pushRulesBytes) +} + +// GetPushRule queries the contents of a client's push rule by scope, kind and rule ID. +// A parsed gjson result is returned. Fails the test if the query to server returns a non-2xx status code. +// +// Example of checking that a global underride rule contains the expected actions: +// +// containsDisplayNameRule := c.GetPushRule(t, "global", "underride", ".m.rule.contains_display_name") +// must.MatchGJSON( +// t, +// containsDisplayNameRule, +// match.JSONKeyEqual("actions", []interface{}{ +// "notify", +// map[string]interface{}{"set_tweak": "sound", "value": "default"}, +// map[string]interface{}{"set_tweak": "highlight"}, +// }), +// ) +func (c *CSAPI) GetPushRule(t *testing.T, scope string, kind string, ruleID string) gjson.Result { + t.Helper() + + res := c.MustDo(t, "GET", []string{"_matrix", "client", "v3", "pushrules", scope, kind, ruleID}) + pushRuleBytes := ParseJSON(t, res) + return gjson.ParseBytes(pushRuleBytes) +} + +// SetPushRule creates a new push rule on the user, or modifies an existing one. +// If `before` or `after` parameters are not set to an empty string, their values +// will be set as the `before` and `after` query parameters respectively on the +// "set push rules" client endpoint: +// https://spec.matrix.org/v1.5/client-server-api/#put_matrixclientv3pushrulesscopekindruleid +// +// Example of setting a push rule with ID 'com.example.rule2' that must come after 'com.example.rule1': +// +// c.SetPushRule(t, "global", "underride", "com.example.rule2", map[string]interface{}{ +// "actions": []string{"dont_notify"}, +// }, nil, "com.example.rule1") +func (c *CSAPI) SetPushRule(t *testing.T, scope string, kind string, ruleID string, body map[string]interface{}, before string, after string) *http.Response { + t.Helper() + + // If the `before` or `after` arguments have been provided, construct same-named query parameters + queryParams := url.Values{} + if before != "" { + queryParams.Add("before", before) + } + if after != "" { + queryParams.Add("after", after) + } + + return c.MustDo(t, "PUT", []string{"_matrix", "client", "v3", "pushrules", scope, kind, ruleID}, WithJSONBody(t, body), WithQueries(queryParams)) +} + +// SendEventUnsynced sends `e` into the room. +// Returns the event ID of the sent event. +func (c *CSAPI) SendEventUnsynced(t *testing.T, roomID string, e b.Event) string { + t.Helper() + txnID := int(atomic.AddInt64(&c.txnID, 1)) + return c.SendEventUnsyncedWithTxnID(t, roomID, e, strconv.Itoa(txnID)) +} + +// SendEventUnsyncedWithTxnID sends `e` into the room with a prescribed transaction ID. +// This is useful for writing tests that interrogate transaction semantics. +// Returns the event ID of the sent event. +func (c *CSAPI) SendEventUnsyncedWithTxnID(t *testing.T, roomID string, e b.Event, txnID string) string { + t.Helper() + paths := []string{"_matrix", "client", "v3", "rooms", roomID, "send", e.Type, txnID} + if e.StateKey != nil { + paths = []string{"_matrix", "client", "v3", "rooms", roomID, "state", e.Type, *e.StateKey} + } + res := c.MustDo(t, "PUT", paths, WithJSONBody(t, e.Content)) + body := ParseJSON(t, res) + eventID := GetJSONFieldStr(t, body, "event_id") + return eventID +} + +// SendEventSynced sends `e` into the room and waits for its event ID to come down /sync. +// Returns the event ID of the sent event. +func (c *CSAPI) SendEventSynced(t *testing.T, roomID string, e b.Event) string { + t.Helper() + eventID := c.SendEventUnsynced(t, roomID, e) + t.Logf("SendEventSynced waiting for event ID %s", eventID) + c.MustSyncUntil(t, SyncReq{}, SyncTimelineHas(roomID, func(r gjson.Result) bool { + return r.Get("event_id").Str == eventID + })) + return eventID +} + +// SendRedaction sends a redaction request. Will fail if the returned HTTP request code is not 200 +func (c *CSAPI) SendRedaction(t *testing.T, roomID string, e b.Event, eventID string) string { + t.Helper() + txnID := int(atomic.AddInt64(&c.txnID, 1)) + paths := []string{"_matrix", "client", "v3", "rooms", roomID, "redact", eventID, strconv.Itoa(txnID)} + res := c.MustDo(t, "PUT", paths, WithJSONBody(t, e.Content)) + body := ParseJSON(t, res) + return GetJSONFieldStr(t, body, "event_id") +} + +// GetCapbabilities queries the server's capabilities +func (c *CSAPI) GetCapabilities(t *testing.T) []byte { + t.Helper() + res := c.MustDo(t, "GET", []string{"_matrix", "client", "v3", "capabilities"}) + body, err := io.ReadAll(res.Body) + if err != nil { + t.Fatalf("unable to read response body: %v", err) + } + return body +} + +// GetDefaultRoomVersion returns the server's default room version +func (c *CSAPI) GetDefaultRoomVersion(t *testing.T) gomatrixserverlib.RoomVersion { + t.Helper() + capabilities := c.GetCapabilities(t) + defaultVersion := gjson.GetBytes(capabilities, `capabilities.m\.room_versions.default`) + if !defaultVersion.Exists() { + // spec says use RoomV1 in this case + return gomatrixserverlib.RoomVersionV1 + } + + return gomatrixserverlib.RoomVersion(defaultVersion.Str) +} + +// WithRawBody sets the HTTP request body to `body` +func WithRawBody(body []byte) RequestOpt { + return func(req *http.Request) { + req.Body = io.NopCloser(bytes.NewReader(body)) + req.GetBody = func() (io.ReadCloser, error) { + r := bytes.NewReader(body) + return io.NopCloser(r), nil + } + // we need to manually set this because we don't set the body + // in http.NewRequest due to using functional options, and only in NewRequest + // does the stdlib set this for us. + req.ContentLength = int64(len(body)) + } +} + +// WithContentType sets the HTTP request Content-Type header to `cType` +func WithContentType(cType string) RequestOpt { + return func(req *http.Request) { + req.Header.Set("Content-Type", cType) + } +} + +// WithJSONBody sets the HTTP request body to the JSON serialised form of `obj` +func WithJSONBody(t *testing.T, obj interface{}) RequestOpt { + return func(req *http.Request) { + t.Helper() + b, err := json.Marshal(obj) + if err != nil { + t.Fatalf("CSAPI.Do failed to marshal JSON body: %s", err) + } + WithRawBody(b)(req) + } +} + +// WithQueries sets the query parameters on the request. +// This function should not be used to set an "access_token" parameter for Matrix authentication. +// Instead, set CSAPI.AccessToken. +func WithQueries(q url.Values) RequestOpt { + return func(req *http.Request) { + req.URL.RawQuery = q.Encode() + } +} + +// WithRetryUntil will retry the request until the provided function returns true. Times out after +// `timeout`, which will then fail the test. +func WithRetryUntil(timeout time.Duration, untilFn func(res *http.Response) bool) RequestOpt { + return func(req *http.Request) { + until := req.Context().Value(CtxKeyWithRetryUntil).(*retryUntilParams) + until.timeout = timeout + until.untilFn = untilFn + } +} + +// MustDo is the same as Do but fails the test if the returned HTTP response code is not 2xx. +func (c *CSAPI) MustDo(t *testing.T, method string, paths []string, opts ...RequestOpt) *http.Response { + t.Helper() + res := c.Do(t, method, paths, opts...) + if res.StatusCode < 200 || res.StatusCode >= 300 { + defer res.Body.Close() + body, _ := io.ReadAll(res.Body) + t.Fatalf("CSAPI.MustDo %s %s returned non-2xx code: %s - body: %s", method, res.Request.URL.String(), res.Status, string(body)) + } + return res +} + +// Do performs an arbitrary HTTP request to the server. This function supports RequestOpts to set +// extra information on the request such as an HTTP request body, query parameters and content-type. +// See all functions in this package starting with `With...`. +// +// Fails the test if an HTTP request could not be made or if there was a network error talking to the +// server. To do assertions on the HTTP response, see the `must` package. For example: +// +// must.MatchResponse(t, res, match.HTTPResponse{ +// StatusCode: 400, +// JSON: []match.JSON{ +// match.JSONKeyEqual("errcode", "M_INVALID_USERNAME"), +// }, +// }) +func (c *CSAPI) Do(t *testing.T, method string, paths []string, opts ...RequestOpt) *http.Response { + t.Helper() + for i := range paths { + paths[i] = url.PathEscape(paths[i]) + } + reqURL := c.BaseURL + "/" + strings.Join(paths, "/") + req, err := http.NewRequest(method, reqURL, nil) + if err != nil { + t.Fatalf("CSAPI.Do failed to create http.NewRequest: %s", err) + } + // set defaults before RequestOpts + if c.AccessToken != "" { + req.Header.Set("Authorization", "Bearer "+c.AccessToken) + } + retryUntil := &retryUntilParams{} + ctx := context.WithValue(req.Context(), CtxKeyWithRetryUntil, retryUntil) + req = req.WithContext(ctx) + + // set functional options + for _, o := range opts { + o(req) + } + // set defaults after RequestOpts + if req.Header.Get("Content-Type") == "" { + req.Header.Set("Content-Type", "application/json") + } + // debug log the request + if c.Debug { + t.Logf("Making %s request to %s (%s)", method, req.URL, c.AccessToken) + contentType := req.Header.Get("Content-Type") + if contentType == "application/json" || strings.HasPrefix(contentType, "text/") { + if req.Body != nil { + body, _ := io.ReadAll(req.Body) + t.Logf("Request body: %s", string(body)) + req.Body = io.NopCloser(bytes.NewBuffer(body)) + } + } else { + t.Logf("Request body: ", contentType) + } + } + now := time.Now() + for { + // Perform the HTTP request + res, err := c.Client.Do(req) + if err != nil { + t.Fatalf("CSAPI.Do response returned error: %s", err) + } + // debug log the response + if c.Debug && res != nil { + var dump []byte + dump, err = httputil.DumpResponse(res, true) + if err != nil { + t.Fatalf("CSAPI.Do failed to dump response body: %s", err) + } + t.Logf("%s", string(dump)) + } + if retryUntil == nil || retryUntil.timeout == 0 { + return res // don't retry + } + + // check the condition, make a copy of the response body first in case the check consumes it + var resBody []byte + if res.Body != nil { + resBody, err = io.ReadAll(res.Body) + if err != nil { + t.Fatalf("CSAPI.Do failed to read response body for RetryUntil check: %s", err) + } + res.Body = io.NopCloser(bytes.NewBuffer(resBody)) + } + if retryUntil.untilFn(res) { + // remake the response and return + res.Body = io.NopCloser(bytes.NewBuffer(resBody)) + return res + } + // condition not satisfied, do we timeout yet? + if time.Since(now) > retryUntil.timeout { + t.Fatalf("CSAPI.Do RetryUntil: %v %v timed out after %v", method, req.URL, retryUntil.timeout) + } + t.Logf("CSAPI.Do RetryUntil: %v %v response condition not yet met, retrying", method, req.URL) + // small sleep to avoid tight-looping + time.Sleep(100 * time.Millisecond) + } +} + +// NewLoggedClient returns an http.Client which logs requests/responses +func NewLoggedClient(t *testing.T, hsName string, cli *http.Client) *http.Client { + t.Helper() + if cli == nil { + cli = &http.Client{ + Timeout: 30 * time.Second, + } + } + transport := cli.Transport + if transport == nil { + transport = http.DefaultTransport + } + cli.Transport = &loggedRoundTripper{t, hsName, transport} + return cli +} + +type loggedRoundTripper struct { + t *testing.T + hsName string + wrap http.RoundTripper +} + +func (t *loggedRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { + start := time.Now() + res, err := t.wrap.RoundTrip(req) + if err != nil { + t.t.Logf("[CSAPI] %s %s%s => error: %s (%s)", req.Method, t.hsName, req.URL.Path, err, time.Since(start)) + } else { + t.t.Logf("[CSAPI] %s %s%s => %s (%s)", req.Method, t.hsName, req.URL.Path, res.Status, time.Since(start)) + } + return res, err +} + +// GetJSONFieldStr extracts a value from a byte-encoded JSON body given a search key +func GetJSONFieldStr(t *testing.T, body []byte, wantKey string) string { + t.Helper() + res := gjson.GetBytes(body, wantKey) + if !res.Exists() { + t.Fatalf("JSONFieldStr: key '%s' missing from %s", wantKey, string(body)) + } + if res.Str == "" { + t.Fatalf("JSONFieldStr: key '%s' is not a string, body: %s", wantKey, string(body)) + } + return res.Str +} + +func GetJSONFieldStringArray(t *testing.T, body []byte, wantKey string) []string { + t.Helper() + + res := gjson.GetBytes(body, wantKey) + + if !res.Exists() { + t.Fatalf("JSONFieldStr: key '%s' missing from %s", wantKey, string(body)) + } + + arrLength := len(res.Array()) + arr := make([]string, arrLength) + i := 0 + res.ForEach(func(key, value gjson.Result) bool { + arr[i] = value.Str + + // Keep iterating + i++ + return true + }) + + return arr +} + +// ParseJSON parses a JSON-encoded HTTP Response body into a byte slice +func ParseJSON(t *testing.T, res *http.Response) []byte { + t.Helper() + defer res.Body.Close() + body, err := io.ReadAll(res.Body) + if err != nil { + t.Fatalf("MustParseJSON: reading HTTP response body returned %s", err) + } + if !gjson.ValidBytes(body) { + t.Fatalf("MustParseJSON: Response is not valid JSON") + } + return body +} + +// GjsonEscape escapes . and * from the input so it can be used with gjson.Get +func GjsonEscape(in string) string { + in = strings.ReplaceAll(in, ".", `\.`) + in = strings.ReplaceAll(in, "*", `\*`) + return in +} + +func loopArray(object gjson.Result, key string, check func(gjson.Result) bool) error { + array := object.Get(key) + if !array.Exists() { + return fmt.Errorf("Key %s does not exist", key) + } + if !array.IsArray() { + return fmt.Errorf("Key %s exists but it isn't an array", key) + } + goArray := array.Array() + for _, ev := range goArray { + if check(ev) { + return nil + } + } + return fmt.Errorf("check function did not pass while iterating over %d elements: %v", len(goArray), array.Raw) +} + +// Splits an MXC URI into its origin and media ID parts +func SplitMxc(mxcUri string) (string, string) { + mxcParts := strings.Split(strings.TrimPrefix(mxcUri, "mxc://"), "/") + origin := mxcParts[0] + mediaId := strings.Join(mxcParts[1:], "/") + + return origin, mediaId +} + +// SendToDeviceMessages sends to-device messages over /sendToDevice/. +// +// The messages parameter is nested as follows: +// user_id -> device_id -> content (map[string]interface{}) +func (c *CSAPI) SendToDeviceMessages(t *testing.T, evType string, messages map[string]map[string]map[string]interface{}) { + t.Helper() + txnID := int(atomic.AddInt64(&c.txnID, 1)) + c.MustDo( + t, + "PUT", + []string{"_matrix", "client", "v3", "sendToDevice", evType, strconv.Itoa(txnID)}, + WithJSONBody( + t, + map[string]map[string]map[string]map[string]interface{}{ + "messages": messages, + }, + ), + ) +} diff --git a/client/sync.go b/client/sync.go new file mode 100644 index 00000000..6634dd23 --- /dev/null +++ b/client/sync.go @@ -0,0 +1,392 @@ +package client + +import ( + "fmt" + "net/url" + "strings" + "testing" + "time" + + "github.com/tidwall/gjson" +) + +// SyncCheckOpt is a functional option for use with MustSyncUntil which should return if +// the response satisfies the check, else return a human friendly error. +// The result object is the entire /sync response from this request. +type SyncCheckOpt func(clientUserID string, topLevelSyncJSON gjson.Result) error + +// SyncReq contains all the /sync request configuration options. The empty struct `SyncReq{}` is valid +// which will do a full /sync due to lack of a since token. +type SyncReq struct { + // A point in time to continue a sync from. This should be the next_batch token returned by an + // earlier call to this endpoint. + Since string + // The ID of a filter created using the filter API or a filter JSON object encoded as a string. + // The server will detect whether it is an ID or a JSON object by whether the first character is + // a "{" open brace. Passing the JSON inline is best suited to one off requests. Creating a + // filter using the filter API is recommended for clients that reuse the same filter multiple + // times, for example in long poll requests. + Filter string + // Controls whether to include the full state for all rooms the user is a member of. + // If this is set to true, then all state events will be returned, even if since is non-empty. + // The timeline will still be limited by the since parameter. In this case, the timeout parameter + // will be ignored and the query will return immediately, possibly with an empty timeline. + // If false, and since is non-empty, only state which has changed since the point indicated by + // since will be returned. + // By default, this is false. + FullState bool + // Controls whether the client is automatically marked as online by polling this API. If this + // parameter is omitted then the client is automatically marked as online when it uses this API. + // Otherwise if the parameter is set to “offline” then the client is not marked as being online + // when it uses this API. When set to “unavailable”, the client is marked as being idle. + // One of: [offline online unavailable]. + SetPresence string + // The maximum time to wait, in milliseconds, before returning this request. If no events + // (or other data) become available before this time elapses, the server will return a response + // with empty fields. + // By default, this is 1000 for Complement testing. + TimeoutMillis string // string for easier conversion to query params +} + +// MustSyncUntil blocks and continually calls /sync (advancing the since token) until all the +// check functions return no error. Returns the final/latest since token. +// +// Initial /sync example: (no since token) +// +// bob.InviteRoom(t, roomID, alice.UserID) +// alice.JoinRoom(t, roomID, nil) +// alice.MustSyncUntil(t, client.SyncReq{}, client.SyncJoinedTo(alice.UserID, roomID)) +// +// Incremental /sync example: (test controls since token) +// +// since := alice.MustSyncUntil(t, client.SyncReq{TimeoutMillis: "0"}) // get a since token +// bob.InviteRoom(t, roomID, alice.UserID) +// since = alice.MustSyncUntil(t, client.SyncReq{Since: since}, client.SyncInvitedTo(alice.UserID, roomID)) +// alice.JoinRoom(t, roomID, nil) +// alice.MustSyncUntil(t, client.SyncReq{Since: since}, client.SyncJoinedTo(alice.UserID, roomID)) +// +// Checking multiple parts of /sync: +// +// alice.MustSyncUntil( +// t, client.SyncReq{}, +// client.SyncJoinedTo(alice.UserID, roomID), +// client.SyncJoinedTo(alice.UserID, roomID2), +// client.SyncJoinedTo(alice.UserID, roomID3), +// ) +// +// Check functions are unordered and independent. Once a check function returns true it is removed +// from the list of checks and won't be called again. +// +// In the unlikely event that you want all the checkers to pass *explicitly* in a single /sync +// response (e.g to assert some form of atomic update which updates multiple parts of the /sync +// response at once) then make your own checker function which does this. +// +// In the unlikely event that you need ordering on your checks, call MustSyncUntil multiple times +// with a single checker, and reuse the returned since token, as in the "Incremental sync" example. +// +// Will time out after CSAPI.SyncUntilTimeout. Returns the `next_batch` token from the final +// response. +func (c *CSAPI) MustSyncUntil(t *testing.T, syncReq SyncReq, checks ...SyncCheckOpt) string { + t.Helper() + start := time.Now() + numResponsesReturned := 0 + checkers := make([]struct { + check SyncCheckOpt + errs []string + }, len(checks)) + for i := range checks { + c := checkers[i] + c.check = checks[i] + checkers[i] = c + } + printErrors := func() string { + err := "Checkers:\n" + for _, c := range checkers { + err += strings.Join(c.errs, "\n") + err += ", \n" + } + return err + } + for { + if time.Since(start) > c.SyncUntilTimeout { + t.Fatalf("%s MustSyncUntil: timed out after %v. Seen %d /sync responses. %s", c.UserID, time.Since(start), numResponsesReturned, printErrors()) + } + response, nextBatch := c.MustSync(t, syncReq) + syncReq.Since = nextBatch + numResponsesReturned += 1 + + for i := 0; i < len(checkers); i++ { + err := checkers[i].check(c.UserID, response) + if err == nil { + // check passed, removed from checkers + checkers = append(checkers[:i], checkers[i+1:]...) + i-- + } else { + c := checkers[i] + c.errs = append(c.errs, fmt.Sprintf("[t=%v] Response #%d: %s", time.Since(start), numResponsesReturned, err)) + checkers[i] = c + } + } + if len(checkers) == 0 { + // every checker has passed! + return syncReq.Since + } + } +} + +// Perform a single /sync request with the given request options. To sync until something happens, +// see `MustSyncUntil`. +// +// Fails the test if the /sync request does not return 200 OK. +// Returns the top-level parsed /sync response JSON as well as the next_batch token from the response. +func (c *CSAPI) MustSync(t *testing.T, syncReq SyncReq) (gjson.Result, string) { + t.Helper() + query := url.Values{ + "timeout": []string{"1000"}, + } + // configure the HTTP request based on SyncReq + if syncReq.TimeoutMillis != "" { + query["timeout"] = []string{syncReq.TimeoutMillis} + } + if syncReq.Since != "" { + query["since"] = []string{syncReq.Since} + } + if syncReq.Filter != "" { + query["filter"] = []string{syncReq.Filter} + } + if syncReq.FullState { + query["full_state"] = []string{"true"} + } + if syncReq.SetPresence != "" { + query["set_presence"] = []string{syncReq.SetPresence} + } + res := c.MustDo(t, "GET", []string{"_matrix", "client", "v3", "sync"}, WithQueries(query)) + body := ParseJSON(t, res) + result := gjson.ParseBytes(body) + nextBatch := GetJSONFieldStr(t, body, "next_batch") + return result, nextBatch +} + +// Check that the timeline for `roomID` has an event which passes the check function. +func SyncTimelineHas(roomID string, check func(gjson.Result) bool) SyncCheckOpt { + return func(clientUserID string, topLevelSyncJSON gjson.Result) error { + err := loopArray( + topLevelSyncJSON, "rooms.join."+GjsonEscape(roomID)+".timeline.events", check, + ) + if err == nil { + return nil + } + return fmt.Errorf("SyncTimelineHas(%s): %s", roomID, err) + } +} + +// Check that the timeline for `roomID` has an event which matches the event ID. +func SyncTimelineHasEventID(roomID string, eventID string) SyncCheckOpt { + return SyncTimelineHas(roomID, func(ev gjson.Result) bool { + return ev.Get("event_id").Str == eventID + }) +} + +// Check that the state section for `roomID` has an event which passes the check function. +// Note that the state section of a sync response only contains the change in state up to the start +// of the timeline and will not contain the entire state of the room for incremental or +// `lazy_load_members` syncs. +func SyncStateHas(roomID string, check func(gjson.Result) bool) SyncCheckOpt { + return func(clientUserID string, topLevelSyncJSON gjson.Result) error { + err := loopArray( + topLevelSyncJSON, "rooms.join."+GjsonEscape(roomID)+".state.events", check, + ) + if err == nil { + return nil + } + return fmt.Errorf("SyncStateHas(%s): %s", roomID, err) + } +} + +func SyncEphemeralHas(roomID string, check func(gjson.Result) bool) SyncCheckOpt { + return func(clientUserID string, topLevelSyncJSON gjson.Result) error { + err := loopArray( + topLevelSyncJSON, "rooms.join."+GjsonEscape(roomID)+".ephemeral.events", check, + ) + if err == nil { + return nil + } + return fmt.Errorf("SyncEphemeralHas(%s): %s", roomID, err) + } +} + +// Check that the sync contains presence from a user, optionally with an expected presence (set to nil to not check), +// and optionally with extra checks. +func SyncPresenceHas(fromUser string, expectedPresence *string, checks ...func(gjson.Result) bool) SyncCheckOpt { + return func(clientUserID string, topLevelSyncJSON gjson.Result) error { + presenceEvents := topLevelSyncJSON.Get("presence.events") + if !presenceEvents.Exists() { + return fmt.Errorf("presence.events does not exist") + } + for _, x := range presenceEvents.Array() { + if !(x.Get("type").Exists() && + x.Get("sender").Exists() && + x.Get("content").Exists() && + x.Get("content.presence").Exists()) { + return fmt.Errorf( + "malformatted presence event, expected the following fields: [sender, type, content, content.presence]: %s", + x.Raw, + ) + } else if x.Get("sender").Str != fromUser { + continue + } else if expectedPresence != nil && x.Get("content.presence").Str != *expectedPresence { + return fmt.Errorf( + "found presence for user %s, but not expected presence: got %s, want %s", + fromUser, x.Get("content.presence").Str, *expectedPresence, + ) + } else { + for i, check := range checks { + if !check(x) { + return fmt.Errorf("matched presence event to user %s, but check %d did not pass", fromUser, i) + } + } + return nil + } + } + return fmt.Errorf("did not find %s in presence events", fromUser) + } +} + +// Checks that `userID` gets invited to `roomID`. +// +// This checks different parts of the /sync response depending on the client making the request. +// If the client is also the person being invited to the room then the 'invite' block will be inspected. +// If the client is different to the person being invited then the 'join' block will be inspected. +func SyncInvitedTo(userID, roomID string) SyncCheckOpt { + return func(clientUserID string, topLevelSyncJSON gjson.Result) error { + // two forms which depend on what the client user is: + // - passively viewing an invite for a room you're joined to (timeline events) + // - actively being invited to a room. + if clientUserID == userID { + // active + err := loopArray( + topLevelSyncJSON, "rooms.invite."+GjsonEscape(roomID)+".invite_state.events", + func(ev gjson.Result) bool { + return ev.Get("type").Str == "m.room.member" && ev.Get("state_key").Str == userID && ev.Get("content.membership").Str == "invite" + }, + ) + if err != nil { + return fmt.Errorf("SyncInvitedTo(%s): %s", roomID, err) + } + return nil + } + // passive + return SyncTimelineHas(roomID, func(ev gjson.Result) bool { + return ev.Get("type").Str == "m.room.member" && ev.Get("state_key").Str == userID && ev.Get("content.membership").Str == "invite" + })(clientUserID, topLevelSyncJSON) + } +} + +// Check that `userID` gets joined to `roomID` by inspecting the join timeline for a membership event. +// +// Additional checks can be passed to narrow down the check, all must pass. +func SyncJoinedTo(userID, roomID string, checks ...func(gjson.Result) bool) SyncCheckOpt { + checkJoined := func(ev gjson.Result) bool { + if ev.Get("type").Str == "m.room.member" && ev.Get("state_key").Str == userID && ev.Get("content.membership").Str == "join" { + for _, check := range checks { + if !check(ev) { + // short-circuit, bail early + return false + } + } + // passed both basic join check and all other checks + return true + } + return false + } + return func(clientUserID string, topLevelSyncJSON gjson.Result) error { + // Check both the timeline and the state events for the join event + // since on initial sync, the state events may only be in + // .state.events. + firstErr := loopArray( + topLevelSyncJSON, "rooms.join."+GjsonEscape(roomID)+".timeline.events", checkJoined, + ) + if firstErr == nil { + return nil + } + + secondErr := loopArray( + topLevelSyncJSON, "rooms.join."+GjsonEscape(roomID)+".state.events", checkJoined, + ) + if secondErr == nil { + return nil + } + return fmt.Errorf("SyncJoinedTo(%s): %s & %s", roomID, firstErr, secondErr) + } +} + +// Check that `userID` is leaving `roomID` by inspecting the timeline for a membership event, or witnessing `roomID` in `rooms.leave` +// Note: This will not work properly with initial syncs, see https://github.com/matrix-org/matrix-doc/issues/3537 +func SyncLeftFrom(userID, roomID string) SyncCheckOpt { + return func(clientUserID string, topLevelSyncJSON gjson.Result) error { + // two forms which depend on what the client user is: + // - passively viewing a membership for a room you're joined in + // - actively leaving the room + if clientUserID == userID { + // active + events := topLevelSyncJSON.Get("rooms.leave." + GjsonEscape(roomID)) + if !events.Exists() { + return fmt.Errorf("no leave section for room %s", roomID) + } else { + return nil + } + } + // passive + return SyncTimelineHas(roomID, func(ev gjson.Result) bool { + return ev.Get("type").Str == "m.room.member" && ev.Get("state_key").Str == userID && ev.Get("content.membership").Str == "leave" + })(clientUserID, topLevelSyncJSON) + } +} + +// Calls the `check` function for each global account data event, and returns with success if the +// `check` function returns true for at least one event. +func SyncGlobalAccountDataHas(check func(gjson.Result) bool) SyncCheckOpt { + return func(clientUserID string, topLevelSyncJSON gjson.Result) error { + return loopArray(topLevelSyncJSON, "account_data.events", check) + } +} + +// Calls the `check` function for each account data event for the given room, +// and returns with success if the `check` function returns true for at least +// one event. +func SyncRoomAccountDataHas(roomID string, check func(gjson.Result) bool) SyncCheckOpt { + return func(clientUserID string, topLevelSyncJSON gjson.Result) error { + err := loopArray( + topLevelSyncJSON, "rooms.join."+GjsonEscape(roomID)+".account_data.events", check, + ) + if err == nil { + return nil + } + return fmt.Errorf("SyncRoomAccountDataHas(%s): %s", roomID, err) + } +} + +// Check that sync has received a to-device message, +// with optional user filtering. +// +// If fromUser == "", all messages will be passed through to the check function. +// `check` will be called for all messages that have passed the filter. +// +// `check` gets passed the full event, including sender and type. +func SyncToDeviceHas(fromUser string, check func(gjson.Result) bool) SyncCheckOpt { + return func(clientUserID string, topLevelSyncJSON gjson.Result) error { + err := loopArray( + topLevelSyncJSON, "to_device.events", func(result gjson.Result) bool { + if fromUser != "" && result.Get("sender").Str != fromUser { + return false + } else { + return check(result) + } + }, + ) + if err == nil { + return nil + } + return fmt.Errorf("SyncToDeviceHas(%v): %s", fromUser, err) + } +} diff --git a/internal/client/client.go b/internal/client/client.go deleted file mode 100644 index 2accca90..00000000 --- a/internal/client/client.go +++ /dev/null @@ -1,1117 +0,0 @@ -package client - -import ( - "bytes" - "context" - "crypto/hmac" - "crypto/sha1" // nolint:gosec - "encoding/hex" - "encoding/json" - "fmt" - "io" - "io/ioutil" - "net/http" - "net/http/httputil" - "net/url" - "strconv" - "strings" - "sync/atomic" - "testing" - "time" - - "github.com/matrix-org/gomatrixserverlib" - "github.com/tidwall/gjson" - - "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/must" -) - -const ( - SharedSecret = "complement" -) - -type CtxKey string - -const ( - CtxKeyWithRetryUntil CtxKey = "complement_retry_until" // contains *retryUntilParams -) - -type retryUntilParams struct { - timeout time.Duration - untilFn func(*http.Response) bool -} - -// RequestOpt is a functional option which will modify an outgoing HTTP request. -// See functions starting with `With...` in this package for more info. -type RequestOpt func(req *http.Request) - -// SyncCheckOpt is a functional option for use with MustSyncUntil which should return if -// the response satisfies the check, else return a human friendly error. -// The result object is the entire /sync response from this request. -type SyncCheckOpt func(clientUserID string, topLevelSyncJSON gjson.Result) error - -// SyncReq contains all the /sync request configuration options. The empty struct `SyncReq{}` is valid -// which will do a full /sync due to lack of a since token. -type SyncReq struct { - // A point in time to continue a sync from. This should be the next_batch token returned by an - // earlier call to this endpoint. - Since string - // The ID of a filter created using the filter API or a filter JSON object encoded as a string. - // The server will detect whether it is an ID or a JSON object by whether the first character is - // a "{" open brace. Passing the JSON inline is best suited to one off requests. Creating a - // filter using the filter API is recommended for clients that reuse the same filter multiple - // times, for example in long poll requests. - Filter string - // Controls whether to include the full state for all rooms the user is a member of. - // If this is set to true, then all state events will be returned, even if since is non-empty. - // The timeline will still be limited by the since parameter. In this case, the timeout parameter - // will be ignored and the query will return immediately, possibly with an empty timeline. - // If false, and since is non-empty, only state which has changed since the point indicated by - // since will be returned. - // By default, this is false. - FullState bool - // Controls whether the client is automatically marked as online by polling this API. If this - // parameter is omitted then the client is automatically marked as online when it uses this API. - // Otherwise if the parameter is set to “offline” then the client is not marked as being online - // when it uses this API. When set to “unavailable”, the client is marked as being idle. - // One of: [offline online unavailable]. - SetPresence string - // The maximum time to wait, in milliseconds, before returning this request. If no events - // (or other data) become available before this time elapses, the server will return a response - // with empty fields. - // By default, this is 1000 for Complement testing. - TimeoutMillis string // string for easier conversion to query params -} - -type CSAPI struct { - UserID string - AccessToken string - DeviceID string - BaseURL string - Client *http.Client - // how long are we willing to wait for MustSyncUntil.... calls - SyncUntilTimeout time.Duration - // True to enable verbose logging - Debug bool - - txnID int64 -} - -// UploadContent uploads the provided content with an optional file name. Fails the test on error. Returns the MXC URI. -func (c *CSAPI) UploadContent(t *testing.T, fileBody []byte, fileName string, contentType string) string { - t.Helper() - query := url.Values{} - if fileName != "" { - query.Set("filename", fileName) - } - res := c.MustDoFunc( - t, "POST", []string{"_matrix", "media", "v3", "upload"}, - WithRawBody(fileBody), WithContentType(contentType), WithQueries(query), - ) - body := ParseJSON(t, res) - return GetJSONFieldStr(t, body, "content_uri") -} - -// DownloadContent downloads media from the server, returning the raw bytes and the Content-Type. Fails the test on error. -func (c *CSAPI) DownloadContent(t *testing.T, mxcUri string) ([]byte, string) { - t.Helper() - origin, mediaId := SplitMxc(mxcUri) - res := c.MustDoFunc(t, "GET", []string{"_matrix", "media", "v3", "download", origin, mediaId}) - contentType := res.Header.Get("Content-Type") - b, err := ioutil.ReadAll(res.Body) - if err != nil { - t.Error(err) - } - return b, contentType -} - -// CreateRoom creates a room with an optional HTTP request body. Fails the test on error. Returns the room ID. -func (c *CSAPI) CreateRoom(t *testing.T, creationContent interface{}) string { - t.Helper() - res := c.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "createRoom"}, WithJSONBody(t, creationContent)) - body := ParseJSON(t, res) - return GetJSONFieldStr(t, body, "room_id") -} - -// JoinRoom joins the room ID or alias given, else fails the test. Returns the room ID. -func (c *CSAPI) JoinRoom(t *testing.T, roomIDOrAlias string, serverNames []string) string { - t.Helper() - // construct URL query parameters - query := make(url.Values, len(serverNames)) - for _, serverName := range serverNames { - query.Add("server_name", serverName) - } - // join the room - res := c.MustDoFunc( - t, "POST", []string{"_matrix", "client", "v3", "join", roomIDOrAlias}, - WithQueries(query), WithJSONBody(t, map[string]interface{}{}), - ) - // return the room ID if we joined with it - if roomIDOrAlias[0] == '!' { - return roomIDOrAlias - } - // otherwise we should be told the room ID if we joined via an alias - body := ParseJSON(t, res) - return GetJSONFieldStr(t, body, "room_id") -} - -// LeaveRoom leaves the room ID, else fails the test. -func (c *CSAPI) LeaveRoom(t *testing.T, roomID string) { - t.Helper() - // leave the room - body := map[string]interface{}{} - c.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "leave"}, WithJSONBody(t, body)) -} - -// InviteRoom invites userID to the room ID, else fails the test. -func (c *CSAPI) InviteRoom(t *testing.T, roomID string, userID string) { - t.Helper() - // Invite the user to the room - body := map[string]interface{}{ - "user_id": userID, - } - c.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "invite"}, WithJSONBody(t, body)) -} - -func (c *CSAPI) GetGlobalAccountData(t *testing.T, eventType string) *http.Response { - return c.MustDoFunc(t, "GET", []string{"_matrix", "client", "v3", "user", c.UserID, "account_data", eventType}) -} - -func (c *CSAPI) SetGlobalAccountData(t *testing.T, eventType string, content map[string]interface{}) *http.Response { - return c.MustDoFunc(t, "PUT", []string{"_matrix", "client", "v3", "user", c.UserID, "account_data", eventType}, WithJSONBody(t, content)) -} - -func (c *CSAPI) GetRoomAccountData(t *testing.T, roomID string, eventType string) *http.Response { - return c.MustDoFunc(t, "GET", []string{"_matrix", "client", "v3", "user", c.UserID, "rooms", roomID, "account_data", eventType}) -} - -func (c *CSAPI) SetRoomAccountData(t *testing.T, roomID string, eventType string, content map[string]interface{}) *http.Response { - return c.MustDoFunc(t, "PUT", []string{"_matrix", "client", "v3", "user", c.UserID, "rooms", roomID, "account_data", eventType}, WithJSONBody(t, content)) -} - -// GetAllPushRules fetches all configured push rules for a user from the homeserver. -// Push rules are returned as a parsed gjson result -// -// Example of printing the IDs of all underride rules of the current user: -// -// allPushRules := c.GetAllPushRules(t) -// globalUnderridePushRules := allPushRules.Get("global").Get("underride").Array() -// -// for index, rule := range globalUnderridePushRules { -// fmt.Printf("This rule's ID is: %s\n", rule.Get("rule_id").Str) -// } -// -// Push rules are returned in the same order received from the homeserver. -func (c *CSAPI) GetAllPushRules(t *testing.T) gjson.Result { - t.Helper() - - // We have to supply an empty string to the end of this path in order to generate a trailing slash. - // See https://github.com/matrix-org/matrix-spec/issues/457 - res := c.MustDoFunc(t, "GET", []string{"_matrix", "client", "v3", "pushrules", ""}) - pushRulesBytes := ParseJSON(t, res) - return gjson.ParseBytes(pushRulesBytes) -} - -// GetPushRule queries the contents of a client's push rule by scope, kind and rule ID. -// A parsed gjson result is returned. Fails the test if the query to server returns a non-2xx status code. -// -// Example of checking that a global underride rule contains the expected actions: -// -// containsDisplayNameRule := c.GetPushRule(t, "global", "underride", ".m.rule.contains_display_name") -// must.MatchGJSON( -// t, -// containsDisplayNameRule, -// match.JSONKeyEqual("actions", []interface{}{ -// "notify", -// map[string]interface{}{"set_tweak": "sound", "value": "default"}, -// map[string]interface{}{"set_tweak": "highlight"}, -// }), -// ) -func (c *CSAPI) GetPushRule(t *testing.T, scope string, kind string, ruleID string) gjson.Result { - t.Helper() - - res := c.MustDoFunc(t, "GET", []string{"_matrix", "client", "v3", "pushrules", scope, kind, ruleID}) - pushRuleBytes := ParseJSON(t, res) - return gjson.ParseBytes(pushRuleBytes) -} - -// SetPushRule creates a new push rule on the user, or modifies an existing one. -// If `before` or `after` parameters are not set to an empty string, their values -// will be set as the `before` and `after` query parameters respectively on the -// "set push rules" client endpoint: -// https://spec.matrix.org/v1.5/client-server-api/#put_matrixclientv3pushrulesscopekindruleid -// -// Example of setting a push rule with ID 'com.example.rule2' that must come after 'com.example.rule1': -// -// c.SetPushRule(t, "global", "underride", "com.example.rule2", map[string]interface{}{ -// "actions": []string{"dont_notify"}, -// }, nil, "com.example.rule1") -func (c *CSAPI) SetPushRule(t *testing.T, scope string, kind string, ruleID string, body map[string]interface{}, before string, after string) *http.Response { - t.Helper() - - // If the `before` or `after` arguments have been provided, construct same-named query parameters - queryParams := url.Values{} - if before != "" { - queryParams.Add("before", before) - } - if after != "" { - queryParams.Add("after", after) - } - - return c.MustDoFunc(t, "PUT", []string{"_matrix", "client", "v3", "pushrules", scope, kind, ruleID}, WithJSONBody(t, body), WithQueries(queryParams)) -} - -// SendEventUnsynced sends `e` into the room. -// Returns the event ID of the sent event. -func (c *CSAPI) SendEventUnsynced(t *testing.T, roomID string, e b.Event) string { - t.Helper() - txnID := int(atomic.AddInt64(&c.txnID, 1)) - return c.SendEventUnsyncedWithTxnID(t, roomID, e, strconv.Itoa(txnID)) -} - -// SendEventUnsyncedWithTxnID sends `e` into the room with a prescribed transaction ID. -// This is useful for writing tests that interrogate transaction semantics. -// Returns the event ID of the sent event. -func (c *CSAPI) SendEventUnsyncedWithTxnID(t *testing.T, roomID string, e b.Event, txnID string) string { - t.Helper() - paths := []string{"_matrix", "client", "v3", "rooms", roomID, "send", e.Type, txnID} - if e.StateKey != nil { - paths = []string{"_matrix", "client", "v3", "rooms", roomID, "state", e.Type, *e.StateKey} - } - res := c.MustDoFunc(t, "PUT", paths, WithJSONBody(t, e.Content)) - body := ParseJSON(t, res) - eventID := GetJSONFieldStr(t, body, "event_id") - return eventID -} - -// SendEventSynced sends `e` into the room and waits for its event ID to come down /sync. -// Returns the event ID of the sent event. -func (c *CSAPI) SendEventSynced(t *testing.T, roomID string, e b.Event) string { - t.Helper() - eventID := c.SendEventUnsynced(t, roomID, e) - t.Logf("SendEventSynced waiting for event ID %s", eventID) - c.MustSyncUntil(t, SyncReq{}, SyncTimelineHas(roomID, func(r gjson.Result) bool { - return r.Get("event_id").Str == eventID - })) - return eventID -} - -// SendRedaction sends a redaction request. Will fail if the returned HTTP request code is not 200 -func (c *CSAPI) SendRedaction(t *testing.T, roomID string, e b.Event, eventID string) string { - t.Helper() - txnID := int(atomic.AddInt64(&c.txnID, 1)) - paths := []string{"_matrix", "client", "v3", "rooms", roomID, "redact", eventID, strconv.Itoa(txnID)} - res := c.MustDoFunc(t, "PUT", paths, WithJSONBody(t, e.Content)) - body := ParseJSON(t, res) - return GetJSONFieldStr(t, body, "event_id") -} - -// Perform a single /sync request with the given request options. To sync until something happens, -// see `MustSyncUntil`. -// -// Fails the test if the /sync request does not return 200 OK. -// Returns the top-level parsed /sync response JSON as well as the next_batch token from the response. -func (c *CSAPI) MustSync(t *testing.T, syncReq SyncReq) (gjson.Result, string) { - t.Helper() - query := url.Values{ - "timeout": []string{"1000"}, - } - // configure the HTTP request based on SyncReq - if syncReq.TimeoutMillis != "" { - query["timeout"] = []string{syncReq.TimeoutMillis} - } - if syncReq.Since != "" { - query["since"] = []string{syncReq.Since} - } - if syncReq.Filter != "" { - query["filter"] = []string{syncReq.Filter} - } - if syncReq.FullState { - query["full_state"] = []string{"true"} - } - if syncReq.SetPresence != "" { - query["set_presence"] = []string{syncReq.SetPresence} - } - res := c.MustDoFunc(t, "GET", []string{"_matrix", "client", "v3", "sync"}, WithQueries(query)) - body := ParseJSON(t, res) - result := gjson.ParseBytes(body) - nextBatch := GetJSONFieldStr(t, body, "next_batch") - return result, nextBatch -} - -// MustSyncUntil blocks and continually calls /sync (advancing the since token) until all the -// check functions return no error. Returns the final/latest since token. -// -// Initial /sync example: (no since token) -// bob.InviteRoom(t, roomID, alice.UserID) -// alice.JoinRoom(t, roomID, nil) -// alice.MustSyncUntil(t, client.SyncReq{}, client.SyncJoinedTo(alice.UserID, roomID)) -// -// Incremental /sync example: (test controls since token) -// since := alice.MustSyncUntil(t, client.SyncReq{TimeoutMillis: "0"}) // get a since token -// bob.InviteRoom(t, roomID, alice.UserID) -// since = alice.MustSyncUntil(t, client.SyncReq{Since: since}, client.SyncInvitedTo(alice.UserID, roomID)) -// alice.JoinRoom(t, roomID, nil) -// alice.MustSyncUntil(t, client.SyncReq{Since: since}, client.SyncJoinedTo(alice.UserID, roomID)) -// -// Checking multiple parts of /sync: -// alice.MustSyncUntil( -// t, client.SyncReq{}, -// client.SyncJoinedTo(alice.UserID, roomID), -// client.SyncJoinedTo(alice.UserID, roomID2), -// client.SyncJoinedTo(alice.UserID, roomID3), -// ) -// -// Check functions are unordered and independent. Once a check function returns true it is removed -// from the list of checks and won't be called again. -// -// In the unlikely event that you want all the checkers to pass *explicitly* in a single /sync -// response (e.g to assert some form of atomic update which updates multiple parts of the /sync -// response at once) then make your own checker function which does this. -// -// In the unlikely event that you need ordering on your checks, call MustSyncUntil multiple times -// with a single checker, and reuse the returned since token, as in the "Incremental sync" example. -// -// Will time out after CSAPI.SyncUntilTimeout. Returns the `next_batch` token from the final -// response. -func (c *CSAPI) MustSyncUntil(t *testing.T, syncReq SyncReq, checks ...SyncCheckOpt) string { - t.Helper() - start := time.Now() - numResponsesReturned := 0 - checkers := make([]struct { - check SyncCheckOpt - errs []string - }, len(checks)) - for i := range checks { - c := checkers[i] - c.check = checks[i] - checkers[i] = c - } - printErrors := func() string { - err := "Checkers:\n" - for _, c := range checkers { - err += strings.Join(c.errs, "\n") - err += ", \n" - } - return err - } - for { - if time.Since(start) > c.SyncUntilTimeout { - t.Fatalf("%s MustSyncUntil: timed out after %v. Seen %d /sync responses. %s", c.UserID, time.Since(start), numResponsesReturned, printErrors()) - } - response, nextBatch := c.MustSync(t, syncReq) - syncReq.Since = nextBatch - numResponsesReturned += 1 - - for i := 0; i < len(checkers); i++ { - err := checkers[i].check(c.UserID, response) - if err == nil { - // check passed, removed from checkers - checkers = append(checkers[:i], checkers[i+1:]...) - i-- - } else { - c := checkers[i] - c.errs = append(c.errs, fmt.Sprintf("[t=%v] Response #%d: %s", time.Since(start), numResponsesReturned, err)) - checkers[i] = c - } - } - if len(checkers) == 0 { - // every checker has passed! - return syncReq.Since - } - } -} - -type LoginOpt func(map[string]interface{}) - -func WithDeviceID(deviceID string) LoginOpt { - return func(loginBody map[string]interface{}) { - loginBody["device_id"] = deviceID - } -} - -// LoginUser will log in to a homeserver and create a new device on an existing user. -func (c *CSAPI) LoginUser(t *testing.T, localpart, password string, opts ...LoginOpt) (userID, accessToken, deviceID string) { - t.Helper() - reqBody := map[string]interface{}{ - "identifier": map[string]interface{}{ - "type": "m.id.user", - "user": localpart, - }, - "password": password, - "type": "m.login.password", - } - - for _, opt := range opts { - opt(reqBody) - } - - res := c.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "login"}, WithJSONBody(t, reqBody)) - - body, err := ioutil.ReadAll(res.Body) - if err != nil { - t.Fatalf("unable to read response body: %v", err) - } - - userID = gjson.GetBytes(body, "user_id").Str - accessToken = gjson.GetBytes(body, "access_token").Str - deviceID = gjson.GetBytes(body, "device_id").Str - return userID, accessToken, deviceID -} - -// LoginUserWithRefreshToken will log in to a homeserver, with refresh token enabled, -// and create a new device on an existing user. -func (c *CSAPI) LoginUserWithRefreshToken(t *testing.T, localpart, password string) (userID, accessToken, refreshToken, deviceID string, expiresInMs int64) { - t.Helper() - reqBody := map[string]interface{}{ - "identifier": map[string]interface{}{ - "type": "m.id.user", - "user": localpart, - }, - "password": password, - "type": "m.login.password", - "refresh_token": true, - } - res := c.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "login"}, WithJSONBody(t, reqBody)) - - body, err := ioutil.ReadAll(res.Body) - if err != nil { - t.Fatalf("unable to read response body: %v", err) - } - - userID = gjson.GetBytes(body, "user_id").Str - accessToken = gjson.GetBytes(body, "access_token").Str - deviceID = gjson.GetBytes(body, "device_id").Str - refreshToken = gjson.GetBytes(body, "refresh_token").Str - expiresInMs = gjson.GetBytes(body, "expires_in_ms").Int() - return userID, accessToken, refreshToken, deviceID, expiresInMs -} - -// RefreshToken will consume a refresh token and return a new access token and refresh token. -func (c *CSAPI) ConsumeRefreshToken(t *testing.T, refreshToken string) (newAccessToken, newRefreshToken string, expiresInMs int64) { - t.Helper() - reqBody := map[string]interface{}{ - "refresh_token": refreshToken, - } - res := c.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "refresh"}, WithJSONBody(t, reqBody)) - - body, err := ioutil.ReadAll(res.Body) - if err != nil { - t.Fatalf("unable to read response body: %v", err) - } - - newAccessToken = gjson.GetBytes(body, "access_token").Str - newRefreshToken = gjson.GetBytes(body, "refresh_token").Str - expiresInMs = gjson.GetBytes(body, "expires_in_ms").Int() - return newAccessToken, newRefreshToken, expiresInMs -} - -// RegisterUser will register the user with given parameters and -// return user ID, access token and device ID. It fails the test on network error. -func (c *CSAPI) RegisterUser(t *testing.T, localpart, password string) (userID, accessToken, deviceID string) { - t.Helper() - reqBody := map[string]interface{}{ - "auth": map[string]string{ - "type": "m.login.dummy", - }, - "username": localpart, - "password": password, - } - res := c.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "register"}, WithJSONBody(t, reqBody)) - - body, err := ioutil.ReadAll(res.Body) - if err != nil { - t.Fatalf("unable to read response body: %v", err) - } - - userID = gjson.GetBytes(body, "user_id").Str - accessToken = gjson.GetBytes(body, "access_token").Str - deviceID = gjson.GetBytes(body, "device_id").Str - return userID, accessToken, deviceID -} - -// RegisterSharedSecret registers a new account with a shared secret via HMAC -// See https://github.com/matrix-org/synapse/blob/e550ab17adc8dd3c48daf7fedcd09418a73f524b/synapse/_scripts/register_new_matrix_user.py#L40 -func (c *CSAPI) RegisterSharedSecret(t *testing.T, user, pass string, isAdmin bool) (userID, accessToken, deviceID string) { - resp := c.DoFunc(t, "GET", []string{"_synapse", "admin", "v1", "register"}) - if resp.StatusCode != 200 { - t.Skipf("Homeserver image does not support shared secret registration, /_synapse/admin/v1/register returned HTTP %d", resp.StatusCode) - return - } - body := must.ParseJSON(t, resp.Body) - nonce := gjson.GetBytes(body, "nonce") - if !nonce.Exists() { - t.Fatalf("Malformed shared secret GET response: %s", string(body)) - } - mac := hmac.New(sha1.New, []byte(SharedSecret)) - mac.Write([]byte(nonce.Str)) - mac.Write([]byte("\x00")) - mac.Write([]byte(user)) - mac.Write([]byte("\x00")) - mac.Write([]byte(pass)) - mac.Write([]byte("\x00")) - if isAdmin { - mac.Write([]byte("admin")) - } else { - mac.Write([]byte("notadmin")) - } - sig := mac.Sum(nil) - reqBody := map[string]interface{}{ - "nonce": nonce.Str, - "username": user, - "password": pass, - "mac": hex.EncodeToString(sig), - "admin": isAdmin, - } - resp = c.MustDoFunc(t, "POST", []string{"_synapse", "admin", "v1", "register"}, WithJSONBody(t, reqBody)) - body = must.ParseJSON(t, resp.Body) - userID = gjson.GetBytes(body, "user_id").Str - accessToken = gjson.GetBytes(body, "access_token").Str - deviceID = gjson.GetBytes(body, "device_id").Str - return userID, accessToken, deviceID -} - -// GetCapbabilities queries the server's capabilities -func (c *CSAPI) GetCapabilities(t *testing.T) []byte { - t.Helper() - res := c.MustDoFunc(t, "GET", []string{"_matrix", "client", "v3", "capabilities"}) - body, err := ioutil.ReadAll(res.Body) - if err != nil { - t.Fatalf("unable to read response body: %v", err) - } - return body -} - -// GetDefaultRoomVersion returns the server's default room version -func (c *CSAPI) GetDefaultRoomVersion(t *testing.T) gomatrixserverlib.RoomVersion { - t.Helper() - capabilities := c.GetCapabilities(t) - defaultVersion := gjson.GetBytes(capabilities, `capabilities.m\.room_versions.default`) - if !defaultVersion.Exists() { - // spec says use RoomV1 in this case - return gomatrixserverlib.RoomVersionV1 - } - - return gomatrixserverlib.RoomVersion(defaultVersion.Str) -} - -// WithRawBody sets the HTTP request body to `body` -func WithRawBody(body []byte) RequestOpt { - return func(req *http.Request) { - req.Body = ioutil.NopCloser(bytes.NewReader(body)) - req.GetBody = func() (io.ReadCloser, error) { - r := bytes.NewReader(body) - return ioutil.NopCloser(r), nil - } - // we need to manually set this because we don't set the body - // in http.NewRequest due to using functional options, and only in NewRequest - // does the stdlib set this for us. - req.ContentLength = int64(len(body)) - } -} - -// WithContentType sets the HTTP request Content-Type header to `cType` -func WithContentType(cType string) RequestOpt { - return func(req *http.Request) { - req.Header.Set("Content-Type", cType) - } -} - -// WithJSONBody sets the HTTP request body to the JSON serialised form of `obj` -func WithJSONBody(t *testing.T, obj interface{}) RequestOpt { - return func(req *http.Request) { - t.Helper() - b, err := json.Marshal(obj) - if err != nil { - t.Fatalf("CSAPI.Do failed to marshal JSON body: %s", err) - } - WithRawBody(b)(req) - } -} - -// WithQueries sets the query parameters on the request. -// This function should not be used to set an "access_token" parameter for Matrix authentication. -// Instead, set CSAPI.AccessToken. -func WithQueries(q url.Values) RequestOpt { - return func(req *http.Request) { - req.URL.RawQuery = q.Encode() - } -} - -// WithRetryUntil will retry the request until the provided function returns true. Times out after -// `timeout`, which will then fail the test. -func WithRetryUntil(timeout time.Duration, untilFn func(res *http.Response) bool) RequestOpt { - return func(req *http.Request) { - until := req.Context().Value(CtxKeyWithRetryUntil).(*retryUntilParams) - until.timeout = timeout - until.untilFn = untilFn - } -} - -// MustDoFunc is the same as DoFunc but fails the test if the returned HTTP response code is not 2xx. -func (c *CSAPI) MustDoFunc(t *testing.T, method string, paths []string, opts ...RequestOpt) *http.Response { - t.Helper() - res := c.DoFunc(t, method, paths, opts...) - if res.StatusCode < 200 || res.StatusCode >= 300 { - defer res.Body.Close() - body, _ := ioutil.ReadAll(res.Body) - t.Fatalf("CSAPI.MustDoFunc %s %s returned non-2xx code: %s - body: %s", method, res.Request.URL.String(), res.Status, string(body)) - } - return res -} - -// DoFunc performs an arbitrary HTTP request to the server. This function supports RequestOpts to set -// extra information on the request such as an HTTP request body, query parameters and content-type. -// See all functions in this package starting with `With...`. -// -// Fails the test if an HTTP request could not be made or if there was a network error talking to the -// server. To do assertions on the HTTP response, see the `must` package. For example: -// must.MatchResponse(t, res, match.HTTPResponse{ -// StatusCode: 400, -// JSON: []match.JSON{ -// match.JSONKeyEqual("errcode", "M_INVALID_USERNAME"), -// }, -// }) -func (c *CSAPI) DoFunc(t *testing.T, method string, paths []string, opts ...RequestOpt) *http.Response { - t.Helper() - for i := range paths { - paths[i] = url.PathEscape(paths[i]) - } - reqURL := c.BaseURL + "/" + strings.Join(paths, "/") - req, err := http.NewRequest(method, reqURL, nil) - if err != nil { - t.Fatalf("CSAPI.DoFunc failed to create http.NewRequest: %s", err) - } - // set defaults before RequestOpts - if c.AccessToken != "" { - req.Header.Set("Authorization", "Bearer "+c.AccessToken) - } - retryUntil := &retryUntilParams{} - ctx := context.WithValue(req.Context(), CtxKeyWithRetryUntil, retryUntil) - req = req.WithContext(ctx) - - // set functional options - for _, o := range opts { - o(req) - } - // set defaults after RequestOpts - if req.Header.Get("Content-Type") == "" { - req.Header.Set("Content-Type", "application/json") - } - // debug log the request - if c.Debug { - t.Logf("Making %s request to %s (%s)", method, req.URL, c.AccessToken) - contentType := req.Header.Get("Content-Type") - if contentType == "application/json" || strings.HasPrefix(contentType, "text/") { - if req.Body != nil { - body, _ := ioutil.ReadAll(req.Body) - t.Logf("Request body: %s", string(body)) - req.Body = ioutil.NopCloser(bytes.NewBuffer(body)) - } - } else { - t.Logf("Request body: ", contentType) - } - } - now := time.Now() - for { - // Perform the HTTP request - res, err := c.Client.Do(req) - if err != nil { - t.Fatalf("CSAPI.DoFunc response returned error: %s", err) - } - // debug log the response - if c.Debug && res != nil { - var dump []byte - dump, err = httputil.DumpResponse(res, true) - if err != nil { - t.Fatalf("CSAPI.DoFunc failed to dump response body: %s", err) - } - t.Logf("%s", string(dump)) - } - if retryUntil == nil || retryUntil.timeout == 0 { - return res // don't retry - } - - // check the condition, make a copy of the response body first in case the check consumes it - var resBody []byte - if res.Body != nil { - resBody, err = ioutil.ReadAll(res.Body) - if err != nil { - t.Fatalf("CSAPI.DoFunc failed to read response body for RetryUntil check: %s", err) - } - res.Body = io.NopCloser(bytes.NewBuffer(resBody)) - } - if retryUntil.untilFn(res) { - // remake the response and return - res.Body = io.NopCloser(bytes.NewBuffer(resBody)) - return res - } - // condition not satisfied, do we timeout yet? - if time.Since(now) > retryUntil.timeout { - t.Fatalf("CSAPI.DoFunc RetryUntil: %v %v timed out after %v", method, req.URL, retryUntil.timeout) - } - t.Logf("CSAPI.DoFunc RetryUntil: %v %v response condition not yet met, retrying", method, req.URL) - // small sleep to avoid tight-looping - time.Sleep(100 * time.Millisecond) - } -} - -// NewLoggedClient returns an http.Client which logs requests/responses -func NewLoggedClient(t *testing.T, hsName string, cli *http.Client) *http.Client { - t.Helper() - if cli == nil { - cli = &http.Client{ - Timeout: 30 * time.Second, - } - } - transport := cli.Transport - if transport == nil { - transport = http.DefaultTransport - } - cli.Transport = &loggedRoundTripper{t, hsName, transport} - return cli -} - -type loggedRoundTripper struct { - t *testing.T - hsName string - wrap http.RoundTripper -} - -func (t *loggedRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { - start := time.Now() - res, err := t.wrap.RoundTrip(req) - if err != nil { - t.t.Logf("[CSAPI] %s %s%s => error: %s (%s)", req.Method, t.hsName, req.URL.Path, err, time.Since(start)) - } else { - t.t.Logf("[CSAPI] %s %s%s => %s (%s)", req.Method, t.hsName, req.URL.Path, res.Status, time.Since(start)) - } - return res, err -} - -// GetJSONFieldStr extracts a value from a byte-encoded JSON body given a search key -func GetJSONFieldStr(t *testing.T, body []byte, wantKey string) string { - t.Helper() - res := gjson.GetBytes(body, wantKey) - if !res.Exists() { - t.Fatalf("JSONFieldStr: key '%s' missing from %s", wantKey, string(body)) - } - if res.Str == "" { - t.Fatalf("JSONFieldStr: key '%s' is not a string, body: %s", wantKey, string(body)) - } - return res.Str -} - -func GetJSONFieldStringArray(t *testing.T, body []byte, wantKey string) []string { - t.Helper() - - res := gjson.GetBytes(body, wantKey) - - if !res.Exists() { - t.Fatalf("JSONFieldStr: key '%s' missing from %s", wantKey, string(body)) - } - - arrLength := len(res.Array()) - arr := make([]string, arrLength) - i := 0 - res.ForEach(func(key, value gjson.Result) bool { - arr[i] = value.Str - - // Keep iterating - i++ - return true - }) - - return arr -} - -// ParseJSON parses a JSON-encoded HTTP Response body into a byte slice -func ParseJSON(t *testing.T, res *http.Response) []byte { - t.Helper() - defer res.Body.Close() - body, err := ioutil.ReadAll(res.Body) - if err != nil { - t.Fatalf("MustParseJSON: reading HTTP response body returned %s", err) - } - if !gjson.ValidBytes(body) { - t.Fatalf("MustParseJSON: Response is not valid JSON") - } - return body -} - -// GjsonEscape escapes . and * from the input so it can be used with gjson.Get -func GjsonEscape(in string) string { - in = strings.ReplaceAll(in, ".", `\.`) - in = strings.ReplaceAll(in, "*", `\*`) - return in -} - -// Check that the timeline for `roomID` has an event which passes the check function. -func SyncTimelineHas(roomID string, check func(gjson.Result) bool) SyncCheckOpt { - return func(clientUserID string, topLevelSyncJSON gjson.Result) error { - err := loopArray( - topLevelSyncJSON, "rooms.join."+GjsonEscape(roomID)+".timeline.events", check, - ) - if err == nil { - return nil - } - return fmt.Errorf("SyncTimelineHas(%s): %s", roomID, err) - } -} - -// Check that the timeline for `roomID` has an event which matches the event ID. -func SyncTimelineHasEventID(roomID string, eventID string) SyncCheckOpt { - return SyncTimelineHas(roomID, func(ev gjson.Result) bool { - return ev.Get("event_id").Str == eventID - }) -} - -// Check that the state section for `roomID` has an event which passes the check function. -// Note that the state section of a sync response only contains the change in state up to the start -// of the timeline and will not contain the entire state of the room for incremental or -// `lazy_load_members` syncs. -func SyncStateHas(roomID string, check func(gjson.Result) bool) SyncCheckOpt { - return func(clientUserID string, topLevelSyncJSON gjson.Result) error { - err := loopArray( - topLevelSyncJSON, "rooms.join."+GjsonEscape(roomID)+".state.events", check, - ) - if err == nil { - return nil - } - return fmt.Errorf("SyncStateHas(%s): %s", roomID, err) - } -} - -func SyncEphemeralHas(roomID string, check func(gjson.Result) bool) SyncCheckOpt { - return func(clientUserID string, topLevelSyncJSON gjson.Result) error { - err := loopArray( - topLevelSyncJSON, "rooms.join."+GjsonEscape(roomID)+".ephemeral.events", check, - ) - if err == nil { - return nil - } - return fmt.Errorf("SyncEphemeralHas(%s): %s", roomID, err) - } -} - -// Check that the sync contains presence from a user, optionally with an expected presence (set to nil to not check), -// and optionally with extra checks. -func SyncPresenceHas(fromUser string, expectedPresence *string, checks ...func(gjson.Result) bool) SyncCheckOpt { - return func(clientUserID string, topLevelSyncJSON gjson.Result) error { - presenceEvents := topLevelSyncJSON.Get("presence.events") - if !presenceEvents.Exists() { - return fmt.Errorf("presence.events does not exist") - } - for _, x := range presenceEvents.Array() { - if !(x.Get("type").Exists() && - x.Get("sender").Exists() && - x.Get("content").Exists() && - x.Get("content.presence").Exists()) { - return fmt.Errorf( - "malformatted presence event, expected the following fields: [sender, type, content, content.presence]: %s", - x.Raw, - ) - } else if x.Get("sender").Str != fromUser { - continue - } else if expectedPresence != nil && x.Get("content.presence").Str != *expectedPresence { - return fmt.Errorf( - "found presence for user %s, but not expected presence: got %s, want %s", - fromUser, x.Get("content.presence").Str, *expectedPresence, - ) - } else { - for i, check := range checks { - if !check(x) { - return fmt.Errorf("matched presence event to user %s, but check %d did not pass", fromUser, i) - } - } - return nil - } - } - return fmt.Errorf("did not find %s in presence events", fromUser) - } -} - -// Checks that `userID` gets invited to `roomID`. -// -// This checks different parts of the /sync response depending on the client making the request. -// If the client is also the person being invited to the room then the 'invite' block will be inspected. -// If the client is different to the person being invited then the 'join' block will be inspected. -func SyncInvitedTo(userID, roomID string) SyncCheckOpt { - return func(clientUserID string, topLevelSyncJSON gjson.Result) error { - // two forms which depend on what the client user is: - // - passively viewing an invite for a room you're joined to (timeline events) - // - actively being invited to a room. - if clientUserID == userID { - // active - err := loopArray( - topLevelSyncJSON, "rooms.invite."+GjsonEscape(roomID)+".invite_state.events", - func(ev gjson.Result) bool { - return ev.Get("type").Str == "m.room.member" && ev.Get("state_key").Str == userID && ev.Get("content.membership").Str == "invite" - }, - ) - if err != nil { - return fmt.Errorf("SyncInvitedTo(%s): %s", roomID, err) - } - return nil - } - // passive - return SyncTimelineHas(roomID, func(ev gjson.Result) bool { - return ev.Get("type").Str == "m.room.member" && ev.Get("state_key").Str == userID && ev.Get("content.membership").Str == "invite" - })(clientUserID, topLevelSyncJSON) - } -} - -// Check that `userID` gets joined to `roomID` by inspecting the join timeline for a membership event. -// -// Additional checks can be passed to narrow down the check, all must pass. -func SyncJoinedTo(userID, roomID string, checks ...func(gjson.Result) bool) SyncCheckOpt { - checkJoined := func(ev gjson.Result) bool { - if ev.Get("type").Str == "m.room.member" && ev.Get("state_key").Str == userID && ev.Get("content.membership").Str == "join" { - for _, check := range checks { - if !check(ev) { - // short-circuit, bail early - return false - } - } - // passed both basic join check and all other checks - return true - } - return false - } - return func(clientUserID string, topLevelSyncJSON gjson.Result) error { - // Check both the timeline and the state events for the join event - // since on initial sync, the state events may only be in - // .state.events. - firstErr := loopArray( - topLevelSyncJSON, "rooms.join."+GjsonEscape(roomID)+".timeline.events", checkJoined, - ) - if firstErr == nil { - return nil - } - - secondErr := loopArray( - topLevelSyncJSON, "rooms.join."+GjsonEscape(roomID)+".state.events", checkJoined, - ) - if secondErr == nil { - return nil - } - return fmt.Errorf("SyncJoinedTo(%s): %s & %s", roomID, firstErr, secondErr) - } -} - -// Check that `userID` is leaving `roomID` by inspecting the timeline for a membership event, or witnessing `roomID` in `rooms.leave` -// Note: This will not work properly with initial syncs, see https://github.com/matrix-org/matrix-doc/issues/3537 -func SyncLeftFrom(userID, roomID string) SyncCheckOpt { - return func(clientUserID string, topLevelSyncJSON gjson.Result) error { - // two forms which depend on what the client user is: - // - passively viewing a membership for a room you're joined in - // - actively leaving the room - if clientUserID == userID { - // active - events := topLevelSyncJSON.Get("rooms.leave." + GjsonEscape(roomID)) - if !events.Exists() { - return fmt.Errorf("no leave section for room %s", roomID) - } else { - return nil - } - } - // passive - return SyncTimelineHas(roomID, func(ev gjson.Result) bool { - return ev.Get("type").Str == "m.room.member" && ev.Get("state_key").Str == userID && ev.Get("content.membership").Str == "leave" - })(clientUserID, topLevelSyncJSON) - } -} - -// Calls the `check` function for each global account data event, and returns with success if the -// `check` function returns true for at least one event. -func SyncGlobalAccountDataHas(check func(gjson.Result) bool) SyncCheckOpt { - return func(clientUserID string, topLevelSyncJSON gjson.Result) error { - return loopArray(topLevelSyncJSON, "account_data.events", check) - } -} - -// Calls the `check` function for each account data event for the given room, -// and returns with success if the `check` function returns true for at least -// one event. -func SyncRoomAccountDataHas(roomID string, check func(gjson.Result) bool) SyncCheckOpt { - return func(clientUserID string, topLevelSyncJSON gjson.Result) error { - err := loopArray( - topLevelSyncJSON, "rooms.join."+GjsonEscape(roomID)+".account_data.events", check, - ) - if err == nil { - return nil - } - return fmt.Errorf("SyncRoomAccountDataHas(%s): %s", roomID, err) - } -} - -func loopArray(object gjson.Result, key string, check func(gjson.Result) bool) error { - array := object.Get(key) - if !array.Exists() { - return fmt.Errorf("Key %s does not exist", key) - } - if !array.IsArray() { - return fmt.Errorf("Key %s exists but it isn't an array", key) - } - goArray := array.Array() - for _, ev := range goArray { - if check(ev) { - return nil - } - } - return fmt.Errorf("check function did not pass while iterating over %d elements: %v", len(goArray), array.Raw) -} - -// Splits an MXC URI into its origin and media ID parts -func SplitMxc(mxcUri string) (string, string) { - mxcParts := strings.Split(strings.TrimPrefix(mxcUri, "mxc://"), "/") - origin := mxcParts[0] - mediaId := strings.Join(mxcParts[1:], "/") - - return origin, mediaId -} - -// SendToDeviceMessages sends to-device messages over /sendToDevice/. -// -// The messages parameter is nested as follows: -// user_id -> device_id -> content (map[string]interface{}) -func (c *CSAPI) SendToDeviceMessages(t *testing.T, evType string, messages map[string]map[string]map[string]interface{}) { - t.Helper() - txnID := int(atomic.AddInt64(&c.txnID, 1)) - c.MustDoFunc( - t, - "PUT", - []string{"_matrix", "client", "v3", "sendToDevice", evType, strconv.Itoa(txnID)}, - WithJSONBody( - t, - map[string]map[string]map[string]map[string]interface{}{ - "messages": messages, - }, - ), - ) -} - -// Check that sync has received a to-device message, -// with optional user filtering. -// -// If fromUser == "", all messages will be passed through to the check function. -// `check` will be called for all messages that have passed the filter. -// -// `check` gets passed the full event, including sender and type. -func SyncToDeviceHas(fromUser string, check func(gjson.Result) bool) SyncCheckOpt { - return func(clientUserID string, topLevelSyncJSON gjson.Result) error { - err := loopArray( - topLevelSyncJSON, "to_device.events", func(result gjson.Result) bool { - if fromUser != "" && result.Get("sender").Str != fromUser { - return false - } else { - return check(result) - } - }, - ) - if err == nil { - return nil - } - return fmt.Errorf("SyncToDeviceHas(%v): %s", fromUser, err) - } -} diff --git a/internal/docker/deployment.go b/internal/docker/deployment.go index cefb2404..00b0dc2f 100644 --- a/internal/docker/deployment.go +++ b/internal/docker/deployment.go @@ -5,7 +5,7 @@ import ( "testing" "time" - "github.com/matrix-org/complement/internal/client" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/config" ) diff --git a/tests/csapi/account_change_password_pushers_test.go b/tests/csapi/account_change_password_pushers_test.go index 3291fc88..38a1d0d5 100644 --- a/tests/csapi/account_change_password_pushers_test.go +++ b/tests/csapi/account_change_password_pushers_test.go @@ -6,8 +6,8 @@ package csapi_tests import ( "testing" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/internal/match" "github.com/matrix-org/complement/internal/must" @@ -37,13 +37,13 @@ func TestChangePasswordPushers(t *testing.T) { "lang": "en", }) - _ = sessionOptional.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "pushers", "set"}, reqBody) + _ = sessionOptional.MustDo(t, "POST", []string{"_matrix", "client", "v3", "pushers", "set"}, reqBody) changePassword(t, passwordClient, password1, password2) pushersSize := 0 - res := passwordClient.DoFunc(t, "GET", []string{"_matrix", "client", "v3", "pushers"}) + res := passwordClient.Do(t, "GET", []string{"_matrix", "client", "v3", "pushers"}) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: 200, JSON: []match.JSON{ @@ -73,13 +73,13 @@ func TestChangePasswordPushers(t *testing.T) { "lang": "en", }) - _ = passwordClient.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "pushers", "set"}, reqBody) + _ = passwordClient.MustDo(t, "POST", []string{"_matrix", "client", "v3", "pushers", "set"}, reqBody) changePassword(t, passwordClient, password2, password1) pushersSize := 0 - res := passwordClient.DoFunc(t, "GET", []string{"_matrix", "client", "v3", "pushers"}) + res := passwordClient.Do(t, "GET", []string{"_matrix", "client", "v3", "pushers"}) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: 200, JSON: []match.JSON{ diff --git a/tests/csapi/account_change_password_test.go b/tests/csapi/account_change_password_test.go index 2369f793..736bfe5c 100644 --- a/tests/csapi/account_change_password_test.go +++ b/tests/csapi/account_change_password_test.go @@ -4,8 +4,8 @@ import ( "io/ioutil" "testing" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/internal/docker" "github.com/matrix-org/complement/internal/match" "github.com/matrix-org/complement/internal/must" @@ -34,7 +34,7 @@ func TestChangePassword(t *testing.T) { "type": "m.login.password", "password": password1, }) - res := unauthedClient.DoFunc(t, "POST", []string{"_matrix", "client", "v3", "login"}, reqBody) + res := unauthedClient.Do(t, "POST", []string{"_matrix", "client", "v3", "login"}, reqBody) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: 403, JSON: []match.JSON{ @@ -53,7 +53,7 @@ func TestChangePassword(t *testing.T) { "type": "m.login.password", "password": password2, }) - res := unauthedClient.DoFunc(t, "POST", []string{"_matrix", "client", "v3", "login"}, reqBody) + res := unauthedClient.Do(t, "POST", []string{"_matrix", "client", "v3", "login"}, reqBody) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: 200, JSON: []match.JSON{ @@ -63,14 +63,14 @@ func TestChangePassword(t *testing.T) { }) // sytest: After changing password, existing session still works t.Run("After changing password, existing session still works", func(t *testing.T) { - res := passwordClient.DoFunc(t, "GET", []string{"_matrix", "client", "v3", "account", "whoami"}) + res := passwordClient.Do(t, "GET", []string{"_matrix", "client", "v3", "account", "whoami"}) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: 200, }) }) // sytest: After changing password, a different session no longer works by default t.Run("After changing password, a different session no longer works by default", func(t *testing.T) { - res := sessionTest.DoFunc(t, "GET", []string{"_matrix", "client", "v3", "account", "whoami"}) + res := sessionTest.Do(t, "GET", []string{"_matrix", "client", "v3", "account", "whoami"}) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: 401, }) @@ -89,12 +89,12 @@ func TestChangePassword(t *testing.T) { "logout_devices": false, }) - res := passwordClient.DoFunc(t, "POST", []string{"_matrix", "client", "v3", "account", "password"}, reqBody) + res := passwordClient.Do(t, "POST", []string{"_matrix", "client", "v3", "account", "password"}, reqBody) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: 200, }) - res = sessionOptional.DoFunc(t, "GET", []string{"_matrix", "client", "v3", "account", "whoami"}) + res = sessionOptional.Do(t, "GET", []string{"_matrix", "client", "v3", "account", "whoami"}) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: 200, @@ -113,7 +113,7 @@ func changePassword(t *testing.T, passwordClient *client.CSAPI, oldPassword stri "new_password": newPassword, }) - res := passwordClient.DoFunc(t, "POST", []string{"_matrix", "client", "v3", "account", "password"}, reqBody) + res := passwordClient.Do(t, "POST", []string{"_matrix", "client", "v3", "account", "password"}, reqBody) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: 200, @@ -130,7 +130,7 @@ func createSession(t *testing.T, deployment *docker.Deployment, userID, password "type": "m.login.password", "password": password, }) - res := authedClient.DoFunc(t, "POST", []string{"_matrix", "client", "v3", "login"}, reqBody) + res := authedClient.Do(t, "POST", []string{"_matrix", "client", "v3", "login"}, reqBody) body, err := ioutil.ReadAll(res.Body) if err != nil { t.Fatalf("unable to read response body: %v", err) diff --git a/tests/csapi/account_deactivate_test.go b/tests/csapi/account_deactivate_test.go index e2faeb45..95982e73 100644 --- a/tests/csapi/account_deactivate_test.go +++ b/tests/csapi/account_deactivate_test.go @@ -6,8 +6,8 @@ import ( "github.com/tidwall/gjson" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/internal/match" "github.com/matrix-org/complement/internal/must" ) @@ -23,7 +23,7 @@ func TestDeactivateAccount(t *testing.T) { // at least one auth flow involving a password. t.Run("Password flow is available", func(t *testing.T) { reqBody := client.WithJSONBody(t, map[string]interface{}{}) - res := authedClient.DoFunc(t, "POST", []string{"_matrix", "client", "v3", "account", "deactivate"}, reqBody) + res := authedClient.Do(t, "POST", []string{"_matrix", "client", "v3", "account", "deactivate"}, reqBody) rawBody := must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: 401, @@ -97,7 +97,7 @@ func TestDeactivateAccount(t *testing.T) { "type": "m.login.password", "password": password, }) - res := unauthedClient.DoFunc(t, "POST", []string{"_matrix", "client", "v3", "login"}, reqBody) + res := unauthedClient.Do(t, "POST", []string{"_matrix", "client", "v3", "login"}, reqBody) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: 403, }) @@ -114,7 +114,7 @@ func deactivateAccount(t *testing.T, authedClient *client.CSAPI, password string }, }) - res := authedClient.DoFunc(t, "POST", []string{"_matrix", "client", "v3", "account", "deactivate"}, reqBody) + res := authedClient.Do(t, "POST", []string{"_matrix", "client", "v3", "account", "deactivate"}, reqBody) return res } diff --git a/tests/csapi/admin_test.go b/tests/csapi/admin_test.go index 1c8d47bf..df844df4 100644 --- a/tests/csapi/admin_test.go +++ b/tests/csapi/admin_test.go @@ -7,8 +7,8 @@ import ( "github.com/tidwall/gjson" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/internal/match" "github.com/matrix-org/complement/internal/must" ) @@ -40,7 +40,7 @@ func TestServerNotices(t *testing.T) { roomID string ) t.Run("/send_server_notice is not allowed as normal user", func(t *testing.T) { - res := alice.DoFunc(t, "POST", []string{"_synapse", "admin", "v1", "send_server_notice"}) + res := alice.Do(t, "POST", []string{"_synapse", "admin", "v1", "send_server_notice"}) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: http.StatusForbidden, JSON: []match.JSON{ @@ -55,7 +55,7 @@ func TestServerNotices(t *testing.T) { roomID = syncUntilInvite(t, alice) }) t.Run("Alice cannot reject the invite", func(t *testing.T) { - res := alice.DoFunc(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "leave"}) + res := alice.Do(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "leave"}) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: http.StatusForbidden, JSON: []match.JSON{ @@ -91,9 +91,9 @@ func TestServerNotices(t *testing.T) { func sendServerNotice(t *testing.T, admin *client.CSAPI, reqBody client.RequestOpt, txnID *string) (eventID string) { var res *http.Response if txnID != nil { - res = admin.MustDoFunc(t, "PUT", []string{"_synapse", "admin", "v1", "send_server_notice", *txnID}, reqBody) + res = admin.MustDo(t, "PUT", []string{"_synapse", "admin", "v1", "send_server_notice", *txnID}, reqBody) } else { - res = admin.MustDoFunc(t, "POST", []string{"_synapse", "admin", "v1", "send_server_notice"}, reqBody) + res = admin.MustDo(t, "POST", []string{"_synapse", "admin", "v1", "send_server_notice"}, reqBody) } body := must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: http.StatusOK, diff --git a/tests/csapi/apidoc_device_management_test.go b/tests/csapi/apidoc_device_management_test.go index a0fe3fc3..72204b56 100644 --- a/tests/csapi/apidoc_device_management_test.go +++ b/tests/csapi/apidoc_device_management_test.go @@ -5,8 +5,8 @@ import ( "github.com/tidwall/gjson" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/internal/match" "github.com/matrix-org/complement/internal/must" ) @@ -30,9 +30,9 @@ func TestDeviceManagement(t *testing.T) { "device_id": deviceID, "initial_device_display_name": "device display", }) - _ = unauthedClient.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "login"}, reqBody) + _ = unauthedClient.MustDo(t, "POST", []string{"_matrix", "client", "v3", "login"}, reqBody) - res := authedClient.MustDoFunc(t, "GET", []string{"_matrix", "client", "v3", "devices", deviceID}) + res := authedClient.MustDo(t, "GET", []string{"_matrix", "client", "v3", "devices", deviceID}) must.MatchResponse(t, res, match.HTTPResponse{ JSON: []match.JSON{ @@ -45,7 +45,7 @@ func TestDeviceManagement(t *testing.T) { // sytest: GET /device/{deviceId} gives a 404 for unknown devices t.Run("GET /device/{deviceId} gives a 404 for unknown devices", func(t *testing.T) { - res := authedClient.DoFunc(t, "GET", []string{"_matrix", "client", "v3", "devices", "unknown_device"}) + res := authedClient.Do(t, "GET", []string{"_matrix", "client", "v3", "devices", "unknown_device"}) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: 404, @@ -66,13 +66,13 @@ func TestDeviceManagement(t *testing.T) { "device_id": deviceIDSecond, "initial_device_display_name": "device display", }) - _ = unauthedClient.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "login"}, reqBody) + _ = unauthedClient.MustDo(t, "POST", []string{"_matrix", "client", "v3", "login"}, reqBody) wantDeviceIDs := map[string]bool{ deviceID: true, deviceIDSecond: true, } - res := authedClient.MustDoFunc(t, "GET", []string{"_matrix", "client", "v3", "devices"}) + res := authedClient.MustDo(t, "GET", []string{"_matrix", "client", "v3", "devices"}) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: 200, JSON: []match.JSON{ @@ -97,9 +97,9 @@ func TestDeviceManagement(t *testing.T) { reqBody := client.WithJSONBody(t, map[string]interface{}{ "display_name": "new device display", }) - _ = authedClient.MustDoFunc(t, "PUT", []string{"_matrix", "client", "v3", "devices", deviceID}, reqBody) + _ = authedClient.MustDo(t, "PUT", []string{"_matrix", "client", "v3", "devices", deviceID}, reqBody) - res := authedClient.MustDoFunc(t, "GET", []string{"_matrix", "client", "v3", "devices", deviceID}) + res := authedClient.MustDo(t, "GET", []string{"_matrix", "client", "v3", "devices", deviceID}) must.MatchResponse(t, res, match.HTTPResponse{ JSON: []match.JSON{ @@ -114,7 +114,7 @@ func TestDeviceManagement(t *testing.T) { reqBody := client.WithJSONBody(t, map[string]interface{}{ "display_name": "new device display", }) - res := authedClient.DoFunc(t, "PUT", []string{"_matrix", "client", "v3", "devices", "unknown_device"}, reqBody) + res := authedClient.Do(t, "PUT", []string{"_matrix", "client", "v3", "devices", "unknown_device"}, reqBody) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: 404, @@ -127,7 +127,7 @@ func TestDeviceManagement(t *testing.T) { session2.MustSync(t, client.SyncReq{}) // sytest: DELETE /device/{deviceId} with no body gives a 401 - res := authedClient.DoFunc(t, "DELETE", []string{"_matrix", "client", "v3", "devices", newDeviceID}) + res := authedClient.Do(t, "DELETE", []string{"_matrix", "client", "v3", "devices", newDeviceID}) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: 401, JSON: []match.JSON{ @@ -149,7 +149,7 @@ func TestDeviceManagement(t *testing.T) { }, }) - res = authedClient.DoFunc(t, "DELETE", []string{"_matrix", "client", "v3", "devices", newDeviceID}, reqBody) + res = authedClient.Do(t, "DELETE", []string{"_matrix", "client", "v3", "devices", newDeviceID}, reqBody) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: 401, JSON: []match.JSON{ @@ -174,19 +174,19 @@ func TestDeviceManagement(t *testing.T) { }, }) - res = authedClient.DoFunc(t, "DELETE", []string{"_matrix", "client", "v3", "devices", newDeviceID}, reqBody) + res = authedClient.Do(t, "DELETE", []string{"_matrix", "client", "v3", "devices", newDeviceID}, reqBody) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: 200, }) // verify device is deleted - res = authedClient.DoFunc(t, "GET", []string{"_matrix", "client", "v3", "devices", newDeviceID}) + res = authedClient.Do(t, "GET", []string{"_matrix", "client", "v3", "devices", newDeviceID}) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: 404, }) // check that the accesstoken is invalidated - res = session2.DoFunc(t, "GET", []string{"_matrix", "client", "v3", "sync"}) + res = session2.Do(t, "GET", []string{"_matrix", "client", "v3", "sync"}) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: 401, }) @@ -210,13 +210,13 @@ func TestDeviceManagement(t *testing.T) { }, }) - res := authedClient.DoFunc(t, "DELETE", []string{"_matrix", "client", "v3", "devices", newDeviceID}, reqBody) + res := authedClient.Do(t, "DELETE", []string{"_matrix", "client", "v3", "devices", newDeviceID}, reqBody) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: 403, }) // verify device still exists - res = authedClient.DoFunc(t, "GET", []string{"_matrix", "client", "v3", "devices", newDeviceID}) + res = authedClient.Do(t, "GET", []string{"_matrix", "client", "v3", "devices", newDeviceID}) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: 200, }) @@ -233,13 +233,13 @@ func TestDeviceManagement(t *testing.T) { }, }) - res = authedClient.DoFunc(t, "DELETE", []string{"_matrix", "client", "v3", "devices", newDeviceID}, reqBody) + res = authedClient.Do(t, "DELETE", []string{"_matrix", "client", "v3", "devices", newDeviceID}, reqBody) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: 200, }) // verify device is deleted - res = authedClient.DoFunc(t, "GET", []string{"_matrix", "client", "v3", "devices", newDeviceID}) + res = authedClient.Do(t, "GET", []string{"_matrix", "client", "v3", "devices", newDeviceID}) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: 404, }) diff --git a/tests/csapi/apidoc_login_test.go b/tests/csapi/apidoc_login_test.go index fe11e3ae..d2319e35 100644 --- a/tests/csapi/apidoc_login_test.go +++ b/tests/csapi/apidoc_login_test.go @@ -7,8 +7,8 @@ import ( "github.com/tidwall/gjson" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/internal/match" "github.com/matrix-org/complement/internal/must" ) @@ -22,7 +22,7 @@ func TestLogin(t *testing.T) { // sytest: GET /login yields a set of flows t.Run("GET /login yields a set of flows", func(t *testing.T) { t.Parallel() - res := unauthedClient.DoFunc(t, "GET", []string{"_matrix", "client", "v3", "login"}, client.WithRawBody(json.RawMessage(`{}`))) + res := unauthedClient.Do(t, "GET", []string{"_matrix", "client", "v3", "login"}, client.WithRawBody(json.RawMessage(`{}`))) must.MatchResponse(t, res, match.HTTPResponse{ Headers: map[string]string{ "Content-Type": "application/json", @@ -43,7 +43,7 @@ func TestLogin(t *testing.T) { // sytest: POST /login can log in as a user t.Run("POST /login can login as user", func(t *testing.T) { t.Parallel() - res := unauthedClient.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "login"}, client.WithRawBody(json.RawMessage(`{ + res := unauthedClient.MustDo(t, "POST", []string{"_matrix", "client", "v3", "login"}, client.WithRawBody(json.RawMessage(`{ "type": "m.login.password", "identifier": { "type": "m.id.user", @@ -62,7 +62,7 @@ func TestLogin(t *testing.T) { t.Run("POST /login returns the same device_id as that in the request", func(t *testing.T) { t.Parallel() deviceID := "test_device_id" - res := unauthedClient.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "login"}, client.WithRawBody(json.RawMessage(`{ + res := unauthedClient.MustDo(t, "POST", []string{"_matrix", "client", "v3", "login"}, client.WithRawBody(json.RawMessage(`{ "type": "m.login.password", "identifier": { "type": "m.id.user", @@ -83,7 +83,7 @@ func TestLogin(t *testing.T) { t.Run("POST /login can log in as a user with just the local part of the id", func(t *testing.T) { t.Parallel() - res := unauthedClient.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "login"}, client.WithRawBody(json.RawMessage(`{ + res := unauthedClient.MustDo(t, "POST", []string{"_matrix", "client", "v3", "login"}, client.WithRawBody(json.RawMessage(`{ "type": "m.login.password", "identifier": { "type": "m.id.user", @@ -101,7 +101,7 @@ func TestLogin(t *testing.T) { // sytest: POST /login as non-existing user is rejected t.Run("POST /login as non-existing user is rejected", func(t *testing.T) { t.Parallel() - res := unauthedClient.DoFunc(t, "POST", []string{"_matrix", "client", "v3", "login"}, client.WithRawBody(json.RawMessage(`{ + res := unauthedClient.Do(t, "POST", []string{"_matrix", "client", "v3", "login"}, client.WithRawBody(json.RawMessage(`{ "type": "m.login.password", "identifier": { "type": "m.id.user", @@ -116,7 +116,7 @@ func TestLogin(t *testing.T) { // sytest: POST /login wrong password is rejected t.Run("POST /login wrong password is rejected", func(t *testing.T) { t.Parallel() - res := unauthedClient.DoFunc(t, "POST", []string{"_matrix", "client", "v3", "login"}, client.WithRawBody(json.RawMessage(`{ + res := unauthedClient.Do(t, "POST", []string{"_matrix", "client", "v3", "login"}, client.WithRawBody(json.RawMessage(`{ "type": "m.login.password", "identifier": { "type": "m.id.user", @@ -136,7 +136,7 @@ func TestLogin(t *testing.T) { t.Run("Login with uppercase username works and GET /whoami afterwards also", func(t *testing.T) { t.Parallel() // login should be possible with uppercase username - res := unauthedClient.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "login"}, client.WithRawBody(json.RawMessage(`{ + res := unauthedClient.MustDo(t, "POST", []string{"_matrix", "client", "v3", "login"}, client.WithRawBody(json.RawMessage(`{ "type": "m.login.password", "identifier": { "type": "m.id.user", @@ -151,7 +151,7 @@ func TestLogin(t *testing.T) { unauthedClient.UserID = js.Get("user_id").Str unauthedClient.AccessToken = js.Get("access_token").Str // check that we can successfully query /whoami - unauthedClient.MustDoFunc(t, "GET", []string{"_matrix", "client", "v3", "account", "whoami"}) + unauthedClient.MustDo(t, "GET", []string{"_matrix", "client", "v3", "account", "whoami"}) }) }) } diff --git a/tests/csapi/apidoc_logout_test.go b/tests/csapi/apidoc_logout_test.go index 2b9afbb0..49b94c84 100644 --- a/tests/csapi/apidoc_logout_test.go +++ b/tests/csapi/apidoc_logout_test.go @@ -22,18 +22,18 @@ func TestLogout(t *testing.T) { // sytest: Can logout current device t.Run("Can logout current device", func(t *testing.T) { deviceID, clientToLogout := createSession(t, deployment, verifyClientUser.UserID, password) - res := clientToLogout.MustDoFunc(t, "GET", []string{"_matrix", "client", "v3", "devices"}) + res := clientToLogout.MustDo(t, "GET", []string{"_matrix", "client", "v3", "devices"}) must.MatchResponse(t, res, match.HTTPResponse{ JSON: []match.JSON{ match.JSONKeyArrayOfSize("devices", 2), }, }) - res = clientToLogout.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "logout"}) + res = clientToLogout.MustDo(t, "POST", []string{"_matrix", "client", "v3", "logout"}) // the session should be invalidated - res = clientToLogout.DoFunc(t, "GET", []string{"_matrix", "client", "v3", "sync"}) + res = clientToLogout.Do(t, "GET", []string{"_matrix", "client", "v3", "sync"}) must.MatchResponse(t, res, match.HTTPResponse{StatusCode: http.StatusUnauthorized}) // verify with first device - res = verifyClientUser.MustDoFunc(t, "GET", []string{"_matrix", "client", "v3", "devices"}) + res = verifyClientUser.MustDo(t, "GET", []string{"_matrix", "client", "v3", "devices"}) must.MatchResponse(t, res, match.HTTPResponse{ JSON: []match.JSON{ match.JSONKeyArrayOfSize("devices", 1), @@ -49,25 +49,25 @@ func TestLogout(t *testing.T) { // sytest: Can logout all devices t.Run("Can logout all devices", func(t *testing.T) { _, clientToLogout := createSession(t, deployment, verifyClientUser.UserID, password) - res := clientToLogout.MustDoFunc(t, "GET", []string{"_matrix", "client", "v3", "devices"}) + res := clientToLogout.MustDo(t, "GET", []string{"_matrix", "client", "v3", "devices"}) must.MatchResponse(t, res, match.HTTPResponse{ JSON: []match.JSON{ match.JSONKeyArrayOfSize("devices", 2), }, }) - res = clientToLogout.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "logout", "all"}) + res = clientToLogout.MustDo(t, "POST", []string{"_matrix", "client", "v3", "logout", "all"}) must.MatchResponse(t, res, match.HTTPResponse{StatusCode: http.StatusOK}) // all sessions should be invalidated - res = clientToLogout.DoFunc(t, "GET", []string{"_matrix", "client", "v3", "sync"}) + res = clientToLogout.Do(t, "GET", []string{"_matrix", "client", "v3", "sync"}) must.MatchResponse(t, res, match.HTTPResponse{StatusCode: http.StatusUnauthorized}) - res = verifyClientUser.DoFunc(t, "GET", []string{"_matrix", "client", "v3", "sync"}) + res = verifyClientUser.Do(t, "GET", []string{"_matrix", "client", "v3", "sync"}) must.MatchResponse(t, res, match.HTTPResponse{StatusCode: http.StatusUnauthorized}) }) // sytest: Request to logout with invalid an access token is rejected t.Run("Request to logout with invalid an access token is rejected", func(t *testing.T) { _, clientToLogout := createSession(t, deployment, verifyClientUser.UserID, password) clientToLogout.AccessToken = "invalidAccessToken" - res := clientToLogout.DoFunc(t, "POST", []string{"_matrix", "client", "v3", "logout"}) + res := clientToLogout.Do(t, "POST", []string{"_matrix", "client", "v3", "logout"}) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: http.StatusUnauthorized, JSON: []match.JSON{ @@ -79,7 +79,7 @@ func TestLogout(t *testing.T) { t.Run("Request to logout without an access token is rejected", func(t *testing.T) { _, clientToLogout := createSession(t, deployment, verifyClientUser.UserID, password) clientToLogout.AccessToken = "" - res := clientToLogout.DoFunc(t, "POST", []string{"_matrix", "client", "v3", "logout"}) + res := clientToLogout.Do(t, "POST", []string{"_matrix", "client", "v3", "logout"}) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: http.StatusUnauthorized, JSON: []match.JSON{ diff --git a/tests/csapi/apidoc_presence_test.go b/tests/csapi/apidoc_presence_test.go index 95a5f763..274460da 100644 --- a/tests/csapi/apidoc_presence_test.go +++ b/tests/csapi/apidoc_presence_test.go @@ -1,3 +1,4 @@ +//go:build !dendrite_blacklist // +build !dendrite_blacklist // Rationale for being included in Dendrite's blacklist: https://github.com/matrix-org/complement/pull/104#discussion_r617646624 @@ -9,8 +10,8 @@ import ( "github.com/tidwall/gjson" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/internal/match" "github.com/matrix-org/complement/internal/must" ) @@ -24,7 +25,7 @@ func TestPresence(t *testing.T) { // sytest: GET /presence/:user_id/status fetches initial status t.Run("GET /presence/:user_id/status fetches initial status", func(t *testing.T) { - res := alice.DoFunc(t, "GET", []string{"_matrix", "client", "v3", "presence", "@alice:hs1", "status"}) + res := alice.Do(t, "GET", []string{"_matrix", "client", "v3", "presence", "@alice:hs1", "status"}) must.MatchResponse(t, res, match.HTTPResponse{ JSON: []match.JSON{ match.JSONKeyPresent("presence"), @@ -38,11 +39,11 @@ func TestPresence(t *testing.T) { "status_msg": statusMsg, "presence": "online", }) - res := alice.DoFunc(t, "PUT", []string{"_matrix", "client", "v3", "presence", "@alice:hs1", "status"}, reqBody) + res := alice.Do(t, "PUT", []string{"_matrix", "client", "v3", "presence", "@alice:hs1", "status"}, reqBody) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: 200, }) - res = alice.DoFunc(t, "GET", []string{"_matrix", "client", "v3", "presence", "@alice:hs1", "status"}) + res = alice.Do(t, "GET", []string{"_matrix", "client", "v3", "presence", "@alice:hs1", "status"}) must.MatchResponse(t, res, match.HTTPResponse{ JSON: []match.JSON{ match.JSONKeyPresent("presence"), @@ -63,7 +64,7 @@ func TestPresence(t *testing.T) { _, bobSinceToken := bob.MustSync(t, client.SyncReq{TimeoutMillis: "0"}) statusMsg := "Update for room members" - alice.MustDoFunc(t, "PUT", []string{"_matrix", "client", "v3", "presence", "@alice:hs1", "status"}, + alice.MustDo(t, "PUT", []string{"_matrix", "client", "v3", "presence", "@alice:hs1", "status"}, client.WithJSONBody(t, map[string]interface{}{ "status_msg": statusMsg, "presence": "online", @@ -80,7 +81,7 @@ func TestPresence(t *testing.T) { t.Run("Presence changes to UNAVAILABLE are reported to local room members", func(t *testing.T) { _, bobSinceToken := bob.MustSync(t, client.SyncReq{TimeoutMillis: "0"}) - alice.MustDoFunc(t, "PUT", []string{"_matrix", "client", "v3", "presence", "@alice:hs1", "status"}, + alice.MustDo(t, "PUT", []string{"_matrix", "client", "v3", "presence", "@alice:hs1", "status"}, client.WithJSONBody(t, map[string]interface{}{ "presence": "unavailable", }), diff --git a/tests/csapi/apidoc_profile_avatar_url_test.go b/tests/csapi/apidoc_profile_avatar_url_test.go index b8c41261..bafdb429 100644 --- a/tests/csapi/apidoc_profile_avatar_url_test.go +++ b/tests/csapi/apidoc_profile_avatar_url_test.go @@ -3,8 +3,8 @@ package csapi_tests import ( "testing" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/internal/match" "github.com/matrix-org/complement/internal/must" ) @@ -20,7 +20,7 @@ func TestProfileAvatarURL(t *testing.T) { reqBody := client.WithJSONBody(t, map[string]interface{}{ "avatar_url": avatarURL, }) - res := authedClient.MustDoFunc(t, "PUT", []string{"_matrix", "client", "v3", "profile", authedClient.UserID, "avatar_url"}, reqBody) + res := authedClient.MustDo(t, "PUT", []string{"_matrix", "client", "v3", "profile", authedClient.UserID, "avatar_url"}, reqBody) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: 200, @@ -29,7 +29,7 @@ func TestProfileAvatarURL(t *testing.T) { // sytest: GET /profile/:user_id/avatar_url publicly accessible t.Run("GET /profile/:user_id/avatar_url publicly accessible", func(t *testing.T) { - res := unauthedClient.DoFunc(t, "GET", []string{"_matrix", "client", "v3", "profile", authedClient.UserID, "avatar_url"}) + res := unauthedClient.Do(t, "GET", []string{"_matrix", "client", "v3", "profile", authedClient.UserID, "avatar_url"}) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: 200, diff --git a/tests/csapi/apidoc_profile_displayname_test.go b/tests/csapi/apidoc_profile_displayname_test.go index 09545411..58eeebb4 100644 --- a/tests/csapi/apidoc_profile_displayname_test.go +++ b/tests/csapi/apidoc_profile_displayname_test.go @@ -3,8 +3,8 @@ package csapi_tests import ( "testing" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/internal/match" "github.com/matrix-org/complement/internal/must" ) @@ -20,11 +20,11 @@ func TestProfileDisplayName(t *testing.T) { reqBody := client.WithJSONBody(t, map[string]interface{}{ "displayname": displayName, }) - _ = authedClient.MustDoFunc(t, "PUT", []string{"_matrix", "client", "v3", "profile", authedClient.UserID, "displayname"}, reqBody) + _ = authedClient.MustDo(t, "PUT", []string{"_matrix", "client", "v3", "profile", authedClient.UserID, "displayname"}, reqBody) }) // sytest: GET /profile/:user_id/displayname publicly accessible t.Run("GET /profile/:user_id/displayname publicly accessible", func(t *testing.T) { - res := unauthedClient.DoFunc(t, "GET", []string{"_matrix", "client", "v3", "profile", authedClient.UserID, "displayname"}) + res := unauthedClient.Do(t, "GET", []string{"_matrix", "client", "v3", "profile", authedClient.UserID, "displayname"}) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: 200, JSON: []match.JSON{ diff --git a/tests/csapi/apidoc_register_test.go b/tests/csapi/apidoc_register_test.go index bed7d72d..f62703fc 100644 --- a/tests/csapi/apidoc_register_test.go +++ b/tests/csapi/apidoc_register_test.go @@ -13,8 +13,8 @@ import ( "github.com/tidwall/gjson" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/internal/match" "github.com/matrix-org/complement/internal/must" ) @@ -42,7 +42,7 @@ func TestRegistration(t *testing.T) { // The name in Sytest is different, the test is actually doing a POST request. t.Run("POST {} returns a set of flows", func(t *testing.T) { t.Parallel() - res := unauthedClient.DoFunc(t, "POST", []string{"_matrix", "client", "v3", "register"}, client.WithRawBody(json.RawMessage(`{}`))) + res := unauthedClient.Do(t, "POST", []string{"_matrix", "client", "v3", "register"}, client.WithRawBody(json.RawMessage(`{}`))) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: 401, Headers: map[string]string{ @@ -61,7 +61,7 @@ func TestRegistration(t *testing.T) { // sytest: POST /register can create a user t.Run("POST /register can create a user", func(t *testing.T) { t.Parallel() - res := unauthedClient.DoFunc(t, "POST", []string{"_matrix", "client", "v3", "register"}, client.WithRawBody(json.RawMessage(`{ + res := unauthedClient.Do(t, "POST", []string{"_matrix", "client", "v3", "register"}, client.WithRawBody(json.RawMessage(`{ "auth": { "type": "m.login.dummy" }, @@ -78,7 +78,7 @@ func TestRegistration(t *testing.T) { // sytest: POST /register downcases capitals in usernames t.Run("POST /register downcases capitals in usernames", func(t *testing.T) { t.Parallel() - res := unauthedClient.DoFunc(t, "POST", []string{"_matrix", "client", "v3", "register"}, client.WithRawBody(json.RawMessage(`{ + res := unauthedClient.Do(t, "POST", []string{"_matrix", "client", "v3", "register"}, client.WithRawBody(json.RawMessage(`{ "auth": { "type": "m.login.dummy" }, @@ -96,7 +96,7 @@ func TestRegistration(t *testing.T) { t.Run("POST /register returns the same device_id as that in the request", func(t *testing.T) { t.Parallel() deviceID := "my_device_id" - res := unauthedClient.DoFunc(t, "POST", []string{"_matrix", "client", "v3", "register"}, client.WithRawBody(json.RawMessage(`{ + res := unauthedClient.Do(t, "POST", []string{"_matrix", "client", "v3", "register"}, client.WithRawBody(json.RawMessage(`{ "auth": { "type": "m.login.dummy" }, @@ -132,7 +132,7 @@ func TestRegistration(t *testing.T) { `'`, } for _, ch := range specialChars { - res := unauthedClient.DoFunc(t, "POST", []string{"_matrix", "client", "v3", "register"}, + res := unauthedClient.Do(t, "POST", []string{"_matrix", "client", "v3", "register"}, client.WithJSONBody(t, map[string]interface{}{ "auth": map[string]string{ "type": "m.login.dummy", @@ -150,7 +150,7 @@ func TestRegistration(t *testing.T) { }) t.Run("POST /register rejects if user already exists", func(t *testing.T) { t.Parallel() - res := unauthedClient.DoFunc(t, "POST", []string{"_matrix", "client", "v3", "register"}, client.WithRawBody(json.RawMessage(`{ + res := unauthedClient.Do(t, "POST", []string{"_matrix", "client", "v3", "register"}, client.WithRawBody(json.RawMessage(`{ "auth": { "type": "m.login.dummy" }, @@ -163,7 +163,7 @@ func TestRegistration(t *testing.T) { match.JSONKeyTypeEqual("user_id", gjson.String), }, }) - res = unauthedClient.DoFunc(t, "POST", []string{"_matrix", "client", "v3", "register"}, client.WithRawBody(json.RawMessage(`{ + res = unauthedClient.Do(t, "POST", []string{"_matrix", "client", "v3", "register"}, client.WithRawBody(json.RawMessage(`{ "auth": { "type": "m.login.dummy" }, @@ -232,7 +232,7 @@ func TestRegistration(t *testing.T) { "password": "übers3kr1t", "device_id": "xyzzy", "initial_device_display_name": "display_name"} - resp := unauthedClient.DoFunc(t, "POST", []string{"_matrix", "client", "v3", "register"}, client.WithJSONBody(t, reqJson)) + resp := unauthedClient.Do(t, "POST", []string{"_matrix", "client", "v3", "register"}, client.WithJSONBody(t, reqJson)) body, err := ioutil.ReadAll(resp.Body) session := gjson.GetBytes(body, "session") if err != nil { @@ -250,7 +250,7 @@ func TestRegistration(t *testing.T) { "initial_device_display_name": "display_name", "auth": auth, } - resp2 := unauthedClient.DoFunc(t, "POST", []string{"_matrix", "client", "v3", "register"}, client.WithJSONBody(t, reqBody)) + resp2 := unauthedClient.Do(t, "POST", []string{"_matrix", "client", "v3", "register"}, client.WithJSONBody(t, reqBody)) must.MatchResponse(t, resp2, match.HTTPResponse{JSON: []match.JSON{ match.JSONKeyPresent("access_token"), }}) @@ -259,7 +259,7 @@ func TestRegistration(t *testing.T) { t.Run("GET /register/available returns available for unregistered user name", func(t *testing.T) { t.Parallel() testUserName := "username_should_be_available" - res := unauthedClient.DoFunc(t, "GET", []string{"_matrix", "client", "v3", "register", "available"}, client.WithQueries(url.Values{ + res := unauthedClient.Do(t, "GET", []string{"_matrix", "client", "v3", "register", "available"}, client.WithQueries(url.Values{ "username": []string{testUserName}, })) must.MatchResponse(t, res, match.HTTPResponse{ @@ -275,9 +275,9 @@ func TestRegistration(t *testing.T) { testUserName := "username_not_available" // Don't need the return value here, just need a user to be registered to test against _ = deployment.NewUser(t, testUserName, "hs1") - res := unauthedClient.DoFunc(t, "GET", []string{"_matrix", "client", "v3", "register", "available"}, client.WithQueries(url.Values{ - "username": []string{testUserName}, - })) + res := unauthedClient.Do(t, "GET", []string{"_matrix", "client", "v3", "register", "available"}, client.WithQueries(url.Values{ + "username": []string{testUserName}, + })) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: 400, JSON: []match.JSON{ @@ -290,9 +290,9 @@ func TestRegistration(t *testing.T) { t.Run("GET /register/available returns M_INVALID_USERNAME for invalid user name", func(t *testing.T) { t.Parallel() testUserName := "username,should_not_be_valid" - res := unauthedClient.DoFunc(t, "GET", []string{"_matrix", "client", "v3", "register", "available"}, client.WithQueries(url.Values{ - "username": []string{testUserName}, - })) + res := unauthedClient.Do(t, "GET", []string{"_matrix", "client", "v3", "register", "available"}, client.WithQueries(url.Values{ + "username": []string{testUserName}, + })) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: 400, JSON: []match.JSON{ @@ -306,7 +306,7 @@ func TestRegistration(t *testing.T) { // registerSharedSecret tries to register using a shared secret, returns the *http.Response func registerSharedSecret(t *testing.T, c *client.CSAPI, user, pass string, isAdmin bool) *http.Response { - resp := c.DoFunc(t, "GET", []string{"_synapse", "admin", "v1", "register"}) + resp := c.Do(t, "GET", []string{"_synapse", "admin", "v1", "register"}) if resp.StatusCode != 200 { t.Skipf("Homeserver image does not support shared secret registration, /_synapse/admin/v1/register returned HTTP %d", resp.StatusCode) return resp @@ -336,6 +336,6 @@ func registerSharedSecret(t *testing.T, c *client.CSAPI, user, pass string, isAd "mac": hex.EncodeToString(sig), "admin": isAdmin, } - resp = c.DoFunc(t, "POST", []string{"_synapse", "admin", "v1", "register"}, client.WithJSONBody(t, reqBody)) + resp = c.Do(t, "POST", []string{"_synapse", "admin", "v1", "register"}, client.WithJSONBody(t, reqBody)) return resp } diff --git a/tests/csapi/apidoc_request_encoding_test.go b/tests/csapi/apidoc_request_encoding_test.go index 969b1299..e65e091c 100644 --- a/tests/csapi/apidoc_request_encoding_test.go +++ b/tests/csapi/apidoc_request_encoding_test.go @@ -5,8 +5,8 @@ import ( "encoding/json" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/internal/match" "github.com/matrix-org/complement/internal/must" ) @@ -18,7 +18,7 @@ func TestRequestEncodingFails(t *testing.T) { testString := `{ "test":"a` + "\x81" + `" }` // sytest: POST rejects invalid utf-8 in JSON t.Run("POST rejects invalid utf-8 in JSON", func(t *testing.T) { - res := unauthedClient.DoFunc(t, "POST", []string{"_matrix", "client", "v3", "register"}, client.WithRawBody(json.RawMessage(testString))) + res := unauthedClient.Do(t, "POST", []string{"_matrix", "client", "v3", "register"}, client.WithRawBody(json.RawMessage(testString))) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: 400, JSON: []match.JSON{ diff --git a/tests/csapi/apidoc_room_alias_test.go b/tests/csapi/apidoc_room_alias_test.go index 6b727f91..bb89eec4 100644 --- a/tests/csapi/apidoc_room_alias_test.go +++ b/tests/csapi/apidoc_room_alias_test.go @@ -7,28 +7,28 @@ import ( "github.com/tidwall/gjson" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/internal/match" "github.com/matrix-org/complement/internal/must" ) func setRoomAliasResp(t *testing.T, c *client.CSAPI, roomID, roomAlias string) *http.Response { - return c.DoFunc(t, "PUT", []string{"_matrix", "client", "v3", "directory", "room", roomAlias}, client.WithJSONBody(t, map[string]interface{}{ + return c.Do(t, "PUT", []string{"_matrix", "client", "v3", "directory", "room", roomAlias}, client.WithJSONBody(t, map[string]interface{}{ "room_id": roomID, })) } func getRoomAliasResp(t *testing.T, c *client.CSAPI, roomAlias string) *http.Response { - return c.DoFunc(t, "GET", []string{"_matrix", "client", "v3", "directory", "room", roomAlias}) + return c.Do(t, "GET", []string{"_matrix", "client", "v3", "directory", "room", roomAlias}) } func deleteRoomAliasResp(t *testing.T, c *client.CSAPI, roomAlias string) *http.Response { - return c.DoFunc(t, "DELETE", []string{"_matrix", "client", "v3", "directory", "room", roomAlias}) + return c.Do(t, "DELETE", []string{"_matrix", "client", "v3", "directory", "room", roomAlias}) } func listRoomAliasesResp(t *testing.T, c *client.CSAPI, roomID string) *http.Response { - return c.DoFunc(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "aliases"}) + return c.Do(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "aliases"}) } func setCanonicalAliasResp(t *testing.T, c *client.CSAPI, roomID string, roomAlias string, altAliases *[]string) *http.Response { @@ -39,7 +39,7 @@ func setCanonicalAliasResp(t *testing.T, c *client.CSAPI, roomID string, roomAli content["alt_aliases"] = altAliases } - return c.DoFunc(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.canonical_alias"}, client.WithJSONBody(t, content)) + return c.Do(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.canonical_alias"}, client.WithJSONBody(t, content)) } func mustSetCanonicalAlias(t *testing.T, c *client.CSAPI, roomID string, roomAlias string, altAliases *[]string) string { @@ -109,7 +109,7 @@ func TestRoomAlias(t *testing.T) { // // If (4) arrives at the reader before (2), the reader responds with // old data. Bodge around this by retrying for up to a second. - res = alice.DoFunc( + res = alice.Do( t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "aliases"}, diff --git a/tests/csapi/apidoc_room_create_test.go b/tests/csapi/apidoc_room_create_test.go index 20d720a7..84d62ac6 100644 --- a/tests/csapi/apidoc_room_create_test.go +++ b/tests/csapi/apidoc_room_create_test.go @@ -5,14 +5,14 @@ import ( "github.com/tidwall/gjson" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/internal/match" "github.com/matrix-org/complement/internal/must" ) func doCreateRoom(t *testing.T, c *client.CSAPI, json map[string]interface{}, match match.HTTPResponse) { - res := c.DoFunc(t, "POST", []string{"_matrix", "client", "v3", "createRoom"}, client.WithJSONBody(t, json)) + res := c.Do(t, "POST", []string{"_matrix", "client", "v3", "createRoom"}, client.WithJSONBody(t, json)) must.MatchResponse(t, res, match) } @@ -60,7 +60,7 @@ func TestRoomCreate(t *testing.T) { "topic": "Test Room", "preset": "public_chat", }) - res := alice.MustDoFunc(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.topic"}) + res := alice.MustDo(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.topic"}) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: 200, JSON: []match.JSON{ @@ -75,7 +75,7 @@ func TestRoomCreate(t *testing.T) { "name": "Test Room", "preset": "public_chat", }) - res := alice.MustDoFunc(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.name"}) + res := alice.MustDo(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.name"}) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: 200, JSON: []match.JSON{ @@ -90,7 +90,7 @@ func TestRoomCreate(t *testing.T) { "room_version": "2", "preset": "public_chat", }) - res := alice.MustDoFunc(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.create"}) + res := alice.MustDo(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.create"}) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: 200, JSON: []match.JSON{ diff --git a/tests/csapi/apidoc_room_forget_test.go b/tests/csapi/apidoc_room_forget_test.go index 54f8837b..d6b6d608 100644 --- a/tests/csapi/apidoc_room_forget_test.go +++ b/tests/csapi/apidoc_room_forget_test.go @@ -8,8 +8,8 @@ import ( "github.com/tidwall/gjson" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/internal/match" "github.com/matrix-org/complement/internal/must" ) @@ -26,7 +26,7 @@ func TestRoomForget(t *testing.T) { t.Run("Can't forget room you're still in", func(t *testing.T) { t.Parallel() roomID := alice.CreateRoom(t, map[string]interface{}{"preset": "private_chat"}) - res := alice.DoFunc(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "forget"}) + res := alice.Do(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "forget"}) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: http.StatusBadRequest, JSON: []match.JSON{ @@ -47,8 +47,8 @@ func TestRoomForget(t *testing.T) { }, }) alice.LeaveRoom(t, roomID) - alice.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "forget"}) - res := alice.DoFunc(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "messages"}) + alice.MustDo(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "forget"}) + res := alice.Do(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "messages"}) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: http.StatusForbidden, JSON: []match.JSON{ @@ -71,7 +71,7 @@ func TestRoomForget(t *testing.T) { alice.LeaveRoom(t, roomID) // Ensure Alice left the room bob.MustSyncUntil(t, client.SyncReq{}, client.SyncLeftFrom(alice.UserID, roomID)) - alice.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "forget"}) + alice.MustDo(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "forget"}) bob.SendEventSynced(t, roomID, b.Event{ Type: "m.room.message", Content: map[string]interface{}{ @@ -117,7 +117,7 @@ func TestRoomForget(t *testing.T) { alice.LeaveRoom(t, roomID) // Ensure Alice left the room bob.MustSyncUntil(t, client.SyncReq{}, client.SyncLeftFrom(alice.UserID, roomID)) - alice.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "forget"}) + alice.MustDo(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "forget"}) bob.SendEventSynced(t, roomID, b.Event{ Type: "m.room.message", Content: map[string]interface{}{ @@ -152,7 +152,7 @@ func TestRoomForget(t *testing.T) { }, }) // Kick Bob - alice.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "kick"}, + alice.MustDo(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "kick"}, client.WithJSONBody(t, map[string]interface{}{ "user_id": bob.UserID, }), @@ -197,9 +197,9 @@ func TestRoomForget(t *testing.T) { bob.LeaveRoom(t, roomID) // Ensure Bob has really left the room alice.MustSyncUntil(t, client.SyncReq{}, client.SyncLeftFrom(bob.UserID, roomID)) - bob.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "forget"}) + bob.MustDo(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "forget"}) // Try to re-join - joinRes := bob.DoFunc(t, "POST", []string{"_matrix", "client", "v3", "join", roomID}) + joinRes := bob.Do(t, "POST", []string{"_matrix", "client", "v3", "join", roomID}) must.MatchResponse(t, joinRes, match.HTTPResponse{ StatusCode: http.StatusForbidden, JSON: []match.JSON{ @@ -214,7 +214,7 @@ func TestRoomForget(t *testing.T) { queryParams.Set("dir", "b") queryParams.Set("limit", "100") // Check if we can see Bobs previous message - res := bob.DoFunc(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "messages"}, client.WithQueries(queryParams)) + res := bob.Do(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "messages"}, client.WithQueries(queryParams)) msgRes := &msgResult{} must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: http.StatusOK, @@ -234,7 +234,7 @@ func TestRoomForget(t *testing.T) { msgRes.found = false // We should now be able to see the new message queryParams.Set("limit", "1") - res = bob.DoFunc(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "messages"}, client.WithQueries(queryParams)) + res = bob.Do(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "messages"}, client.WithQueries(queryParams)) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: http.StatusOK, JSON: []match.JSON{findMessageId(messageID, msgRes)}, @@ -251,11 +251,11 @@ func TestRoomForget(t *testing.T) { // Bob rejects the invite bob.LeaveRoom(t, roomID) // Bob tries to forget about this room - bob.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "forget"}) + bob.MustDo(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "forget"}) // Alice also leaves the room alice.LeaveRoom(t, roomID) // Alice tries to forget about this room - alice.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "forget"}) + alice.MustDo(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "forget"}) }) }) } diff --git a/tests/csapi/apidoc_room_history_visibility_test.go b/tests/csapi/apidoc_room_history_visibility_test.go index a8b153d3..3857f20e 100644 --- a/tests/csapi/apidoc_room_history_visibility_test.go +++ b/tests/csapi/apidoc_room_history_visibility_test.go @@ -6,8 +6,8 @@ import ( "github.com/tidwall/gjson" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/internal/match" "github.com/matrix-org/complement/internal/must" ) @@ -15,7 +15,7 @@ import ( // TODO most of this can be refactored into data-driven tests func fetchEvent(t *testing.T, c *client.CSAPI, roomId, eventId string) *http.Response { - return c.DoFunc(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomId, "event", eventId}) + return c.Do(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomId, "event", eventId}) } func createRoomWithVisibility(t *testing.T, c *client.CSAPI, visibility string) string { diff --git a/tests/csapi/apidoc_room_members_test.go b/tests/csapi/apidoc_room_members_test.go index 731a151f..c32d5fd5 100644 --- a/tests/csapi/apidoc_room_members_test.go +++ b/tests/csapi/apidoc_room_members_test.go @@ -5,8 +5,8 @@ import ( "github.com/tidwall/gjson" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/internal/match" "github.com/matrix-org/complement/internal/must" ) @@ -25,7 +25,7 @@ func TestRoomMembers(t *testing.T) { "preset": "public_chat", }) - res := bob.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "join"}) + res := bob.MustDo(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "join"}) must.MatchResponse(t, res, match.HTTPResponse{ JSON: []match.JSON{ @@ -46,7 +46,7 @@ func TestRoomMembers(t *testing.T) { "room_alias_name": "room_alias_random", }) - res := bob.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "join", "#room_alias_random:hs1"}) + res := bob.MustDo(t, "POST", []string{"_matrix", "client", "v3", "join", "#room_alias_random:hs1"}) must.MatchResponse(t, res, match.HTTPResponse{ JSON: []match.JSON{ @@ -66,7 +66,7 @@ func TestRoomMembers(t *testing.T) { "preset": "public_chat", }) - res := bob.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "join", roomID}) + res := bob.MustDo(t, "POST", []string{"_matrix", "client", "v3", "join", roomID}) must.MatchResponse(t, res, match.HTTPResponse{ JSON: []match.JSON{ @@ -144,7 +144,7 @@ func TestRoomMembers(t *testing.T) { joinBody := client.WithJSONBody(t, map[string]string{"foo": "bar"}) - res := bob.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "join", roomID}, joinBody) + res := bob.MustDo(t, "POST", []string{"_matrix", "client", "v3", "join", roomID}, joinBody) must.MatchResponse(t, res, match.HTTPResponse{ JSON: []match.JSON{ @@ -155,7 +155,7 @@ func TestRoomMembers(t *testing.T) { }) alice.MustSyncUntil(t, client.SyncReq{}, client.SyncJoinedTo(bob.UserID, roomID)) - res = alice.DoFunc(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.member", bob.UserID}) + res = alice.Do(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.member", bob.UserID}) must.MatchResponse(t, res, match.HTTPResponse{ JSON: []match.JSON{ @@ -173,7 +173,7 @@ func TestRoomMembers(t *testing.T) { "room_alias_name": "room_alias_random2", }) joinBody := client.WithJSONBody(t, map[string]string{"foo": "bar"}) - res := bob.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "join", "#room_alias_random2:hs1"}, joinBody) + res := bob.MustDo(t, "POST", []string{"_matrix", "client", "v3", "join", "#room_alias_random2:hs1"}, joinBody) must.MatchResponse(t, res, match.HTTPResponse{ JSON: []match.JSON{ @@ -184,7 +184,7 @@ func TestRoomMembers(t *testing.T) { }) alice.MustSyncUntil(t, client.SyncReq{}, client.SyncJoinedTo(bob.UserID, roomID)) - res = alice.DoFunc(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.member", bob.UserID}) + res = alice.Do(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.member", bob.UserID}) must.MatchResponse(t, res, match.HTTPResponse{ JSON: []match.JSON{ @@ -202,7 +202,7 @@ func TestRoomMembers(t *testing.T) { "preset": "public_chat", }) - bob.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "join", roomID}) + bob.MustDo(t, "POST", []string{"_matrix", "client", "v3", "join", roomID}) alice.MustSyncUntil(t, client.SyncReq{}, client.SyncJoinedTo(bob.UserID, roomID)) // ban bob from room @@ -210,7 +210,7 @@ func TestRoomMembers(t *testing.T) { "user_id": bob.UserID, "reason": "Testing", }) - res := alice.DoFunc(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "ban"}, banBody) + res := alice.Do(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "ban"}, banBody) must.MatchResponse(t, res, match.HTTPResponse{StatusCode: 200}) alice.MustSyncUntil(t, client.SyncReq{}, client.SyncTimelineHas(roomID, func(ev gjson.Result) bool { if ev.Get("type").Str != "m.room.member" || ev.Get("state_key").Str != bob.UserID { @@ -219,7 +219,7 @@ func TestRoomMembers(t *testing.T) { return ev.Get("content.membership").Str == "ban" })) // verify bob is banned - res = alice.DoFunc(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.member", bob.UserID}) + res = alice.Do(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.member", bob.UserID}) must.MatchResponse(t, res, match.HTTPResponse{ JSON: []match.JSON{ match.JSONKeyEqual("membership", "ban"), @@ -233,7 +233,7 @@ func TestRoomMembers(t *testing.T) { roomID := alice.CreateRoom(t, map[string]interface{}{}) alice.InviteRoom(t, roomID, bob.UserID) alice.MustSyncUntil(t, client.SyncReq{}, client.SyncInvitedTo(bob.UserID, roomID)) - res := alice.DoFunc(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.member", bob.UserID}) + res := alice.Do(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.member", bob.UserID}) must.MatchResponse(t, res, match.HTTPResponse{ JSON: []match.JSON{ match.JSONKeyEqual("membership", "invite"), @@ -252,7 +252,7 @@ func TestRoomMembers(t *testing.T) { bob.LeaveRoom(t, roomID) alice.MustSyncUntil(t, client.SyncReq{}, client.SyncLeftFrom(bob.UserID, roomID)) - res := alice.DoFunc(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.member", bob.UserID}) + res := alice.Do(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.member", bob.UserID}) must.MatchResponse(t, res, match.HTTPResponse{ JSON: []match.JSON{ match.JSONKeyEqual("membership", "leave"), diff --git a/tests/csapi/apidoc_room_receipts_test.go b/tests/csapi/apidoc_room_receipts_test.go index f3a83ffb..3048af1e 100644 --- a/tests/csapi/apidoc_room_receipts_test.go +++ b/tests/csapi/apidoc_room_receipts_test.go @@ -3,8 +3,8 @@ package csapi_tests import ( "testing" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/internal/docker" "github.com/tidwall/gjson" ) @@ -41,7 +41,7 @@ func TestRoomReceipts(t *testing.T) { alice := deployment.Client(t, "hs1", "@alice:hs1") roomID, eventID := createRoomForReadReceipts(t, alice, deployment) - alice.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "receipt", "m.read", eventID}, client.WithJSONBody(t, struct{}{})) + alice.MustDo(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "receipt", "m.read", eventID}, client.WithJSONBody(t, struct{}{})) // Make sure the read receipt shows up in sync. alice.MustSyncUntil(t, client.SyncReq{}, syncHasReadReceipt(roomID, alice.UserID, eventID)) @@ -58,7 +58,7 @@ func TestRoomReadMarkers(t *testing.T) { "m.fully_read": eventID, "m.read": eventID, }) - alice.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "read_markers"}, reqBody) + alice.MustDo(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "read_markers"}, reqBody) // Make sure the read receipt shows up in sync. alice.MustSyncUntil(t, client.SyncReq{}, syncHasReadReceipt(roomID, alice.UserID, eventID)) diff --git a/tests/csapi/apidoc_room_state_test.go b/tests/csapi/apidoc_room_state_test.go index 3355acc1..8e3cb4db 100644 --- a/tests/csapi/apidoc_room_state_test.go +++ b/tests/csapi/apidoc_room_state_test.go @@ -8,8 +8,8 @@ import ( "github.com/tidwall/gjson" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/internal/match" "github.com/matrix-org/complement/internal/must" ) @@ -26,7 +26,7 @@ func TestRoomState(t *testing.T) { "visibility": "public", "preset": "public_chat", }) - res := authedClient.MustDoFunc(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.member", authedClient.UserID}) + res := authedClient.MustDo(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.member", authedClient.UserID}) must.MatchResponse(t, res, match.HTTPResponse{ JSON: []match.JSON{ match.JSONKeyPresent("membership"), @@ -44,7 +44,7 @@ func TestRoomState(t *testing.T) { "visibility": "public", "preset": "public_chat", }) - res := authedClient.MustDoFunc(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.member", authedClient.UserID}, client.WithQueries(queryParams)) + res := authedClient.MustDo(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.member", authedClient.UserID}, client.WithQueries(queryParams)) must.MatchResponse(t, res, match.HTTPResponse{ JSON: []match.JSON{ match.JSONKeyPresent("sender"), @@ -65,7 +65,7 @@ func TestRoomState(t *testing.T) { "preset": "public_chat", "room_alias_name": "room_alias", }) - res := authedClient.MustDoFunc(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.power_levels"}) + res := authedClient.MustDo(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.power_levels"}) must.MatchResponse(t, res, match.HTTPResponse{ JSON: []match.JSON{ @@ -88,7 +88,7 @@ func TestRoomState(t *testing.T) { "preset": "public_chat", }) - res := authedClient.MustDoFunc(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "joined_members"}) + res := authedClient.MustDo(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "joined_members"}) must.MatchResponse(t, res, match.HTTPResponse{ JSON: []match.JSON{ match.JSONKeyPresent("joined"), @@ -106,7 +106,7 @@ func TestRoomState(t *testing.T) { "preset": "public_chat", }) - authedClient.MustDoFunc(t, "GET", []string{"_matrix", "client", "v3", "publicRooms"}, + authedClient.MustDo(t, "GET", []string{"_matrix", "client", "v3", "publicRooms"}, client.WithRetryUntil(time.Second, func(res *http.Response) bool { foundRoom := false @@ -142,7 +142,7 @@ func TestRoomState(t *testing.T) { "room_alias_name": "room_new", }) - res := authedClient.MustDoFunc(t, "GET", []string{"_matrix", "client", "v3", "directory", "room", "#room_new:hs1"}) + res := authedClient.MustDo(t, "GET", []string{"_matrix", "client", "v3", "directory", "room", "#room_new:hs1"}) must.MatchResponse(t, res, match.HTTPResponse{ JSON: []match.JSON{ @@ -161,7 +161,7 @@ func TestRoomState(t *testing.T) { "visibility": "public", "preset": "public_chat", }) - res := authedClient.MustDoFunc(t, "GET", []string{"_matrix", "client", "v3", "joined_rooms"}) + res := authedClient.MustDo(t, "GET", []string{"_matrix", "client", "v3", "joined_rooms"}) foundRoom := false @@ -193,7 +193,7 @@ func TestRoomState(t *testing.T) { "name": "room_name_test", }) - res := authedClient.MustDoFunc(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.name"}) + res := authedClient.MustDo(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.name"}) must.MatchResponse(t, res, match.HTTPResponse{ JSON: []match.JSON{ @@ -215,9 +215,9 @@ func TestRoomState(t *testing.T) { "name": "room_test_name", }) - _ = authedClient.MustDoFunc(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.name"}, reqBody) + _ = authedClient.MustDo(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.name"}, reqBody) - res := authedClient.MustDoFunc(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.name"}) + res := authedClient.MustDo(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.name"}) must.MatchResponse(t, res, match.HTTPResponse{ JSON: []match.JSON{ @@ -236,7 +236,7 @@ func TestRoomState(t *testing.T) { "topic": "room_topic_test", }) - res := authedClient.MustDoFunc(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.topic"}) + res := authedClient.MustDo(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.topic"}) must.MatchResponse(t, res, match.HTTPResponse{ JSON: []match.JSON{ @@ -258,9 +258,9 @@ func TestRoomState(t *testing.T) { "topic": "room_test_topic", }) - _ = authedClient.MustDoFunc(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.topic"}, reqBody) + _ = authedClient.MustDo(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.topic"}, reqBody) - res := authedClient.MustDoFunc(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.topic"}) + res := authedClient.MustDo(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.topic"}) must.MatchResponse(t, res, match.HTTPResponse{ JSON: []match.JSON{ @@ -288,7 +288,7 @@ func TestRoomState(t *testing.T) { "m.room.topic": true, } - res := authedClient.MustDoFunc(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state"}) + res := authedClient.MustDo(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state"}) must.MatchResponse(t, res, match.HTTPResponse{ JSON: []match.JSON{ @@ -318,7 +318,7 @@ func TestRoomState(t *testing.T) { }, }) - res := authedClient.MustDoFunc(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.create"}) + res := authedClient.MustDo(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.create"}) must.MatchResponse(t, res, match.HTTPResponse{ JSON: []match.JSON{ @@ -331,7 +331,7 @@ func TestRoomState(t *testing.T) { t.Parallel() roomID := authedClient.CreateRoom(t, map[string]interface{}{}) authedClient.LeaveRoom(t, roomID) - res := authedClient.DoFunc(t, "GET", []string{"_matrix", "client", "r0", "rooms", roomID, "joined_members"}) + res := authedClient.Do(t, "GET", []string{"_matrix", "client", "r0", "rooms", roomID, "joined_members"}) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: http.StatusForbidden, JSON: []match.JSON{ diff --git a/tests/csapi/apidoc_search_test.go b/tests/csapi/apidoc_search_test.go index 2b98a042..dd40ff09 100644 --- a/tests/csapi/apidoc_search_test.go +++ b/tests/csapi/apidoc_search_test.go @@ -9,8 +9,8 @@ import ( "github.com/matrix-org/util" "github.com/tidwall/gjson" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/internal/match" "github.com/matrix-org/complement/internal/must" ) @@ -50,7 +50,7 @@ func TestSearch(t *testing.T) { }, }) - resp := alice.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "search"}, searchRequest) + resp := alice.MustDo(t, "POST", []string{"_matrix", "client", "v3", "search"}, searchRequest) sce := "search_categories.room_events" result0 := sce + ".results.0.result" must.MatchResponse(t, resp, match.HTTPResponse{ @@ -103,7 +103,7 @@ func TestSearch(t *testing.T) { }, }) - resp := alice.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "search"}, searchRequest) + resp := alice.MustDo(t, "POST", []string{"_matrix", "client", "v3", "search"}, searchRequest) sce := "search_categories.room_events" result0 := sce + ".results.0.result" resBefore := sce + ".results.0.context.events_before" @@ -160,7 +160,7 @@ func TestSearch(t *testing.T) { }, }) - resp := alice.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "search"}, searchRequest) + resp := alice.MustDo(t, "POST", []string{"_matrix", "client", "v3", "search"}, searchRequest) // First search result nextBatch := checkBackpaginateResult(t, resp, 20, eventIDs[19], eventIDs[10]) @@ -172,14 +172,14 @@ func TestSearch(t *testing.T) { values := url.Values{} values.Set("next_batch", nextBatch) params := client.WithQueries(values) - resp = alice.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "search"}, searchRequest, params) + resp = alice.MustDo(t, "POST", []string{"_matrix", "client", "v3", "search"}, searchRequest, params) // Second search result nextBatch = checkBackpaginateResult(t, resp, 20, eventIDs[9], eventIDs[0]) // At this point we expect next_batch to be empty values.Set("next_batch", nextBatch) params = client.WithQueries(values) - resp = alice.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "search"}, searchRequest, params) + resp = alice.MustDo(t, "POST", []string{"_matrix", "client", "v3", "search"}, searchRequest, params) // third search result sce := "search_categories.room_events" result0 := sce + ".results.0.result" @@ -215,7 +215,7 @@ func TestSearch(t *testing.T) { upgradeBody := client.WithJSONBody(t, map[string]string{ "new_version": "9", }) - upgradeResp := alice.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "upgrade"}, upgradeBody) + upgradeResp := alice.MustDo(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "upgrade"}, upgradeBody) body := must.ParseJSON(t, upgradeResp.Body) newRoomID := must.GetJSONFieldStr(t, body, "replacement_room") t.Logf("Replaced room %s with %s", roomID, newRoomID) @@ -241,7 +241,7 @@ func TestSearch(t *testing.T) { }, }) - resp := alice.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "search"}, searchRequest) + resp := alice.MustDo(t, "POST", []string{"_matrix", "client", "v3", "search"}, searchRequest) sce := "search_categories.room_events" expectedEvents := map[string]string{ @@ -301,7 +301,7 @@ func TestSearch(t *testing.T) { // redact the event redactBody := client.WithJSONBody(t, map[string]interface{}{"reason": "testing"}) txnID := util.RandomString(8) // random string, as time.Now().Unix() might create the same txnID - resp := alice.MustDoFunc(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "redact", redactedEventID, txnID}, redactBody) + resp := alice.MustDo(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "redact", redactedEventID, txnID}, redactBody) j := must.ParseJSON(t, resp.Body) redactionEventID := must.GetJSONFieldStr(t, j, "event_id") // wait for the redaction to come down sync @@ -320,7 +320,7 @@ func TestSearch(t *testing.T) { }, }) - resp = alice.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "search"}, searchRequest) + resp = alice.MustDo(t, "POST", []string{"_matrix", "client", "v3", "search"}, searchRequest) sce := "search_categories.room_events" result0 := sce + ".results.0.result" must.MatchResponse(t, resp, match.HTTPResponse{ diff --git a/tests/csapi/apidoc_server_capabilities_test.go b/tests/csapi/apidoc_server_capabilities_test.go index e33b5f78..13912ee5 100644 --- a/tests/csapi/apidoc_server_capabilities_test.go +++ b/tests/csapi/apidoc_server_capabilities_test.go @@ -27,7 +27,7 @@ func TestServerCapabilities(t *testing.T) { ) // sytest: GET /v3/capabilities is not public - res := unauthedClient.DoFunc(t, "GET", []string{"_matrix", "client", "v3", "capabilities"}) + res := unauthedClient.Do(t, "GET", []string{"_matrix", "client", "v3", "capabilities"}) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: http.StatusUnauthorized, }) diff --git a/tests/csapi/apidoc_version_test.go b/tests/csapi/apidoc_version_test.go index d0ce70f5..df7e6dd4 100644 --- a/tests/csapi/apidoc_version_test.go +++ b/tests/csapi/apidoc_version_test.go @@ -28,7 +28,7 @@ func TestVersionStructure(t *testing.T) { // sytest: Version responds 200 OK with valid structure t.Run("Version responds 200 OK with valid structure", func(t *testing.T) { - res := client.MustDoFunc(t, "GET", []string{"_matrix", "client", "versions"}) + res := client.MustDo(t, "GET", []string{"_matrix", "client", "versions"}) // Matches; // - r0.?.? diff --git a/tests/csapi/device_lists_test.go b/tests/csapi/device_lists_test.go index a8ae6d90..bdd759b0 100644 --- a/tests/csapi/device_lists_test.go +++ b/tests/csapi/device_lists_test.go @@ -5,8 +5,8 @@ import ( "sync/atomic" "testing" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/internal/docker" "github.com/matrix-org/complement/internal/match" "github.com/matrix-org/complement/internal/must" @@ -38,7 +38,7 @@ func TestDeviceListUpdates(t *testing.T) { ed25519KeyID := fmt.Sprintf("ed25519:%s", user.DeviceID) curve25519KeyID := fmt.Sprintf("curve25519:%s", user.DeviceID) - user.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "keys", "upload"}, + user.MustDo(t, "POST", []string{"_matrix", "client", "v3", "keys", "upload"}, client.WithJSONBody(t, map[string]interface{}{ "device_keys": map[string]interface{}{ "user_id": user.UserID, @@ -67,7 +67,7 @@ func TestDeviceListUpdates(t *testing.T) { mustQueryKeys := func(t *testing.T, user *client.CSAPI, userID string, check []match.JSON) { t.Helper() - res := user.DoFunc(t, "POST", []string{"_matrix", "client", "v3", "keys", "query"}, + res := user.Do(t, "POST", []string{"_matrix", "client", "v3", "keys", "query"}, client.WithJSONBody(t, map[string]interface{}{ "device_keys": map[string]interface{}{ userID: []string{}, diff --git a/tests/csapi/e2e_key_backup_test.go b/tests/csapi/e2e_key_backup_test.go index 65f9425d..6b832381 100644 --- a/tests/csapi/e2e_key_backup_test.go +++ b/tests/csapi/e2e_key_backup_test.go @@ -6,8 +6,8 @@ import ( "github.com/tidwall/gjson" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/internal/match" "github.com/matrix-org/complement/internal/must" ) @@ -21,9 +21,9 @@ type backupKey struct { // This test checks that the rules for replacing room keys are implemented correctly. // Specifically: // -// if the keys have different values for is_verified, then it will keep the key that has is_verified set to true; -// if they have the same values for is_verified, then it will keep the key with a lower first_message_index; -// and finally, is is_verified and first_message_index are equal, then it will keep the key with a lower forwarded_count. +// if the keys have different values for is_verified, then it will keep the key that has is_verified set to true; +// if they have the same values for is_verified, then it will keep the key with a lower first_message_index; +// and finally, is is_verified and first_message_index are equal, then it will keep the key with a lower forwarded_count. func TestE2EKeyBackupReplaceRoomKeyRules(t *testing.T) { deployment := Deploy(t, b.BlueprintAlice) defer deployment.Destroy(t) @@ -32,7 +32,7 @@ func TestE2EKeyBackupReplaceRoomKeyRules(t *testing.T) { alice := deployment.Client(t, "hs1", userID) // make a new key backup - res := alice.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "room_keys", "version"}, client.WithJSONBody(t, map[string]interface{}{ + res := alice.MustDo(t, "POST", []string{"_matrix", "client", "v3", "room_keys", "version"}, client.WithJSONBody(t, map[string]interface{}{ "algorithm": "m.megolm_backup.v1", "auth_data": map[string]interface{}{ "foo": "bar", @@ -123,7 +123,7 @@ func TestE2EKeyBackupReplaceRoomKeyRules(t *testing.T) { t.Run(fmt.Sprintf("%+v", tc.input), func(t *testing.T) { t.Parallel() // insert the key that will be tested against - alice.MustDoFunc(t, "PUT", []string{"_matrix", "client", "v3", "room_keys", "keys", roomID, tc.sessionID}, + alice.MustDo(t, "PUT", []string{"_matrix", "client", "v3", "room_keys", "keys", roomID, tc.sessionID}, client.WithQueries(map[string][]string{"version": {backupVersion}}), client.WithJSONBody(t, map[string]interface{}{ "first_message_index": tc.input.firstMessageIndex, "forwarded_count": tc.input.forwardedCount, @@ -133,7 +133,7 @@ func TestE2EKeyBackupReplaceRoomKeyRules(t *testing.T) { ) // now check that each key in keysThatDontReplace do not replace this key for _, testKey := range tc.keysThatDontReplace { - alice.MustDoFunc(t, "PUT", []string{"_matrix", "client", "v3", "room_keys", "keys", roomID, tc.sessionID}, + alice.MustDo(t, "PUT", []string{"_matrix", "client", "v3", "room_keys", "keys", roomID, tc.sessionID}, client.WithQueries(map[string][]string{"version": {backupVersion}}), client.WithJSONBody(t, map[string]interface{}{ "first_message_index": testKey.firstMessageIndex, "forwarded_count": testKey.forwardedCount, @@ -141,7 +141,7 @@ func TestE2EKeyBackupReplaceRoomKeyRules(t *testing.T) { "session_data": map[string]interface{}{"a": "b"}, }), ) - checkResp := alice.MustDoFunc(t, "GET", []string{"_matrix", "client", "v3", "room_keys", "keys", roomID, tc.sessionID}, + checkResp := alice.MustDo(t, "GET", []string{"_matrix", "client", "v3", "room_keys", "keys", roomID, tc.sessionID}, client.WithQueries(map[string][]string{"version": {backupVersion}}), ) must.MatchResponse(t, checkResp, match.HTTPResponse{ diff --git a/tests/csapi/ignored_users_test.go b/tests/csapi/ignored_users_test.go index 9001985f..ab35205d 100644 --- a/tests/csapi/ignored_users_test.go +++ b/tests/csapi/ignored_users_test.go @@ -10,14 +10,16 @@ import ( "github.com/tidwall/gjson" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/internal/match" "github.com/matrix-org/complement/internal/must" ) // The Spec says here -// https://spec.matrix.org/v1.1/client-server-api/#server-behaviour-13 +// +// https://spec.matrix.org/v1.1/client-server-api/#server-behaviour-13 +// // that // > Servers must not send room invites from ignored users to clients. // @@ -40,7 +42,7 @@ func TestInviteFromIgnoredUsersDoesNotAppearInSync(t *testing.T) { alice.MustSyncUntil(t, client.SyncReq{}, client.SyncJoinedTo(alice.UserID, publicRoom)) // Alice ignores Bob. - alice.MustDoFunc( + alice.MustDo( t, "PUT", []string{"_matrix", "client", "v3", "user", alice.UserID, "account_data", "m.ignored_user_list"}, @@ -82,7 +84,7 @@ func TestInviteFromIgnoredUsersDoesNotAppearInSync(t *testing.T) { } // Note: SyncUntil only runs its callback on array elements. I want to investigate an object. // So let's make the HTTP request more directly. - response := alice.MustDoFunc( + response := alice.MustDo( t, "GET", []string{"_matrix", "client", "v3", "sync"}, diff --git a/tests/csapi/invalid_test.go b/tests/csapi/invalid_test.go index c6a074dd..be5e37e7 100644 --- a/tests/csapi/invalid_test.go +++ b/tests/csapi/invalid_test.go @@ -4,8 +4,8 @@ import ( "strings" "testing" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/internal/match" "github.com/matrix-org/complement/internal/must" "github.com/matrix-org/complement/runtime" @@ -34,7 +34,7 @@ func TestJson(t *testing.T) { } for _, testCase := range testCases { - res := alice.DoFunc(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "send", "complement.dummy"}, client.WithJSONBody(t, testCase)) + res := alice.Do(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "send", "complement.dummy"}, client.WithJSONBody(t, testCase)) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: 400, @@ -56,7 +56,7 @@ func TestJson(t *testing.T) { } for _, testCase := range testCases { - res := alice.DoFunc(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "send", "complement.dummy"}, client.WithJSONBody(t, testCase)) + res := alice.Do(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "send", "complement.dummy"}, client.WithJSONBody(t, testCase)) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: 400, @@ -177,7 +177,7 @@ func TestFilter(t *testing.T) { filters := getFilters() for _, filter := range filters { - res := alice.DoFunc(t, "POST", []string{"_matrix", "client", "v3", "user", alice.UserID, "filter"}, client.WithJSONBody(t, filter)) + res := alice.Do(t, "POST", []string{"_matrix", "client", "v3", "user", alice.UserID, "filter"}, client.WithJSONBody(t, filter)) if res.StatusCode >= 500 || res.StatusCode < 400 { t.Errorf("Expected 4XX status code, got %d for testing filter %s", res.StatusCode, filter) @@ -205,7 +205,7 @@ func TestEvent(t *testing.T) { "body": strings.Repeat("and they dont stop coming ", 2700), // 2700 * 26 == 70200 } - res := alice.DoFunc(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "send", "m.room.message", "1"}, client.WithJSONBody(t, event)) + res := alice.Do(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "send", "m.room.message", "1"}, client.WithJSONBody(t, event)) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: 413, @@ -219,7 +219,7 @@ func TestEvent(t *testing.T) { "body": strings.Repeat("Dormammu, I've Come To Bargain.\n", 2200), // 2200 * 32 == 70400 } - res := alice.DoFunc(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "marvel.universe.fate"}, client.WithJSONBody(t, stateEvent)) + res := alice.Do(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "marvel.universe.fate"}, client.WithJSONBody(t, stateEvent)) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: 413, diff --git a/tests/csapi/keychanges_test.go b/tests/csapi/keychanges_test.go index 7e8f719a..d8abc525 100644 --- a/tests/csapi/keychanges_test.go +++ b/tests/csapi/keychanges_test.go @@ -8,8 +8,8 @@ import ( "github.com/tidwall/gjson" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/internal/match" "github.com/matrix-org/complement/internal/must" ) @@ -39,7 +39,7 @@ func TestKeyChangesLocal(t *testing.T) { "password": password, }) // Create a new device by logging in - res := unauthedClient.MustDoFunc(t, "POST", []string{"_matrix", "client", "r0", "login"}, reqBody) + res := unauthedClient.MustDo(t, "POST", []string{"_matrix", "client", "r0", "login"}, reqBody) loginResp := must.ParseJSON(t, res.Body) unauthedClient.AccessToken = must.GetJSONFieldStr(t, loginResp, "access_token") unauthedClient.DeviceID = must.GetJSONFieldStr(t, loginResp, "device_id") @@ -63,7 +63,7 @@ func TestKeyChangesLocal(t *testing.T) { queryParams := url.Values{} queryParams.Set("from", nextBatch1) queryParams.Set("to", nextBatch) - resp := alice.MustDoFunc(t, "GET", []string{"_matrix", "client", "v3", "keys", "changes"}, client.WithQueries(queryParams)) + resp := alice.MustDo(t, "GET", []string{"_matrix", "client", "v3", "keys", "changes"}, client.WithQueries(queryParams)) must.MatchResponse(t, resp, match.HTTPResponse{ StatusCode: http.StatusOK, JSON: []match.JSON{ @@ -77,7 +77,7 @@ func TestKeyChangesLocal(t *testing.T) { bob.UserID: {}, }, }) - resp = alice.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "keys", "query"}, queryKeys) + resp = alice.MustDo(t, "POST", []string{"_matrix", "client", "v3", "keys", "query"}, queryKeys) keyCount := 0 must.MatchResponse(t, resp, match.HTTPResponse{ StatusCode: http.StatusOK, @@ -102,5 +102,5 @@ func mustUploadKeys(t *testing.T, user *client.CSAPI) { "device_keys": deviceKeys, "one_time_keys": oneTimeKeys, }) - user.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "keys", "upload"}, reqBody) + user.MustDo(t, "POST", []string{"_matrix", "client", "v3", "keys", "upload"}, reqBody) } diff --git a/tests/csapi/media_misc_test.go b/tests/csapi/media_misc_test.go index a6b81c21..3ae93476 100644 --- a/tests/csapi/media_misc_test.go +++ b/tests/csapi/media_misc_test.go @@ -6,8 +6,8 @@ import ( "github.com/tidwall/gjson" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/internal/data" "github.com/matrix-org/complement/internal/match" "github.com/matrix-org/complement/internal/must" @@ -45,7 +45,7 @@ func TestRoomImageRoundtrip(t *testing.T) { }, }) - messages := alice.MustDoFunc(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomId, "messages"}, client.WithQueries(url.Values{ + messages := alice.MustDo(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomId, "messages"}, client.WithQueries(url.Values{ "filter": []string{`{"contains_url":true}`}, "dir": []string{"b"}, })) @@ -66,7 +66,7 @@ func TestMediaConfig(t *testing.T) { alice := deployment.Client(t, "hs1", "@alice:hs1") - res := alice.MustDoFunc(t, "GET", []string{"_matrix", "media", "v3", "config"}) + res := alice.MustDo(t, "GET", []string{"_matrix", "media", "v3", "config"}) must.MatchResponse(t, res, match.HTTPResponse{ JSON: []match.JSON{ diff --git a/tests/csapi/power_levels_test.go b/tests/csapi/power_levels_test.go index 21f0f063..90a73019 100644 --- a/tests/csapi/power_levels_test.go +++ b/tests/csapi/power_levels_test.go @@ -6,8 +6,8 @@ import ( "github.com/tidwall/gjson" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/internal/match" "github.com/matrix-org/complement/internal/must" ) @@ -58,7 +58,7 @@ func TestPowerLevels(t *testing.T) { // sytest: GET /rooms/:room_id/state/m.room.power_levels can fetch levels t.Run("GET /rooms/:room_id/state/m.room.power_levels can fetch levels", func(t *testing.T) { // Test if the old state still exists - res := alice.MustDoFunc(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.power_levels"}) + res := alice.MustDo(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.power_levels"}) // note: before v10 we technically cannot assume that powerlevel integers are json numbers, // as they can be both strings and numbers. @@ -123,7 +123,7 @@ func TestPowerLevels(t *testing.T) { Content: PLContent, }) - res := alice.MustDoFunc( + res := alice.MustDo( t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "event", eventId}, @@ -157,7 +157,7 @@ func TestPowerLevels(t *testing.T) { }) // This should give a 403 (not a 500) - res := alice.DoFunc( + res := alice.Do( t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.power_levels"}, @@ -170,7 +170,7 @@ func TestPowerLevels(t *testing.T) { }) // Test if the old state still exists - res = alice.MustDoFunc(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.power_levels"}) + res = alice.MustDo(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.power_levels"}) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: 200, diff --git a/tests/csapi/push_test.go b/tests/csapi/push_test.go index b5db96e5..1ce0ec4b 100644 --- a/tests/csapi/push_test.go +++ b/tests/csapi/push_test.go @@ -7,8 +7,8 @@ import ( "github.com/tidwall/gjson" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/internal/match" "github.com/matrix-org/complement/internal/must" ) @@ -58,7 +58,7 @@ func TestPushSync(t *testing.T) { "actions": []string{"notify"}, }) - alice.MustDoFunc(t, "PUT", []string{"_matrix", "client", "v3", "pushrules", "global", "room", "!foo:example.com"}, body) + alice.MustDo(t, "PUT", []string{"_matrix", "client", "v3", "pushrules", "global", "room", "!foo:example.com"}, body) }) }) @@ -69,7 +69,7 @@ func TestPushSync(t *testing.T) { "enabled": false, }) - alice.MustDoFunc(t, "PUT", []string{"_matrix", "client", "v3", "pushrules", "global", "room", "!foo:example.com", "enabled"}, body) + alice.MustDo(t, "PUT", []string{"_matrix", "client", "v3", "pushrules", "global", "room", "!foo:example.com", "enabled"}, body) }) }) @@ -80,7 +80,7 @@ func TestPushSync(t *testing.T) { "enabled": true, }) - alice.MustDoFunc(t, "PUT", []string{"_matrix", "client", "v3", "pushrules", "global", "room", "!foo:example.com", "enabled"}, body) + alice.MustDo(t, "PUT", []string{"_matrix", "client", "v3", "pushrules", "global", "room", "!foo:example.com", "enabled"}, body) }) }) @@ -91,7 +91,7 @@ func TestPushSync(t *testing.T) { "actions": []string{"dont_notify"}, }) - alice.MustDoFunc(t, "PUT", []string{"_matrix", "client", "v3", "pushrules", "global", "room", "!foo:example.com", "actions"}, body) + alice.MustDo(t, "PUT", []string{"_matrix", "client", "v3", "pushrules", "global", "room", "!foo:example.com", "actions"}, body) }) }) } diff --git a/tests/csapi/room_ban_test.go b/tests/csapi/room_ban_test.go index bb2e99a7..54bd9020 100644 --- a/tests/csapi/room_ban_test.go +++ b/tests/csapi/room_ban_test.go @@ -3,8 +3,8 @@ package csapi_tests import ( "testing" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/internal/match" "github.com/matrix-org/complement/internal/must" ) @@ -59,7 +59,7 @@ func TestNotPresentUserCannotBanOthers(t *testing.T) { bob.MustSyncUntil(t, client.SyncReq{}, client.SyncJoinedTo(bob.UserID, roomID)) - res := charlie.DoFunc(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "ban"}, client.WithJSONBody(t, map[string]interface{}{ + res := charlie.Do(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "ban"}, client.WithJSONBody(t, map[string]interface{}{ "user_id": bob.UserID, "reason": "testing", })) diff --git a/tests/csapi/room_kick_test.go b/tests/csapi/room_kick_test.go index 6e6ef1e5..38312fd6 100644 --- a/tests/csapi/room_kick_test.go +++ b/tests/csapi/room_kick_test.go @@ -3,8 +3,8 @@ package csapi_tests import ( "testing" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/internal/match" "github.com/matrix-org/complement/internal/must" ) @@ -21,7 +21,7 @@ func TestCannotKickNonPresentUser(t *testing.T) { "preset": "public_chat", }) - resp := alice.DoFunc(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "kick"}, + resp := alice.Do(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "kick"}, client.WithJSONBody(t, map[string]interface{}{ "user_id": bob.UserID, "reason": "testing", @@ -53,7 +53,7 @@ func TestCannotKickLeftUser(t *testing.T) { alice.MustSyncUntil(t, client.SyncReq{}, client.SyncLeftFrom(bob.UserID, roomID)) - resp := alice.DoFunc(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "kick"}, + resp := alice.Do(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "kick"}, client.WithJSONBody(t, map[string]interface{}{ "user_id": bob.UserID, "reason": "testing", diff --git a/tests/csapi/room_leave_test.go b/tests/csapi/room_leave_test.go index 98662573..db3257b4 100644 --- a/tests/csapi/room_leave_test.go +++ b/tests/csapi/room_leave_test.go @@ -7,8 +7,8 @@ import ( "github.com/tidwall/gjson" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/internal/match" "github.com/matrix-org/complement/internal/must" ) @@ -123,7 +123,7 @@ func TestLeftRoomFixture(t *testing.T) { // sytest: Can get rooms/{roomId}/state for a departed room (SPEC-216) t.Run("Can get rooms/{roomId}/state for a departed room", func(t *testing.T) { // Bob gets the old state - resp := bob.MustDoFunc( + resp := bob.MustDo( t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", madeUpStateKey}, @@ -135,7 +135,7 @@ func TestLeftRoomFixture(t *testing.T) { }) // ...While Alice gets the new state - resp = alice.MustDoFunc( + resp = alice.MustDo( t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", madeUpStateKey}, @@ -149,7 +149,7 @@ func TestLeftRoomFixture(t *testing.T) { // sytest: Can get rooms/{roomId}/members for a departed room (SPEC-216) t.Run("Can get rooms/{roomId}/members for a departed room", func(t *testing.T) { - resp := bob.MustDoFunc( + resp := bob.MustDo( t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "members"}, @@ -174,7 +174,7 @@ func TestLeftRoomFixture(t *testing.T) { // sytest: Can get rooms/{roomId}/messages for a departed room (SPEC-216) t.Run("Can get rooms/{roomId}/messages for a departed room", func(t *testing.T) { - resp := bob.MustDoFunc(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "messages"}, client.WithQueries(url.Values{ + resp := bob.MustDo(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "messages"}, client.WithQueries(url.Values{ "dir": []string{"b"}, "limit": []string{"3"}, "from": []string{bobSinceToken}, @@ -200,7 +200,7 @@ func TestLeftRoomFixture(t *testing.T) { // sytest: Can get 'm.room.name' state for a departed room (SPEC-216) t.Run("Can get 'm.room.name' state for a departed room", func(t *testing.T) { // Bob gets the old name - resp := bob.MustDoFunc( + resp := bob.MustDo( t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.name"}, @@ -212,7 +212,7 @@ func TestLeftRoomFixture(t *testing.T) { }) // ...While Alice gets the new name - resp = alice.MustDoFunc( + resp = alice.MustDo( t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.name"}, @@ -227,7 +227,7 @@ func TestLeftRoomFixture(t *testing.T) { // sytest: Getting messages going forward is limited for a departed room (SPEC-216) t.Run("Getting messages going forward is limited for a departed room", func(t *testing.T) { // TODO: try this with the most recent since token too - resp := bob.MustDoFunc(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "messages"}, client.WithQueries(url.Values{ + resp := bob.MustDo(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "messages"}, client.WithQueries(url.Values{ "dir": []string{"f"}, "limit": []string{"100"}, "from": []string{bobSinceToken}, diff --git a/tests/csapi/room_members_test.go b/tests/csapi/room_members_test.go index 4cfeb567..f5c2fda6 100644 --- a/tests/csapi/room_members_test.go +++ b/tests/csapi/room_members_test.go @@ -7,8 +7,8 @@ import ( "github.com/tidwall/gjson" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/internal/match" "github.com/matrix-org/complement/internal/must" ) @@ -34,7 +34,7 @@ func TestGetRoomMembers(t *testing.T) { alice.MustSyncUntil(t, client.SyncReq{}, client.SyncJoinedTo(bob.UserID, roomID)) - resp := alice.MustDoFunc( + resp := alice.MustDo( t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "members"}, @@ -91,7 +91,7 @@ func TestGetRoomMembersAtPoint(t *testing.T) { }, }) - resp := alice.MustDoFunc( + resp := alice.MustDo( t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "members"}, @@ -138,7 +138,7 @@ func TestGetFilteredRoomMembers(t *testing.T) { alice.MustSyncUntil(t, client.SyncReq{}, client.SyncLeftFrom(bob.UserID, roomID)) t.Run("not_membership", func(t *testing.T) { - resp := alice.MustDoFunc( + resp := alice.MustDo( t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "members"}, @@ -163,7 +163,7 @@ func TestGetFilteredRoomMembers(t *testing.T) { }) t.Run("membership/leave", func(t *testing.T) { - resp := alice.MustDoFunc( + resp := alice.MustDo( t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "members"}, @@ -188,7 +188,7 @@ func TestGetFilteredRoomMembers(t *testing.T) { }) t.Run("membership/join", func(t *testing.T) { - resp := alice.MustDoFunc( + resp := alice.MustDo( t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "members"}, diff --git a/tests/csapi/room_messages_relation_filter_test.go b/tests/csapi/room_messages_relation_filter_test.go index 225894bb..62657f6f 100644 --- a/tests/csapi/room_messages_relation_filter_test.go +++ b/tests/csapi/room_messages_relation_filter_test.go @@ -10,8 +10,8 @@ import ( "github.com/tidwall/gjson" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/internal/match" "github.com/matrix-org/complement/internal/must" "github.com/matrix-org/complement/runtime" @@ -30,13 +30,13 @@ func TestFilterMessagesByRelType(t *testing.T) { beforeToken := alice.MustSyncUntil(t, client.SyncReq{}) // Send messages with different relations. - res := alice.MustDoFunc(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "send", "m.room.message", "txn-1"}, client.WithJSONBody(t, map[string]interface{}{ + res := alice.MustDo(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "send", "m.room.message", "txn-1"}, client.WithJSONBody(t, map[string]interface{}{ "msgtype": "m.text", "body": "Message without a relation", })) rootEventID := client.GetJSONFieldStr(t, client.ParseJSON(t, res), "event_id") - res = alice.MustDoFunc(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "send", "m.room.message", "txn-2"}, client.WithJSONBody(t, map[string]interface{}{ + res = alice.MustDo(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "send", "m.room.message", "txn-2"}, client.WithJSONBody(t, map[string]interface{}{ "msgtype": "m.text", "body": "Threaded Reply", "m.relates_to": map[string]interface{}{ @@ -46,7 +46,7 @@ func TestFilterMessagesByRelType(t *testing.T) { })) threadEventID := client.GetJSONFieldStr(t, client.ParseJSON(t, res), "event_id") - res = alice.MustDoFunc(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "send", "m.room.message", "txn-3"}, client.WithJSONBody(t, map[string]interface{}{ + res = alice.MustDo(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "send", "m.room.message", "txn-3"}, client.WithJSONBody(t, map[string]interface{}{ "msgtype": "m.text", "body": "Reference Reply", "m.relates_to": map[string]interface{}{ @@ -66,7 +66,7 @@ func TestFilterMessagesByRelType(t *testing.T) { queryParams.Set("dir", "f") queryParams.Set("from", beforeToken) queryParams.Set("filter", `{ "org.matrix.msc3874.rel_types" : ["m.thread"] }`) - res = alice.MustDoFunc(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "messages"}, client.WithQueries(queryParams)) + res = alice.MustDo(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "messages"}, client.WithQueries(queryParams)) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: http.StatusOK, JSON: []match.JSON{ @@ -84,7 +84,7 @@ func TestFilterMessagesByRelType(t *testing.T) { queryParams.Set("dir", "f") queryParams.Set("from", beforeToken) queryParams.Set("filter", `{ "org.matrix.msc3874.rel_types" : ["m.reference"] }`) - res = alice.MustDoFunc(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "messages"}, client.WithQueries(queryParams)) + res = alice.MustDo(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "messages"}, client.WithQueries(queryParams)) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: http.StatusOK, JSON: []match.JSON{ @@ -102,7 +102,7 @@ func TestFilterMessagesByRelType(t *testing.T) { queryParams.Set("dir", "f") queryParams.Set("from", beforeToken) queryParams.Set("filter", `{ "org.matrix.msc3874.rel_types" : ["m.thread", "m.reference"] }`) - res = alice.MustDoFunc(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "messages"}, client.WithQueries(queryParams)) + res = alice.MustDo(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "messages"}, client.WithQueries(queryParams)) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: http.StatusOK, JSON: []match.JSON{ @@ -120,7 +120,7 @@ func TestFilterMessagesByRelType(t *testing.T) { queryParams.Set("dir", "f") queryParams.Set("from", beforeToken) queryParams.Set("filter", `{ "org.matrix.msc3874.not_rel_types" : ["m.thread"] }`) - res = alice.MustDoFunc(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "messages"}, client.WithQueries(queryParams)) + res = alice.MustDo(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "messages"}, client.WithQueries(queryParams)) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: http.StatusOK, JSON: []match.JSON{ @@ -138,7 +138,7 @@ func TestFilterMessagesByRelType(t *testing.T) { queryParams.Set("dir", "f") queryParams.Set("from", beforeToken) queryParams.Set("filter", `{ "org.matrix.msc3874.not_rel_types" : ["m.reference"] }`) - res = alice.MustDoFunc(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "messages"}, client.WithQueries(queryParams)) + res = alice.MustDo(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "messages"}, client.WithQueries(queryParams)) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: http.StatusOK, JSON: []match.JSON{ @@ -156,7 +156,7 @@ func TestFilterMessagesByRelType(t *testing.T) { queryParams.Set("dir", "f") queryParams.Set("from", beforeToken) queryParams.Set("filter", `{ "org.matrix.msc3874.not_rel_types" : ["m.thread", "m.reference"] }`) - res = alice.MustDoFunc(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "messages"}, client.WithQueries(queryParams)) + res = alice.MustDo(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "messages"}, client.WithQueries(queryParams)) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: http.StatusOK, JSON: []match.JSON{ diff --git a/tests/csapi/room_messages_test.go b/tests/csapi/room_messages_test.go index 48e30234..5fba1d25 100644 --- a/tests/csapi/room_messages_test.go +++ b/tests/csapi/room_messages_test.go @@ -8,8 +8,8 @@ import ( "github.com/tidwall/gjson" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/internal/match" "github.com/matrix-org/complement/internal/must" "github.com/matrix-org/complement/runtime" @@ -31,7 +31,7 @@ func TestSendAndFetchMessage(t *testing.T) { _, token := alice.MustSync(t, client.SyncReq{}) // first use the non-txn endpoint - alice.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "send", "m.room.message"}, client.WithJSONBody(t, map[string]interface{}{ + alice.MustDo(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "send", "m.room.message"}, client.WithJSONBody(t, map[string]interface{}{ "msgtype": "m.text", "body": testMessage, })) @@ -45,7 +45,7 @@ func TestSendAndFetchMessage(t *testing.T) { queryParams := url.Values{} queryParams.Set("dir", "f") queryParams.Set("from", token) - res := alice.MustDoFunc(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "messages"}, client.WithQueries(queryParams)) + res := alice.MustDo(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "messages"}, client.WithQueries(queryParams)) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: http.StatusOK, JSON: []match.JSON{ @@ -71,7 +71,7 @@ func TestFetchMessagesFromNonExistentRoom(t *testing.T) { // then request messages from the room queryParams := url.Values{} queryParams.Set("dir", "b") - res := alice.DoFunc(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "messages"}, client.WithQueries(queryParams)) + res := alice.Do(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "messages"}, client.WithQueries(queryParams)) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: http.StatusForbidden, }) @@ -89,13 +89,13 @@ func TestSendMessageWithTxn(t *testing.T) { const txnID = "lorem" - res := alice.MustDoFunc(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "send", "m.room.message", txnID}, client.WithJSONBody(t, map[string]interface{}{ + res := 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": "test", })) eventID := client.GetJSONFieldStr(t, client.ParseJSON(t, res), "event_id") - res = alice.MustDoFunc(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "send", "m.room.message", txnID}, client.WithJSONBody(t, map[string]interface{}{ + res = 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": "test", })) @@ -166,7 +166,7 @@ func TestRoomMessagesLazyLoading(t *testing.T) { queryParams.Set("filter", `{ "lazy_load_members" : true }`) queryParams.Set("from", beforeToken) queryParams.Set("to", afterToken) - res := alice.DoFunc(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "messages"}, client.WithQueries(queryParams)) + res := alice.Do(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "messages"}, client.WithQueries(queryParams)) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: http.StatusOK, JSON: []match.JSON{ @@ -189,11 +189,13 @@ func TestRoomMessagesLazyLoading(t *testing.T) { } // TODO We should probably see if this should be removed. -// Sytest tests for a very specific bug; check if local user member event loads properly when going backwards from a prev_event. -// However, note that the sytest *only* checks for the *local, single* user in a room to be included in `/messages`. -// This function exists here for sytest exhaustiveness, but I question its usefulness, thats why TestRoomMessagesLazyLoading -// exists to do a more generic check. -// We should probably see if this should be removed. +// +// Sytest tests for a very specific bug; check if local user member event loads properly when going backwards from a prev_event. +// However, note that the sytest *only* checks for the *local, single* user in a room to be included in `/messages`. +// This function exists here for sytest exhaustiveness, but I question its usefulness, thats why TestRoomMessagesLazyLoading +// exists to do a more generic check. +// We should probably see if this should be removed. +// // sytest: GET /rooms/:room_id/messages lazy loads members correctly func TestRoomMessagesLazyLoadingLocalUser(t *testing.T) { deployment := Deploy(t, b.BlueprintAlice) @@ -217,7 +219,7 @@ func TestRoomMessagesLazyLoadingLocalUser(t *testing.T) { queryParams.Set("dir", "b") queryParams.Set("filter", `{ "lazy_load_members" : true }`) queryParams.Set("from", token) - res := alice.DoFunc(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "messages"}, client.WithQueries(queryParams)) + res := alice.Do(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "messages"}, client.WithQueries(queryParams)) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: http.StatusOK, JSON: []match.JSON{ diff --git a/tests/csapi/room_profile_test.go b/tests/csapi/room_profile_test.go index a8c2b100..bbf60986 100644 --- a/tests/csapi/room_profile_test.go +++ b/tests/csapi/room_profile_test.go @@ -5,8 +5,8 @@ import ( "github.com/tidwall/gjson" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" ) func TestAvatarUrlUpdate(t *testing.T) { @@ -32,7 +32,7 @@ func testProfileFieldUpdate(t *testing.T, field string) { sinceToken := alice.MustSyncUntil(t, client.SyncReq{}, client.SyncJoinedTo(alice.UserID, roomID)) - alice.MustDoFunc( + alice.MustDo( t, "PUT", []string{"_matrix", "client", "v3", "profile", alice.UserID, field}, diff --git a/tests/csapi/room_relations_test.go b/tests/csapi/room_relations_test.go index 2ca85433..9187c3ba 100644 --- a/tests/csapi/room_relations_test.go +++ b/tests/csapi/room_relations_test.go @@ -8,8 +8,8 @@ import ( "github.com/tidwall/gjson" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/internal/match" "github.com/matrix-org/complement/internal/must" "github.com/matrix-org/complement/runtime" @@ -23,14 +23,14 @@ func TestRelations(t *testing.T) { roomID := alice.CreateRoom(t, map[string]interface{}{"preset": "public_chat"}) _, token := alice.MustSync(t, client.SyncReq{}) - res := alice.MustDoFunc(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "send", "m.room.message", "txn-1"}, client.WithJSONBody(t, map[string]interface{}{ + res := alice.MustDo(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "send", "m.room.message", "txn-1"}, client.WithJSONBody(t, map[string]interface{}{ "msgtype": "m.text", "body": "root", })) rootEventID := client.GetJSONFieldStr(t, client.ParseJSON(t, res), "event_id") // Send a few related messages. - res = alice.MustDoFunc(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "send", "m.room.message", "txn-2"}, client.WithJSONBody(t, map[string]interface{}{ + res = alice.MustDo(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "send", "m.room.message", "txn-2"}, client.WithJSONBody(t, map[string]interface{}{ "msgtype": "m.text", "body": "reply", "m.relates_to": map[string]interface{}{ @@ -40,7 +40,7 @@ func TestRelations(t *testing.T) { })) threadEventID := client.GetJSONFieldStr(t, client.ParseJSON(t, res), "event_id") - res = alice.MustDoFunc(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "send", "m.dummy", "txn-3"}, client.WithJSONBody(t, map[string]interface{}{ + res = alice.MustDo(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "send", "m.dummy", "txn-3"}, client.WithJSONBody(t, map[string]interface{}{ "m.relates_to": map[string]interface{}{ "event_id": rootEventID, "rel_type": "m.thread", @@ -48,7 +48,7 @@ func TestRelations(t *testing.T) { })) dummyEventID := client.GetJSONFieldStr(t, client.ParseJSON(t, res), "event_id") - res = alice.MustDoFunc(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "send", "m.room.message", "txn-4"}, client.WithJSONBody(t, map[string]interface{}{ + res = alice.MustDo(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "send", "m.room.message", "txn-4"}, client.WithJSONBody(t, map[string]interface{}{ "msgtype": "m.text", "body": "* edited root", "m.new_content": map[string]interface{}{ @@ -68,7 +68,7 @@ func TestRelations(t *testing.T) { })) // Request the relations. - res = alice.MustDoFunc(t, "GET", []string{"_matrix", "client", "v1", "rooms", roomID, "relations", rootEventID}) + res = alice.MustDo(t, "GET", []string{"_matrix", "client", "v1", "rooms", roomID, "relations", rootEventID}) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: http.StatusOK, JSON: []match.JSON{ @@ -82,7 +82,7 @@ func TestRelations(t *testing.T) { }) // Also test filtering by the relation type. - res = alice.MustDoFunc(t, "GET", []string{"_matrix", "client", "v1", "rooms", roomID, "relations", rootEventID, "m.thread"}) + res = alice.MustDo(t, "GET", []string{"_matrix", "client", "v1", "rooms", roomID, "relations", rootEventID, "m.thread"}) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: http.StatusOK, JSON: []match.JSON{ @@ -96,7 +96,7 @@ func TestRelations(t *testing.T) { }) // And test filtering by relation type + event type. - res = alice.MustDoFunc(t, "GET", []string{"_matrix", "client", "v1", "rooms", roomID, "relations", rootEventID, "m.thread", "m.room.message"}) + res = alice.MustDo(t, "GET", []string{"_matrix", "client", "v1", "rooms", roomID, "relations", rootEventID, "m.thread", "m.room.message"}) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: http.StatusOK, JSON: []match.JSON{ @@ -118,7 +118,7 @@ func TestRelationsPagination(t *testing.T) { roomID := alice.CreateRoom(t, map[string]interface{}{"preset": "public_chat"}) _, token := alice.MustSync(t, client.SyncReq{}) - res := alice.MustDoFunc(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "send", "m.room.message", "txn-1"}, client.WithJSONBody(t, map[string]interface{}{ + res := alice.MustDo(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "send", "m.room.message", "txn-1"}, client.WithJSONBody(t, map[string]interface{}{ "msgtype": "m.text", "body": "root", })) @@ -127,7 +127,7 @@ func TestRelationsPagination(t *testing.T) { // Create some related events. event_ids := [10]string{} for i := 0; i < 10; i++ { - res = alice.MustDoFunc(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "send", "m.room.message", fmt.Sprintf("txn-%d", 2+i)}, client.WithJSONBody(t, map[string]interface{}{ + res = alice.MustDo(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "send", "m.room.message", fmt.Sprintf("txn-%d", 2+i)}, client.WithJSONBody(t, map[string]interface{}{ "msgtype": "m.text", "body": fmt.Sprintf("reply %d", i), "m.relates_to": map[string]interface{}{ @@ -146,7 +146,7 @@ func TestRelationsPagination(t *testing.T) { // Fetch the first page. queryParams := url.Values{} queryParams.Set("limit", "3") - res = alice.MustDoFunc(t, "GET", []string{"_matrix", "client", "v1", "rooms", roomID, "relations", rootEventID}, client.WithQueries(queryParams)) + res = alice.MustDo(t, "GET", []string{"_matrix", "client", "v1", "rooms", roomID, "relations", rootEventID}, client.WithQueries(queryParams)) body := must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: http.StatusOK, JSON: []match.JSON{ @@ -161,7 +161,7 @@ func TestRelationsPagination(t *testing.T) { // Fetch the next page. queryParams.Set("from", client.GetJSONFieldStr(t, body, "next_batch")) - res = alice.MustDoFunc(t, "GET", []string{"_matrix", "client", "v1", "rooms", roomID, "relations", rootEventID}, client.WithQueries(queryParams)) + res = alice.MustDo(t, "GET", []string{"_matrix", "client", "v1", "rooms", roomID, "relations", rootEventID}, client.WithQueries(queryParams)) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: http.StatusOK, JSON: []match.JSON{ @@ -178,7 +178,7 @@ func TestRelationsPagination(t *testing.T) { queryParams = url.Values{} queryParams.Set("limit", "3") queryParams.Set("dir", "f") - res = alice.MustDoFunc(t, "GET", []string{"_matrix", "client", "v1", "rooms", roomID, "relations", rootEventID}, client.WithQueries(queryParams)) + res = alice.MustDo(t, "GET", []string{"_matrix", "client", "v1", "rooms", roomID, "relations", rootEventID}, client.WithQueries(queryParams)) body = must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: http.StatusOK, JSON: []match.JSON{ @@ -193,7 +193,7 @@ func TestRelationsPagination(t *testing.T) { // Fetch the next page in the forward direction. queryParams.Set("from", client.GetJSONFieldStr(t, body, "next_batch")) - res = alice.MustDoFunc(t, "GET", []string{"_matrix", "client", "v1", "rooms", roomID, "relations", rootEventID}, client.WithQueries(queryParams)) + res = alice.MustDo(t, "GET", []string{"_matrix", "client", "v1", "rooms", roomID, "relations", rootEventID}, client.WithQueries(queryParams)) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: http.StatusOK, JSON: []match.JSON{ @@ -273,7 +273,7 @@ func TestRelationsPaginationSync(t *testing.T) { queryParams.Set("limit", "3") queryParams.Set("from", nextBatch) queryParams.Set("dir", "f") - res := alice.MustDoFunc(t, "GET", []string{"_matrix", "client", "v1", "rooms", roomID, "relations", rootEventID}, client.WithQueries(queryParams)) + res := alice.MustDo(t, "GET", []string{"_matrix", "client", "v1", "rooms", roomID, "relations", rootEventID}, client.WithQueries(queryParams)) body := must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: http.StatusOK, JSON: []match.JSON{ @@ -288,7 +288,7 @@ func TestRelationsPaginationSync(t *testing.T) { // Fetch the next page. queryParams.Set("from", client.GetJSONFieldStr(t, body, "next_batch")) - res = alice.MustDoFunc(t, "GET", []string{"_matrix", "client", "v1", "rooms", roomID, "relations", rootEventID}, client.WithQueries(queryParams)) + res = alice.MustDo(t, "GET", []string{"_matrix", "client", "v1", "rooms", roomID, "relations", rootEventID}, client.WithQueries(queryParams)) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: http.StatusOK, JSON: []match.JSON{ diff --git a/tests/csapi/room_threads_test.go b/tests/csapi/room_threads_test.go index f324f00f..27d756ee 100644 --- a/tests/csapi/room_threads_test.go +++ b/tests/csapi/room_threads_test.go @@ -6,8 +6,8 @@ import ( "github.com/tidwall/gjson" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/internal/match" "github.com/matrix-org/complement/internal/must" "github.com/matrix-org/complement/runtime" @@ -40,20 +40,20 @@ func TestThreadsEndpoint(t *testing.T) { _, token := alice.MustSync(t, client.SyncReq{}) // Create 2 threads in the room. - res := alice.MustDoFunc(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "send", "m.room.message", "txn-1"}, client.WithJSONBody(t, map[string]interface{}{ + res := alice.MustDo(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "send", "m.room.message", "txn-1"}, client.WithJSONBody(t, map[string]interface{}{ "msgtype": "m.text", "body": "Thread 1 Root", })) threadID1 := client.GetJSONFieldStr(t, client.ParseJSON(t, res), "event_id") - res = alice.MustDoFunc(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "send", "m.room.message", "txn-2"}, client.WithJSONBody(t, map[string]interface{}{ + res = alice.MustDo(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "send", "m.room.message", "txn-2"}, client.WithJSONBody(t, map[string]interface{}{ "msgtype": "m.text", "body": "Thraed 2 Root", })) threadID2 := client.GetJSONFieldStr(t, client.ParseJSON(t, res), "event_id") // Add threaded replies. - res = alice.MustDoFunc(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "send", "m.room.message", "txn-3"}, client.WithJSONBody(t, map[string]interface{}{ + res = alice.MustDo(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "send", "m.room.message", "txn-3"}, client.WithJSONBody(t, map[string]interface{}{ "msgtype": "m.text", "body": "Thread 1 Reply", "m.relates_to": map[string]interface{}{ @@ -63,7 +63,7 @@ func TestThreadsEndpoint(t *testing.T) { })) replyID1 := client.GetJSONFieldStr(t, client.ParseJSON(t, res), "event_id") - res = alice.MustDoFunc(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "send", "m.room.message", "txn-4"}, client.WithJSONBody(t, map[string]interface{}{ + res = alice.MustDo(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "send", "m.room.message", "txn-4"}, client.WithJSONBody(t, map[string]interface{}{ "msgtype": "m.text", "body": "Thread 2 Reply", "m.relates_to": map[string]interface{}{ @@ -79,7 +79,7 @@ func TestThreadsEndpoint(t *testing.T) { })) // Request the threads. - res = alice.MustDoFunc(t, "GET", []string{"_matrix", "client", "v1", "rooms", roomID, "threads"}) + res = alice.MustDo(t, "GET", []string{"_matrix", "client", "v1", "rooms", roomID, "threads"}) body := must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: http.StatusOK, }) @@ -88,7 +88,7 @@ func TestThreadsEndpoint(t *testing.T) { checkResults(t, body, []string{threadKey(threadID2, replyID2), threadKey(threadID1, replyID1)}) // Update thread 1 and ensure it gets updated. - res = alice.MustDoFunc(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "send", "m.room.message", "txn-5"}, client.WithJSONBody(t, map[string]interface{}{ + res = alice.MustDo(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "send", "m.room.message", "txn-5"}, client.WithJSONBody(t, map[string]interface{}{ "msgtype": "m.text", "body": "Thread 1 Reply 2", "m.relates_to": map[string]interface{}{ @@ -103,7 +103,7 @@ func TestThreadsEndpoint(t *testing.T) { return r.Get("event_id").Str == replyID3 })) - res = alice.MustDoFunc(t, "GET", []string{"_matrix", "client", "v1", "rooms", roomID, "threads"}) + res = alice.MustDo(t, "GET", []string{"_matrix", "client", "v1", "rooms", roomID, "threads"}) body = must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: http.StatusOK, }) diff --git a/tests/csapi/room_typing_test.go b/tests/csapi/room_typing_test.go index 8cf46426..fc55acd5 100644 --- a/tests/csapi/room_typing_test.go +++ b/tests/csapi/room_typing_test.go @@ -5,8 +5,8 @@ import ( "github.com/tidwall/gjson" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/internal/match" "github.com/matrix-org/complement/internal/must" ) @@ -25,7 +25,7 @@ func TestTyping(t *testing.T) { token := bob.MustSyncUntil(t, client.SyncReq{}, client.SyncJoinedTo(bob.UserID, roomID)) - alice.MustDoFunc(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "typing", alice.UserID}, client.WithJSONBody(t, map[string]interface{}{ + alice.MustDo(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "typing", alice.UserID}, client.WithJSONBody(t, map[string]interface{}{ "typing": true, "timeout": 10000, })) @@ -57,7 +57,7 @@ func TestTyping(t *testing.T) { // sytest: Typing can be explicitly stopped t.Run("Typing can be explicitly stopped", func(t *testing.T) { - alice.MustDoFunc(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "typing", alice.UserID}, client.WithJSONBody(t, map[string]interface{}{ + alice.MustDo(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "typing", alice.UserID}, client.WithJSONBody(t, map[string]interface{}{ "typing": false, })) @@ -89,7 +89,7 @@ func TestLeakyTyping(t *testing.T) { _, charlieToken := charlie.MustSync(t, client.SyncReq{TimeoutMillis: "0"}) // Alice types in that room. Bob should see her typing. - alice.MustDoFunc(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "typing", alice.UserID}, client.WithJSONBody(t, map[string]interface{}{ + alice.MustDo(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "typing", alice.UserID}, client.WithJSONBody(t, map[string]interface{}{ "typing": true, "timeout": 10000, })) diff --git a/tests/csapi/rooms_invite_test.go b/tests/csapi/rooms_invite_test.go index b960c1a0..521208f8 100644 --- a/tests/csapi/rooms_invite_test.go +++ b/tests/csapi/rooms_invite_test.go @@ -4,8 +4,8 @@ import ( "net/http" "testing" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/internal/match" "github.com/matrix-org/complement/internal/must" "github.com/tidwall/gjson" @@ -38,7 +38,7 @@ func TestRoomsInvite(t *testing.T) { roomID := alice.CreateRoom(t, map[string]interface{}{ "preset": "private_chat", }) - res := bob.DoFunc(t, "POST", []string{"_matrix", "client", "v3", "join", roomID}) + res := bob.Do(t, "POST", []string{"_matrix", "client", "v3", "join", roomID}) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: http.StatusForbidden, }) @@ -88,7 +88,7 @@ func TestRoomsInvite(t *testing.T) { body := client.WithJSONBody(t, map[string]interface{}{ "user_id": alice.UserID, }) - res := alice.DoFunc(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "invite"}, body) + res := alice.Do(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "invite"}, body) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: http.StatusForbidden, }) @@ -109,7 +109,7 @@ func TestRoomsInvite(t *testing.T) { body := client.WithJSONBody(t, map[string]interface{}{ "user_id": bob.UserID, }) - res := alice.DoFunc(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "invite"}, body) + res := alice.Do(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "invite"}, body) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: http.StatusForbidden, }) @@ -149,7 +149,7 @@ func TestRoomsInvite(t *testing.T) { bob.UserID: 100, }, }) - alice.MustDoFunc(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.power_levels"}, reqBody) + alice.MustDo(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.power_levels"}, reqBody) // Alice leaves the room alice.LeaveRoom(t, roomID) @@ -180,7 +180,7 @@ func verifyState(t *testing.T, res gjson.Result, roomID string, cl *client.CSAPI eventContent := event.Get("content." + field).Str eventStateKey := event.Get("state_key").Str - res := cl.MustDoFunc(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", eventType, eventStateKey}) + res := cl.MustDo(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", eventType, eventStateKey}) must.MatchResponse(t, res, match.HTTPResponse{ JSON: []match.JSON{ diff --git a/tests/csapi/rooms_members_local_test.go b/tests/csapi/rooms_members_local_test.go index 09ae5356..6b2796ff 100644 --- a/tests/csapi/rooms_members_local_test.go +++ b/tests/csapi/rooms_members_local_test.go @@ -3,8 +3,8 @@ package csapi_tests import ( "testing" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/runtime" ) @@ -18,7 +18,7 @@ func TestMembersLocal(t *testing.T) { bob := deployment.RegisterUser(t, "hs1", "bob", "bobspassword", false) roomID := alice.CreateRoom(t, map[string]interface{}{"preset": "public_chat"}) - bob.MustDoFunc( + bob.MustDo( t, "PUT", []string{"_matrix", "client", "v3", "presence", bob.UserID, "status"}, client.WithJSONBody(t, map[string]interface{}{ "presence": "online", diff --git a/tests/csapi/rooms_state_test.go b/tests/csapi/rooms_state_test.go index 624a7b04..c00da6d2 100644 --- a/tests/csapi/rooms_state_test.go +++ b/tests/csapi/rooms_state_test.go @@ -9,8 +9,8 @@ import ( "github.com/tidwall/gjson" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/internal/must" ) @@ -134,7 +134,7 @@ func TestRoomCreationReportsEventsToMyself(t *testing.T) { } func getEventIdForState(t *testing.T, client *client.CSAPI, roomID, evType, stateKey string) *string { - res := client.MustDoFunc(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state"}) + res := client.MustDo(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state"}) jsonBody := must.ParseJSON(t, res.Body) result := gjson.ParseBytes(jsonBody) diff --git a/tests/csapi/sync_archive_test.go b/tests/csapi/sync_archive_test.go index 19994e75..fadc03ce 100644 --- a/tests/csapi/sync_archive_test.go +++ b/tests/csapi/sync_archive_test.go @@ -5,8 +5,8 @@ import ( "github.com/tidwall/gjson" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/runtime" ) @@ -306,7 +306,8 @@ func TestOlderLeftRoomsNotInLeaveSection(t *testing.T) { } // sytest: We should see our own leave event, even if history_visibility is -// restricted (SYN-662) +// +// restricted (SYN-662) func TestLeaveEventVisibility(t *testing.T) { runtime.SkipIf(t, runtime.Dendrite) // FIXME: https://github.com/matrix-org/dendrite/issues/1323 @@ -392,7 +393,8 @@ func TestLeaveEventVisibility(t *testing.T) { } // sytest: We should see our own leave event when rejecting an invite, -// even if history_visibility is restricted (riot-web/3462) +// +// even if history_visibility is restricted (riot-web/3462) func TestLeaveEventInviteRejection(t *testing.T) { runtime.SkipIf(t, runtime.Dendrite) // FIXME: https://github.com/matrix-org/dendrite/issues/1323 diff --git a/tests/csapi/sync_filter_test.go b/tests/csapi/sync_filter_test.go index 3a8dce11..64ae1122 100644 --- a/tests/csapi/sync_filter_test.go +++ b/tests/csapi/sync_filter_test.go @@ -6,8 +6,8 @@ import ( "github.com/tidwall/gjson" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/internal/match" "github.com/matrix-org/complement/internal/must" ) @@ -35,7 +35,7 @@ func TestSyncFilter(t *testing.T) { }, }, }) - res := authedClient.MustDoFunc(t, "GET", []string{"_matrix", "client", "v3", "user", "@alice:hs1", "filter", filterID}) + res := authedClient.MustDo(t, "GET", []string{"_matrix", "client", "v3", "user", "@alice:hs1", "filter", filterID}) must.MatchResponse(t, res, match.HTTPResponse{ JSON: []match.JSON{ match.JSONKeyPresent("room"), @@ -48,7 +48,7 @@ func TestSyncFilter(t *testing.T) { func createFilter(t *testing.T, c *client.CSAPI, filterContent map[string]interface{}) string { t.Helper() - res := c.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "user", c.UserID, "filter"}, client.WithJSONBody(t, filterContent)) + res := c.MustDo(t, "POST", []string{"_matrix", "client", "v3", "user", c.UserID, "filter"}, client.WithJSONBody(t, filterContent)) if res.StatusCode != 200 { t.Fatalf("MatchResponse got status %d want 200", res.StatusCode) } diff --git a/tests/csapi/sync_test.go b/tests/csapi/sync_test.go index f9d9410e..98ee05af 100644 --- a/tests/csapi/sync_test.go +++ b/tests/csapi/sync_test.go @@ -8,8 +8,8 @@ import ( "github.com/tidwall/gjson" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/internal/federation" "github.com/matrix-org/complement/runtime" ) @@ -403,8 +403,8 @@ func TestPresenceSyncDifferentRooms(t *testing.T) { reqBody := client.WithJSONBody(t, map[string]interface{}{ "presence": "online", }) - bob.DoFunc(t, "PUT", []string{"_matrix", "client", "v3", "presence", "@bob:hs1", "status"}, reqBody) - charlie.DoFunc(t, "PUT", []string{"_matrix", "client", "v3", "presence", "@charlie:hs1", "status"}, reqBody) + bob.Do(t, "PUT", []string{"_matrix", "client", "v3", "presence", "@bob:hs1", "status"}, reqBody) + charlie.Do(t, "PUT", []string{"_matrix", "client", "v3", "presence", "@charlie:hs1", "status"}, reqBody) // Alice should see that Bob and Charlie are online. She may see this happen // simultaneously in one /sync response, or separately in two /sync diff --git a/tests/csapi/thread_notifications_test.go b/tests/csapi/thread_notifications_test.go index 09847b64..a0e7bea8 100644 --- a/tests/csapi/thread_notifications_test.go +++ b/tests/csapi/thread_notifications_test.go @@ -6,8 +6,8 @@ import ( "github.com/tidwall/gjson" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/runtime" ) @@ -194,7 +194,7 @@ func TestThreadedReceipts(t *testing.T) { // Mark the first event as read with a threaded receipt. This causes only the // notification from that event to be marked as read and only impacts the main // timeline. - bob.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "receipt", "m.read", eventA}, client.WithJSONBody(t, map[string]interface{}{"thread_id": "main"})) + bob.MustDo(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "receipt", "m.read", eventA}, client.WithJSONBody(t, map[string]interface{}{"thread_id": "main"})) bob.MustSyncUntil( t, client.SyncReq{Since: bobNextBatch}, client.SyncTimelineHas(roomID, func(r gjson.Result) bool { @@ -221,7 +221,7 @@ func TestThreadedReceipts(t *testing.T) { // Mark the first thread event as read. This causes only the notification from // that event to be marked as read and only impacts the thread timeline. - bob.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "receipt", "m.read", eventB}, client.WithJSONBody(t, map[string]interface{}{"thread_id": eventA})) + bob.MustDo(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "receipt", "m.read", eventB}, client.WithJSONBody(t, map[string]interface{}{"thread_id": eventA})) bob.MustSyncUntil( t, client.SyncReq{Since: bobNextBatch}, client.SyncTimelineHas(roomID, func(r gjson.Result) bool { @@ -249,7 +249,7 @@ func TestThreadedReceipts(t *testing.T) { ) // Use an unthreaded receipt to mark the second thread event and an unthreaded event as read. - bob.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "receipt", "m.read", eventD}, client.WithJSONBody(t, struct{}{})) + bob.MustDo(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "receipt", "m.read", eventD}, client.WithJSONBody(t, struct{}{})) bob.MustSyncUntil( t, client.SyncReq{Since: bobNextBatch}, client.SyncTimelineHas(roomID, func(r gjson.Result) bool { @@ -277,7 +277,7 @@ func TestThreadedReceipts(t *testing.T) { // Finally, mark the entire thread as read, using the annotation. // // Note that this will *not* affect the main timeline. - bob.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "receipt", "m.read", eventG}, client.WithJSONBody(t, map[string]interface{}{"thread_id": eventA})) + bob.MustDo(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "receipt", "m.read", eventG}, client.WithJSONBody(t, map[string]interface{}{"thread_id": eventA})) bob.MustSyncUntil( t, client.SyncReq{Since: bobNextBatch}, client.SyncTimelineHas(roomID, func(r gjson.Result) bool { diff --git a/tests/csapi/to_device_test.go b/tests/csapi/to_device_test.go index d98a12c4..3b8606b5 100644 --- a/tests/csapi/to_device_test.go +++ b/tests/csapi/to_device_test.go @@ -6,8 +6,8 @@ import ( "github.com/tidwall/gjson" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" ) // sytest: Can send a message directly to a device using PUT /sendToDevice diff --git a/tests/csapi/txnid_test.go b/tests/csapi/txnid_test.go index 5ff7f512..4ce2d0ca 100644 --- a/tests/csapi/txnid_test.go +++ b/tests/csapi/txnid_test.go @@ -4,8 +4,8 @@ import ( "fmt" "testing" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/internal/must" "github.com/matrix-org/complement/runtime" "github.com/tidwall/gjson" @@ -36,7 +36,7 @@ func TestTxnInEvent(t *testing.T) { }, txnId) // The transaction ID should be present on the GET /rooms/{roomID}/event/{eventID} response. - res := c.MustDoFunc(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "event", eventID}) + res := c.MustDo(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "event", eventID}) body := client.ParseJSON(t, res) result := gjson.ParseBytes(body) unsignedTxnId := result.Get("unsigned.transaction_id") @@ -47,7 +47,6 @@ func TestTxnInEvent(t *testing.T) { must.EqualStr(t, unsignedTxnId.Str, txnId, fmt.Sprintf("Event had an incorrect 'unsigned.transaction_id' on GET /rooms/%s/event/%s response", eventID, roomID)) } - func mustHaveTransactionIDForEvent(t *testing.T, roomID, eventID, expectedTxnId string) client.SyncCheckOpt { return client.SyncTimelineHas(roomID, func(r gjson.Result) bool { if r.Get("event_id").Str == eventID { @@ -200,47 +199,47 @@ func TestTxnIdempotency(t *testing.T) { // TestTxnIdWithRefreshToken tests that when a client refreshes its access token, // it still gets back a transaction ID in the sync response and idempotency is respected. func TestTxnIdWithRefreshToken(t *testing.T) { - // Dendrite and Conduit don't support refresh tokens yet. - runtime.SkipIf(t, runtime.Dendrite, runtime.Conduit) + // Dendrite and Conduit don't support refresh tokens yet. + runtime.SkipIf(t, runtime.Dendrite, runtime.Conduit) - deployment := Deploy(t, b.BlueprintCleanHS) - defer deployment.Destroy(t) + deployment := Deploy(t, b.BlueprintCleanHS) + defer deployment.Destroy(t) - deployment.RegisterUser(t, "hs1", "alice", "password", false) + deployment.RegisterUser(t, "hs1", "alice", "password", false) - c := deployment.Client(t, "hs1", "") + c := deployment.Client(t, "hs1", "") - var refreshToken string - c.UserID, c.AccessToken, refreshToken, c.DeviceID, _ = c.LoginUserWithRefreshToken(t, "alice", "password") + 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{}{}) + // Create a room where we can send events. + roomID := c.CreateRoom(t, map[string]interface{}{}) txnId := "abcdef" // We send an event - eventID1 := c.SendEventUnsyncedWithTxnID(t, roomID, b.Event{ - Type: "m.room.message", - Content: map[string]interface{}{ - "msgtype": "m.text", - "body": "first", - }, - }, txnId) - - // 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 the correct transaction ID even + eventID1 := c.SendEventUnsyncedWithTxnID(t, roomID, b.Event{ + Type: "m.room.message", + Content: map[string]interface{}{ + "msgtype": "m.text", + "body": "first", + }, + }, txnId) + + // 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 the correct transaction ID even // though the access token is different. - c.MustSyncUntil(t, client.SyncReq{}, mustHaveTransactionIDForEvent(t, roomID, eventID1, txnId)) + c.MustSyncUntil(t, client.SyncReq{}, mustHaveTransactionIDForEvent(t, roomID, eventID1, txnId)) // We try sending the event again with the same transaction ID - eventID2 := c.SendEventUnsyncedWithTxnID(t, roomID, b.Event{ - Type: "m.room.message", - Content: map[string]interface{}{ - "msgtype": "m.text", - "body": "first", - }, - }, txnId) + eventID2 := c.SendEventUnsyncedWithTxnID(t, roomID, b.Event{ + Type: "m.room.message", + Content: map[string]interface{}{ + "msgtype": "m.text", + "body": "first", + }, + }, txnId) // The event should have been deduplicated and we should get back the same event ID must.EqualStr(t, eventID2, eventID1, "Expected eventID1 and eventID2 to be the same from a client using a refresh token") diff --git a/tests/csapi/upload_keys_test.go b/tests/csapi/upload_keys_test.go index e1127411..3597ae81 100644 --- a/tests/csapi/upload_keys_test.go +++ b/tests/csapi/upload_keys_test.go @@ -9,8 +9,8 @@ import ( "github.com/tidwall/gjson" "maunium.net/go/mautrix/crypto/olm" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/internal/match" "github.com/matrix-org/complement/internal/must" "github.com/matrix-org/complement/runtime" @@ -31,7 +31,7 @@ func TestUploadKey(t *testing.T) { "device_keys": deviceKeys, "one_time_keys": oneTimeKeys, }) - resp := alice.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "keys", "upload"}, reqBody) + resp := alice.MustDo(t, "POST", []string{"_matrix", "client", "v3", "keys", "upload"}, reqBody) must.MatchResponse(t, resp, match.HTTPResponse{ StatusCode: http.StatusOK, JSON: []match.JSON{ @@ -64,7 +64,7 @@ func TestUploadKey(t *testing.T) { }, "one_time_keys": oneTimeKeys, }) - resp := bob.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "keys", "upload"}, reqBody) + resp := bob.MustDo(t, "POST", []string{"_matrix", "client", "v3", "keys", "upload"}, reqBody) must.MatchResponse(t, resp, match.HTTPResponse{ StatusCode: http.StatusBadRequest, JSON: []match.JSON{ @@ -83,7 +83,7 @@ func TestUploadKey(t *testing.T) { "device_id": alice.DeviceID, }, }) - resp := bob.DoFunc(t, "POST", []string{"_matrix", "client", "v3", "keys", "upload"}, reqBody) + resp := bob.Do(t, "POST", []string{"_matrix", "client", "v3", "keys", "upload"}, reqBody) must.MatchResponse(t, resp, match.HTTPResponse{ StatusCode: http.StatusBadRequest, }) @@ -96,7 +96,7 @@ func TestUploadKey(t *testing.T) { alice.UserID: {}, }, }) - resp := alice.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "keys", "query"}, reqBody) + resp := alice.MustDo(t, "POST", []string{"_matrix", "client", "v3", "keys", "query"}, reqBody) must.MatchResponse(t, resp, match.HTTPResponse{ StatusCode: http.StatusOK, JSON: []match.JSON{ @@ -111,7 +111,7 @@ func TestUploadKey(t *testing.T) { alice.UserID: {alice.DeviceID}, }, }) - resp := alice.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "keys", "query"}, reqBody) + resp := alice.MustDo(t, "POST", []string{"_matrix", "client", "v3", "keys", "query"}, reqBody) deviceKeysField := "device_keys." + client.GjsonEscape(alice.UserID) + "." + client.GjsonEscape(alice.DeviceID) must.MatchResponse(t, resp, match.HTTPResponse{ StatusCode: http.StatusOK, @@ -131,7 +131,7 @@ func TestUploadKey(t *testing.T) { bob.UserID: {}, }, }) - resp := alice.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "keys", "query"}, reqBody) + resp := alice.MustDo(t, "POST", []string{"_matrix", "client", "v3", "keys", "query"}, reqBody) deviceKeysField := "device_keys." + client.GjsonEscape(bob.UserID) must.MatchResponse(t, resp, match.HTTPResponse{ StatusCode: http.StatusOK, @@ -151,7 +151,7 @@ func TestUploadKey(t *testing.T) { }, }, }) - resp := alice.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "keys", "claim"}, reqBody) + resp := alice.MustDo(t, "POST", []string{"_matrix", "client", "v3", "keys", "claim"}, reqBody) otksField := "one_time_keys." + client.GjsonEscape(alice.UserID) + "." + client.GjsonEscape(alice.DeviceID) must.MatchResponse(t, resp, match.HTTPResponse{ StatusCode: http.StatusOK, @@ -162,7 +162,7 @@ func TestUploadKey(t *testing.T) { }) // there should be no OTK left now - resp = alice.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "keys", "claim"}, reqBody) + resp = alice.MustDo(t, "POST", []string{"_matrix", "client", "v3", "keys", "claim"}, reqBody) must.MatchResponse(t, resp, match.HTTPResponse{ StatusCode: http.StatusOK, JSON: []match.JSON{ diff --git a/tests/csapi/url_preview_test.go b/tests/csapi/url_preview_test.go index d8896c9a..6ee28e18 100644 --- a/tests/csapi/url_preview_test.go +++ b/tests/csapi/url_preview_test.go @@ -10,8 +10,8 @@ import ( "github.com/gorilla/mux" "github.com/tidwall/gjson" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/internal/data" "github.com/matrix-org/complement/internal/match" "github.com/matrix-org/complement/internal/must" @@ -64,7 +64,7 @@ func TestUrlPreview(t *testing.T) { alice := deployment.Client(t, "hs1", "@alice:hs1") - res := alice.MustDoFunc(t, "GET", []string{"_matrix", "media", "v3", "preview_url"}, + res := alice.MustDo(t, "GET", []string{"_matrix", "media", "v3", "preview_url"}, client.WithQueries(url.Values{ "url": []string{webServer.URL + "/test.html"}, }), diff --git a/tests/csapi/user_directory_display_names_test.go b/tests/csapi/user_directory_display_names_test.go index d208f20e..78c81e3c 100644 --- a/tests/csapi/user_directory_display_names_test.go +++ b/tests/csapi/user_directory_display_names_test.go @@ -7,8 +7,8 @@ package csapi_tests import ( "testing" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/internal/match" "github.com/matrix-org/complement/internal/must" ) @@ -50,7 +50,7 @@ func setupUsers(t *testing.T) (*client.CSAPI, *client.CSAPI, *client.CSAPI, func // Alice sets her profile displayname. This ensures that her // public name, private name and userid localpart are all // distinguishable, even case-insensitively. - alice.MustDoFunc( + alice.MustDo( t, "PUT", []string{"_matrix", "client", "v3", "profile", alice.UserID, "displayname"}, @@ -66,7 +66,7 @@ func setupUsers(t *testing.T) (*client.CSAPI, *client.CSAPI, *client.CSAPI, func func checkExpectations(t *testing.T, bob, eve *client.CSAPI) { t.Run("Eve can find Alice by profile display name", func(t *testing.T) { - res := eve.MustDoFunc( + res := eve.MustDo( t, "POST", []string{"_matrix", "client", "v3", "user_directory", "search"}, @@ -78,7 +78,7 @@ func checkExpectations(t *testing.T, bob, eve *client.CSAPI) { }) t.Run("Eve can find Alice by mxid", func(t *testing.T) { - res := eve.MustDoFunc( + res := eve.MustDo( t, "POST", []string{"_matrix", "client", "v3", "user_directory", "search"}, @@ -90,7 +90,7 @@ func checkExpectations(t *testing.T, bob, eve *client.CSAPI) { }) t.Run("Eve cannot find Alice by room-specific name that Eve is not privy to", func(t *testing.T) { - res := eve.MustDoFunc( + res := eve.MustDo( t, "POST", []string{"_matrix", "client", "v3", "user_directory", "search"}, @@ -102,7 +102,7 @@ func checkExpectations(t *testing.T, bob, eve *client.CSAPI) { }) t.Run("Bob can find Alice by profile display name", func(t *testing.T) { - res := bob.MustDoFunc( + res := bob.MustDo( t, "POST", []string{"_matrix", "client", "v3", "user_directory", "search"}, @@ -116,7 +116,7 @@ func checkExpectations(t *testing.T, bob, eve *client.CSAPI) { }) t.Run("Bob can find Alice by mxid", func(t *testing.T) { - res := bob.MustDoFunc( + res := bob.MustDo( t, "POST", []string{"_matrix", "client", "v3", "user_directory", "search"}, @@ -145,7 +145,7 @@ func TestRoomSpecificUsernameChange(t *testing.T) { alice.JoinRoom(t, privateRoom, nil) // Alice reveals her private name to Bob - alice.MustDoFunc( + alice.MustDo( t, "PUT", []string{"_matrix", "client", "v3", "rooms", privateRoom, "state", "m.room.member", alice.UserID}, @@ -174,7 +174,7 @@ func TestRoomSpecificUsernameAtJoin(t *testing.T) { alice.JoinRoom(t, privateRoom, nil) // Alice reveals her private name to Bob - alice.MustDoFunc( + alice.MustDo( t, "PUT", []string{"_matrix", "client", "v3", "rooms", privateRoom, "state", "m.room.member", alice.UserID}, diff --git a/tests/csapi/user_query_keys_test.go b/tests/csapi/user_query_keys_test.go index bc1e00ce..b9ece4cf 100644 --- a/tests/csapi/user_query_keys_test.go +++ b/tests/csapi/user_query_keys_test.go @@ -3,8 +3,8 @@ package csapi_tests import ( "testing" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/internal/match" "github.com/matrix-org/complement/internal/must" ) @@ -20,7 +20,7 @@ func TestKeysQueryWithDeviceIDAsObjectFails(t *testing.T) { userID := "@alice:hs1" alice := deployment.Client(t, "hs1", userID) - res := alice.DoFunc(t, "POST", []string{"_matrix", "client", "v3", "keys", "query"}, + res := alice.Do(t, "POST", []string{"_matrix", "client", "v3", "keys", "query"}, client.WithJSONBody(t, map[string]interface{}{ "device_keys": map[string]interface{}{ "@bob:hs1": map[string]bool{ diff --git a/tests/direct_messaging_test.go b/tests/direct_messaging_test.go index 6b310a03..e4eaad62 100644 --- a/tests/direct_messaging_test.go +++ b/tests/direct_messaging_test.go @@ -6,8 +6,8 @@ import ( "testing" "time" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/internal/federation" "github.com/matrix-org/complement/internal/match" "github.com/matrix-org/complement/internal/must" diff --git a/tests/federation_acl_test.go b/tests/federation_acl_test.go index adcc729e..ead0a429 100644 --- a/tests/federation_acl_test.go +++ b/tests/federation_acl_test.go @@ -4,8 +4,8 @@ import ( "fmt" "testing" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/internal/match" "github.com/matrix-org/complement/internal/must" "github.com/matrix-org/complement/runtime" @@ -142,7 +142,7 @@ func TestACLs(t *testing.T) { } // Validate the ACL event is actually in the rooms state - res := user.DoFunc(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.server_acl"}) + res := user.Do(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.server_acl"}) must.MatchResponse(t, res, match.HTTPResponse{ JSON: []match.JSON{ match.JSONKeyEqual("allow", []string{"*"}), diff --git a/tests/federation_presence_test.go b/tests/federation_presence_test.go index 64adeb23..5dd412a7 100644 --- a/tests/federation_presence_test.go +++ b/tests/federation_presence_test.go @@ -5,8 +5,8 @@ import ( "github.com/tidwall/gjson" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" ) func TestRemotePresence(t *testing.T) { @@ -21,7 +21,7 @@ func TestRemotePresence(t *testing.T) { _, bobSinceToken := bob.MustSync(t, client.SyncReq{TimeoutMillis: "0"}) statusMsg := "Update for room members" - alice.MustDoFunc(t, "PUT", []string{"_matrix", "client", "v3", "presence", "@alice:hs1", "status"}, + alice.MustDo(t, "PUT", []string{"_matrix", "client", "v3", "presence", "@alice:hs1", "status"}, client.WithJSONBody(t, map[string]interface{}{ "status_msg": statusMsg, "presence": "online", @@ -38,7 +38,7 @@ func TestRemotePresence(t *testing.T) { t.Run("Presence changes to UNAVAILABLE are reported to remote room members", func(t *testing.T) { _, bobSinceToken := bob.MustSync(t, client.SyncReq{TimeoutMillis: "0"}) - alice.MustDoFunc(t, "PUT", []string{"_matrix", "client", "v3", "presence", "@alice:hs1", "status"}, + alice.MustDo(t, "PUT", []string{"_matrix", "client", "v3", "presence", "@alice:hs1", "status"}, client.WithJSONBody(t, map[string]interface{}{ "presence": "unavailable", }), diff --git a/tests/federation_query_profile_test.go b/tests/federation_query_profile_test.go index 91a1d102..4872cb9d 100644 --- a/tests/federation_query_profile_test.go +++ b/tests/federation_query_profile_test.go @@ -8,8 +8,8 @@ import ( "github.com/matrix-org/gomatrixserverlib" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/internal/federation" "github.com/matrix-org/complement/internal/match" "github.com/matrix-org/complement/internal/must" @@ -59,7 +59,7 @@ func TestOutboundFederationProfile(t *testing.T) { // query the display name which should do an outbound federation hit unauthedClient := deployment.Client(t, "hs1", "") - res := unauthedClient.MustDoFunc(t, "GET", []string{"_matrix", "client", "v3", "profile", remoteUserID, "displayname"}) + res := unauthedClient.MustDo(t, "GET", []string{"_matrix", "client", "v3", "profile", remoteUserID, "displayname"}) must.MatchResponse(t, res, match.HTTPResponse{ JSON: []match.JSON{ match.JSONKeyEqual("displayname", remoteDisplayName), @@ -105,7 +105,7 @@ func TestInboundFederationProfile(t *testing.T) { t.Run("Inbound federation can query profile data", func(t *testing.T) { const alicePublicName = "Alice Cooper" - alice.MustDoFunc( + alice.MustDo( t, "PUT", []string{"_matrix", "client", "v3", "profile", alice.UserID, "displayname"}, diff --git a/tests/federation_room_alias_test.go b/tests/federation_room_alias_test.go index 5792fb70..20561174 100644 --- a/tests/federation_room_alias_test.go +++ b/tests/federation_room_alias_test.go @@ -3,8 +3,8 @@ package tests import ( "testing" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/internal/match" "github.com/matrix-org/complement/internal/must" ) @@ -21,11 +21,11 @@ func TestRemoteAliasRequestsUnderstandUnicode(t *testing.T) { roomID := alice.CreateRoom(t, map[string]interface{}{}) - alice.MustDoFunc(t, "PUT", []string{"_matrix", "client", "v3", "directory", "room", unicodeAlias}, client.WithJSONBody(t, map[string]interface{}{ + alice.MustDo(t, "PUT", []string{"_matrix", "client", "v3", "directory", "room", unicodeAlias}, client.WithJSONBody(t, map[string]interface{}{ "room_id": roomID, })) - res := bob.DoFunc(t, "GET", []string{"_matrix", "client", "v3", "directory", "room", unicodeAlias}) + res := bob.Do(t, "GET", []string{"_matrix", "client", "v3", "directory", "room", unicodeAlias}) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: 200, JSON: []match.JSON{ diff --git a/tests/federation_room_ban_test.go b/tests/federation_room_ban_test.go index 0eae4920..444a5306 100644 --- a/tests/federation_room_ban_test.go +++ b/tests/federation_room_ban_test.go @@ -3,8 +3,8 @@ package tests import ( "testing" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/runtime" ) @@ -25,13 +25,13 @@ func TestUnbanViaInvite(t *testing.T) { alice.JoinRoom(t, roomID, []string{"hs2"}) // Ban Alice - bob.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "ban"}, client.WithJSONBody(t, map[string]interface{}{ + bob.MustDo(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "ban"}, client.WithJSONBody(t, map[string]interface{}{ "user_id": alice.UserID, })) alice.MustSyncUntil(t, client.SyncReq{}, client.SyncLeftFrom(alice.UserID, roomID)) // Unban Alice - bob.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "unban"}, client.WithJSONBody(t, map[string]interface{}{ + bob.MustDo(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "unban"}, client.WithJSONBody(t, map[string]interface{}{ "user_id": alice.UserID, })) bob.MustSyncUntil(t, client.SyncReq{}, client.SyncLeftFrom(alice.UserID, roomID)) diff --git a/tests/federation_room_event_auth_test.go b/tests/federation_room_event_auth_test.go index 0292f411..ae0f9fea 100644 --- a/tests/federation_room_event_auth_test.go +++ b/tests/federation_room_event_auth_test.go @@ -15,8 +15,8 @@ import ( "github.com/matrix-org/gomatrixserverlib" "github.com/tidwall/gjson" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/internal/federation" "github.com/matrix-org/complement/internal/must" ) @@ -219,7 +219,7 @@ func TestInboundFederationRejectsEventsWithRejectedAuthEvents(t *testing.T) { // now inspect the results. Each of the rejected events should give a 404 for /event t.Run("Outlier should be rejected", func(t *testing.T) { - res := alice.DoFunc(t, "GET", []string{"_matrix", "client", "v3", "rooms", room.RoomID, "event", outlierEvent.EventID()}) + res := alice.Do(t, "GET", []string{"_matrix", "client", "v3", "rooms", room.RoomID, "event", outlierEvent.EventID()}) defer res.Body.Close() if res.StatusCode != 404 { t.Errorf("Expected a 404 when fetching outlier event, but got %d", res.StatusCode) @@ -227,7 +227,7 @@ func TestInboundFederationRejectsEventsWithRejectedAuthEvents(t *testing.T) { }) t.Run("sent event 1 should be rejected", func(t *testing.T) { - res := alice.DoFunc(t, "GET", []string{"_matrix", "client", "v3", "rooms", room.RoomID, "event", sentEvent1.EventID()}) + res := alice.Do(t, "GET", []string{"_matrix", "client", "v3", "rooms", room.RoomID, "event", sentEvent1.EventID()}) defer res.Body.Close() if res.StatusCode != 404 { t.Errorf("Expected a 404 when fetching sent event 1, but got %d", res.StatusCode) @@ -235,7 +235,7 @@ func TestInboundFederationRejectsEventsWithRejectedAuthEvents(t *testing.T) { }) t.Run("sent event 2 should be rejected", func(t *testing.T) { - res := alice.DoFunc(t, "GET", []string{"_matrix", "client", "v3", "rooms", room.RoomID, "event", sentEvent2.EventID()}) + res := alice.Do(t, "GET", []string{"_matrix", "client", "v3", "rooms", room.RoomID, "event", sentEvent2.EventID()}) defer res.Body.Close() if res.StatusCode != 404 { t.Errorf("Expected a 404 when fetching sent event 2, but got %d", res.StatusCode) diff --git a/tests/federation_room_get_missing_events_test.go b/tests/federation_room_get_missing_events_test.go index 1aeeb791..75b0e25e 100644 --- a/tests/federation_room_get_missing_events_test.go +++ b/tests/federation_room_get_missing_events_test.go @@ -12,8 +12,8 @@ import ( "github.com/matrix-org/util" "github.com/tidwall/gjson" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/internal/federation" "github.com/matrix-org/complement/internal/match" "github.com/matrix-org/complement/internal/must" diff --git a/tests/federation_room_join_partial_state_test.go b/tests/federation_room_join_partial_state_test.go index 0562cea7..f7c12b0b 100644 --- a/tests/federation_room_join_partial_state_test.go +++ b/tests/federation_room_join_partial_state_test.go @@ -10,7 +10,6 @@ import ( "context" "encoding/json" "fmt" - "github.com/matrix-org/complement/runtime" "io/ioutil" "net" "net/http" @@ -21,14 +20,16 @@ import ( "testing" "time" + "github.com/matrix-org/complement/runtime" + "github.com/gorilla/mux" "github.com/tidwall/gjson" "github.com/matrix-org/gomatrix" "github.com/matrix-org/gomatrixserverlib" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/internal/docker" "github.com/matrix-org/complement/internal/federation" "github.com/matrix-org/complement/internal/match" @@ -475,7 +476,7 @@ func TestPartialStateJoin(t *testing.T) { alice.Client.Timeout = 2 * time.Second paths := []string{"_matrix", "client", "v3", "rooms", serverRoom.RoomID, "send", "m.room.message", "0"} - res := alice.MustDoFunc(t, "PUT", paths, client.WithJSONBody(t, map[string]interface{}{ + res := alice.MustDo(t, "PUT", paths, client.WithJSONBody(t, map[string]interface{}{ "msgtype": "m.text", "body": "Hello world!", })) @@ -1132,7 +1133,7 @@ func TestPartialStateJoin(t *testing.T) { go func() { queryParams := url.Values{} queryParams.Set("at", syncToken) - clientMembersRequestResponseChan <- alice.MustDoFunc( + clientMembersRequestResponseChan <- alice.MustDo( t, "GET", []string{"_matrix", "client", "v3", "rooms", serverRoom.RoomID, "members"}, @@ -1542,7 +1543,7 @@ func TestPartialStateJoin(t *testing.T) { // ... and check that the bad state event is *not* visible must.MatchResponse(t, - alice.DoFunc(t, "GET", []string{"_matrix", "client", "r0", "rooms", serverRoom.RoomID, "event", badStateEvent.EventID()}), + alice.Do(t, "GET", []string{"_matrix", "client", "r0", "rooms", serverRoom.RoomID, "event", badStateEvent.EventID()}), match.HTTPResponse{ StatusCode: 404, JSON: []match.JSON{ @@ -1558,7 +1559,7 @@ func TestPartialStateJoin(t *testing.T) { // check that the bad state event is *still* not visible must.MatchResponse(t, - alice.DoFunc(t, "GET", []string{"_matrix", "client", "r0", "rooms", serverRoom.RoomID, "event", badStateEvent.EventID()}), + alice.Do(t, "GET", []string{"_matrix", "client", "r0", "rooms", serverRoom.RoomID, "event", badStateEvent.EventID()}), match.HTTPResponse{ StatusCode: 404, JSON: []match.JSON{ @@ -1636,7 +1637,7 @@ func TestPartialStateJoin(t *testing.T) { // the bad state event should now *not* be visible must.MatchResponse(t, - alice.DoFunc(t, "GET", []string{"_matrix", "client", "r0", "rooms", serverRoom.RoomID, "event", badStateEvent.EventID()}), + alice.Do(t, "GET", []string{"_matrix", "client", "r0", "rooms", serverRoom.RoomID, "event", badStateEvent.EventID()}), match.HTTPResponse{ StatusCode: 404, JSON: []match.JSON{ @@ -1736,7 +1737,7 @@ func TestPartialStateJoin(t *testing.T) { // ... but the rejected state event should not. syncToken = awaitEventViaSync(t, alice, serverRoom.RoomID, sentinelEvent.EventID(), syncToken) must.MatchResponse(t, - alice.DoFunc(t, "GET", []string{"_matrix", "client", "r0", "rooms", serverRoom.RoomID, "event", rejectedStateEvent.EventID()}), + alice.Do(t, "GET", []string{"_matrix", "client", "r0", "rooms", serverRoom.RoomID, "event", rejectedStateEvent.EventID()}), match.HTTPResponse{ StatusCode: 404, JSON: []match.JSON{ @@ -1752,7 +1753,7 @@ func TestPartialStateJoin(t *testing.T) { // the bad kick event should now *not* be visible must.MatchResponse(t, - alice.DoFunc(t, "GET", []string{"_matrix", "client", "r0", "rooms", serverRoom.RoomID, "event", badKickEvent.EventID()}), + alice.Do(t, "GET", []string{"_matrix", "client", "r0", "rooms", serverRoom.RoomID, "event", badKickEvent.EventID()}), match.HTTPResponse{ StatusCode: 404, JSON: []match.JSON{ @@ -1894,7 +1895,7 @@ func TestPartialStateJoin(t *testing.T) { // attempts to joined_members should now block. Fire off a goroutine to try it. jmResponseChan := make(chan *http.Response) go func() { - response := alice.MustDoFunc(t, "GET", []string{"_matrix", "client", "v3", "rooms", serverRoom.RoomID, "joined_members"}) + response := alice.MustDo(t, "GET", []string{"_matrix", "client", "v3", "rooms", serverRoom.RoomID, "joined_members"}) jmResponseChan <- response close(jmResponseChan) }() @@ -2117,7 +2118,7 @@ func TestPartialStateJoin(t *testing.T) { renameDevice := func(t *testing.T, user *client.CSAPI, displayName string) { t.Helper() - user.MustDoFunc( + user.MustDo( t, "PUT", []string{"_matrix", "client", "v3", "devices", user.DeviceID}, @@ -2726,7 +2727,7 @@ func TestPartialStateJoin(t *testing.T) { mustQueryKeys := func(t *testing.T, user *client.CSAPI, userID string) { t.Helper() - user.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "keys", "query"}, + user.MustDo(t, "POST", []string{"_matrix", "client", "v3", "keys", "query"}, client.WithJSONBody(t, map[string]interface{}{ "device_keys": map[string]interface{}{ userID: []string{}, @@ -2816,7 +2817,7 @@ func TestPartialStateJoin(t *testing.T) { syncDeviceListsHas(section, expectedUserID), ) - res := user.MustDoFunc(t, "GET", []string{"_matrix", "client", "v3", "keys", "changes"}, + res := user.MustDo(t, "GET", []string{"_matrix", "client", "v3", "keys", "changes"}, client.WithQueries(url.Values{ "from": []string{syncToken}, "to": []string{nextSyncToken}, @@ -3192,7 +3193,7 @@ func TestPartialStateJoin(t *testing.T) { // Check that the last kick was incorrectly rejected. must.MatchResponse(t, - alice.DoFunc(t, "GET", []string{"_matrix", "client", "r0", "rooms", room.RoomID, "event", kickEvent.EventID()}), + alice.Do(t, "GET", []string{"_matrix", "client", "r0", "rooms", room.RoomID, "event", kickEvent.EventID()}), match.HTTPResponse{ StatusCode: 404, JSON: []match.JSON{ @@ -3385,7 +3386,7 @@ func TestPartialStateJoin(t *testing.T) { // Alice creates an alias for the room aliasName := "#t40alice-room:hs1" - alice.MustDoFunc( + alice.MustDo( t, "PUT", []string{"_matrix", "client", "v3", "directory", "room", aliasName}, @@ -3395,7 +3396,7 @@ func TestPartialStateJoin(t *testing.T) { ) // Alice then queries that alias - response := alice.MustDoFunc( + response := alice.MustDo( t, "GET", []string{"_matrix", "client", "v3", "directory", "room", aliasName}, @@ -3436,7 +3437,7 @@ func TestPartialStateJoin(t *testing.T) { // Alice creates an alias for the room aliasName := "#t41alice-room:hs1" - alice.MustDoFunc( + alice.MustDo( t, "PUT", []string{"_matrix", "client", "v3", "directory", "room", aliasName}, @@ -3446,7 +3447,7 @@ func TestPartialStateJoin(t *testing.T) { ) // Alice then deletes that alias - response := alice.MustDoFunc( + response := alice.MustDo( t, "DELETE", []string{"_matrix", "client", "v3", "directory", "room", aliasName}, @@ -3515,7 +3516,7 @@ func TestPartialStateJoin(t *testing.T) { ) defer removePDUHandler() - alice.MustDoFunc(t, + alice.MustDo(t, "PUT", []string{"_matrix", "client", "v3", "profile", alice.UserID, "displayname"}, client.WithJSONBody(t, map[string]interface{}{ @@ -3877,7 +3878,7 @@ func TestPartialStateJoin(t *testing.T) { t.Log("Alice tries to rejoin...") queryParams := url.Values{} queryParams.Add("server_name", server.ServerName()) - response := alice.DoFunc(t, "POST", []string{"_matrix", "client", "v3", "join", serverRoom.RoomID}, client.WithQueries(queryParams)) + response := alice.Do(t, "POST", []string{"_matrix", "client", "v3", "join", serverRoom.RoomID}, client.WithQueries(queryParams)) t.Log("... but Alice was forbidden from rejoining") must.MatchResponse(t, response, match.HTTPResponse{StatusCode: http.StatusForbidden}) @@ -3909,12 +3910,12 @@ func TestPartialStateJoin(t *testing.T) { reqBody := client.WithJSONBody(t, map[string]interface{}{ "visibility": "public", }) - terry.MustDoFunc(t, "PUT", []string{"_matrix", "client", "v3", "directory", "list", "room", serverRoom.RoomID}, reqBody) + terry.MustDo(t, "PUT", []string{"_matrix", "client", "v3", "directory", "list", "room", serverRoom.RoomID}, reqBody) assertPublicRoomDirectoryMemberCountEquals := func(t *testing.T, expectedMemberCount int64) { // In Synapse, rooms stats are updated by a background job which runs asynchronously. // To account for that, we check for up to 3 seconds that the job has completed. - terry.MustDoFunc(t, "GET", []string{"_matrix", "client", "v3", "publicRooms"}, + terry.MustDo(t, "GET", []string{"_matrix", "client", "v3", "publicRooms"}, client.WithRetryUntil(time.Second*3, func(res *http.Response) bool { body, err := ioutil.ReadAll(res.Body) if err != nil { @@ -3964,7 +3965,7 @@ func TestPartialStateJoin(t *testing.T) { // The user directory is updated by a background job in Synapse which runs // asynchronously. We check for up to 3 seconds that the job has completed, after which // the job should have finished and the user directory should be up to date. - rocky.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "user_directory", "search"}, reqBody, + rocky.MustDo(t, "POST", []string{"_matrix", "client", "v3", "user_directory", "search"}, reqBody, client.WithRetryUntil(time.Second*3, func(res *http.Response) bool { body, err := ioutil.ReadAll(res.Body) if err != nil { @@ -3985,7 +3986,7 @@ func TestPartialStateJoin(t *testing.T) { reqBody := client.WithJSONBody(t, map[string]interface{}{ "search_term": "rod", }) - res := rocky.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "user_directory", "search"}, reqBody) + res := rocky.MustDo(t, "POST", []string{"_matrix", "client", "v3", "user_directory", "search"}, reqBody) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: 200, JSON: []match.JSON{ @@ -4039,7 +4040,7 @@ func TestPartialStateJoin(t *testing.T) { t.Log("Alice purges that room") // Ignore PDUs (leaves from shutting down the room). server.AddPDUHandler(func(e *gomatrixserverlib.Event) bool { return true }) - alice.MustDoFunc(t, "DELETE", []string{"_synapse", "admin", "v1", "rooms", serverRoom.RoomID}, client.WithJSONBody(t, map[string]interface{}{})) + alice.MustDo(t, "DELETE", []string{"_synapse", "admin", "v1", "rooms", serverRoom.RoomID}, client.WithJSONBody(t, map[string]interface{}{})) // Note: clients don't get told about purged rooms. No leave event for you! t.Log("Alice does an initial sync after the purge, until the response does not include the purged room") @@ -4053,7 +4054,7 @@ func TestPartialStateJoin(t *testing.T) { matcher := match.JSONKeyMissing( fmt.Sprintf("rooms.join.%s", client.GjsonEscape(serverRoom.RoomID)), ) - alice.MustDoFunc( + alice.MustDo( t, "GET", []string{"_matrix", "client", "v3", "sync"}, @@ -4130,7 +4131,7 @@ func testReceiveEventDuringPartialStateJoin( // our request may be rejected due to https://github.com/matrix-org/synapse/issues/13288. // By way of a workaround, request a remote user's current membership, which should block until the current state // is updated. - alice.DoFunc( + alice.Do( t, "GET", []string{"_matrix", "client", "v3", "rooms", psjResult.ServerRoom.RoomID, "state", "m.room.member", "@non-existent:remote"}, @@ -4183,7 +4184,7 @@ func awaitEventArrival(t *testing.T, timeout time.Duration, alice *client.CSAPI, t.Helper() // Alice should be able to see the event with an /event request. We might have to try it a few times. - alice.DoFunc(t, "GET", []string{"_matrix", "client", "r0", "rooms", roomID, "event", eventID}, + alice.Do(t, "GET", []string{"_matrix", "client", "r0", "rooms", roomID, "event", eventID}, client.WithRetryUntil(timeout, func(res *http.Response) bool { if res.StatusCode == 200 { return true @@ -4208,7 +4209,7 @@ func awaitPartialStateJoinCompletion( // Use a `/members` request to wait for the room to be un-partial stated. // We avoid using `/sync`, as it only waits (or used to wait) for full state at // particular events, rather than the whole room. - user.MustDoFunc( + user.MustDo( t, "GET", []string{"_matrix", "client", "v3", "rooms", room.RoomID, "members"}, diff --git a/tests/federation_room_join_test.go b/tests/federation_room_join_test.go index 5c302f94..7d61abf0 100644 --- a/tests/federation_room_join_test.go +++ b/tests/federation_room_join_test.go @@ -17,8 +17,8 @@ import ( "github.com/tidwall/gjson" "github.com/tidwall/sjson" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/internal/federation" "github.com/matrix-org/complement/internal/match" "github.com/matrix-org/complement/internal/must" @@ -79,7 +79,7 @@ func TestJoinViaRoomIDAndServerName(t *testing.T) { queryParams := url.Values{} queryParams.Set("server_name", "hs1") - res := bob.DoFunc(t, "POST", []string{"_matrix", "client", "v3", "join", serverRoom.RoomID}, client.WithQueries(queryParams)) + res := bob.Do(t, "POST", []string{"_matrix", "client", "v3", "join", serverRoom.RoomID}, client.WithQueries(queryParams)) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: 200, JSON: []match.JSON{ @@ -347,7 +347,7 @@ func TestBannedUserCannotSendJoin(t *testing.T) { } // Alice checks the room state to check that charlie isn't a member - res := alice.MustDoFunc( + res := alice.MustDo( t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.member", charlie}, diff --git a/tests/federation_room_typing_test.go b/tests/federation_room_typing_test.go index 14af3305..aa892d90 100644 --- a/tests/federation_room_typing_test.go +++ b/tests/federation_room_typing_test.go @@ -5,8 +5,8 @@ import ( "github.com/tidwall/gjson" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" ) func awaitTyping(userId string) func(result gjson.Result) bool { @@ -41,7 +41,7 @@ func TestRemoteTyping(t *testing.T) { bobToken := bob.MustSyncUntil(t, client.SyncReq{}, client.SyncJoinedTo(bob.UserID, roomID)) charlieToken := charlie.MustSyncUntil(t, client.SyncReq{}, client.SyncJoinedTo(charlie.UserID, roomID)) - alice.MustDoFunc(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "typing", alice.UserID}, client.WithJSONBody(t, map[string]interface{}{ + alice.MustDo(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "typing", alice.UserID}, client.WithJSONBody(t, map[string]interface{}{ "typing": true, "timeout": 10000, })) diff --git a/tests/federation_rooms_invite_test.go b/tests/federation_rooms_invite_test.go index 0bdd688d..a26fb289 100644 --- a/tests/federation_rooms_invite_test.go +++ b/tests/federation_rooms_invite_test.go @@ -6,8 +6,8 @@ import ( "github.com/matrix-org/gomatrixserverlib" "github.com/tidwall/gjson" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/internal/match" "github.com/matrix-org/complement/internal/must" ) @@ -128,7 +128,7 @@ func verifyState(t *testing.T, res gjson.Result, wantFields, wantValues map[stri wantValue := wantValues[eventType] eventStateKey := event.Get("state_key").Str - res := cl.MustDoFunc(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", eventType, eventStateKey}) + res := cl.MustDo(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", eventType, eventStateKey}) must.MatchResponse(t, res, match.HTTPResponse{ JSON: []match.JSON{ diff --git a/tests/federation_unreject_rejected_test.go b/tests/federation_unreject_rejected_test.go index a372cd0d..f7f38079 100644 --- a/tests/federation_unreject_rejected_test.go +++ b/tests/federation_unreject_rejected_test.go @@ -4,8 +4,8 @@ import ( "encoding/json" "testing" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/internal/federation" ) diff --git a/tests/federation_upload_keys_test.go b/tests/federation_upload_keys_test.go index f89471dd..eb2866e8 100644 --- a/tests/federation_upload_keys_test.go +++ b/tests/federation_upload_keys_test.go @@ -9,8 +9,8 @@ import ( "github.com/tidwall/gjson" "maunium.net/go/mautrix/crypto/olm" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/internal/match" "github.com/matrix-org/complement/internal/must" ) @@ -28,7 +28,7 @@ func TestFederationKeyUploadQuery(t *testing.T) { "device_keys": deviceKeys, "one_time_keys": oneTimeKeys, }) - resp := alice.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "keys", "upload"}, reqBody) + resp := alice.MustDo(t, "POST", []string{"_matrix", "client", "v3", "keys", "upload"}, reqBody) must.MatchResponse(t, resp, match.HTTPResponse{ StatusCode: http.StatusOK, JSON: []match.JSON{ @@ -60,7 +60,7 @@ func TestFederationKeyUploadQuery(t *testing.T) { }, }, }) - resp = bob.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "keys", "claim"}, reqBody) + resp = bob.MustDo(t, "POST", []string{"_matrix", "client", "v3", "keys", "claim"}, reqBody) otksField := "one_time_keys." + client.GjsonEscape(alice.UserID) + "." + client.GjsonEscape(alice.DeviceID) must.MatchResponse(t, resp, match.HTTPResponse{ StatusCode: http.StatusOK, @@ -71,7 +71,7 @@ func TestFederationKeyUploadQuery(t *testing.T) { }) // there should be no OTK left now - resp = bob.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "keys", "claim"}, reqBody) + resp = bob.MustDo(t, "POST", []string{"_matrix", "client", "v3", "keys", "claim"}, reqBody) must.MatchResponse(t, resp, match.HTTPResponse{ StatusCode: http.StatusOK, JSON: []match.JSON{ @@ -88,7 +88,7 @@ func TestFederationKeyUploadQuery(t *testing.T) { body := client.WithJSONBody(t, map[string]interface{}{ "display_name": displayName, }) - alice.MustDoFunc(t, http.MethodPut, []string{"_matrix", "client", "v3", "devices", alice.DeviceID}, body) + alice.MustDo(t, http.MethodPut, []string{"_matrix", "client", "v3", "devices", alice.DeviceID}, body) // wait for bob to receive the displayname change bob.MustSyncUntil(t, client.SyncReq{}, func(clientUserID string, topLevelSyncJSON gjson.Result) error { devicesChanged := topLevelSyncJSON.Get("device_lists.changed") @@ -106,7 +106,7 @@ func TestFederationKeyUploadQuery(t *testing.T) { alice.UserID: []string{}, }, }) - resp = bob.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "keys", "query"}, reqBody) + resp = bob.MustDo(t, "POST", []string{"_matrix", "client", "v3", "keys", "query"}, reqBody) deviceKeysField := "device_keys." + client.GjsonEscape(alice.UserID) + "." + client.GjsonEscape(alice.DeviceID) must.MatchResponse(t, resp, match.HTTPResponse{ diff --git a/tests/knocking_test.go b/tests/knocking_test.go index e84f7ca8..8e06cdaa 100644 --- a/tests/knocking_test.go +++ b/tests/knocking_test.go @@ -19,8 +19,8 @@ import ( "github.com/matrix-org/gomatrixserverlib" "github.com/tidwall/gjson" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/internal/federation" "github.com/matrix-org/complement/internal/match" "github.com/matrix-org/complement/internal/must" @@ -122,7 +122,7 @@ func knockingBetweenTwoUsersTest(t *testing.T, roomID string, inRoomUser, knocki "server_name": []string{"hs1"}, } - res := knockingUser.DoFunc( + res := knockingUser.Do( t, "POST", []string{"_matrix", "client", "v3", "join", roomID}, @@ -146,7 +146,7 @@ func knockingBetweenTwoUsersTest(t *testing.T, roomID string, inRoomUser, knocki // wait for the membership to arrive over federation start := time.Now() knockerState := serverRoom.CurrentState("m.room.member", knockingUser.UserID) - for knockerState == nil && time.Since(start) < 5 * time.Second { + for knockerState == nil && time.Since(start) < 5*time.Second { time.Sleep(100 * time.Millisecond) knockerState = serverRoom.CurrentState("m.room.member", knockingUser.UserID) } @@ -181,7 +181,7 @@ func knockingBetweenTwoUsersTest(t *testing.T, roomID string, inRoomUser, knocki _, since := knockingUser.MustSync(t, client.SyncReq{TimeoutMillis: "0"}) // Rescind knock - knockingUser.MustDoFunc( + knockingUser.MustDo( t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "leave"}, @@ -218,7 +218,7 @@ func knockingBetweenTwoUsersTest(t *testing.T, roomID string, inRoomUser, knocki // // In the case of federation, this test will still check that a knock can be // carried out after a previous knock is rejected. - inRoomUser.MustDoFunc( + inRoomUser.MustDo( t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "kick"}, @@ -241,7 +241,7 @@ func knockingBetweenTwoUsersTest(t *testing.T, roomID string, inRoomUser, knocki t.Run("A user can knock on a room without a reason", func(t *testing.T) { // Reject the knock - inRoomUser.MustDoFunc( + inRoomUser.MustDo( t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "kick"}, @@ -256,7 +256,7 @@ func knockingBetweenTwoUsersTest(t *testing.T, roomID string, inRoomUser, knocki }) t.Run("A user in the room can accept a knock", func(t *testing.T) { - inRoomUser.MustDoFunc( + inRoomUser.MustDo( t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "invite"}, @@ -285,7 +285,7 @@ func knockingBetweenTwoUsersTest(t *testing.T, roomID string, inRoomUser, knocki // // In the case of federation, this test will still check that a knock can not be // carried out after a ban. - inRoomUser.MustDoFunc( + inRoomUser.MustDo( t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "ban"}, @@ -349,7 +349,7 @@ func knockOnRoomWithStatus(t *testing.T, c *client.CSAPI, roomID, reason string, } // Knock on the room - res := c.DoFunc( + res := c.Do( t, "POST", []string{"_matrix", "client", "v3", "knock", roomID}, @@ -416,7 +416,7 @@ func doTestKnockRoomsInPublicRoomsDirectory(t *testing.T, roomVersion string, jo // It will then query the directory and ensure the room is listed, and has a given 'join_rule' entry func publishAndCheckRoomJoinRule(t *testing.T, c *client.CSAPI, roomID, expectedJoinRule string) { // Publish the room to the public room directory - c.MustDoFunc( + c.MustDo( t, "PUT", []string{"_matrix", "client", "v3", "directory", "list", "room", roomID}, @@ -426,7 +426,7 @@ func publishAndCheckRoomJoinRule(t *testing.T, c *client.CSAPI, roomID, expected ) // Check that we can see the room in the directory - c.MustDoFunc(t, "GET", []string{"_matrix", "client", "v3", "publicRooms"}, + c.MustDo(t, "GET", []string{"_matrix", "client", "v3", "publicRooms"}, client.WithRetryUntil(time.Second, func(res *http.Response) bool { roomFound := false must.MatchResponse(t, res, match.HTTPResponse{ diff --git a/tests/media_filename_test.go b/tests/media_filename_test.go index 637c996f..e2e55e39 100644 --- a/tests/media_filename_test.go +++ b/tests/media_filename_test.go @@ -5,8 +5,8 @@ import ( "mime" "testing" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/internal/data" ) @@ -132,7 +132,7 @@ func downloadForFilename(t *testing.T, c *client.CSAPI, mxcUri string, diffName path = []string{"_matrix", "media", "v3", "download", origin, mediaId} } - res := c.MustDoFunc(t, "GET", path) + res := c.MustDo(t, "GET", path) mediaType, params, err := mime.ParseMediaType(res.Header.Get("Content-Disposition")) if err != nil { diff --git a/tests/media_thumbnail_test.go b/tests/media_thumbnail_test.go index 97808150..16bcc8a2 100644 --- a/tests/media_thumbnail_test.go +++ b/tests/media_thumbnail_test.go @@ -9,8 +9,8 @@ import ( "strings" "testing" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/internal/data" ) @@ -52,7 +52,7 @@ func fetchAndValidateThumbnail(t *testing.T, c *client.CSAPI, mxcUri string) { origin, mediaId := client.SplitMxc(mxcUri) - res := c.MustDoFunc(t, "GET", []string{"_matrix", "media", "v3", "thumbnail", origin, mediaId}, client.WithQueries(url.Values{ + res := c.MustDo(t, "GET", []string{"_matrix", "media", "v3", "thumbnail", origin, mediaId}, client.WithQueries(url.Values{ "width": []string{"32"}, "height": []string{"32"}, "method": []string{"scale"}, diff --git a/tests/msc2836_test.go b/tests/msc2836_test.go index 20b191ad..693b2d30 100644 --- a/tests/msc2836_test.go +++ b/tests/msc2836_test.go @@ -18,8 +18,8 @@ import ( "github.com/matrix-org/gomatrixserverlib" "github.com/tidwall/gjson" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" "github.com/matrix-org/complement/internal/federation" "github.com/matrix-org/complement/internal/match" "github.com/matrix-org/complement/internal/must" @@ -27,11 +27,13 @@ import ( // This test checks that federated threading works when the remote server joins after the messages // have been sent. The test configures a thread like: -// A -// | -// B -// / \ -// C D +// +// A +// | +// B +// / \ +// C D +// // Then a remote server joins the room. /event_relationships is then hit with event ID 'D' which the // joined server does not have. This should cause a remote /event_relationships request to service the // request. The request parameters will pull in events D,B. This gets repeated for a second time with @@ -94,7 +96,7 @@ func TestEventRelationships(t *testing.T) { bob.MustSyncUntil(t, client.SyncReq{}, client.SyncJoinedTo(bob.UserID, roomID)) // Now hit /event_relationships with eventD - res := bob.MustDoFunc(t, "POST", []string{"_matrix", "client", "unstable", "event_relationships"}, client.WithJSONBody(t, map[string]interface{}{ + res := bob.MustDo(t, "POST", []string{"_matrix", "client", "unstable", "event_relationships"}, client.WithJSONBody(t, map[string]interface{}{ "event_id": eventD, "room_id": roomID, // required so the server knows which servers to ask "direction": "down", // no newer events, so nothing should be added @@ -126,7 +128,7 @@ func TestEventRelationships(t *testing.T) { }, []string{eventC, eventD}) // now hit /event_relationships again with B, which should return everything (and fetch the missing events A,C) - res = bob.MustDoFunc(t, "POST", []string{"_matrix", "client", "unstable", "event_relationships"}, client.WithJSONBody(t, map[string]interface{}{ + res = bob.MustDo(t, "POST", []string{"_matrix", "client", "unstable", "event_relationships"}, client.WithJSONBody(t, map[string]interface{}{ "event_id": eventB, "room_id": roomID, // required so the server knows which servers to ask "direction": "down", // this pulls in C,D @@ -171,13 +173,15 @@ func TestEventRelationships(t *testing.T) { // This test checks that the homeserver makes a federated request to /event_relationships // when walking a thread when it encounters an unknown event ID. The test configures a // room on the Complement server with a thread which has following shape: -// A -// / \ -// B C -// | -// D <- Test server joins here -// | -// E +// +// A +// / \ +// B C +// | +// D <- Test server joins here +// | +// E +// // The test server is notified of event E in a /send transaction after joining the room. // The client on the test server then hits /event_relationships with event ID 'E' and direction 'up'. // This *should* cause the server to walk up the thread, realise it is missing event D and then ask @@ -335,7 +339,7 @@ func TestFederatedEventRelationships(t *testing.T) { })) // Hit /event_relationships to make sure it spiders the whole thing by asking /event_relationships on Complement - res := alice.MustDoFunc(t, "POST", []string{"_matrix", "client", "unstable", "event_relationships"}, client.WithJSONBody(t, map[string]interface{}{ + res := alice.MustDo(t, "POST", []string{"_matrix", "client", "unstable", "event_relationships"}, client.WithJSONBody(t, map[string]interface{}{ "event_id": eventE.EventID(), "max_depth": 10, "direction": "up", @@ -356,7 +360,7 @@ func TestFederatedEventRelationships(t *testing.T) { must.HaveInOrder(t, gotEventIDs, []string{eventE.EventID(), eventD.EventID(), eventC.EventID(), eventA.EventID()}) // now querying for the children of A should return A,B,C (it should've been remembered B from the previous /event_relationships request) - res = alice.MustDoFunc(t, "POST", []string{"_matrix", "client", "unstable", "event_relationships"}, client.WithJSONBody(t, map[string]interface{}{ + res = alice.MustDo(t, "POST", []string{"_matrix", "client", "unstable", "event_relationships"}, client.WithJSONBody(t, map[string]interface{}{ "event_id": eventA.EventID(), "max_depth": 1, "direction": "down", diff --git a/tests/msc3391_test.go b/tests/msc3391_test.go index e74f9703..d824bb97 100644 --- a/tests/msc3391_test.go +++ b/tests/msc3391_test.go @@ -12,7 +12,7 @@ import ( "testing" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/match" "github.com/matrix-org/complement/internal/must" @@ -152,7 +152,7 @@ func deleteUserAccountData(t *testing.T, c *client.CSAPI, viaDelete bool) { // Delete user account data if viaDelete { // Delete via the DELETE method - c.MustDoFunc( + c.MustDo( t, "DELETE", []string{"_matrix", "client", "unstable", "org.matrix.msc3391", "user", c.UserID, "account_data", testAccountDataType}, @@ -174,7 +174,7 @@ func deleteUserAccountData(t *testing.T, c *client.CSAPI, viaDelete bool) { ) // Also check the account data item is no longer found - res := c.DoFunc(t, "GET", []string{"_matrix", "client", "v3", "user", c.UserID, "account_data", testAccountDataType}) + res := c.Do(t, "GET", []string{"_matrix", "client", "v3", "user", c.UserID, "account_data", testAccountDataType}) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: 404, }) @@ -210,7 +210,7 @@ func deleteRoomAccountData(t *testing.T, c *client.CSAPI, viaDelete bool, roomID // Delete room account data if viaDelete { // Delete via the DELETE method - c.MustDoFunc( + c.MustDo( t, "DELETE", []string{"_matrix", "client", "unstable", "org.matrix.msc3391", "user", c.UserID, "rooms", roomID, "account_data", testAccountDataType}, @@ -232,7 +232,7 @@ func deleteRoomAccountData(t *testing.T, c *client.CSAPI, viaDelete bool, roomID ) // Also check the account data item is no longer found - res := c.DoFunc(t, "GET", []string{"_matrix", "client", "v3", "user", c.UserID, "room", roomID, "account_data", testAccountDataType}) + res := c.Do(t, "GET", []string{"_matrix", "client", "v3", "user", c.UserID, "room", roomID, "account_data", testAccountDataType}) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: 404, }) diff --git a/tests/msc3890_test.go b/tests/msc3890_test.go index 9cb4df4c..a73972ad 100644 --- a/tests/msc3890_test.go +++ b/tests/msc3890_test.go @@ -11,7 +11,7 @@ import ( "testing" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/match" "github.com/matrix-org/complement/internal/must" "github.com/tidwall/gjson" @@ -68,8 +68,8 @@ func TestDeletingDeviceRemovesDeviceLocalNotificationSettings(t *testing.T) { client.SyncGlobalAccountDataHas(checkAccountDataContent), ) // Also check via the dedicated account data endpoint to ensure the similar check later is not 404'ing for some other reason. - // Using `MustDoFunc` ensures that the response code is 2xx. - res := aliceDeviceOne.MustDoFunc(t, "GET", []string{"_matrix", "client", "v3", "user", aliceDeviceOne.UserID, "account_data", accountDataType}) + // Using `MustDo` ensures that the response code is 2xx. + res := aliceDeviceOne.MustDo(t, "GET", []string{"_matrix", "client", "v3", "user", aliceDeviceOne.UserID, "account_data", accountDataType}) must.MatchResponse(t, res, match.HTTPResponse{ JSON: []match.JSON{ match.JSONKeyEqual("is_silenced", true), @@ -77,10 +77,10 @@ func TestDeletingDeviceRemovesDeviceLocalNotificationSettings(t *testing.T) { }) // Log out the second device - aliceDeviceTwo.MustDoFunc(t, "POST", []string{"_matrix", "client", "v3", "logout"}) + aliceDeviceTwo.MustDo(t, "POST", []string{"_matrix", "client", "v3", "logout"}) // Using the first device, check that the local notification setting account data for the deleted device was removed. - res = aliceDeviceOne.DoFunc(t, "GET", []string{"_matrix", "client", "v3", "user", aliceDeviceOne.UserID, "account_data", accountDataType}) + res = aliceDeviceOne.Do(t, "GET", []string{"_matrix", "client", "v3", "user", aliceDeviceOne.UserID, "account_data", accountDataType}) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: 404, JSON: []match.JSON{ diff --git a/tests/restricted_room_hierarchy_test.go b/tests/restricted_room_hierarchy_test.go index 54231706..9c7a97e1 100644 --- a/tests/restricted_room_hierarchy_test.go +++ b/tests/restricted_room_hierarchy_test.go @@ -8,7 +8,7 @@ import ( "github.com/tidwall/gjson" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/match" "github.com/matrix-org/complement/internal/must" ) @@ -17,7 +17,7 @@ import ( func requestAndAssertSummary(t *testing.T, user *client.CSAPI, space string, expected_rooms []interface{}) { t.Helper() - res := user.MustDoFunc(t, "GET", []string{"_matrix", "client", "v1", "rooms", space, "hierarchy"}) + res := user.MustDo(t, "GET", []string{"_matrix", "client", "v1", "rooms", space, "hierarchy"}) must.MatchResponse(t, res, match.HTTPResponse{ JSON: []match.JSON{ match.JSONCheckOff("rooms", expected_rooms, func(r gjson.Result) interface{} { diff --git a/tests/restricted_rooms_test.go b/tests/restricted_rooms_test.go index c55c4ce5..674ec2ee 100644 --- a/tests/restricted_rooms_test.go +++ b/tests/restricted_rooms_test.go @@ -9,7 +9,7 @@ import ( "github.com/tidwall/gjson" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/docker" "github.com/matrix-org/complement/internal/match" "github.com/matrix-org/complement/internal/must" @@ -22,7 +22,7 @@ func failJoinRoom(t *testing.T, c *client.CSAPI, roomIDOrAlias string, serverNam // This is copied from Client.JoinRoom to test a join failure. query := make(url.Values, 1) query.Set("server_name", serverName) - res := c.DoFunc( + res := c.Do( t, "POST", []string{"_matrix", "client", "v3", "join", roomIDOrAlias}, @@ -272,7 +272,7 @@ func doTestRestrictedRoomsRemoteJoinLocalUser(t *testing.T, roomVersion string, body := map[string]interface{}{ "user_id": bob.UserID, } - res := alice.DoFunc( + res := alice.Do( t, "POST", []string{"_matrix", "client", "v3", "rooms", room, "invite"}, diff --git a/tests/room_hierarchy_test.go b/tests/room_hierarchy_test.go index 1d929ff2..a9d18156 100644 --- a/tests/room_hierarchy_test.go +++ b/tests/room_hierarchy_test.go @@ -21,7 +21,7 @@ import ( "github.com/tidwall/gjson" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/match" "github.com/matrix-org/complement/internal/must" ) @@ -219,7 +219,7 @@ func TestClientSpacesSummary(t *testing.T) { // - Rooms are returned correctly along with the custom fields `room_type`. // - Events are returned correctly. t.Run("query whole graph", func(t *testing.T) { - res := alice.MustDoFunc(t, "GET", []string{"_matrix", "client", "v1", "rooms", root, "hierarchy"}) + res := alice.MustDo(t, "GET", []string{"_matrix", "client", "v1", "rooms", root, "hierarchy"}) must.MatchResponse(t, res, match.HTTPResponse{ JSON: []match.JSON{ match.JSONCheckOff("rooms", []interface{}{ @@ -257,7 +257,7 @@ func TestClientSpacesSummary(t *testing.T) { // Should only include R1, SS1, and R2. query := make(url.Values, 1) query.Set("max_depth", "1") - res := alice.MustDoFunc( + res := alice.MustDo( t, "GET", []string{"_matrix", "client", "v1", "rooms", root, "hierarchy"}, @@ -283,7 +283,7 @@ func TestClientSpacesSummary(t *testing.T) { // Should only include R1, SS1, and R2. query := make(url.Values, 1) query.Set("suggested_only", "true") - res := alice.MustDoFunc( + res := alice.MustDo( t, "GET", []string{"_matrix", "client", "v1", "rooms", root, "hierarchy"}, @@ -309,7 +309,7 @@ func TestClientSpacesSummary(t *testing.T) { // The initial page should only include Root, R1, SS1, and SS2. query := make(url.Values, 1) query.Set("limit", "4") - res := alice.MustDoFunc( + res := alice.MustDo( t, "GET", []string{"_matrix", "client", "v1", "rooms", root, "hierarchy"}, @@ -328,7 +328,7 @@ func TestClientSpacesSummary(t *testing.T) { // The following page should include R3, R4, and R2. query = make(url.Values, 1) query.Set("from", client.GetJSONFieldStr(t, body, "next_batch")) - res = alice.MustDoFunc( + res = alice.MustDo( t, "GET", []string{"_matrix", "client", "v1", "rooms", root, "hierarchy"}, @@ -352,7 +352,7 @@ func TestClientSpacesSummary(t *testing.T) { StateKey: &ss1, Content: map[string]interface{}{}, }) - res := alice.MustDoFunc(t, "GET", []string{"_matrix", "client", "v1", "rooms", root, "hierarchy"}) + res := alice.MustDo(t, "GET", []string{"_matrix", "client", "v1", "rooms", root, "hierarchy"}) must.MatchResponse(t, res, match.HTTPResponse{ JSON: []match.JSON{ match.JSONCheckOff("rooms", []interface{}{ @@ -464,7 +464,7 @@ func TestClientSpacesSummaryJoinRules(t *testing.T) { bob := deployment.Client(t, "hs1", "@bob:hs1") bob.JoinRoom(t, root, []string{"hs1"}) - res := bob.MustDoFunc(t, "GET", []string{"_matrix", "client", "v1", "rooms", root, "hierarchy"}) + res := bob.MustDo(t, "GET", []string{"_matrix", "client", "v1", "rooms", root, "hierarchy"}) must.MatchResponse(t, res, match.HTTPResponse{ JSON: []match.JSON{ match.JSONCheckOff("rooms", []interface{}{ @@ -482,7 +482,7 @@ func TestClientSpacesSummaryJoinRules(t *testing.T) { alice.InviteRoom(t, r1, bob.UserID) alice.InviteRoom(t, r3, bob.UserID) - res = bob.MustDoFunc(t, "GET", []string{"_matrix", "client", "v1", "rooms", root, "hierarchy"}) + res = bob.MustDo(t, "GET", []string{"_matrix", "client", "v1", "rooms", root, "hierarchy"}) must.MatchResponse(t, res, match.HTTPResponse{ JSON: []match.JSON{ match.JSONCheckOff("rooms", []interface{}{ @@ -499,7 +499,7 @@ func TestClientSpacesSummaryJoinRules(t *testing.T) { // Invite to SS1 and it now appears, as well as the rooms under it. alice.InviteRoom(t, ss1, bob.UserID) - res = bob.MustDoFunc(t, "GET", []string{"_matrix", "client", "v1", "rooms", root, "hierarchy"}) + res = bob.MustDo(t, "GET", []string{"_matrix", "client", "v1", "rooms", root, "hierarchy"}) must.MatchResponse(t, res, match.HTTPResponse{ JSON: []match.JSON{ match.JSONCheckOff("rooms", []interface{}{ @@ -627,7 +627,7 @@ func TestFederatedClientSpaces(t *testing.T) { } t.Logf("rooms: %v", allEvents) - res := alice.MustDoFunc(t, "GET", []string{"_matrix", "client", "v1", "rooms", root, "hierarchy"}) + res := alice.MustDo(t, "GET", []string{"_matrix", "client", "v1", "rooms", root, "hierarchy"}) must.MatchResponse(t, res, match.HTTPResponse{ JSON: []match.JSON{ match.JSONCheckOff("rooms", []interface{}{ diff --git a/tests/room_timestamp_to_event_test.go b/tests/room_timestamp_to_event_test.go index b3085d89..236d8e91 100644 --- a/tests/room_timestamp_to_event_test.go +++ b/tests/room_timestamp_to_event_test.go @@ -16,7 +16,7 @@ import ( "time" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/match" "github.com/matrix-org/complement/internal/must" "github.com/tidwall/gjson" @@ -119,7 +119,7 @@ func TestJumpToDateEndpoint(t *testing.T) { // Make the `/timestamp_to_event` request from Bob's perspective (non room member) timestamp := makeTimestampFromTime(timeBeforeRoomCreation) timestampString := strconv.FormatInt(timestamp, 10) - timestampToEventRes := nonMemberUser.DoFunc(t, "GET", []string{"_matrix", "client", "v1", "rooms", roomID, "timestamp_to_event"}, client.WithContentType("application/json"), client.WithQueries(url.Values{ + timestampToEventRes := nonMemberUser.Do(t, "GET", []string{"_matrix", "client", "v1", "rooms", roomID, "timestamp_to_event"}, client.WithContentType("application/json"), client.WithQueries(url.Values{ "ts": []string{timestampString}, "dir": []string{"f"}, })) @@ -147,7 +147,7 @@ func TestJumpToDateEndpoint(t *testing.T) { // Make the `/timestamp_to_event` request from Bob's perspective (non room member) timestamp := makeTimestampFromTime(timeBeforeRoomCreation) timestampString := strconv.FormatInt(timestamp, 10) - timestampToEventRes := nonMemberUser.DoFunc(t, "GET", []string{"_matrix", "client", "v1", "rooms", roomID, "timestamp_to_event"}, client.WithContentType("application/json"), client.WithQueries(url.Values{ + timestampToEventRes := nonMemberUser.Do(t, "GET", []string{"_matrix", "client", "v1", "rooms", roomID, "timestamp_to_event"}, client.WithContentType("application/json"), client.WithQueries(url.Values{ "ts": []string{timestampString}, "dir": []string{"f"}, })) @@ -198,7 +198,7 @@ func TestJumpToDateEndpoint(t *testing.T) { mustCheckEventisReturnedForTime(t, remoteCharlie, roomID, eventB.AfterTimestamp, "b", eventB.EventID) // Get a pagination token from eventB - contextRes := remoteCharlie.MustDoFunc(t, "GET", []string{"_matrix", "client", "r0", "rooms", roomID, "context", eventB.EventID}, client.WithContentType("application/json"), client.WithQueries(url.Values{ + contextRes := remoteCharlie.MustDo(t, "GET", []string{"_matrix", "client", "r0", "rooms", roomID, "context", eventB.EventID}, client.WithContentType("application/json"), client.WithQueries(url.Values{ "limit": []string{"0"}, })) contextResResBody := client.ParseJSON(t, contextRes) @@ -212,7 +212,7 @@ func TestJumpToDateEndpoint(t *testing.T) { }) // Paginate backwards from eventB - messagesRes := remoteCharlie.MustDoFunc(t, "GET", []string{"_matrix", "client", "r0", "rooms", roomID, "messages"}, client.WithContentType("application/json"), client.WithQueries(url.Values{ + messagesRes := remoteCharlie.MustDo(t, "GET", []string{"_matrix", "client", "r0", "rooms", roomID, "messages"}, client.WithContentType("application/json"), client.WithQueries(url.Values{ "dir": []string{"b"}, "limit": []string{"100"}, "from": []string{paginationToken}, @@ -289,7 +289,7 @@ func sendMessageWithTimestamp(t *testing.T, as *client.CSAPI, c *client.CSAPI, r // // We can't use as.SendEventSynced(...) because application services can't use // the /sync API. - sendRes := as.DoFunc(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "send", "m.room.message", getTxnID("sendMessageWithTimestamp-txn")}, client.WithContentType("application/json"), client.WithJSONBody(t, map[string]interface{}{ + sendRes := as.Do(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "send", "m.room.message", getTxnID("sendMessageWithTimestamp-txn")}, client.WithContentType("application/json"), client.WithJSONBody(t, map[string]interface{}{ "body": message, "msgtype": "m.text", }), client.WithQueries(url.Values{ @@ -311,7 +311,7 @@ func mustCheckEventisReturnedForTime(t *testing.T, c *client.CSAPI, roomID strin givenTimestamp := makeTimestampFromTime(givenTime) timestampString := strconv.FormatInt(givenTimestamp, 10) - timestampToEventRes := c.DoFunc(t, "GET", []string{"_matrix", "client", "v1", "rooms", roomID, "timestamp_to_event"}, client.WithContentType("application/json"), client.WithQueries(url.Values{ + timestampToEventRes := c.Do(t, "GET", []string{"_matrix", "client", "v1", "rooms", roomID, "timestamp_to_event"}, client.WithContentType("application/json"), client.WithQueries(url.Values{ "ts": []string{timestampString}, "dir": []string{direction}, })) @@ -348,7 +348,7 @@ func fetchUntilMessagesResponseHas(t *testing.T, c *client.CSAPI, roomID string, t.Fatalf("fetchUntilMessagesResponseHas timed out. Called check function %d times", checkCounter) } - messagesRes := c.MustDoFunc(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "messages"}, client.WithContentType("application/json"), client.WithQueries(url.Values{ + messagesRes := c.MustDo(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "messages"}, client.WithContentType("application/json"), client.WithQueries(url.Values{ "dir": []string{"b"}, "limit": []string{"100"}, })) @@ -378,7 +378,7 @@ func fetchUntilMessagesResponseHas(t *testing.T, c *client.CSAPI, roomID string, func getDebugMessageListFromMessagesResponse(t *testing.T, c *client.CSAPI, roomID string, expectedEventId string, actualEventId string, givenTimestamp int64) string { t.Helper() - messagesRes := c.MustDoFunc(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "messages"}, client.WithContentType("application/json"), client.WithQueries(url.Values{ + messagesRes := c.MustDo(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "messages"}, client.WithContentType("application/json"), client.WithQueries(url.Values{ // The events returned will be from the newest -> oldest since we're going backwards "dir": []string{"b"}, "limit": []string{"100"}, diff --git a/tests/unknown_endpoints_test.go b/tests/unknown_endpoints_test.go index f777ac44..19bd908f 100644 --- a/tests/unknown_endpoints_test.go +++ b/tests/unknown_endpoints_test.go @@ -5,7 +5,7 @@ import ( "testing" "github.com/matrix-org/complement/internal/b" - "github.com/matrix-org/complement/internal/client" + "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/match" "github.com/matrix-org/complement/internal/must" ) @@ -13,7 +13,7 @@ import ( func queryUnknownEndpoint(t *testing.T, user *client.CSAPI, paths []string) { t.Helper() - res := user.DoFunc(t, "GET", paths) + res := user.Do(t, "GET", paths) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: http.StatusNotFound, JSON: []match.JSON{ @@ -25,7 +25,7 @@ func queryUnknownEndpoint(t *testing.T, user *client.CSAPI, paths []string) { func queryUnknownMethod(t *testing.T, user *client.CSAPI, method string, paths []string) { t.Helper() - res := user.DoFunc(t, method, paths) + res := user.Do(t, method, paths) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: http.StatusMethodNotAllowed, JSON: []match.JSON{ From b8ef7fe4890caa7a2972fcedc3d64bf73aabefd0 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Tue, 3 Oct 2023 13:47:23 +0100 Subject: [PATCH 2/9] Add TestLike interface for using the client without a testing.T Also fix bad merge conflict --- client/auth.go | 16 +++--- client/client.go | 69 +++++++++++++++----------- client/sync.go | 5 +- tests/csapi/apidoc_room_forget_test.go | 2 +- 4 files changed, 50 insertions(+), 42 deletions(-) diff --git a/client/auth.go b/client/auth.go index 3284f82c..89d43fee 100644 --- a/client/auth.go +++ b/client/auth.go @@ -5,9 +5,7 @@ import ( "crypto/sha1" "encoding/hex" "io" - "testing" - "github.com/matrix-org/complement/internal/must" "github.com/tidwall/gjson" ) @@ -20,7 +18,7 @@ func WithDeviceID(deviceID string) LoginOpt { } // LoginUser will log in to a homeserver and create a new device on an existing user. -func (c *CSAPI) LoginUser(t *testing.T, localpart, password string, opts ...LoginOpt) (userID, accessToken, deviceID string) { +func (c *CSAPI) LoginUser(t TestLike, localpart, password string, opts ...LoginOpt) (userID, accessToken, deviceID string) { t.Helper() reqBody := map[string]interface{}{ "identifier": map[string]interface{}{ @@ -50,7 +48,7 @@ func (c *CSAPI) LoginUser(t *testing.T, localpart, password string, opts ...Logi // LoginUserWithRefreshToken will log in to a homeserver, with refresh token enabled, // and create a new device on an existing user. -func (c *CSAPI) LoginUserWithRefreshToken(t *testing.T, localpart, password string) (userID, accessToken, refreshToken, deviceID string, expiresInMs int64) { +func (c *CSAPI) LoginUserWithRefreshToken(t TestLike, localpart, password string) (userID, accessToken, refreshToken, deviceID string, expiresInMs int64) { t.Helper() reqBody := map[string]interface{}{ "identifier": map[string]interface{}{ @@ -77,7 +75,7 @@ func (c *CSAPI) LoginUserWithRefreshToken(t *testing.T, localpart, password stri } // RefreshToken will consume a refresh token and return a new access token and refresh token. -func (c *CSAPI) ConsumeRefreshToken(t *testing.T, refreshToken string) (newAccessToken, newRefreshToken string, expiresInMs int64) { +func (c *CSAPI) ConsumeRefreshToken(t TestLike, refreshToken string) (newAccessToken, newRefreshToken string, expiresInMs int64) { t.Helper() reqBody := map[string]interface{}{ "refresh_token": refreshToken, @@ -97,7 +95,7 @@ func (c *CSAPI) ConsumeRefreshToken(t *testing.T, refreshToken string) (newAcces // RegisterUser will register the user with given parameters and // return user ID, access token and device ID. It fails the test on network error. -func (c *CSAPI) RegisterUser(t *testing.T, localpart, password string) (userID, accessToken, deviceID string) { +func (c *CSAPI) RegisterUser(t TestLike, localpart, password string) (userID, accessToken, deviceID string) { t.Helper() reqBody := map[string]interface{}{ "auth": map[string]string{ @@ -121,13 +119,13 @@ func (c *CSAPI) RegisterUser(t *testing.T, localpart, password string) (userID, // RegisterSharedSecret registers a new account with a shared secret via HMAC // See https://github.com/matrix-org/synapse/blob/e550ab17adc8dd3c48daf7fedcd09418a73f524b/synapse/_scripts/register_new_matrix_user.py#L40 -func (c *CSAPI) RegisterSharedSecret(t *testing.T, user, pass string, isAdmin bool) (userID, accessToken, deviceID string) { +func (c *CSAPI) RegisterSharedSecret(t TestLike, user, pass string, isAdmin bool) (userID, accessToken, deviceID string) { resp := c.Do(t, "GET", []string{"_synapse", "admin", "v1", "register"}) if resp.StatusCode != 200 { t.Skipf("Homeserver image does not support shared secret registration, /_synapse/admin/v1/register returned HTTP %d", resp.StatusCode) return } - body := must.ParseJSON(t, resp.Body) + body := ParseJSON(t, resp) nonce := gjson.GetBytes(body, "nonce") if !nonce.Exists() { t.Fatalf("Malformed shared secret GET response: %s", string(body)) @@ -153,7 +151,7 @@ func (c *CSAPI) RegisterSharedSecret(t *testing.T, user, pass string, isAdmin bo "admin": isAdmin, } resp = c.MustDo(t, "POST", []string{"_synapse", "admin", "v1", "register"}, WithJSONBody(t, reqBody)) - body = must.ParseJSON(t, resp.Body) + body = ParseJSON(t, resp) userID = gjson.GetBytes(body, "user_id").Str accessToken = gjson.GetBytes(body, "access_token").Str deviceID = gjson.GetBytes(body, "device_id").Str diff --git a/client/client.go b/client/client.go index c4d02e21..39110619 100644 --- a/client/client.go +++ b/client/client.go @@ -12,7 +12,6 @@ import ( "strconv" "strings" "sync/atomic" - "testing" "time" "github.com/matrix-org/gomatrixserverlib" @@ -25,6 +24,18 @@ const ( SharedSecret = "complement" ) +// TestLike is an interface that testing.T satisfies. All client functions accept a TestLike interface, +// with the intention of a `testing.T` being passed into them. However, the client may be used in non-test +// scenarios e.g benchmarks, which can then use the same client by just implementing this interface. +type TestLike interface { + Helper() + Logf(msg string, args ...interface{}) + Skipf(msg string, args ...interface{}) + Error(args ...interface{}) + Errorf(msg string, args ...interface{}) + Fatalf(msg string, args ...interface{}) +} + type CtxKey string const ( @@ -55,7 +66,7 @@ type CSAPI struct { } // UploadContent uploads the provided content with an optional file name. Fails the test on error. Returns the MXC URI. -func (c *CSAPI) UploadContent(t *testing.T, fileBody []byte, fileName string, contentType string) string { +func (c *CSAPI) UploadContent(t TestLike, fileBody []byte, fileName string, contentType string) string { t.Helper() query := url.Values{} if fileName != "" { @@ -70,7 +81,7 @@ func (c *CSAPI) UploadContent(t *testing.T, fileBody []byte, fileName string, co } // DownloadContent downloads media from the server, returning the raw bytes and the Content-Type. Fails the test on error. -func (c *CSAPI) DownloadContent(t *testing.T, mxcUri string) ([]byte, string) { +func (c *CSAPI) DownloadContent(t TestLike, mxcUri string) ([]byte, string) { t.Helper() origin, mediaId := SplitMxc(mxcUri) res := c.MustDo(t, "GET", []string{"_matrix", "media", "v3", "download", origin, mediaId}) @@ -83,7 +94,7 @@ func (c *CSAPI) DownloadContent(t *testing.T, mxcUri string) ([]byte, string) { } // CreateRoom creates a room with an optional HTTP request body. Fails the test on error. Returns the room ID. -func (c *CSAPI) CreateRoom(t *testing.T, creationContent interface{}) string { +func (c *CSAPI) CreateRoom(t TestLike, creationContent interface{}) string { t.Helper() res := c.MustDo(t, "POST", []string{"_matrix", "client", "v3", "createRoom"}, WithJSONBody(t, creationContent)) body := ParseJSON(t, res) @@ -91,7 +102,7 @@ func (c *CSAPI) CreateRoom(t *testing.T, creationContent interface{}) string { } // JoinRoom joins the room ID or alias given, else fails the test. Returns the room ID. -func (c *CSAPI) JoinRoom(t *testing.T, roomIDOrAlias string, serverNames []string) string { +func (c *CSAPI) JoinRoom(t TestLike, roomIDOrAlias string, serverNames []string) string { t.Helper() // construct URL query parameters query := make(url.Values, len(serverNames)) @@ -113,7 +124,7 @@ func (c *CSAPI) JoinRoom(t *testing.T, roomIDOrAlias string, serverNames []strin } // LeaveRoom leaves the room ID, else fails the test. -func (c *CSAPI) LeaveRoom(t *testing.T, roomID string) { +func (c *CSAPI) LeaveRoom(t TestLike, roomID string) { t.Helper() // leave the room body := map[string]interface{}{} @@ -121,7 +132,7 @@ func (c *CSAPI) LeaveRoom(t *testing.T, roomID string) { } // InviteRoom invites userID to the room ID, else fails the test. -func (c *CSAPI) InviteRoom(t *testing.T, roomID string, userID string) { +func (c *CSAPI) InviteRoom(t TestLike, roomID string, userID string) { t.Helper() // Invite the user to the room body := map[string]interface{}{ @@ -130,19 +141,19 @@ func (c *CSAPI) InviteRoom(t *testing.T, roomID string, userID string) { c.MustDo(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "invite"}, WithJSONBody(t, body)) } -func (c *CSAPI) GetGlobalAccountData(t *testing.T, eventType string) *http.Response { +func (c *CSAPI) GetGlobalAccountData(t TestLike, eventType string) *http.Response { return c.MustDo(t, "GET", []string{"_matrix", "client", "v3", "user", c.UserID, "account_data", eventType}) } -func (c *CSAPI) SetGlobalAccountData(t *testing.T, eventType string, content map[string]interface{}) *http.Response { +func (c *CSAPI) SetGlobalAccountData(t TestLike, eventType string, content map[string]interface{}) *http.Response { return c.MustDo(t, "PUT", []string{"_matrix", "client", "v3", "user", c.UserID, "account_data", eventType}, WithJSONBody(t, content)) } -func (c *CSAPI) GetRoomAccountData(t *testing.T, roomID string, eventType string) *http.Response { +func (c *CSAPI) GetRoomAccountData(t TestLike, roomID string, eventType string) *http.Response { return c.MustDo(t, "GET", []string{"_matrix", "client", "v3", "user", c.UserID, "rooms", roomID, "account_data", eventType}) } -func (c *CSAPI) SetRoomAccountData(t *testing.T, roomID string, eventType string, content map[string]interface{}) *http.Response { +func (c *CSAPI) SetRoomAccountData(t TestLike, roomID string, eventType string, content map[string]interface{}) *http.Response { return c.MustDo(t, "PUT", []string{"_matrix", "client", "v3", "user", c.UserID, "rooms", roomID, "account_data", eventType}, WithJSONBody(t, content)) } @@ -159,7 +170,7 @@ func (c *CSAPI) SetRoomAccountData(t *testing.T, roomID string, eventType string // } // // Push rules are returned in the same order received from the homeserver. -func (c *CSAPI) GetAllPushRules(t *testing.T) gjson.Result { +func (c *CSAPI) GetAllPushRules(t TestLike) gjson.Result { t.Helper() // We have to supply an empty string to the end of this path in order to generate a trailing slash. @@ -184,7 +195,7 @@ func (c *CSAPI) GetAllPushRules(t *testing.T) gjson.Result { // map[string]interface{}{"set_tweak": "highlight"}, // }), // ) -func (c *CSAPI) GetPushRule(t *testing.T, scope string, kind string, ruleID string) gjson.Result { +func (c *CSAPI) GetPushRule(t TestLike, scope string, kind string, ruleID string) gjson.Result { t.Helper() res := c.MustDo(t, "GET", []string{"_matrix", "client", "v3", "pushrules", scope, kind, ruleID}) @@ -203,7 +214,7 @@ func (c *CSAPI) GetPushRule(t *testing.T, scope string, kind string, ruleID stri // c.SetPushRule(t, "global", "underride", "com.example.rule2", map[string]interface{}{ // "actions": []string{"dont_notify"}, // }, nil, "com.example.rule1") -func (c *CSAPI) SetPushRule(t *testing.T, scope string, kind string, ruleID string, body map[string]interface{}, before string, after string) *http.Response { +func (c *CSAPI) SetPushRule(t TestLike, scope string, kind string, ruleID string, body map[string]interface{}, before string, after string) *http.Response { t.Helper() // If the `before` or `after` arguments have been provided, construct same-named query parameters @@ -220,7 +231,7 @@ func (c *CSAPI) SetPushRule(t *testing.T, scope string, kind string, ruleID stri // SendEventUnsynced sends `e` into the room. // Returns the event ID of the sent event. -func (c *CSAPI) SendEventUnsynced(t *testing.T, roomID string, e b.Event) string { +func (c *CSAPI) SendEventUnsynced(t TestLike, roomID string, e b.Event) string { t.Helper() txnID := int(atomic.AddInt64(&c.txnID, 1)) return c.SendEventUnsyncedWithTxnID(t, roomID, e, strconv.Itoa(txnID)) @@ -229,7 +240,7 @@ func (c *CSAPI) SendEventUnsynced(t *testing.T, roomID string, e b.Event) string // SendEventUnsyncedWithTxnID sends `e` into the room with a prescribed transaction ID. // This is useful for writing tests that interrogate transaction semantics. // Returns the event ID of the sent event. -func (c *CSAPI) SendEventUnsyncedWithTxnID(t *testing.T, roomID string, e b.Event, txnID string) string { +func (c *CSAPI) SendEventUnsyncedWithTxnID(t TestLike, roomID string, e b.Event, txnID string) string { t.Helper() paths := []string{"_matrix", "client", "v3", "rooms", roomID, "send", e.Type, txnID} if e.StateKey != nil { @@ -243,7 +254,7 @@ func (c *CSAPI) SendEventUnsyncedWithTxnID(t *testing.T, roomID string, e b.Even // SendEventSynced sends `e` into the room and waits for its event ID to come down /sync. // Returns the event ID of the sent event. -func (c *CSAPI) SendEventSynced(t *testing.T, roomID string, e b.Event) string { +func (c *CSAPI) SendEventSynced(t TestLike, roomID string, e b.Event) string { t.Helper() eventID := c.SendEventUnsynced(t, roomID, e) t.Logf("SendEventSynced waiting for event ID %s", eventID) @@ -254,7 +265,7 @@ func (c *CSAPI) SendEventSynced(t *testing.T, roomID string, e b.Event) string { } // SendRedaction sends a redaction request. Will fail if the returned HTTP request code is not 200 -func (c *CSAPI) SendRedaction(t *testing.T, roomID string, e b.Event, eventID string) string { +func (c *CSAPI) SendRedaction(t TestLike, roomID string, e b.Event, eventID string) string { t.Helper() txnID := int(atomic.AddInt64(&c.txnID, 1)) paths := []string{"_matrix", "client", "v3", "rooms", roomID, "redact", eventID, strconv.Itoa(txnID)} @@ -264,7 +275,7 @@ func (c *CSAPI) SendRedaction(t *testing.T, roomID string, e b.Event, eventID st } // GetCapbabilities queries the server's capabilities -func (c *CSAPI) GetCapabilities(t *testing.T) []byte { +func (c *CSAPI) GetCapabilities(t TestLike) []byte { t.Helper() res := c.MustDo(t, "GET", []string{"_matrix", "client", "v3", "capabilities"}) body, err := io.ReadAll(res.Body) @@ -275,7 +286,7 @@ func (c *CSAPI) GetCapabilities(t *testing.T) []byte { } // GetDefaultRoomVersion returns the server's default room version -func (c *CSAPI) GetDefaultRoomVersion(t *testing.T) gomatrixserverlib.RoomVersion { +func (c *CSAPI) GetDefaultRoomVersion(t TestLike) gomatrixserverlib.RoomVersion { t.Helper() capabilities := c.GetCapabilities(t) defaultVersion := gjson.GetBytes(capabilities, `capabilities.m\.room_versions.default`) @@ -310,7 +321,7 @@ func WithContentType(cType string) RequestOpt { } // WithJSONBody sets the HTTP request body to the JSON serialised form of `obj` -func WithJSONBody(t *testing.T, obj interface{}) RequestOpt { +func WithJSONBody(t TestLike, obj interface{}) RequestOpt { return func(req *http.Request) { t.Helper() b, err := json.Marshal(obj) @@ -341,7 +352,7 @@ func WithRetryUntil(timeout time.Duration, untilFn func(res *http.Response) bool } // MustDo is the same as Do but fails the test if the returned HTTP response code is not 2xx. -func (c *CSAPI) MustDo(t *testing.T, method string, paths []string, opts ...RequestOpt) *http.Response { +func (c *CSAPI) MustDo(t TestLike, method string, paths []string, opts ...RequestOpt) *http.Response { t.Helper() res := c.Do(t, method, paths, opts...) if res.StatusCode < 200 || res.StatusCode >= 300 { @@ -365,7 +376,7 @@ func (c *CSAPI) MustDo(t *testing.T, method string, paths []string, opts ...Requ // match.JSONKeyEqual("errcode", "M_INVALID_USERNAME"), // }, // }) -func (c *CSAPI) Do(t *testing.T, method string, paths []string, opts ...RequestOpt) *http.Response { +func (c *CSAPI) Do(t TestLike, method string, paths []string, opts ...RequestOpt) *http.Response { t.Helper() for i := range paths { paths[i] = url.PathEscape(paths[i]) @@ -450,7 +461,7 @@ func (c *CSAPI) Do(t *testing.T, method string, paths []string, opts ...RequestO } // NewLoggedClient returns an http.Client which logs requests/responses -func NewLoggedClient(t *testing.T, hsName string, cli *http.Client) *http.Client { +func NewLoggedClient(t TestLike, hsName string, cli *http.Client) *http.Client { t.Helper() if cli == nil { cli = &http.Client{ @@ -466,7 +477,7 @@ func NewLoggedClient(t *testing.T, hsName string, cli *http.Client) *http.Client } type loggedRoundTripper struct { - t *testing.T + t TestLike hsName string wrap http.RoundTripper } @@ -483,7 +494,7 @@ func (t *loggedRoundTripper) RoundTrip(req *http.Request) (*http.Response, error } // GetJSONFieldStr extracts a value from a byte-encoded JSON body given a search key -func GetJSONFieldStr(t *testing.T, body []byte, wantKey string) string { +func GetJSONFieldStr(t TestLike, body []byte, wantKey string) string { t.Helper() res := gjson.GetBytes(body, wantKey) if !res.Exists() { @@ -495,7 +506,7 @@ func GetJSONFieldStr(t *testing.T, body []byte, wantKey string) string { return res.Str } -func GetJSONFieldStringArray(t *testing.T, body []byte, wantKey string) []string { +func GetJSONFieldStringArray(t TestLike, body []byte, wantKey string) []string { t.Helper() res := gjson.GetBytes(body, wantKey) @@ -519,7 +530,7 @@ func GetJSONFieldStringArray(t *testing.T, body []byte, wantKey string) []string } // ParseJSON parses a JSON-encoded HTTP Response body into a byte slice -func ParseJSON(t *testing.T, res *http.Response) []byte { +func ParseJSON(t TestLike, res *http.Response) []byte { t.Helper() defer res.Body.Close() body, err := io.ReadAll(res.Body) @@ -569,7 +580,7 @@ func SplitMxc(mxcUri string) (string, string) { // // The messages parameter is nested as follows: // user_id -> device_id -> content (map[string]interface{}) -func (c *CSAPI) SendToDeviceMessages(t *testing.T, evType string, messages map[string]map[string]map[string]interface{}) { +func (c *CSAPI) SendToDeviceMessages(t TestLike, evType string, messages map[string]map[string]map[string]interface{}) { t.Helper() txnID := int(atomic.AddInt64(&c.txnID, 1)) c.MustDo( diff --git a/client/sync.go b/client/sync.go index 6634dd23..cf154cd1 100644 --- a/client/sync.go +++ b/client/sync.go @@ -4,7 +4,6 @@ import ( "fmt" "net/url" "strings" - "testing" "time" "github.com/tidwall/gjson" @@ -86,7 +85,7 @@ type SyncReq struct { // // Will time out after CSAPI.SyncUntilTimeout. Returns the `next_batch` token from the final // response. -func (c *CSAPI) MustSyncUntil(t *testing.T, syncReq SyncReq, checks ...SyncCheckOpt) string { +func (c *CSAPI) MustSyncUntil(t TestLike, syncReq SyncReq, checks ...SyncCheckOpt) string { t.Helper() start := time.Now() numResponsesReturned := 0 @@ -139,7 +138,7 @@ func (c *CSAPI) MustSyncUntil(t *testing.T, syncReq SyncReq, checks ...SyncCheck // // Fails the test if the /sync request does not return 200 OK. // Returns the top-level parsed /sync response JSON as well as the next_batch token from the response. -func (c *CSAPI) MustSync(t *testing.T, syncReq SyncReq) (gjson.Result, string) { +func (c *CSAPI) MustSync(t TestLike, syncReq SyncReq) (gjson.Result, string) { t.Helper() query := url.Values{ "timeout": []string{"1000"}, diff --git a/tests/csapi/apidoc_room_forget_test.go b/tests/csapi/apidoc_room_forget_test.go index c927b58e..a7f886d5 100644 --- a/tests/csapi/apidoc_room_forget_test.go +++ b/tests/csapi/apidoc_room_forget_test.go @@ -47,7 +47,7 @@ func TestRoomForget(t *testing.T) { }, }) alice.LeaveRoom(t, roomID) - alice.MustDo(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "forget"}, , client.WithJSONBody(t, struct{}{})) + alice.MustDo(t, "POST", []string{"_matrix", "client", "v3", "rooms", roomID, "forget"}, client.WithJSONBody(t, struct{}{})) res := alice.Do(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "messages"}) must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: http.StatusForbidden, From 81193acb39d2c10b8aa9d6945237eea5c866369e Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Tue, 3 Oct 2023 14:36:15 +0100 Subject: [PATCH 3/9] Add GenerateOneTimeKeys, Prefix Unsafe_ to unsafe functions --- client/client.go | 67 ++++++++++++++++++++++++---- tests/csapi/keychanges_test.go | 2 +- tests/csapi/room_relations_test.go | 10 ++--- tests/csapi/txnid_test.go | 20 ++++----- tests/csapi/upload_keys_test.go | 52 +-------------------- tests/federation_upload_keys_test.go | 51 +-------------------- 6 files changed, 78 insertions(+), 124 deletions(-) diff --git a/client/client.go b/client/client.go index 39110619..0066d6c6 100644 --- a/client/client.go +++ b/client/client.go @@ -16,6 +16,7 @@ import ( "github.com/matrix-org/gomatrixserverlib" "github.com/tidwall/gjson" + "maunium.net/go/mautrix/crypto/olm" "github.com/matrix-org/complement/internal/b" ) @@ -36,10 +37,10 @@ type TestLike interface { Fatalf(msg string, args ...interface{}) } -type CtxKey string +type ctxKey string const ( - CtxKeyWithRetryUntil CtxKey = "complement_retry_until" // contains *retryUntilParams + CtxKeyWithRetryUntil ctxKey = "complement_retry_until" // contains *retryUntilParams ) type retryUntilParams struct { @@ -229,18 +230,20 @@ func (c *CSAPI) SetPushRule(t TestLike, scope string, kind string, ruleID string return c.MustDo(t, "PUT", []string{"_matrix", "client", "v3", "pushrules", scope, kind, ruleID}, WithJSONBody(t, body), WithQueries(queryParams)) } -// SendEventUnsynced sends `e` into the room. +// Unsafe_SendEventUnsynced sends `e` into the room. This function is UNSAFE as it does not wait +// for the event to be fully processed. This can cause flakey tests. Prefer `SendEventSynced`. // Returns the event ID of the sent event. -func (c *CSAPI) SendEventUnsynced(t TestLike, roomID string, e b.Event) string { +func (c *CSAPI) Unsafe_SendEventUnsynced(t TestLike, roomID string, e b.Event) string { t.Helper() txnID := int(atomic.AddInt64(&c.txnID, 1)) - return c.SendEventUnsyncedWithTxnID(t, roomID, e, strconv.Itoa(txnID)) + return c.Unsafe_SendEventUnsyncedWithTxnID(t, roomID, e, strconv.Itoa(txnID)) } // SendEventUnsyncedWithTxnID sends `e` into the room with a prescribed transaction ID. -// This is useful for writing tests that interrogate transaction semantics. +// This is useful for writing tests that interrogate transaction semantics. This function is UNSAFE +// as it does not wait for the event to be fully processed. This can cause flakey tests. Prefer `SendEventSynced`. // Returns the event ID of the sent event. -func (c *CSAPI) SendEventUnsyncedWithTxnID(t TestLike, roomID string, e b.Event, txnID string) string { +func (c *CSAPI) Unsafe_SendEventUnsyncedWithTxnID(t TestLike, roomID string, e b.Event, txnID string) string { t.Helper() paths := []string{"_matrix", "client", "v3", "rooms", roomID, "send", e.Type, txnID} if e.StateKey != nil { @@ -256,7 +259,7 @@ func (c *CSAPI) SendEventUnsyncedWithTxnID(t TestLike, roomID string, e b.Event, // Returns the event ID of the sent event. func (c *CSAPI) SendEventSynced(t TestLike, roomID string, e b.Event) string { t.Helper() - eventID := c.SendEventUnsynced(t, roomID, e) + eventID := c.Unsafe_SendEventUnsynced(t, roomID, e) t.Logf("SendEventSynced waiting for event ID %s", eventID) c.MustSyncUntil(t, SyncReq{}, SyncTimelineHas(roomID, func(r gjson.Result) bool { return r.Get("event_id").Str == eventID @@ -298,6 +301,54 @@ func (c *CSAPI) GetDefaultRoomVersion(t TestLike) gomatrixserverlib.RoomVersion return gomatrixserverlib.RoomVersion(defaultVersion.Str) } +func (c *CSAPI) GenerateOneTimeKeys(t TestLike, otkCount uint) (deviceKeys map[string]interface{}, oneTimeKeys map[string]interface{}) { + t.Helper() + account := olm.NewAccount() + ed25519Key, curveKey := account.IdentityKeys() + + ed25519KeyID := fmt.Sprintf("ed25519:%s", c.DeviceID) + curveKeyID := fmt.Sprintf("curve25519:%s", c.DeviceID) + + deviceKeys = map[string]interface{}{ + "user_id": c.UserID, + "device_id": c.DeviceID, + "algorithms": []interface{}{"m.olm.v1.curve25519-aes-sha2", "m.megolm.v1.aes-sha2"}, + "keys": map[string]interface{}{ + ed25519KeyID: ed25519Key.String(), + curveKeyID: curveKey.String(), + }, + } + + signature, _ := account.SignJSON(deviceKeys) + + deviceKeys["signatures"] = map[string]interface{}{ + c.UserID: map[string]interface{}{ + ed25519KeyID: signature, + }, + } + + account.GenOneTimeKeys(otkCount) + oneTimeKeys = map[string]interface{}{} + + for kid, key := range account.OneTimeKeys() { + keyID := fmt.Sprintf("signed_curve25519:%s", kid) + keyMap := map[string]interface{}{ + "key": key.String(), + } + + signature, _ = account.SignJSON(keyMap) + + keyMap["signatures"] = map[string]interface{}{ + c.UserID: map[string]interface{}{ + ed25519KeyID: signature, + }, + } + + oneTimeKeys[keyID] = keyMap + } + return deviceKeys, oneTimeKeys +} + // WithRawBody sets the HTTP request body to `body` func WithRawBody(body []byte) RequestOpt { return func(req *http.Request) { diff --git a/tests/csapi/keychanges_test.go b/tests/csapi/keychanges_test.go index d8abc525..ffc25c12 100644 --- a/tests/csapi/keychanges_test.go +++ b/tests/csapi/keychanges_test.go @@ -97,7 +97,7 @@ func TestKeyChangesLocal(t *testing.T) { func mustUploadKeys(t *testing.T, user *client.CSAPI) { t.Helper() - deviceKeys, oneTimeKeys := generateKeys(t, user, 5) + deviceKeys, oneTimeKeys := user.GenerateOneTimeKeys(t, 5) reqBody := client.WithJSONBody(t, map[string]interface{}{ "device_keys": deviceKeys, "one_time_keys": oneTimeKeys, diff --git a/tests/csapi/room_relations_test.go b/tests/csapi/room_relations_test.go index 9187c3ba..adbe4eb6 100644 --- a/tests/csapi/room_relations_test.go +++ b/tests/csapi/room_relations_test.go @@ -217,7 +217,7 @@ func TestRelationsPaginationSync(t *testing.T) { roomID := alice.CreateRoom(t, map[string]interface{}{"preset": "public_chat"}) _, token := alice.MustSync(t, client.SyncReq{}) - rootEventID := alice.SendEventUnsynced(t, roomID, b.Event{ + rootEventID := alice.Unsafe_SendEventUnsynced(t, roomID, b.Event{ Type: "m.room.message", Content: map[string]interface{}{ "msgtype": "m.text", @@ -227,9 +227,9 @@ func TestRelationsPaginationSync(t *testing.T) { }) // Create some related events. - event_id := "" + eventID := "" for i := 0; i < 5; i++ { - event_id = alice.SendEventUnsynced(t, roomID, b.Event{ + eventID = alice.Unsafe_SendEventUnsynced(t, roomID, b.Event{ Type: "m.room.message", Content: map[string]interface{}{ "msgtype": "m.text", @@ -245,13 +245,13 @@ func TestRelationsPaginationSync(t *testing.T) { // Sync and keep the token. nextBatch := alice.MustSyncUntil(t, client.SyncReq{Since: token}, client.SyncTimelineHas(roomID, func(r gjson.Result) bool { - return r.Get("event_id").Str == event_id + return r.Get("event_id").Str == eventID })) // Create more related events. event_ids := [5]string{} for i := 0; i < 5; i++ { - event_ids[i] = alice.SendEventUnsynced(t, roomID, b.Event{ + event_ids[i] = alice.Unsafe_SendEventUnsynced(t, roomID, b.Event{ Type: "m.room.message", Content: map[string]interface{}{ "msgtype": "m.text", diff --git a/tests/csapi/txnid_test.go b/tests/csapi/txnid_test.go index 4ce2d0ca..e91e9cbb 100644 --- a/tests/csapi/txnid_test.go +++ b/tests/csapi/txnid_test.go @@ -27,7 +27,7 @@ func TestTxnInEvent(t *testing.T) { txnId := "abcdefg" // Let's send an event, and wait for it to appear in the timeline. - eventID := c.SendEventUnsyncedWithTxnID(t, roomID, b.Event{ + eventID := c.Unsafe_SendEventUnsyncedWithTxnID(t, roomID, b.Event{ Type: "m.room.message", Content: map[string]interface{}{ "msgtype": "m.text", @@ -82,7 +82,7 @@ func TestTxnScopeOnLocalEcho(t *testing.T) { txnId := "abdefgh" // Let's send an event, and wait for it to appear in the timeline. - eventID := c1.SendEventUnsyncedWithTxnID(t, roomID, b.Event{ + eventID := c1.Unsafe_SendEventUnsyncedWithTxnID(t, roomID, b.Event{ Type: "m.room.message", Content: map[string]interface{}{ "msgtype": "m.text", @@ -128,7 +128,7 @@ func TestTxnIdempotencyScopedToDevice(t *testing.T) { }, } // send an event with set txnId - eventID1 := c1.SendEventUnsyncedWithTxnID(t, roomID, event, txnId) + eventID1 := c1.Unsafe_SendEventUnsyncedWithTxnID(t, roomID, event, txnId) // Create a second client, inheriting the first device ID. c2 := deployment.Client(t, "hs1", "") @@ -136,7 +136,7 @@ func TestTxnIdempotencyScopedToDevice(t *testing.T) { must.EqualStr(t, c1.DeviceID, c2.DeviceID, "Device ID should be the same") // send another event with the same txnId via the second client - eventID2 := c2.SendEventUnsyncedWithTxnID(t, roomID, event, txnId) + eventID2 := c2.Unsafe_SendEventUnsyncedWithTxnID(t, roomID, event, txnId) // the two events should have the same event IDs as they came from the same device must.EqualStr(t, eventID2, eventID1, "Expected eventID1 and eventID2 to be the same from two clients sharing the same device ID") @@ -178,20 +178,20 @@ func TestTxnIdempotency(t *testing.T) { } // we send the event and get an event ID back - eventID1 := c1.SendEventUnsyncedWithTxnID(t, roomID1, event1, txnId) + eventID1 := c1.Unsafe_SendEventUnsyncedWithTxnID(t, roomID1, event1, txnId) // we send the identical event again and should get back the same event ID - eventID2 := c1.SendEventUnsyncedWithTxnID(t, roomID1, event1, txnId) + eventID2 := c1.Unsafe_SendEventUnsyncedWithTxnID(t, roomID1, event1, txnId) must.EqualStr(t, eventID2, eventID1, "Expected eventID1 and eventID2 to be the same, but they were not") // even if we change the content we should still get back the same event ID as transaction ID is the same - eventID3 := c1.SendEventUnsyncedWithTxnID(t, roomID1, event2, txnId) + eventID3 := c1.Unsafe_SendEventUnsyncedWithTxnID(t, roomID1, event2, txnId) must.EqualStr(t, eventID3, eventID1, "Expected eventID3 and eventID2 to be the same even with different content, but they were not") // if we change the room ID we should be able to use the same transaction ID - eventID4 := c1.SendEventUnsyncedWithTxnID(t, roomID2, event1, txnId) + eventID4 := c1.Unsafe_SendEventUnsyncedWithTxnID(t, roomID2, event1, txnId) must.NotEqualStr(t, eventID4, eventID3, "Expected eventID4 and eventID3 to be different, but they were not") } @@ -217,7 +217,7 @@ func TestTxnIdWithRefreshToken(t *testing.T) { txnId := "abcdef" // We send an event - eventID1 := c.SendEventUnsyncedWithTxnID(t, roomID, b.Event{ + eventID1 := c.Unsafe_SendEventUnsyncedWithTxnID(t, roomID, b.Event{ Type: "m.room.message", Content: map[string]interface{}{ "msgtype": "m.text", @@ -233,7 +233,7 @@ func TestTxnIdWithRefreshToken(t *testing.T) { c.MustSyncUntil(t, client.SyncReq{}, mustHaveTransactionIDForEvent(t, roomID, eventID1, txnId)) // We try sending the event again with the same transaction ID - eventID2 := c.SendEventUnsyncedWithTxnID(t, roomID, b.Event{ + eventID2 := c.Unsafe_SendEventUnsyncedWithTxnID(t, roomID, b.Event{ Type: "m.room.message", Content: map[string]interface{}{ "msgtype": "m.text", diff --git a/tests/csapi/upload_keys_test.go b/tests/csapi/upload_keys_test.go index 3597ae81..d7b96e59 100644 --- a/tests/csapi/upload_keys_test.go +++ b/tests/csapi/upload_keys_test.go @@ -7,7 +7,6 @@ import ( "testing" "github.com/tidwall/gjson" - "maunium.net/go/mautrix/crypto/olm" "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" @@ -23,7 +22,8 @@ func TestUploadKey(t *testing.T) { alice := deployment.Client(t, "hs1", "@alice:hs1") bob := deployment.Client(t, "hs1", "@bob:hs1") - deviceKeys, oneTimeKeys := generateKeys(t, alice, 1) + deviceKeys, oneTimeKeys := alice.GenerateOneTimeKeys(t, 1) + t.Run("Parallel", func(t *testing.T) { // sytest: Can upload device keys t.Run("Can upload device keys", func(t *testing.T) { @@ -172,51 +172,3 @@ func TestUploadKey(t *testing.T) { }) }) } - -func generateKeys(t *testing.T, user *client.CSAPI, otkCount uint) (deviceKeys map[string]interface{}, oneTimeKeys map[string]interface{}) { - t.Helper() - account := olm.NewAccount() - ed25519Key, curveKey := account.IdentityKeys() - - ed25519KeyID := fmt.Sprintf("ed25519:%s", user.DeviceID) - curveKeyID := fmt.Sprintf("curve25519:%s", user.DeviceID) - - deviceKeys = map[string]interface{}{ - "user_id": user.UserID, - "device_id": user.DeviceID, - "algorithms": []interface{}{"m.olm.v1.curve25519-aes-sha2", "m.megolm.v1.aes-sha2"}, - "keys": map[string]interface{}{ - ed25519KeyID: ed25519Key.String(), - curveKeyID: curveKey.String(), - }, - } - - signature, _ := account.SignJSON(deviceKeys) - - deviceKeys["signatures"] = map[string]interface{}{ - user.UserID: map[string]interface{}{ - ed25519KeyID: signature, - }, - } - - account.GenOneTimeKeys(otkCount) - oneTimeKeys = map[string]interface{}{} - - for kid, key := range account.OneTimeKeys() { - keyID := fmt.Sprintf("signed_curve25519:%s", kid) - keyMap := map[string]interface{}{ - "key": key.String(), - } - - signature, _ = account.SignJSON(keyMap) - - keyMap["signatures"] = map[string]interface{}{ - user.UserID: map[string]interface{}{ - ed25519KeyID: signature, - }, - } - - oneTimeKeys[keyID] = keyMap - } - return deviceKeys, oneTimeKeys -} diff --git a/tests/federation_upload_keys_test.go b/tests/federation_upload_keys_test.go index 2f32d042..23a5ccdd 100644 --- a/tests/federation_upload_keys_test.go +++ b/tests/federation_upload_keys_test.go @@ -7,7 +7,6 @@ import ( "testing" "github.com/tidwall/gjson" - "maunium.net/go/mautrix/crypto/olm" "github.com/matrix-org/complement/client" "github.com/matrix-org/complement/internal/b" @@ -25,7 +24,7 @@ func TestFederationKeyUploadQuery(t *testing.T) { // Do an initial sync so that we can see the changes come down sync. _, nextBatchBeforeKeyUpload := bob.MustSync(t, client.SyncReq{}) - deviceKeys, oneTimeKeys := generateKeys(t, alice, 1) + deviceKeys, oneTimeKeys := alice.GenerateOneTimeKeys(t, 1) // Upload keys reqBody := client.WithJSONBody(t, map[string]interface{}{ "device_keys": deviceKeys, @@ -134,51 +133,3 @@ func TestFederationKeyUploadQuery(t *testing.T) { }) }) } - -func generateKeys(t *testing.T, user *client.CSAPI, otkCount uint) (deviceKeys map[string]interface{}, oneTimeKeys map[string]interface{}) { - t.Helper() - account := olm.NewAccount() - ed25519Key, curveKey := account.IdentityKeys() - - ed25519KeyID := fmt.Sprintf("ed25519:%s", user.DeviceID) - curveKeyID := fmt.Sprintf("curve25519:%s", user.DeviceID) - - deviceKeys = map[string]interface{}{ - "user_id": user.UserID, - "device_id": user.DeviceID, - "algorithms": []interface{}{"m.olm.v1.curve25519-aes-sha2", "m.megolm.v1.aes-sha2"}, - "keys": map[string]interface{}{ - ed25519KeyID: ed25519Key.String(), - curveKeyID: curveKey.String(), - }, - } - - signature, _ := account.SignJSON(deviceKeys) - - deviceKeys["signatures"] = map[string]interface{}{ - user.UserID: map[string]interface{}{ - ed25519KeyID: signature, - }, - } - - account.GenOneTimeKeys(otkCount) - oneTimeKeys = map[string]interface{}{} - - for kid, key := range account.OneTimeKeys() { - keyID := fmt.Sprintf("signed_curve25519:%s", kid) - keyMap := map[string]interface{}{ - "key": key.String(), - } - - signature, _ = account.SignJSON(keyMap) - - keyMap["signatures"] = map[string]interface{}{ - user.UserID: map[string]interface{}{ - ed25519KeyID: signature, - }, - } - - oneTimeKeys[keyID] = keyMap - } - return deviceKeys, oneTimeKeys -} From d68b04419191c9330b4d0fa36892a78a1826c04c Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Tue, 3 Oct 2023 14:56:20 +0100 Subject: [PATCH 4/9] Add dedicated federation.Event Fixes #381 --- client/client.go | 3 +++ internal/b/blueprints.go | 18 --------------- internal/federation/server.go | 7 +++--- internal/federation/server_room.go | 22 +++++++++++++++++-- tests/csapi/sync_test.go | 9 ++++---- tests/direct_messaging_test.go | 2 +- tests/federation_redaction_test.go | 19 +++++++++------- tests/federation_room_event_auth_test.go | 10 ++++----- ...federation_room_get_missing_events_test.go | 8 +++---- tests/federation_room_join_test.go | 18 +++++++-------- tests/federation_unreject_rejected_test.go | 10 ++++----- 11 files changed, 65 insertions(+), 61 deletions(-) diff --git a/client/client.go b/client/client.go index 0066d6c6..f624aa6f 100644 --- a/client/client.go +++ b/client/client.go @@ -249,6 +249,9 @@ func (c *CSAPI) Unsafe_SendEventUnsyncedWithTxnID(t TestLike, roomID string, e b if e.StateKey != nil { paths = []string{"_matrix", "client", "v3", "rooms", roomID, "state", e.Type, *e.StateKey} } + if e.Sender != "" { + t.Fatalf("Event.Sender must not be set, as this is set by the client in use (%s)", c.UserID) + } res := c.MustDo(t, "PUT", paths, WithJSONBody(t, e.Content)) body := ParseJSON(t, res) eventID := GetJSONFieldStr(t, body, "event_id") diff --git a/internal/b/blueprints.go b/internal/b/blueprints.go index 70976776..11aea5c2 100644 --- a/internal/b/blueprints.go +++ b/internal/b/blueprints.go @@ -97,24 +97,6 @@ type Event struct { Sender string StateKey *string Content map[string]interface{} - - /* The following fields are ignored in blueprints as clients are unable to set them. - * They are used with federation.Server. - */ - - Unsigned map[string]interface{} - - // The events needed to authenticate this event. - // This can be either []EventReference for room v1/v2, or []string for room v3 onwards. - // If it is left at nil, MustCreateEvent will populate it automatically based on the room state. - AuthEvents interface{} - - // The prev events of the event if we want to override or falsify them. - // If it is left at nil, MustCreateEvent will populate it automatically based on the forward extremities. - PrevEvents interface{} - - // If this is a redaction, the event that it redacts - Redacts string } func MustValidate(bp Blueprint) Blueprint { diff --git a/internal/federation/server.go b/internal/federation/server.go index c82827a7..448db2c8 100644 --- a/internal/federation/server.go +++ b/internal/federation/server.go @@ -29,7 +29,6 @@ import ( "github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/util" - "github.com/matrix-org/complement/internal/b" "github.com/matrix-org/complement/internal/config" "github.com/matrix-org/complement/internal/docker" ) @@ -162,7 +161,7 @@ func (s *Server) MakeAliasMapping(aliasLocalpart, roomID string) string { // MustMakeRoom will add a room to this server so it is accessible to other servers when prompted via federation. // The `events` will be added to this room. Returns the created room. -func (s *Server) MustMakeRoom(t *testing.T, roomVer gomatrixserverlib.RoomVersion, events []b.Event) *ServerRoom { +func (s *Server) MustMakeRoom(t *testing.T, roomVer gomatrixserverlib.RoomVersion, events []Event) *ServerRoom { if !s.listening { s.t.Fatalf("MustMakeRoom() called before Listen() - this is not supported because Listen() chooses a high-numbered port and thus changes the server name and thus changes the room ID. Ensure you Listen() first!") } @@ -291,7 +290,7 @@ func (s *Server) DoFederationRequest( // MustCreateEvent will create and sign a new latest event for the given room. // It does not insert this event into the room however. See ServerRoom.AddEvent for that. -func (s *Server) MustCreateEvent(t *testing.T, room *ServerRoom, ev b.Event) gomatrixserverlib.PDU { +func (s *Server) MustCreateEvent(t *testing.T, room *ServerRoom, ev Event) gomatrixserverlib.PDU { t.Helper() content, err := json.Marshal(ev.Content) if err != nil { @@ -451,7 +450,7 @@ func (s *Server) MustLeaveRoom(t *testing.T, deployment *docker.Deployment, remo } } else { // make the leave event - leaveEvent = s.MustCreateEvent(t, room, b.Event{ + leaveEvent = s.MustCreateEvent(t, room, Event{ Type: "m.room.member", StateKey: &userID, Sender: userID, diff --git a/internal/federation/server_room.go b/internal/federation/server_room.go index 82e1ef7f..a0b46c55 100644 --- a/internal/federation/server_room.go +++ b/internal/federation/server_room.go @@ -11,6 +11,24 @@ import ( "github.com/matrix-org/complement/internal/b" ) +type Event struct { + Type string + Sender string + StateKey *string + Content map[string]interface{} + + Unsigned map[string]interface{} + // The events needed to authenticate this event. + // This can be either []EventReference for room v1/v2, or []string for room v3 onwards. + // If it is left at nil, MustCreateEvent will populate it automatically based on the room state. + AuthEvents interface{} + // The prev events of the event if we want to override or falsify them. + // If it is left at nil, MustCreateEvent will populate it automatically based on the forward extremities. + PrevEvents interface{} + // If this is a redaction, the event that it redacts + Redacts string +} + // ServerRoom represents a room on this test federation server type ServerRoom struct { Version gomatrixserverlib.RoomVersion @@ -212,13 +230,13 @@ func initialPowerLevelsContent(roomCreator string) (c gomatrixserverlib.PowerLev } // InitialRoomEvents returns the initial set of events that get created when making a room. -func InitialRoomEvents(roomVer gomatrixserverlib.RoomVersion, creator string) []b.Event { +func InitialRoomEvents(roomVer gomatrixserverlib.RoomVersion, creator string) []Event { // need to serialise/deserialise to get map[string]interface{} annoyingly plContent := initialPowerLevelsContent(creator) plBytes, _ := json.Marshal(plContent) var plContentMap map[string]interface{} json.Unmarshal(plBytes, &plContentMap) - return []b.Event{ + return []Event{ { Type: "m.room.create", StateKey: b.Ptr(""), diff --git a/tests/csapi/sync_test.go b/tests/csapi/sync_test.go index 98ee05af..918e9637 100644 --- a/tests/csapi/sync_test.go +++ b/tests/csapi/sync_test.go @@ -291,17 +291,16 @@ func TestSync(t *testing.T) { // a good event - in another room - to act as a sentinel. It's not // guaranteed, but hopefully if the sentinel is received, so was the // redaction. - redactionEvent := srv.MustCreateEvent(t, redactionRoom, b.Event{ + redactionEvent := srv.MustCreateEvent(t, redactionRoom, federation.Event{ Type: "m.room.redaction", Sender: charlie, Content: map[string]interface{}{}, - Redacts: "$12345", - }) + Redacts: "$12345"}) redactionRoom.AddEvent(redactionEvent) t.Logf("Created redaction event %s", redactionEvent.EventID()) srv.MustSendTransaction(t, deployment, "hs1", []json.RawMessage{redactionEvent.JSON()}, nil) - sentinelEvent := srv.MustCreateEvent(t, sentinelRoom, b.Event{ + sentinelEvent := srv.MustCreateEvent(t, sentinelRoom, federation.Event{ Type: "m.room.test", Sender: charlie, Content: map[string]interface{}{"body": "1234"}, @@ -318,7 +317,7 @@ func TestSync(t *testing.T) { pdus := make([]json.RawMessage, 11) var lastSentEventId string for i := range pdus { - ev := srv.MustCreateEvent(t, redactionRoom, b.Event{ + ev := srv.MustCreateEvent(t, redactionRoom, federation.Event{ Type: "m.room.message", Sender: charlie, Content: map[string]interface{}{}, diff --git a/tests/direct_messaging_test.go b/tests/direct_messaging_test.go index 7ed86598..93854111 100644 --- a/tests/direct_messaging_test.go +++ b/tests/direct_messaging_test.go @@ -126,7 +126,7 @@ func TestIsDirectFlagFederation(t *testing.T) { bob := srv.UserID("bob") room := srv.MustMakeRoom(t, roomVer, federation.InitialRoomEvents(roomVer, bob)) - dmInviteEvent := srv.MustCreateEvent(t, room, b.Event{ + dmInviteEvent := srv.MustCreateEvent(t, room, federation.Event{ Type: "m.room.member", StateKey: &alice.UserID, Sender: bob, diff --git a/tests/federation_redaction_test.go b/tests/federation_redaction_test.go index ef9a89a6..29c2c00b 100644 --- a/tests/federation_redaction_test.go +++ b/tests/federation_redaction_test.go @@ -1,12 +1,13 @@ package tests import ( + "testing" + "time" + "github.com/matrix-org/complement/internal/b" "github.com/matrix-org/complement/internal/federation" "github.com/matrix-org/complement/runtime" "github.com/matrix-org/gomatrixserverlib" - "testing" - "time" ) // test that a redaction is sent out over federation even if we don't have the original event @@ -56,13 +57,12 @@ func TestFederationRedactSendsWithoutEvent(t *testing.T) { alice.JoinRoom(t, roomAlias, []string{srv.ServerName()}) // inject event to redact in the room - badEvent := srv.MustCreateEvent(t, serverRoom, b.Event{ + badEvent := srv.MustCreateEvent(t, serverRoom, federation.Event{ Type: "m.room.message", Sender: charlie, Content: map[string]interface{}{ "body": "666", - }, - }) + }}) serverRoom.AddEvent(badEvent) eventID := badEvent.EventID() @@ -70,9 +70,12 @@ func TestFederationRedactSendsWithoutEvent(t *testing.T) { eventToRedact := eventID + ":" + fullServerName // the client sends a request to the local homeserver to send the redaction - res := alice.SendRedaction(t, serverRoom.RoomID, b.Event{Type: wantEventType, Content: map[string]interface{}{ - "msgtype": "m.room.redaction"}, - Redacts: eventToRedact}, eventToRedact) + res := alice.SendRedaction(t, serverRoom.RoomID, b.Event{ + Type: wantEventType, + Content: map[string]interface{}{ + "reason": "reasons...", + }, + }, eventToRedact) // wait for redaction to arrive at remote homeserver waiter.Wait(t, 1*time.Second) diff --git a/tests/federation_room_event_auth_test.go b/tests/federation_room_event_auth_test.go index 58d3f08e..3a317ba4 100644 --- a/tests/federation_room_event_auth_test.go +++ b/tests/federation_room_event_auth_test.go @@ -118,7 +118,7 @@ func TestInboundFederationRejectsEventsWithRejectedAuthEvents(t *testing.T) { charlieMembershipEvent := room.CurrentState("m.room.member", charlie) // have Charlie send a PL event which will be rejected - rejectedEvent := srv.MustCreateEvent(t, room, b.Event{ + rejectedEvent := srv.MustCreateEvent(t, room, federation.Event{ Type: "m.room.power_levels", StateKey: b.Ptr(""), Sender: charlie, @@ -140,7 +140,7 @@ func TestInboundFederationRejectsEventsWithRejectedAuthEvents(t *testing.T) { // create an event to be pulled in as an outlier, which is valid according to its prev events, // but uses the rejected event among its auth events. - outlierEvent := srv.MustCreateEvent(t, room, b.Event{ + outlierEvent := srv.MustCreateEvent(t, room, federation.Event{ Type: "m.room.member", StateKey: &charlie, Sender: charlie, @@ -166,7 +166,7 @@ func TestInboundFederationRejectsEventsWithRejectedAuthEvents(t *testing.T) { charlieMembershipEvent, outlierEvent, } - sentEvent1 := srv.MustCreateEvent(t, room, b.Event{ + sentEvent1 := srv.MustCreateEvent(t, room, federation.Event{ Type: "m.room.message", Sender: charlie, Content: map[string]interface{}{"body": "sentEvent1"}, @@ -178,7 +178,7 @@ func TestInboundFederationRejectsEventsWithRejectedAuthEvents(t *testing.T) { // another a regular event which refers to the outlier event, but // this time we will give a different answer to /event_auth - sentEvent2 := srv.MustCreateEvent(t, room, b.Event{ + sentEvent2 := srv.MustCreateEvent(t, room, federation.Event{ Type: "m.room.message", Sender: charlie, Content: map[string]interface{}{"body": "sentEvent1"}, @@ -190,7 +190,7 @@ func TestInboundFederationRejectsEventsWithRejectedAuthEvents(t *testing.T) { t.Logf("Created sent event 2 %s", sentEvent2.EventID()) // finally, a genuine regular event. - sentinelEvent := srv.MustCreateEvent(t, room, b.Event{ + sentinelEvent := srv.MustCreateEvent(t, room, federation.Event{ Type: "m.room.message", Sender: charlie, Content: map[string]interface{}{"body": "sentinelEvent"}, diff --git a/tests/federation_room_get_missing_events_test.go b/tests/federation_room_get_missing_events_test.go index 48c84e01..a568af79 100644 --- a/tests/federation_room_get_missing_events_test.go +++ b/tests/federation_room_get_missing_events_test.go @@ -73,7 +73,7 @@ func TestGetMissingEventsGapFilling(t *testing.T) { var missingEventIDs []string numMissingEvents := 5 for i := 0; i < numMissingEvents; i++ { - missingEvent := srv.MustCreateEvent(t, srvRoom, b.Event{ + missingEvent := srv.MustCreateEvent(t, srvRoom, federation.Event{ Sender: bob, Type: "m.room.message", Content: map[string]interface{}{ @@ -86,7 +86,7 @@ func TestGetMissingEventsGapFilling(t *testing.T) { } // 3) Inject a final event into Complement - mostRecentEvent := srv.MustCreateEvent(t, srvRoom, b.Event{ + mostRecentEvent := srv.MustCreateEvent(t, srvRoom, federation.Event{ Sender: bob, Type: "m.room.message", Content: map[string]interface{}{ @@ -237,7 +237,7 @@ func TestOutboundFederationIgnoresMissingEventWithBadJSONForRoomVersion6(t *test room.AddEvent(signedBadEvent) // send the first "good" event, referencing the broken event as a prev_event - sentEvent := srv.MustCreateEvent(t, room, b.Event{ + sentEvent := srv.MustCreateEvent(t, room, federation.Event{ Type: "m.room.message", Sender: charlie, Content: map[string]interface{}{ @@ -291,7 +291,7 @@ func TestOutboundFederationIgnoresMissingEventWithBadJSONForRoomVersion6(t *test // it just ignores it, so we need to send another event referring to the // first one and check that we get a /get_missing_events request. - message3 := srv.MustCreateEvent(t, room, b.Event{ + message3 := srv.MustCreateEvent(t, room, federation.Event{ Type: "m.room.message", Sender: charlie, Content: map[string]interface{}{ diff --git a/tests/federation_room_join_test.go b/tests/federation_room_join_test.go index 0d51963f..7ee127f9 100644 --- a/tests/federation_room_join_test.go +++ b/tests/federation_room_join_test.go @@ -158,7 +158,7 @@ func TestJoinFederatedRoomWithUnverifiableEvents(t *testing.T) { room := srv.MustMakeRoom(t, ver, federation.InitialRoomEvents(ver, charlie)) roomAlias := srv.MakeAliasMapping("MissingSignatures", room.RoomID) // create a normal event then remove the signatures key - signedEvent := srv.MustCreateEvent(t, room, b.Event{ + signedEvent := srv.MustCreateEvent(t, room, federation.Event{ Sender: charlie, StateKey: b.Ptr(""), Type: "m.room.name", @@ -181,7 +181,7 @@ func TestJoinFederatedRoomWithUnverifiableEvents(t *testing.T) { room := srv.MustMakeRoom(t, ver, federation.InitialRoomEvents(ver, charlie)) roomAlias := srv.MakeAliasMapping("BadSignatures", room.RoomID) // create a normal event then modify the signatures - signedEvent := srv.MustCreateEvent(t, room, b.Event{ + signedEvent := srv.MustCreateEvent(t, room, federation.Event{ Sender: charlie, StateKey: b.Ptr(""), Type: "m.room.name", @@ -212,7 +212,7 @@ func TestJoinFederatedRoomWithUnverifiableEvents(t *testing.T) { roomAlias := srv.MakeAliasMapping("UnobtainableKeys", room.RoomID) // create a normal event then modify the signatures to have a bogus key ID which Complement does // not have the keys for - signedEvent := srv.MustCreateEvent(t, room, b.Event{ + signedEvent := srv.MustCreateEvent(t, room, federation.Event{ Sender: charlie, StateKey: b.Ptr(""), Type: "m.room.name", @@ -246,7 +246,7 @@ func TestJoinFederatedRoomWithUnverifiableEvents(t *testing.T) { roomAlias := srv.MakeAliasMapping("UnverifiableAuthEvents", room.RoomID) // create a normal event then modify the signatures - rawEvent := srv.MustCreateEvent(t, room, b.Event{ + rawEvent := srv.MustCreateEvent(t, room, federation.Event{ Sender: charlie, StateKey: &charlie, Type: "m.room.member", @@ -271,7 +271,7 @@ func TestJoinFederatedRoomWithUnverifiableEvents(t *testing.T) { t.Logf("Created badly signed auth event %s", badlySignedEvent.EventID()) // and now add another event which will use it as an auth event. - goodEvent := srv.MustCreateEvent(t, room, b.Event{ + goodEvent := srv.MustCreateEvent(t, room, federation.Event{ Sender: charlie, StateKey: &charlie, Type: "m.room.member", @@ -453,7 +453,7 @@ func testValidationForSendMembershipEndpoint(t *testing.T, baseApiPath, expected } t.Run("regular event", func(t *testing.T) { - event := srv.MustCreateEvent(t, room, b.Event{ + event := srv.MustCreateEvent(t, room, federation.Event{ Type: "m.room.message", Sender: charlie, Content: map[string]interface{}{"body": "bzz"}, @@ -461,7 +461,7 @@ func testValidationForSendMembershipEndpoint(t *testing.T, baseApiPath, expected assertRequestFails(t, event) }) t.Run("non-state membership event", func(t *testing.T) { - event := srv.MustCreateEvent(t, room, b.Event{ + event := srv.MustCreateEvent(t, room, federation.Event{ Type: "m.room.member", Sender: charlie, Content: map[string]interface{}{"body": "bzz"}, @@ -475,7 +475,7 @@ func testValidationForSendMembershipEndpoint(t *testing.T, baseApiPath, expected if membershipType == expectedMembership { continue } - event := srv.MustCreateEvent(t, room, b.Event{ + event := srv.MustCreateEvent(t, room, federation.Event{ Type: "m.room.member", Sender: charlie, StateKey: &charlie, @@ -488,7 +488,7 @@ func testValidationForSendMembershipEndpoint(t *testing.T, baseApiPath, expected // right sort of membership, but mismatched state_key t.Run("event with mismatched state key", func(t *testing.T) { - event := srv.MustCreateEvent(t, room, b.Event{ + event := srv.MustCreateEvent(t, room, federation.Event{ Type: "m.room.member", Sender: charlie, StateKey: b.Ptr(srv.UserID("doris")), diff --git a/tests/federation_unreject_rejected_test.go b/tests/federation_unreject_rejected_test.go index f7f38079..e255dfa9 100644 --- a/tests/federation_unreject_rejected_test.go +++ b/tests/federation_unreject_rejected_test.go @@ -44,20 +44,20 @@ func TestUnrejectRejectedEvents(t *testing.T) { // Create the events. Event A will have whatever the current forward // extremities are as prev events. Event B will refer to event A only // to guarantee the test will work. - eventA := srv.MustCreateEvent(t, serverRoom, b.Event{ + eventA := srv.MustCreateEvent(t, serverRoom, federation.Event{ Type: "m.event.a", Sender: bob, Content: map[string]interface{}{ "event": "A", }, }) - eventB := srv.MustCreateEvent(t, serverRoom, b.Event{ - Type: "m.event.b", - Sender: bob, - PrevEvents: []string{eventA.EventID()}, + eventB := srv.MustCreateEvent(t, serverRoom, federation.Event{ + Type: "m.event.b", + Sender: bob, Content: map[string]interface{}{ "event": "B", }, + PrevEvents: []string{eventA.EventID()}, }) // Send event B into the room. Event A at this point is unknown From 2fa739f5da6acd5621e3dfba5e174096b54debe9 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Tue, 3 Oct 2023 14:59:43 +0100 Subject: [PATCH 5/9] Unbreak partial state test --- tests/federation_room_join_partial_state_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/federation_room_join_partial_state_test.go b/tests/federation_room_join_partial_state_test.go index 6e8d8930..1ef07615 100644 --- a/tests/federation_room_join_partial_state_test.go +++ b/tests/federation_room_join_partial_state_test.go @@ -305,7 +305,7 @@ func TestPartialStateJoin(t *testing.T) { t.Log("4. Have Alice send a message to the remote room.") removePDUHandler := server.AddPDUHandler(func(gomatrixserverlib.PDU) bool { return true }) defer removePDUHandler() - messageId := alice.SendEventUnsynced(t, serverRoom.RoomID, b.Event{ + messageId := alice.Unsafe_SendEventUnsynced(t, serverRoom.RoomID, b.Event{ Type: "m.room.message", Content: map[string]interface{}{ "body": "Hello world", From 1d2502dcbbcbd7e10eb4746828f986c0e971855e Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Tue, 3 Oct 2023 16:01:07 +0100 Subject: [PATCH 6/9] Only fail the test if the Sender is different --- client/client.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/client.go b/client/client.go index f624aa6f..5562057e 100644 --- a/client/client.go +++ b/client/client.go @@ -249,7 +249,7 @@ func (c *CSAPI) Unsafe_SendEventUnsyncedWithTxnID(t TestLike, roomID string, e b if e.StateKey != nil { paths = []string{"_matrix", "client", "v3", "rooms", roomID, "state", e.Type, *e.StateKey} } - if e.Sender != "" { + if e.Sender != "" && e.Sender != c.UserID { t.Fatalf("Event.Sender must not be set, as this is set by the client in use (%s)", c.UserID) } res := c.MustDo(t, "PUT", paths, WithJSONBody(t, e.Content)) From c2aace8f184ad54e2c7dbc3b2273be01813e8680 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Wed, 4 Oct 2023 10:02:13 +0100 Subject: [PATCH 7/9] Update build tag tests --- client/auth.go | 4 +++ client/client.go | 4 --- ...federation_room_join_partial_state_test.go | 30 +++++++++---------- tests/msc2836_test.go | 10 +++---- 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/client/auth.go b/client/auth.go index 89d43fee..cd6f91f6 100644 --- a/client/auth.go +++ b/client/auth.go @@ -9,6 +9,10 @@ import ( "github.com/tidwall/gjson" ) +const ( + SharedSecret = "complement" +) + type LoginOpt func(map[string]interface{}) func WithDeviceID(deviceID string) LoginOpt { diff --git a/client/client.go b/client/client.go index 5562057e..1cdab01e 100644 --- a/client/client.go +++ b/client/client.go @@ -21,10 +21,6 @@ import ( "github.com/matrix-org/complement/internal/b" ) -const ( - SharedSecret = "complement" -) - // TestLike is an interface that testing.T satisfies. All client functions accept a TestLike interface, // with the intention of a `testing.T` being passed into them. However, the client may be used in non-test // scenarios e.g benchmarks, which can then use the same client by just implementing this interface. diff --git a/tests/federation_room_join_partial_state_test.go b/tests/federation_room_join_partial_state_test.go index 1ef07615..49ad59e0 100644 --- a/tests/federation_room_join_partial_state_test.go +++ b/tests/federation_room_join_partial_state_test.go @@ -170,7 +170,7 @@ func TestPartialStateJoin(t *testing.T) { ) gomatrixserverlib.PDU { t.Helper() - return signingServer.MustCreateEvent(t, room, b.Event{ + return signingServer.MustCreateEvent(t, room, federation.Event{ Type: "m.room.member", StateKey: b.Ptr(userId), Sender: userId, @@ -1328,7 +1328,7 @@ func TestPartialStateJoin(t *testing.T) { // we will do a gappy sync after, which will only pick up the last message. var lastEventID string for i := 0; i < 2; i++ { - event := server.MustCreateEvent(t, serverRoom, b.Event{ + event := server.MustCreateEvent(t, serverRoom, federation.Event{ Type: "m.room.message", Sender: server.UserID("derek"), Content: map[string]interface{}{ @@ -1416,7 +1416,7 @@ func TestPartialStateJoin(t *testing.T) { outlierEventIDs := make([]string, len(outliers)) for i := range outliers { body := fmt.Sprintf("outlier event %d", i) - outliers[i] = server.MustCreateEvent(t, serverRoom, b.Event{ + outliers[i] = server.MustCreateEvent(t, serverRoom, federation.Event{ Type: "outlier_state", Sender: server.UserID("charlie"), StateKey: b.Ptr(fmt.Sprintf("state_%d", i)), @@ -1517,7 +1517,7 @@ func TestPartialStateJoin(t *testing.T) { federation.HandleEventAuthRequests()(server.Server) // derek sends a state event, despite not having permission to send state. This should be rejected. - badStateEvent := server.MustCreateEvent(t, serverRoom, b.Event{ + badStateEvent := server.MustCreateEvent(t, serverRoom, federation.Event{ Type: "m.room.test", StateKey: b.Ptr(""), Sender: server.UserID("derek"), @@ -1608,7 +1608,7 @@ func TestPartialStateJoin(t *testing.T) { // derek now sends a state event with auth_events that say he was in the room. It will be // accepted during the faster join, but should then ultimately be rejected. - badStateEvent := server.MustCreateEvent(t, serverRoom, b.Event{ + badStateEvent := server.MustCreateEvent(t, serverRoom, federation.Event{ Type: "m.room.test", StateKey: b.Ptr(""), Sender: derek, @@ -1691,7 +1691,7 @@ func TestPartialStateJoin(t *testing.T) { // Derek now kicks Elsie, with auth_events that say he was in the room. It will be // accepted during the faster join, but should then ultimately be rejected. - badKickEvent := server.MustCreateEvent(t, serverRoom, b.Event{ + badKickEvent := server.MustCreateEvent(t, serverRoom, federation.Event{ Type: "m.room.member", StateKey: &elsie, Sender: derek, @@ -1711,7 +1711,7 @@ func TestPartialStateJoin(t *testing.T) { t.Logf("derek created bad kick event %s with auth events %#v", badKickEvent.EventID(), badKickEvent.AuthEventIDs()) // elsie sends some state. This should be rejected during the faster join, but ultimately accepted. - rejectedStateEvent := server.MustCreateEvent(t, serverRoom, b.Event{ + rejectedStateEvent := server.MustCreateEvent(t, serverRoom, federation.Event{ Type: "m.room.test", StateKey: b.Ptr(""), Sender: elsie, @@ -2331,7 +2331,7 @@ func TestPartialStateJoin(t *testing.T) { var powerLevelsContent map[string]interface{} json.Unmarshal(room.CurrentState("m.room.power_levels", "").Content(), &powerLevelsContent) powerLevelsContent["users"].(map[string]interface{})[derek] = 100 - room.AddEvent(server1.MustCreateEvent(t, room, b.Event{ + room.AddEvent(server1.MustCreateEvent(t, room, federation.Event{ Type: "m.room.power_levels", StateKey: b.Ptr(""), Sender: server1.UserID("charlie"), @@ -2366,7 +2366,7 @@ func TestPartialStateJoin(t *testing.T) { t.Log("@charlie, @derek and @elsie received device list update.") // @derek:server1 "kicks" @elsie:server2. - badKickEvent := server1.MustCreateEvent(t, room, b.Event{ + badKickEvent := server1.MustCreateEvent(t, room, federation.Event{ Type: "m.room.member", StateKey: b.Ptr(elsie), Sender: derek, @@ -3141,7 +3141,7 @@ func TestPartialStateJoin(t *testing.T) { json.Unmarshal(room.CurrentState("m.room.power_levels", "").Content(), &powerLevelsContent) powerLevelsContent["users"].(map[string]interface{})[derek] = 50 powerLevelsContent["users"].(map[string]interface{})[fred] = 100 - room.AddEvent(server.MustCreateEvent(t, room, b.Event{ + room.AddEvent(server.MustCreateEvent(t, room, federation.Event{ Type: "m.room.power_levels", StateKey: b.Ptr(""), Sender: charlie, @@ -3168,7 +3168,7 @@ func TestPartialStateJoin(t *testing.T) { // @fred is really in the room. // This event has to be a ban, rather than a kick, otherwise state resolution can bring // @derek back into the room and ruin the test setup. - badKickEvent := server.MustCreateEvent(t, room, b.Event{ + badKickEvent := server.MustCreateEvent(t, room, federation.Event{ Type: "m.room.member", StateKey: b.Ptr(derek), Sender: fred, @@ -3188,7 +3188,7 @@ func TestPartialStateJoin(t *testing.T) { // @derek kicks @elsie. // This is incorrectly rejected since the homeserver under test incorrectly thinks // @derek had been kicked from the room. - kickEvent := server.MustCreateEvent(t, room, b.Event{ + kickEvent := server.MustCreateEvent(t, room, federation.Event{ Type: "m.room.member", StateKey: b.Ptr(elsie), Sender: derek, @@ -3809,7 +3809,7 @@ func TestPartialStateJoin(t *testing.T) { ) t.Log("A resident server user kicks Alice from the room.") - kickEvent := server.MustCreateEvent(t, serverRoom, b.Event{ + kickEvent := server.MustCreateEvent(t, serverRoom, federation.Event{ Type: "m.room.member", StateKey: b.Ptr(alice.UserID), Sender: server.UserID("charlie"), @@ -3861,7 +3861,7 @@ func TestPartialStateJoin(t *testing.T) { ) t.Log("A resident server user bans Alice from the room.") - banEvent := server.MustCreateEvent(t, serverRoom, b.Event{ + banEvent := server.MustCreateEvent(t, serverRoom, federation.Event{ Type: "m.room.member", StateKey: b.Ptr(alice.UserID), Sender: server.UserID("charlie"), @@ -4350,7 +4350,7 @@ func (psj *partialStateJoinResult) CreateMessageEvent(t *testing.T, senderLocalp prevEvents = prevEventIDs } - event := psj.Server.MustCreateEvent(t, psj.ServerRoom, b.Event{ + event := psj.Server.MustCreateEvent(t, psj.ServerRoom, federation.Event{ Type: "m.room.message", Sender: psj.Server.UserID(senderLocalpart), Content: map[string]interface{}{ diff --git a/tests/msc2836_test.go b/tests/msc2836_test.go index 693b2d30..bce90b8e 100644 --- a/tests/msc2836_test.go +++ b/tests/msc2836_test.go @@ -209,7 +209,7 @@ func TestFederatedEventRelationships(t *testing.T) { roomVer := alice.GetDefaultRoomVersion(t) charlie := srv.UserID("charlie") room := srv.MustMakeRoom(t, roomVer, federation.InitialRoomEvents(roomVer, charlie)) - eventA := srv.MustCreateEvent(t, room, b.Event{ + eventA := srv.MustCreateEvent(t, room, federation.Event{ Type: "m.room.message", Sender: charlie, Content: map[string]interface{}{ @@ -218,7 +218,7 @@ func TestFederatedEventRelationships(t *testing.T) { }, }) room.AddEvent(eventA) - eventB := srv.MustCreateEvent(t, room, b.Event{ + eventB := srv.MustCreateEvent(t, room, federation.Event{ Type: "m.room.message", Sender: charlie, Content: map[string]interface{}{ @@ -233,7 +233,7 @@ func TestFederatedEventRelationships(t *testing.T) { room.AddEvent(eventB) // wait 1ms to ensure that the timestamp changes, which is important when using the recent_first flag time.Sleep(1 * time.Millisecond) - eventC := srv.MustCreateEvent(t, room, b.Event{ + eventC := srv.MustCreateEvent(t, room, federation.Event{ Type: "m.room.message", Sender: charlie, Content: map[string]interface{}{ @@ -246,7 +246,7 @@ func TestFederatedEventRelationships(t *testing.T) { }, }) room.AddEvent(eventC) - eventD := srv.MustCreateEvent(t, room, b.Event{ + eventD := srv.MustCreateEvent(t, room, federation.Event{ Type: "m.room.message", Sender: charlie, Content: map[string]interface{}{ @@ -307,7 +307,7 @@ func TestFederatedEventRelationships(t *testing.T) { alice.JoinRoom(t, room.RoomID, []string{srv.ServerName()}) // send a new child in the thread (child of D) so the HS has something to latch on to. - eventE := srv.MustCreateEvent(t, room, b.Event{ + eventE := srv.MustCreateEvent(t, room, federation.Event{ Type: "m.room.message", Sender: charlie, Content: map[string]interface{}{ From 7dcfd5e7b3185183c47fbe59b12b5ec59ed4edcb Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Wed, 4 Oct 2023 11:49:34 +0100 Subject: [PATCH 8/9] Prefer GetJSONFieldStr as it does more validation --- client/auth.go | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/client/auth.go b/client/auth.go index cd6f91f6..c469166b 100644 --- a/client/auth.go +++ b/client/auth.go @@ -44,9 +44,9 @@ func (c *CSAPI) LoginUser(t TestLike, localpart, password string, opts ...LoginO t.Fatalf("unable to read response body: %v", err) } - userID = gjson.GetBytes(body, "user_id").Str - accessToken = gjson.GetBytes(body, "access_token").Str - deviceID = gjson.GetBytes(body, "device_id").Str + userID = GetJSONFieldStr(t, body, "user_id") + accessToken = GetJSONFieldStr(t, body, "access_token") + deviceID = GetJSONFieldStr(t, body, "device_id") return userID, accessToken, deviceID } @@ -70,10 +70,10 @@ func (c *CSAPI) LoginUserWithRefreshToken(t TestLike, localpart, password string t.Fatalf("unable to read response body: %v", err) } - userID = gjson.GetBytes(body, "user_id").Str - accessToken = gjson.GetBytes(body, "access_token").Str - deviceID = gjson.GetBytes(body, "device_id").Str - refreshToken = gjson.GetBytes(body, "refresh_token").Str + userID = GetJSONFieldStr(t, body, "user_id") + accessToken = GetJSONFieldStr(t, body, "access_token") + deviceID = GetJSONFieldStr(t, body, "device_id") + refreshToken = GetJSONFieldStr(t, body, "refresh_token") expiresInMs = gjson.GetBytes(body, "expires_in_ms").Int() return userID, accessToken, refreshToken, deviceID, expiresInMs } @@ -91,8 +91,8 @@ func (c *CSAPI) ConsumeRefreshToken(t TestLike, refreshToken string) (newAccessT t.Fatalf("unable to read response body: %v", err) } - newAccessToken = gjson.GetBytes(body, "access_token").Str - newRefreshToken = gjson.GetBytes(body, "refresh_token").Str + newAccessToken = GetJSONFieldStr(t, body, "access_token") + newRefreshToken = GetJSONFieldStr(t, body, "refresh_token") expiresInMs = gjson.GetBytes(body, "expires_in_ms").Int() return newAccessToken, newRefreshToken, expiresInMs } @@ -115,9 +115,9 @@ func (c *CSAPI) RegisterUser(t TestLike, localpart, password string) (userID, ac t.Fatalf("unable to read response body: %v", err) } - userID = gjson.GetBytes(body, "user_id").Str - accessToken = gjson.GetBytes(body, "access_token").Str - deviceID = gjson.GetBytes(body, "device_id").Str + userID = GetJSONFieldStr(t, body, "user_id") + accessToken = GetJSONFieldStr(t, body, "access_token") + deviceID = GetJSONFieldStr(t, body, "device_id") return userID, accessToken, deviceID } @@ -156,8 +156,8 @@ func (c *CSAPI) RegisterSharedSecret(t TestLike, user, pass string, isAdmin bool } resp = c.MustDo(t, "POST", []string{"_synapse", "admin", "v1", "register"}, WithJSONBody(t, reqBody)) body = ParseJSON(t, resp) - userID = gjson.GetBytes(body, "user_id").Str - accessToken = gjson.GetBytes(body, "access_token").Str - deviceID = gjson.GetBytes(body, "device_id").Str + userID = GetJSONFieldStr(t, body, "user_id") + accessToken = GetJSONFieldStr(t, body, "access_token") + deviceID = GetJSONFieldStr(t, body, "device_id") return userID, accessToken, deviceID } From cca8bf8a47ede01f25a0e951b75a3b5f590aeb4d Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Wed, 4 Oct 2023 14:51:36 +0100 Subject: [PATCH 9/9] Review comments --- client/client.go | 2 +- client/sync.go | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/client/client.go b/client/client.go index 1cdab01e..20b2fdf6 100644 --- a/client/client.go +++ b/client/client.go @@ -600,7 +600,7 @@ func GjsonEscape(in string) string { return in } -func loopArray(object gjson.Result, key string, check func(gjson.Result) bool) error { +func checkArrayElements(object gjson.Result, key string, check func(gjson.Result) bool) error { array := object.Get(key) if !array.Exists() { return fmt.Errorf("Key %s does not exist", key) diff --git a/client/sync.go b/client/sync.go index cf154cd1..99495426 100644 --- a/client/sync.go +++ b/client/sync.go @@ -169,7 +169,7 @@ func (c *CSAPI) MustSync(t TestLike, syncReq SyncReq) (gjson.Result, string) { // Check that the timeline for `roomID` has an event which passes the check function. func SyncTimelineHas(roomID string, check func(gjson.Result) bool) SyncCheckOpt { return func(clientUserID string, topLevelSyncJSON gjson.Result) error { - err := loopArray( + err := checkArrayElements( topLevelSyncJSON, "rooms.join."+GjsonEscape(roomID)+".timeline.events", check, ) if err == nil { @@ -192,7 +192,7 @@ func SyncTimelineHasEventID(roomID string, eventID string) SyncCheckOpt { // `lazy_load_members` syncs. func SyncStateHas(roomID string, check func(gjson.Result) bool) SyncCheckOpt { return func(clientUserID string, topLevelSyncJSON gjson.Result) error { - err := loopArray( + err := checkArrayElements( topLevelSyncJSON, "rooms.join."+GjsonEscape(roomID)+".state.events", check, ) if err == nil { @@ -204,7 +204,7 @@ func SyncStateHas(roomID string, check func(gjson.Result) bool) SyncCheckOpt { func SyncEphemeralHas(roomID string, check func(gjson.Result) bool) SyncCheckOpt { return func(clientUserID string, topLevelSyncJSON gjson.Result) error { - err := loopArray( + err := checkArrayElements( topLevelSyncJSON, "rooms.join."+GjsonEscape(roomID)+".ephemeral.events", check, ) if err == nil { @@ -263,7 +263,7 @@ func SyncInvitedTo(userID, roomID string) SyncCheckOpt { // - actively being invited to a room. if clientUserID == userID { // active - err := loopArray( + err := checkArrayElements( topLevelSyncJSON, "rooms.invite."+GjsonEscape(roomID)+".invite_state.events", func(ev gjson.Result) bool { return ev.Get("type").Str == "m.room.member" && ev.Get("state_key").Str == userID && ev.Get("content.membership").Str == "invite" @@ -302,14 +302,14 @@ func SyncJoinedTo(userID, roomID string, checks ...func(gjson.Result) bool) Sync // Check both the timeline and the state events for the join event // since on initial sync, the state events may only be in // .state.events. - firstErr := loopArray( + firstErr := checkArrayElements( topLevelSyncJSON, "rooms.join."+GjsonEscape(roomID)+".timeline.events", checkJoined, ) if firstErr == nil { return nil } - secondErr := loopArray( + secondErr := checkArrayElements( topLevelSyncJSON, "rooms.join."+GjsonEscape(roomID)+".state.events", checkJoined, ) if secondErr == nil { @@ -346,7 +346,7 @@ func SyncLeftFrom(userID, roomID string) SyncCheckOpt { // `check` function returns true for at least one event. func SyncGlobalAccountDataHas(check func(gjson.Result) bool) SyncCheckOpt { return func(clientUserID string, topLevelSyncJSON gjson.Result) error { - return loopArray(topLevelSyncJSON, "account_data.events", check) + return checkArrayElements(topLevelSyncJSON, "account_data.events", check) } } @@ -355,7 +355,7 @@ func SyncGlobalAccountDataHas(check func(gjson.Result) bool) SyncCheckOpt { // one event. func SyncRoomAccountDataHas(roomID string, check func(gjson.Result) bool) SyncCheckOpt { return func(clientUserID string, topLevelSyncJSON gjson.Result) error { - err := loopArray( + err := checkArrayElements( topLevelSyncJSON, "rooms.join."+GjsonEscape(roomID)+".account_data.events", check, ) if err == nil { @@ -374,7 +374,7 @@ func SyncRoomAccountDataHas(roomID string, check func(gjson.Result) bool) SyncCh // `check` gets passed the full event, including sender and type. func SyncToDeviceHas(fromUser string, check func(gjson.Result) bool) SyncCheckOpt { return func(clientUserID string, topLevelSyncJSON gjson.Result) error { - err := loopArray( + err := checkArrayElements( topLevelSyncJSON, "to_device.events", func(result gjson.Result) bool { if fromUser != "" && result.Get("sender").Str != fromUser { return false