@@ -71,6 +71,14 @@ func (c *CSAPI) CreateMedia(t ct.TestLike) string {
7171 return GetJSONFieldStr (t , body , "content_uri" )
7272}
7373
74+ // CreateMedia creates an MXC URI for asynchronous media uploads.
75+ func (c * CSAPI ) MustCreateMediaRestricted (t ct.TestLike ) string {
76+ t .Helper ()
77+ res := c .MustDo (t , "POST" , []string {"_matrix" , "client" , "unstable" , "org.matrix.msc3911" , "media" , "create" })
78+ body := ParseJSON (t , res )
79+ return GetJSONFieldStr (t , body , "content_uri" )
80+ }
81+
7482// UploadMediaAsync uploads the provided content to the given server and media ID. Fails the test on error.
7583func (c * CSAPI ) UploadMediaAsync (t ct.TestLike , serverName , mediaID string , fileBody []byte , fileName string , contentType string ) {
7684 t .Helper ()
@@ -99,6 +107,23 @@ func (c *CSAPI) UploadContent(t ct.TestLike, fileBody []byte, fileName string, c
99107 return GetJSONFieldStr (t , body , "content_uri" )
100108}
101109
110+ // MustUploadContentRestricted uploads the provided content with and attachment parameter and an optional file name. Fails the test on error. Returns the MXC URI.
111+ func (c * CSAPI ) MustUploadContentRestricted (t ct.TestLike , fileBody []byte , fileName string , contentType string ) string {
112+ t .Helper ()
113+ query := url.Values {}
114+ if fileName != "" {
115+ query .Set ("filename" , fileName )
116+ }
117+ res := c .Do (
118+ // /_matrix/client/unstable/org.matrix.msc3911/media/upload
119+ t , "POST" , []string {"_matrix" , "client" , "unstable" , "org.matrix.msc3911" , "media" , "upload" },
120+ WithRawBody (fileBody ), WithContentType (contentType ), WithQueries (query ),
121+ )
122+ mustRespond2xx (t , res )
123+ body := ParseJSON (t , res )
124+ return GetJSONFieldStr (t , body , "content_uri" )
125+ }
126+
102127// DownloadContent downloads media from the server, returning the raw bytes and the Content-Type. Fails the test on error.
103128func (c * CSAPI ) DownloadContent (t ct.TestLike , mxcUri string ) ([]byte , string ) {
104129 t .Helper ()
@@ -125,6 +150,16 @@ func (c *CSAPI) DownloadContentAuthenticated(t ct.TestLike, mxcUri string) ([]by
125150 return b , contentType
126151}
127152
153+ // UncheckedDownloadContentAuthenticated makes the raw request for a piece of media and returns the http.Response.
154+ // Response is unchecked in any way. The existing DownloadContentAuthenticated() should have been a "Must" variant. Rather
155+ // than refactor that across the code base, this version just uses an explicit name
156+ func (c * CSAPI ) UncheckedDownloadContentAuthenticated (t ct.TestLike , mxcUri string ) * http.Response {
157+ t .Helper ()
158+ origin , mediaId := SplitMxc (mxcUri )
159+ res := c .Do (t , "GET" , []string {"_matrix" , "client" , "v1" , "media" , "download" , origin , mediaId })
160+ return res
161+ }
162+
128163// MustCreateRoom creates a room with an optional HTTP request body. Fails the test on error. Returns the room ID.
129164func (c * CSAPI ) MustCreateRoom (t ct.TestLike , reqBody map [string ]interface {}) string {
130165 t .Helper ()
@@ -337,6 +372,15 @@ func (c *CSAPI) Unsafe_SendEventUnsynced(t ct.TestLike, roomID string, e b.Event
337372 return c .Unsafe_SendEventUnsyncedWithTxnID (t , roomID , e , strconv .Itoa (txnID ))
338373}
339374
375+ // Unsafe_SendEventWithAttachedMediaUnsynced sends `e` with a media attachment into the room. This function is UNSAFE as it does not wait
376+ // for the event to be fully processed. This can cause flakey tests. Prefer `SendEventSynced`.
377+ // Returns the event ID of the sent event.
378+ func (c * CSAPI ) Unsafe_SendEventWithAttachedMediaUnsynced (t ct.TestLike , roomID string , e b.Event , mxcUri string ) string {
379+ t .Helper ()
380+ txnID := int (atomic .AddInt64 (& c .txnID , 1 ))
381+ return c .Unsafe_SendEventWithAttachedMediaUnsyncedWithTxnID (t , roomID , e , mxcUri , strconv .Itoa (txnID ))
382+ }
383+
340384// SendEventUnsyncedWithTxnID sends `e` into the room with a prescribed transaction ID.
341385// This is useful for writing tests that interrogate transaction semantics. This function is UNSAFE
342386// as it does not wait for the event to be fully processed. This can cause flakey tests. Prefer `SendEventSynced`.
@@ -356,6 +400,29 @@ func (c *CSAPI) Unsafe_SendEventUnsyncedWithTxnID(t ct.TestLike, roomID string,
356400 return eventID
357401}
358402
403+ // Unsafe_SendEventWithAttachedMediaUnsyncedWithTxnID sends `e` with a media attachment into the room with a prescribed transaction ID.
404+ // This is useful for writing tests that interrogate transaction semantics. This function is UNSAFE
405+ // as it does not wait for the event to be fully processed. This can cause flakey tests. Prefer `SendEventSynced`.
406+ // Returns the event ID of the sent event.
407+ func (c * CSAPI ) Unsafe_SendEventWithAttachedMediaUnsyncedWithTxnID (t ct.TestLike , roomID string , e b.Event , mxcUri string , txnID string ) string {
408+ t .Helper ()
409+ paths := []string {"_matrix" , "client" , "v3" , "rooms" , roomID , "send" , e .Type , txnID }
410+ if e .StateKey != nil {
411+ paths = []string {"_matrix" , "client" , "v3" , "rooms" , roomID , "state" , e .Type , * e .StateKey }
412+ }
413+ if e .Sender != "" && e .Sender != c .UserID {
414+ ct .Fatalf (t , "Event.Sender must not be set, as this is set by the client in use (%s)" , c .UserID )
415+ }
416+ queries := url.Values {}
417+ if mxcUri != "" {
418+ queries .Add ("org.matrix.msc3911.attach_media" , mxcUri )
419+ }
420+ res := c .MustDo (t , "PUT" , paths , WithJSONBody (t , e .Content ), WithQueries (queries ))
421+ body := ParseJSON (t , res )
422+ eventID := GetJSONFieldStr (t , body , "event_id" )
423+ return eventID
424+ }
425+
359426// SendEventSynced sends `e` into the room and waits for its event ID to come down /sync.
360427// Returns the event ID of the sent event.
361428func (c * CSAPI ) SendEventSynced (t ct.TestLike , roomID string , e b.Event ) string {
@@ -368,6 +435,18 @@ func (c *CSAPI) SendEventSynced(t ct.TestLike, roomID string, e b.Event) string
368435 return eventID
369436}
370437
438+ // SendEventWithAttachedMediaSynced sends `e` with a media attachment into the room and waits for its event ID to come down /sync.
439+ // Returns the event ID of the sent event.
440+ func (c * CSAPI ) SendEventWithAttachedMediaSynced (t ct.TestLike , roomID string , e b.Event , mxcUri string ) string {
441+ t .Helper ()
442+ eventID := c .Unsafe_SendEventWithAttachedMediaUnsynced (t , roomID , e , mxcUri )
443+ t .Logf ("SendEventSynced waiting for event ID %s" , eventID )
444+ c .MustSyncUntil (t , SyncReq {}, SyncTimelineHas (roomID , func (r gjson.Result ) bool {
445+ return r .Get ("event_id" ).Str == eventID
446+ }))
447+ return eventID
448+ }
449+
371450// SendRedaction sends a redaction request. Will fail if the returned HTTP request code is not 200. Returns the
372451// event ID of the redaction event.
373452func (c * CSAPI ) MustSendRedaction (t ct.TestLike , roomID string , content map [string ]interface {}, eventID string ) string {
@@ -441,6 +520,17 @@ func (c *CSAPI) GetDefaultRoomVersion(t ct.TestLike) gomatrixserverlib.RoomVersi
441520 return gomatrixserverlib .RoomVersion (defaultVersion .Str )
442521}
443522
523+ // GetVersions queries the server's client versions
524+ func (c * CSAPI ) GetVersions (t ct.TestLike ) []byte {
525+ t .Helper ()
526+ res := c .MustDo (t , "GET" , []string {"_matrix" , "client" , "versions" })
527+ body , err := io .ReadAll (res .Body )
528+ if err != nil {
529+ ct .Fatalf (t , "unable to read response body: %v" , err )
530+ }
531+ return body
532+ }
533+
444534// MustUploadKeys uploads device and/or one time keys to the server, returning the current OTK counts.
445535// Both device keys and one time keys are optional. Fails the test if the upload fails.
446536func (c * CSAPI ) MustUploadKeys (t ct.TestLike , deviceKeys map [string ]interface {}, oneTimeKeys map [string ]interface {}) (otkCounts map [string ]int ) {
@@ -545,11 +635,20 @@ func (c *CSAPI) MustGenerateOneTimeKeys(t ct.TestLike, otkCount uint) (deviceKey
545635
546636// MustSetDisplayName sets the global display name for this account or fails the test.
547637func (c * CSAPI ) MustSetDisplayName (t ct.TestLike , displayname string ) {
638+ t .Helper ()
548639 c .MustDo (t , "PUT" , []string {"_matrix" , "client" , "v3" , "profile" , c .UserID , "displayname" }, WithJSONBody (t , map [string ]any {
549640 "displayname" : displayname ,
550641 }))
551642}
552643
644+ // MustSetDisplayName sets the global display name for this account or fails the test.
645+ func (c * CSAPI ) MustSetProfileAvatar (t ct.TestLike , mxcUri string ) {
646+ t .Helper ()
647+ c .MustDo (t , "PUT" , []string {"_matrix" , "client" , "v3" , "profile" , c .UserID , "avatar_url" }, WithJSONBody (t , map [string ]any {
648+ "avatar_url" : mxcUri ,
649+ }))
650+ }
651+
553652// MustGetDisplayName returns the global display name for this user or fails the test.
554653func (c * CSAPI ) MustGetDisplayName (t ct.TestLike , userID string ) string {
555654 res := c .MustDo (t , "GET" , []string {"_matrix" , "client" , "v3" , "profile" , userID , "displayname" })
0 commit comments