@@ -35,17 +35,19 @@ use ruma::{
35
35
directory:: PublicRoomsChunk ,
36
36
encryption:: { CrossSigningKey , DeviceKeys , OneTimeKey } ,
37
37
events:: {
38
- receipt:: ReceiptThread , room:: member:: RoomMemberEvent , AnyStateEvent , AnyTimelineEvent ,
39
- GlobalAccountDataEventType , MessageLikeEventType , RoomAccountDataEventType , StateEventType ,
38
+ receipt:: ReceiptThread , room:: member:: RoomMemberEvent , AnyStateEvent , AnySyncTimelineEvent ,
39
+ AnyTimelineEvent , GlobalAccountDataEventType , MessageLikeEventType ,
40
+ RoomAccountDataEventType , StateEventType ,
40
41
} ,
41
42
media:: Method ,
42
43
serde:: Raw ,
43
44
time:: Duration ,
44
- DeviceId , EventId , MxcUri , OwnedDeviceId , OwnedEventId , OwnedOneTimeKeyId , OwnedRoomId ,
45
- OwnedUserId , RoomId , ServerName , UserId ,
45
+ DeviceId , EventId , MilliSecondsSinceUnixEpoch , MxcUri , OwnedDeviceId , OwnedEventId ,
46
+ OwnedOneTimeKeyId , OwnedRoomId , OwnedUserId , RoomId , ServerName , UserId ,
46
47
} ;
47
48
use serde:: Deserialize ;
48
- use serde_json:: { json, Value } ;
49
+ use serde_json:: { from_value, json, Value } ;
50
+ use tokio:: sync:: oneshot:: { self , Receiver } ;
49
51
use wiremock:: {
50
52
matchers:: { body_json, body_partial_json, header, method, path, path_regex, query_param} ,
51
53
Mock , MockBuilder , MockGuard , MockServer , Request , Respond , ResponseTemplate , Times ,
@@ -342,6 +344,36 @@ impl MatrixMockServer {
342
344
. expect_default_access_token ( )
343
345
}
344
346
347
+ /// Creates a prebuilt mock for joining a room.
348
+ ///
349
+ /// # Examples
350
+ ///
351
+ /// ```
352
+ /// # tokio_test::block_on(async {
353
+ /// use matrix_sdk::{ruma::{room_id, event_id}, test_utils::mocks::MatrixMockServer};
354
+ /// use serde_json::json;
355
+ ///
356
+ /// let mock_server = MatrixMockServer::new().await;
357
+ /// let client = mock_server.client_builder().build().await;
358
+ /// let room_id = room_id!("!test:localhost");
359
+ ///
360
+ /// mock_server.mock_room_join(room_id).ok().mount();
361
+ ///
362
+ /// let room = client.join_room_by_id(room_id).await?;
363
+ ///
364
+ /// assert_eq!(
365
+ /// room_id,
366
+ /// room.room_id(),
367
+ /// "The room ID we mocked should match the one we received when we joined the room"
368
+ /// );
369
+ /// # anyhow::Ok(()) });
370
+ /// ```
371
+ pub fn mock_room_join ( & self , room_id : & RoomId ) -> MockEndpoint < ' _ , JoinRoomEndpoint > {
372
+ let mock = Mock :: given ( method ( "POST" ) )
373
+ . and ( path_regex ( format ! ( "^/_matrix/client/v3/rooms/{room_id}/join" ) ) ) ;
374
+ self . mock_endpoint ( mock, JoinRoomEndpoint { room_id : room_id. to_owned ( ) } )
375
+ }
376
+
345
377
/// Creates a prebuilt mock for sending an event in a room.
346
378
///
347
379
/// Note: works with *any* room.
@@ -1832,6 +1864,102 @@ impl<'a> MockEndpoint<'a, RoomSendEndpoint> {
1832
1864
pub fn ok ( self , returned_event_id : impl Into < OwnedEventId > ) -> MatrixMock < ' a > {
1833
1865
self . ok_with_event_id ( returned_event_id. into ( ) )
1834
1866
}
1867
+
1868
+ /// Returns a send endpoint that emulates success, i.e. the event has been
1869
+ /// sent with the given event id.
1870
+ ///
1871
+ /// The sent event is captured and can be accessed using the returned
1872
+ /// [`Receiver`]. The [`Receiver`] is valid only for a send call. The given
1873
+ /// `event_sender` are added to the event JSON.
1874
+ ///
1875
+ /// # Examples
1876
+ ///
1877
+ /// ```no_run
1878
+ /// # tokio_test::block_on(async {
1879
+ /// use matrix_sdk::{
1880
+ /// ruma::{
1881
+ /// event_id, events::room::message::RoomMessageEventContent, room_id,
1882
+ /// },
1883
+ /// test_utils::mocks::MatrixMockServer,
1884
+ /// };
1885
+ /// use matrix_sdk_test::JoinedRoomBuilder;
1886
+ ///
1887
+ /// let room_id = room_id!("!room_id:localhost");
1888
+ /// let event_id = event_id!("$some_id");
1889
+ ///
1890
+ /// let server = MatrixMockServer::new().await;
1891
+ /// let client = server.client_builder().build().await;
1892
+ ///
1893
+ /// let user_id = client.user_id().expect("We should have a user ID by now");
1894
+ ///
1895
+ /// let (receiver, mock) =
1896
+ /// server.mock_room_send().ok_with_capture(event_id, user_id);
1897
+ ///
1898
+ /// server
1899
+ /// .mock_sync()
1900
+ /// .ok_and_run(&client, |builder| {
1901
+ /// builder.add_joined_room(JoinedRoomBuilder::new(room_id));
1902
+ /// })
1903
+ /// .await;
1904
+ ///
1905
+ /// // Mock any additional endpoints that might be needed to send the message.
1906
+ ///
1907
+ /// let room = client
1908
+ /// .get_room(room_id)
1909
+ /// .expect("We should have access to our room now");
1910
+ ///
1911
+ /// let event_id = room
1912
+ /// .send(RoomMessageEventContent::text_plain("It's a secret to everybody"))
1913
+ /// .await
1914
+ /// .expect("We should be able to send an initial message")
1915
+ /// .event_id;
1916
+ ///
1917
+ /// let event = receiver.await?;
1918
+ /// # anyhow::Ok(()) });
1919
+ /// ```
1920
+ pub fn ok_with_capture (
1921
+ self ,
1922
+ returned_event_id : impl Into < OwnedEventId > ,
1923
+ event_sender : impl Into < OwnedUserId > ,
1924
+ ) -> ( Receiver < Raw < AnySyncTimelineEvent > > , MatrixMock < ' a > ) {
1925
+ let event_id = returned_event_id. into ( ) ;
1926
+ let event_sender = event_sender. into ( ) ;
1927
+
1928
+ let ( sender, receiver) = oneshot:: channel ( ) ;
1929
+ let sender = Arc :: new ( Mutex :: new ( Some ( sender) ) ) ;
1930
+
1931
+ let ret = self . respond_with ( move |request : & Request | {
1932
+ if let Some ( sender) = sender. lock ( ) . unwrap ( ) . take ( ) {
1933
+ let uri = & request. url ;
1934
+ let path_segments = uri. path_segments ( ) ;
1935
+ let maybe_event_type = path_segments. and_then ( |mut s| s. nth_back ( 1 ) ) ;
1936
+ let event_type = maybe_event_type
1937
+ . as_ref ( )
1938
+ . map ( |& e| e. to_owned ( ) )
1939
+ . unwrap_or ( "m.room.message" . to_owned ( ) ) ;
1940
+
1941
+ let body: Value =
1942
+ request. body_json ( ) . expect ( "The received body should be valid JSON" ) ;
1943
+
1944
+ let event = json ! ( {
1945
+ "event_id" : event_id. clone( ) ,
1946
+ "sender" : event_sender,
1947
+ "type" : event_type,
1948
+ "origin_server_ts" : MilliSecondsSinceUnixEpoch :: now( ) ,
1949
+ "content" : body,
1950
+ } ) ;
1951
+
1952
+ let event: Raw < AnySyncTimelineEvent > = from_value ( event)
1953
+ . expect ( "We should be able to create a raw event from the content" ) ;
1954
+
1955
+ sender. send ( event) . expect ( "We should be able to send the event to the receiver" ) ;
1956
+ }
1957
+
1958
+ ResponseTemplate :: new ( 200 ) . set_body_json ( json ! ( { "event_id" : event_id. clone( ) } ) )
1959
+ } ) ;
1960
+
1961
+ ( receiver, ret)
1962
+ }
1835
1963
}
1836
1964
1837
1965
/// A prebuilt mock for sending a state event in a room.
@@ -2444,8 +2572,58 @@ impl<'a> MockEndpoint<'a, UploadEndpoint> {
2444
2572
Self { mock : self . mock . and ( header ( "content-type" , content_type) ) , ..self }
2445
2573
}
2446
2574
2447
- /// Returns a redact endpoint that emulates success, i.e. the redaction
2448
- /// event has been sent with the given event id.
2575
+ /// Returns a upload endpoint that emulates success, i.e. the media has been
2576
+ /// uploaded to the media server and can be accessed using the given
2577
+ /// event has been sent with the given [`MxcUri`].
2578
+ ///
2579
+ /// The uploaded content is captured and can be accessed using the returned
2580
+ /// [`Receiver`]. The [`Receiver`] is valid only for a single media
2581
+ /// upload.
2582
+ ///
2583
+ /// # Examples
2584
+ ///
2585
+ /// ```no_run
2586
+ /// # tokio_test::block_on(async {
2587
+ /// use matrix_sdk::{
2588
+ /// ruma::{event_id, mxc_uri, room_id},
2589
+ /// test_utils::mocks::MatrixMockServer,
2590
+ /// };
2591
+ ///
2592
+ /// let mxid = mxc_uri!("mxc://localhost/12345");
2593
+ ///
2594
+ /// let server = MatrixMockServer::new().await;
2595
+ /// let (receiver, upload_mock) = server.mock_upload().ok_with_capture(mxid);
2596
+ /// let client = server.client_builder().build().await;
2597
+ ///
2598
+ /// client.media().upload(&mime::TEXT_PLAIN, vec![1, 2, 3, 4, 5], None).await?;
2599
+ ///
2600
+ /// let uploaded = receiver.await?;
2601
+ ///
2602
+ /// assert_eq!(uploaded, vec![1, 2, 3, 4, 5]);
2603
+ /// # anyhow::Ok(()) });
2604
+ /// ```
2605
+ pub fn ok_with_capture ( self , mxc_id : & MxcUri ) -> ( Receiver < Vec < u8 > > , MatrixMock < ' a > ) {
2606
+ let ( sender, receiver) = oneshot:: channel ( ) ;
2607
+ let sender = Arc :: new ( Mutex :: new ( Some ( sender) ) ) ;
2608
+ let response_body = json ! ( { "content_uri" : mxc_id} ) ;
2609
+
2610
+ let ret = self . respond_with ( move |request : & Request | {
2611
+ let maybe_sender = sender. lock ( ) . unwrap ( ) . take ( ) ;
2612
+
2613
+ if let Some ( sender) = maybe_sender {
2614
+ let body = request. body . clone ( ) ;
2615
+ let _ = sender. send ( body) ;
2616
+ }
2617
+
2618
+ ResponseTemplate :: new ( 200 ) . set_body_json ( response_body. clone ( ) )
2619
+ } ) ;
2620
+
2621
+ ( receiver, ret)
2622
+ }
2623
+
2624
+ /// Returns a upload endpoint that emulates success, i.e. the media has been
2625
+ /// uploaded to the media server and can be accessed using the given
2626
+ /// event has been sent with the given [`MxcUri`].
2449
2627
pub fn ok ( self , mxc_id : & MxcUri ) -> MatrixMock < ' a > {
2450
2628
self . respond_with ( ResponseTemplate :: new ( 200 ) . set_body_json ( json ! ( {
2451
2629
"content_uri" : mxc_id
@@ -3269,7 +3447,7 @@ impl<'a> MockEndpoint<'a, LoginEndpoint> {
3269
3447
///
3270
3448
/// # Examples
3271
3449
///
3272
- /// ```rust
3450
+ /// ```
3273
3451
/// use matrix_sdk::test_utils::mocks::{
3274
3452
/// LoginResponseTemplate200, MatrixMockServer,
3275
3453
/// };
@@ -3483,6 +3661,13 @@ impl<'a> MockEndpoint<'a, MediaDownloadEndpoint> {
3483
3661
self . respond_with ( ResponseTemplate :: new ( 200 ) . set_body_string ( "Hello, World!" ) )
3484
3662
}
3485
3663
3664
+ /// Returns a successful response with the given bytes.
3665
+ pub fn ok_bytes ( self , bytes : Vec < u8 > ) -> MatrixMock < ' a > {
3666
+ self . respond_with (
3667
+ ResponseTemplate :: new ( 200 ) . set_body_raw ( bytes, "application/octet-stream" ) ,
3668
+ )
3669
+ }
3670
+
3486
3671
/// Returns a successful response with a fake image content.
3487
3672
pub fn ok_image ( self ) -> MatrixMock < ' a > {
3488
3673
self . respond_with (
@@ -3531,3 +3716,19 @@ impl<'a> MockEndpoint<'a, AuthedMediaThumbnailEndpoint> {
3531
3716
)
3532
3717
}
3533
3718
}
3719
+
3720
+ /// A prebuilt mock for `GET /client/v3/rooms/{room_id}/join` requests.
3721
+ pub struct JoinRoomEndpoint {
3722
+ room_id : OwnedRoomId ,
3723
+ }
3724
+
3725
+ impl < ' a > MockEndpoint < ' a , JoinRoomEndpoint > {
3726
+ /// Returns a successful response using the provided [`RoomId`].
3727
+ pub fn ok ( self ) -> MatrixMock < ' a > {
3728
+ let room_id = self . endpoint . room_id . to_owned ( ) ;
3729
+
3730
+ self . respond_with ( ResponseTemplate :: new ( 200 ) . set_body_json ( json ! ( {
3731
+ "room_id" : room_id,
3732
+ } ) ) )
3733
+ }
3734
+ }
0 commit comments