Skip to content

Commit d42d0f3

Browse files
committed
test(sdk): Add a bunch more useful mock helpers
1 parent e4849d5 commit d42d0f3

File tree

1 file changed

+209
-8
lines changed
  • crates/matrix-sdk/src/test_utils/mocks

1 file changed

+209
-8
lines changed

crates/matrix-sdk/src/test_utils/mocks/mod.rs

Lines changed: 209 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,17 +35,19 @@ use ruma::{
3535
directory::PublicRoomsChunk,
3636
encryption::{CrossSigningKey, DeviceKeys, OneTimeKey},
3737
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,
4041
},
4142
media::Method,
4243
serde::Raw,
4344
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,
4647
};
4748
use serde::Deserialize;
48-
use serde_json::{json, Value};
49+
use serde_json::{from_value, json, Value};
50+
use tokio::sync::oneshot::{self, Receiver};
4951
use wiremock::{
5052
matchers::{body_json, body_partial_json, header, method, path, path_regex, query_param},
5153
Mock, MockBuilder, MockGuard, MockServer, Request, Respond, ResponseTemplate, Times,
@@ -342,6 +344,36 @@ impl MatrixMockServer {
342344
.expect_default_access_token()
343345
}
344346

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+
345377
/// Creates a prebuilt mock for sending an event in a room.
346378
///
347379
/// Note: works with *any* room.
@@ -1832,6 +1864,102 @@ impl<'a> MockEndpoint<'a, RoomSendEndpoint> {
18321864
pub fn ok(self, returned_event_id: impl Into<OwnedEventId>) -> MatrixMock<'a> {
18331865
self.ok_with_event_id(returned_event_id.into())
18341866
}
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+
}
18351963
}
18361964

18371965
/// A prebuilt mock for sending a state event in a room.
@@ -2444,8 +2572,58 @@ impl<'a> MockEndpoint<'a, UploadEndpoint> {
24442572
Self { mock: self.mock.and(header("content-type", content_type)), ..self }
24452573
}
24462574

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`].
24492627
pub fn ok(self, mxc_id: &MxcUri) -> MatrixMock<'a> {
24502628
self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
24512629
"content_uri": mxc_id
@@ -3269,7 +3447,7 @@ impl<'a> MockEndpoint<'a, LoginEndpoint> {
32693447
///
32703448
/// # Examples
32713449
///
3272-
/// ```rust
3450+
/// ```
32733451
/// use matrix_sdk::test_utils::mocks::{
32743452
/// LoginResponseTemplate200, MatrixMockServer,
32753453
/// };
@@ -3483,6 +3661,13 @@ impl<'a> MockEndpoint<'a, MediaDownloadEndpoint> {
34833661
self.respond_with(ResponseTemplate::new(200).set_body_string("Hello, World!"))
34843662
}
34853663

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+
34863671
/// Returns a successful response with a fake image content.
34873672
pub fn ok_image(self) -> MatrixMock<'a> {
34883673
self.respond_with(
@@ -3531,3 +3716,19 @@ impl<'a> MockEndpoint<'a, AuthedMediaThumbnailEndpoint> {
35313716
)
35323717
}
35333718
}
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

Comments
 (0)