Skip to main content

matrix_sdk/test_utils/mocks/
mod.rs

1// Copyright 2024 The Matrix.org Foundation C.I.C.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Helpers to mock a server and have a client automatically connected to that
16//! server, for the purpose of integration tests.
17
18#![allow(missing_debug_implementations)]
19
20use std::{
21    collections::BTreeMap,
22    sync::{Arc, Mutex, atomic::AtomicU32},
23};
24
25use js_int::UInt;
26use matrix_sdk_base::deserialized_responses::TimelineEvent;
27#[cfg(feature = "experimental-element-recent-emojis")]
28use matrix_sdk_base::recent_emojis::RecentEmojisContent;
29use matrix_sdk_test::{
30    InvitedRoomBuilder, JoinedRoomBuilder, KnockedRoomBuilder, LeftRoomBuilder,
31    SyncResponseBuilder, event_factory::EventFactory, test_json,
32};
33use percent_encoding::{AsciiSet, CONTROLS};
34use ruma::{
35    DeviceId, EventId, MilliSecondsSinceUnixEpoch, MxcUri, OwnedDeviceId, OwnedEventId,
36    OwnedOneTimeKeyId, OwnedRoomId, OwnedUserId, RoomId, ServerName, UserId,
37    api::client::{
38        profile::{ProfileFieldName, ProfileFieldValue},
39        receipt::create_receipt::v3::ReceiptType,
40        room::Visibility,
41        sync::sync_events::v5,
42        threads::get_thread_subscriptions_changes::unstable::{
43            ThreadSubscription, ThreadUnsubscription,
44        },
45    },
46    device_id,
47    directory::PublicRoomsChunk,
48    encryption::{CrossSigningKey, DeviceKeys, OneTimeKey},
49    events::{
50        AnyStateEvent, AnySyncTimelineEvent, AnyTimelineEvent, GlobalAccountDataEventType,
51        MessageLikeEventType, RoomAccountDataEventType, StateEventType, receipt::ReceiptThread,
52        room::member::RoomMemberEvent,
53    },
54    media::Method,
55    push::RuleKind,
56    serde::Raw,
57    time::Duration,
58};
59use serde::{Deserialize, Serialize};
60use serde_json::{Value, from_value, json};
61use tokio::sync::oneshot::{self, Receiver};
62use wiremock::{
63    Mock, MockBuilder, MockGuard, MockServer, Request, Respond, ResponseTemplate, Times,
64    matchers::{
65        body_json, body_partial_json, header, method, path, path_regex, query_param,
66        query_param_is_missing,
67    },
68};
69
70#[cfg(feature = "e2e-encryption")]
71pub mod encryption;
72pub mod oauth;
73
74use super::client::MockClientBuilder;
75use crate::{Client, OwnedServerName, Room, SlidingSyncBuilder, room::IncludeRelations};
76
77/// Structure used to store the crypto keys uploaded to the server.
78/// They will be served back to clients when requested.
79#[derive(Debug, Default)]
80struct Keys {
81    device: BTreeMap<OwnedUserId, BTreeMap<String, Raw<DeviceKeys>>>,
82    master: BTreeMap<OwnedUserId, Raw<CrossSigningKey>>,
83    self_signing: BTreeMap<OwnedUserId, Raw<CrossSigningKey>>,
84    user_signing: BTreeMap<OwnedUserId, Raw<CrossSigningKey>>,
85    one_time_keys: BTreeMap<
86        OwnedUserId,
87        BTreeMap<OwnedDeviceId, BTreeMap<OwnedOneTimeKeyId, Raw<OneTimeKey>>>,
88    >,
89}
90
91/// A [`wiremock`] [`MockServer`] along with useful methods to help mocking
92/// Matrix client-server API endpoints easily.
93///
94/// It implements mock endpoints, limiting the shared code as much as possible,
95/// so the mocks are still flexible to use as scoped/unscoped mounts, named, and
96/// so on.
97///
98/// It works like this:
99///
100/// * start by saying which endpoint you'd like to mock, e.g.
101///   [`Self::mock_room_send()`]. This returns a specialized [`MockEndpoint`]
102///   data structure, with its own impl. For this example, it's
103///   `MockEndpoint<RoomSendEndpoint>`.
104/// * configure the response on the endpoint-specific mock data structure. For
105///   instance, if you want the sending to result in a transient failure, call
106///   [`MockEndpoint::error500`]; if you want it to succeed and return the event
107///   `$42`, call [`MockEndpoint::ok()`]. It's still possible to call
108///   [`MockEndpoint::respond_with()`], as we do with wiremock MockBuilder, for
109///   maximum flexibility when the helpers aren't sufficient.
110/// * once the endpoint's response is configured, for any mock builder, you get
111///   a [`MatrixMock`]; this is a plain [`wiremock::Mock`] with the server
112///   curried, so one doesn't have to pass it around when calling
113///   [`MatrixMock::mount()`] or [`MatrixMock::mount_as_scoped()`]. As such, it
114///   mostly defers its implementations to [`wiremock::Mock`] under the hood.
115///
116/// # Examples
117///
118/// ```
119/// # tokio_test::block_on(async {
120/// use matrix_sdk::{ruma::{room_id, event_id}, test_utils::mocks::MatrixMockServer};
121/// use serde_json::json;
122///
123/// // First create the mock server and client pair.
124/// let mock_server = MatrixMockServer::new().await;
125/// let client = mock_server.client_builder().build().await;
126///
127/// // Let's say that our rooms are not encrypted.
128/// mock_server.mock_room_state_encryption().plain().mount().await;
129///
130/// // Let us get a room where we will send an event.
131/// let room = mock_server
132///     .sync_joined_room(&client, room_id!("!room_id:localhost"))
133///     .await;
134///
135/// // Now we mock the endpoint so we can actually send the event.
136/// let event_id = event_id!("$some_id");
137/// let send_guard = mock_server
138///     .mock_room_send()
139///     .ok(event_id)
140///     .expect(1)
141///     .mount_as_scoped()
142///     .await;
143///
144/// // And we send it out.
145/// let result = room.send_raw("m.room.message", json!({ "body": "Hello world" })).await?;
146///
147/// assert_eq!(
148///     event_id,
149///     result.response.event_id,
150///     "The event ID we mocked should match the one we received when we sent the event"
151/// );
152/// # anyhow::Ok(()) });
153/// ```
154pub struct MatrixMockServer {
155    server: MockServer,
156
157    /// Make the sync response builder stateful, to keep in memory the batch
158    /// token and avoid the client ignoring subsequent responses after the first
159    /// one.
160    sync_response_builder: Arc<Mutex<SyncResponseBuilder>>,
161
162    /// Make this mock server capable of mocking real end to end communications
163    keys: Arc<Mutex<Keys>>,
164
165    /// For crypto API end-points to work we need to be able to recognise
166    /// what client is doing the request by mapping the token to the user_id
167    token_to_user_id_map: Arc<Mutex<BTreeMap<String, OwnedUserId>>>,
168    token_counter: AtomicU32,
169}
170
171impl MatrixMockServer {
172    /// Create a new [`wiremock`] server specialized for Matrix usage.
173    pub async fn new() -> Self {
174        let server = MockServer::start().await;
175        let keys: Arc<Mutex<Keys>> = Default::default();
176        Self {
177            server,
178            sync_response_builder: Default::default(),
179            keys,
180            token_to_user_id_map: Default::default(),
181            token_counter: AtomicU32::new(0),
182        }
183    }
184
185    /// Creates a new [`MatrixMockServer`] from a [`wiremock`] server.
186    pub fn from_server(server: MockServer) -> Self {
187        let keys: Arc<Mutex<Keys>> = Default::default();
188        Self {
189            server,
190            sync_response_builder: Default::default(),
191            keys,
192            token_to_user_id_map: Default::default(),
193            token_counter: AtomicU32::new(0),
194        }
195    }
196
197    /// Creates a new [`MockClientBuilder`] configured to use this server,
198    /// preconfigured with a session expected by the server endpoints.
199    pub fn client_builder(&self) -> MockClientBuilder {
200        MockClientBuilder::new(Some(&self.server.uri()))
201    }
202
203    /// Return the underlying [`wiremock`] server.
204    pub fn server(&self) -> &MockServer {
205        &self.server
206    }
207
208    /// Return the URI of this server.
209    pub fn uri(&self) -> String {
210        self.server.uri()
211    }
212
213    /// Get an `OAuthMockServer` that uses the same mock server as this one.
214    pub fn oauth(&self) -> oauth::OAuthMockServer<'_> {
215        oauth::OAuthMockServer::new(self)
216    }
217
218    /// Mock the given endpoint.
219    fn mock_endpoint<T>(&self, mock: MockBuilder, endpoint: T) -> MockEndpoint<'_, T> {
220        MockEndpoint::new(&self.server, mock, endpoint)
221    }
222
223    /// Overrides the sync/ endpoint with knowledge that the given
224    /// invited/joined/knocked/left room exists, runs a sync and returns the
225    /// given room.
226    ///
227    /// # Examples
228    ///
229    /// ```
230    /// # tokio_test::block_on(async {
231    /// use matrix_sdk::{ruma::{room_id, event_id}, test_utils::mocks::MatrixMockServer};
232    /// use matrix_sdk_test::LeftRoomBuilder;
233    ///
234    /// let mock_server = MatrixMockServer::new().await;
235    /// let client = mock_server.client_builder().build().await;
236    ///
237    /// let left_room = mock_server
238    ///     .sync_room(&client, LeftRoomBuilder::new(room_id!("!room_id:localhost")))
239    ///     .await;
240    /// # anyhow::Ok(()) });
241    pub async fn sync_room(&self, client: &Client, room_data: impl Into<AnyRoomBuilder>) -> Room {
242        let any_room = room_data.into();
243        let room_id = any_room.room_id().to_owned();
244
245        self.mock_sync()
246            .ok_and_run(client, move |builder| match any_room {
247                AnyRoomBuilder::Invited(invited) => {
248                    builder.add_invited_room(invited);
249                }
250                AnyRoomBuilder::Joined(joined) => {
251                    builder.add_joined_room(joined);
252                }
253                AnyRoomBuilder::Left(left) => {
254                    builder.add_left_room(left);
255                }
256                AnyRoomBuilder::Knocked(knocked) => {
257                    builder.add_knocked_room(knocked);
258                }
259            })
260            .await;
261
262        client.get_room(&room_id).expect("look at me, the room is known now")
263    }
264
265    /// Overrides the sync/ endpoint with knowledge that the given room exists
266    /// in the joined state, runs a sync and returns the given room.
267    ///
268    /// # Examples
269    ///
270    /// ```
271    /// # tokio_test::block_on(async {
272    /// use matrix_sdk::{ruma::room_id, test_utils::mocks::MatrixMockServer};
273    ///
274    /// let mock_server = MatrixMockServer::new().await;
275    /// let client = mock_server.client_builder().build().await;
276    ///
277    /// let room = mock_server
278    ///     .sync_joined_room(&client, room_id!("!room_id:localhost"))
279    ///     .await;
280    /// # anyhow::Ok(()) });
281    pub async fn sync_joined_room(&self, client: &Client, room_id: &RoomId) -> Room {
282        self.sync_room(client, JoinedRoomBuilder::new(room_id)).await
283    }
284
285    /// Verify that the previous mocks expected number of requests match
286    /// reality, and then cancels all active mocks.
287    ///
288    /// # Examples
289    ///
290    /// ```
291    /// # tokio_test::block_on(async {
292    /// use matrix_sdk::{ruma::{room_id, event_id}, test_utils::mocks::MatrixMockServer};
293    /// use serde_json::json;
294    ///
295    /// let mock_server = MatrixMockServer::new().await;
296    /// let client = mock_server.client_builder().build().await;
297    ///
298    /// mock_server.mock_room_state_encryption().plain().mount().await;
299    /// let room = mock_server
300    ///     .sync_joined_room(&client, room_id!("!room_id:localhost"))
301    ///     .await;
302    /// mock_server.mock_room_send().ok(event_id!("$some_id")).mount().await;
303    ///
304    /// // This will succeed.
305    /// let response = room.send_raw("m.room.message", json!({ "body": "Hello world" })).await?;
306    ///
307    /// // Now we reset the mocks.
308    /// mock_server.verify_and_reset().await;
309    ///
310    /// // And we can't send anymore.
311    /// let response = room
312    ///     .send_raw("m.room.message", json!({ "body": "Hello world" }))
313    ///     .await
314    ///     .expect_err("We removed the mock so sending should now fail");
315    /// # anyhow::Ok(()) });
316    /// ```
317    pub async fn verify_and_reset(&self) {
318        self.server.verify().await;
319        self.server.reset().await;
320    }
321}
322
323// Specific mount endpoints.
324impl MatrixMockServer {
325    /// Mocks a sync endpoint.
326    ///
327    /// # Examples
328    ///
329    /// ```
330    /// # tokio_test::block_on(async {
331    /// use matrix_sdk::{ruma::room_id, test_utils::mocks::MatrixMockServer};
332    /// use matrix_sdk_test::JoinedRoomBuilder;
333    ///
334    /// // First create the mock server and client pair.
335    /// let mock_server = MatrixMockServer::new().await;
336    /// let client = mock_server.client_builder().build().await;
337    /// let room_id = room_id!("!room_id:localhost");
338    ///
339    /// // Let's emulate what `MatrixMockServer::sync_joined_room()` does.
340    /// mock_server
341    ///     .mock_sync()
342    ///     .ok_and_run(&client, |builder| {
343    ///         builder.add_joined_room(JoinedRoomBuilder::new(room_id));
344    ///     })
345    ///     .await;
346    ///
347    /// let room = client
348    ///     .get_room(room_id)
349    ///     .expect("The room should be available after we mocked the sync");
350    /// # anyhow::Ok(()) });
351    /// ```
352    pub fn mock_sync(&self) -> MockEndpoint<'_, SyncEndpoint> {
353        let mock = Mock::given(method("GET")).and(path("/_matrix/client/v3/sync"));
354        self.mock_endpoint(
355            mock,
356            SyncEndpoint { sync_response_builder: self.sync_response_builder.clone() },
357        )
358    }
359
360    /// Mocks the sliding sync endpoint.
361    pub fn mock_sliding_sync(&self) -> MockEndpoint<'_, SlidingSyncEndpoint> {
362        let mock = Mock::given(method("POST"))
363            .and(path("/_matrix/client/unstable/org.matrix.simplified_msc3575/sync"));
364        self.mock_endpoint(mock, SlidingSyncEndpoint)
365    }
366
367    /// Creates a prebuilt mock for joining a room.
368    ///
369    /// # Examples
370    ///
371    /// ```
372    /// # tokio_test::block_on(async {
373    /// use matrix_sdk::{ruma::{room_id, event_id}, test_utils::mocks::MatrixMockServer};
374    /// use serde_json::json;
375    ///
376    /// let mock_server = MatrixMockServer::new().await;
377    /// let client = mock_server.client_builder().build().await;
378    /// let room_id = room_id!("!test:localhost");
379    ///
380    /// mock_server.mock_room_join(room_id).ok().mount();
381    ///
382    /// let room = client.join_room_by_id(room_id).await?;
383    ///
384    /// assert_eq!(
385    ///     room_id,
386    ///     room.room_id(),
387    ///     "The room ID we mocked should match the one we received when we joined the room"
388    /// );
389    /// # anyhow::Ok(()) });
390    /// ```
391    pub fn mock_room_join(&self, room_id: &RoomId) -> MockEndpoint<'_, JoinRoomEndpoint> {
392        let mock = Mock::given(method("POST"))
393            .and(path_regex(format!("^/_matrix/client/v3/rooms/{room_id}/join")));
394        self.mock_endpoint(mock, JoinRoomEndpoint { room_id: room_id.to_owned() })
395    }
396
397    /// Creates a prebuilt mock for sending an event in a room.
398    ///
399    /// Note: works with *any* room.
400    ///
401    /// # Examples
402    ///
403    /// ```
404    /// # tokio_test::block_on(async {
405    /// use matrix_sdk::{ruma::{room_id, event_id}, test_utils::mocks::MatrixMockServer};
406    /// use serde_json::json;
407    ///
408    /// let mock_server = MatrixMockServer::new().await;
409    /// let client = mock_server.client_builder().build().await;
410    ///
411    /// mock_server.mock_room_state_encryption().plain().mount().await;
412    ///
413    /// let room = mock_server
414    ///     .sync_joined_room(&client, room_id!("!room_id:localhost"))
415    ///     .await;
416    ///
417    /// let event_id = event_id!("$some_id");
418    /// mock_server
419    ///     .mock_room_send()
420    ///     .ok(event_id)
421    ///     .expect(1)
422    ///     .mount()
423    ///     .await;
424    ///
425    /// let result = room.send_raw("m.room.message", json!({ "body": "Hello world" })).await?;
426    ///
427    /// assert_eq!(
428    ///     event_id,
429    ///     result.response.event_id,
430    ///     "The event ID we mocked should match the one we received when we sent the event"
431    /// );
432    /// # anyhow::Ok(()) });
433    /// ```
434    pub fn mock_room_send(&self) -> MockEndpoint<'_, RoomSendEndpoint> {
435        let mock = Mock::given(method("PUT"))
436            .and(path_regex(r"^/_matrix/client/v3/rooms/.*/send/.*".to_owned()));
437        self.mock_endpoint(mock, RoomSendEndpoint)
438    }
439
440    /// Creates a prebuilt mock for sending a state event in a room.
441    ///
442    /// Similar to: [`MatrixMockServer::mock_room_send`]
443    ///
444    /// Note: works with *any* room.
445    /// Note: works with *any* event type.
446    ///
447    /// ```
448    /// # tokio_test::block_on(async {
449    /// use matrix_sdk::{ruma::{room_id, event_id}, test_utils::mocks::MatrixMockServer};
450    /// use serde_json::json;
451    ///
452    /// let mock_server = MatrixMockServer::new().await;
453    /// let client = mock_server.client_builder().build().await;
454    ///
455    /// mock_server.mock_room_state_encryption().plain().mount().await;
456    ///
457    /// let room = mock_server
458    ///     .sync_joined_room(&client, room_id!("!room_id:localhost"))
459    ///     .await;
460    ///
461    /// let event_id = event_id!("$some_id");
462    /// mock_server
463    ///     .mock_room_send_state()
464    ///     .ok(event_id)
465    ///     .expect(1)
466    ///     .mount()
467    ///     .await;
468    ///
469    /// let response_not_mocked = room.send_raw("m.room.create", json!({ "body": "Hello world" })).await;
470    /// // The `/send` endpoint should not be mocked by the server.
471    /// assert!(response_not_mocked.is_err());
472    ///
473    ///
474    /// let response = room.send_state_event_raw("m.room.message", "my_key", json!({ "body": "Hello world" })).await?;
475    /// // The `/state` endpoint should be mocked by the server.
476    /// assert_eq!(
477    ///     event_id,
478    ///     response.event_id,
479    ///     "The event ID we mocked should match the one we received when we sent the event"
480    /// );
481    /// # anyhow::Ok(()) });
482    /// ```
483    pub fn mock_room_send_state(&self) -> MockEndpoint<'_, RoomSendStateEndpoint> {
484        let mock =
485            Mock::given(method("PUT")).and(path_regex(r"^/_matrix/client/v3/rooms/.*/state/.*/.*"));
486        self.mock_endpoint(mock, RoomSendStateEndpoint::default()).expect_default_access_token()
487    }
488
489    /// Creates a prebuilt mock for asking whether *a* room is encrypted or not.
490    ///
491    /// Note: Applies to all rooms.
492    ///
493    /// # Examples
494    ///
495    /// ```
496    /// # tokio_test::block_on(async {
497    /// use matrix_sdk::{ruma::room_id, test_utils::mocks::MatrixMockServer};
498    ///
499    /// let mock_server = MatrixMockServer::new().await;
500    /// let client = mock_server.client_builder().build().await;
501    ///
502    /// mock_server.mock_room_state_encryption().encrypted().mount().await;
503    ///
504    /// let room = mock_server
505    ///     .sync_joined_room(&client, room_id!("!room_id:localhost"))
506    ///     .await;
507    ///
508    /// assert!(
509    ///     room.latest_encryption_state().await?.is_encrypted(),
510    ///     "The room should be marked as encrypted."
511    /// );
512    /// # anyhow::Ok(()) });
513    /// ```
514    pub fn mock_room_state_encryption(&self) -> MockEndpoint<'_, EncryptionStateEndpoint> {
515        let mock = Mock::given(method("GET"))
516            .and(path_regex(r"^/_matrix/client/v3/rooms/.*/state/m.*room.*encryption.?"));
517        self.mock_endpoint(mock, EncryptionStateEndpoint).expect_default_access_token()
518    }
519
520    /// Creates a prebuilt mock for setting the room encryption state.
521    ///
522    /// Note: Applies to all rooms.
523    ///
524    /// # Examples
525    ///
526    /// ```
527    /// # tokio_test::block_on(async {
528    /// use matrix_sdk::{
529    ///     ruma::{event_id, room_id},
530    ///     test_utils::mocks::MatrixMockServer,
531    /// };
532    ///
533    /// let mock_server = MatrixMockServer::new().await;
534    /// let client = mock_server.client_builder().build().await;
535    ///
536    /// mock_server.mock_room_state_encryption().plain().mount().await;
537    /// mock_server
538    ///     .mock_set_room_state_encryption()
539    ///     .ok(event_id!("$id"))
540    ///     .mock_once()
541    ///     .mount()
542    ///     .await;
543    ///
544    /// let room = mock_server
545    ///     .sync_joined_room(&client, room_id!("!room_id:localhost"))
546    ///     .await;
547    ///
548    /// room.enable_encryption()
549    ///     .await
550    ///     .expect("We should be able to enable encryption in the room");
551    /// # anyhow::Ok(()) });
552    /// ```
553    pub fn mock_set_room_state_encryption(&self) -> MockEndpoint<'_, SetEncryptionStateEndpoint> {
554        let mock = Mock::given(method("PUT"))
555            .and(path_regex(r"^/_matrix/client/v3/rooms/.*/state/m.*room.*encryption.?"));
556        self.mock_endpoint(mock, SetEncryptionStateEndpoint).expect_default_access_token()
557    }
558
559    /// Creates a prebuilt mock for the room redact endpoint.
560    ///
561    /// # Examples
562    ///
563    /// ```
564    /// # tokio_test::block_on(async {
565    /// use matrix_sdk::{
566    ///     ruma::{event_id, room_id},
567    ///     test_utils::mocks::MatrixMockServer,
568    /// };
569    ///
570    /// let mock_server = MatrixMockServer::new().await;
571    /// let client = mock_server.client_builder().build().await;
572    /// let event_id = event_id!("$id");
573    ///
574    /// mock_server.mock_room_redact().ok(event_id).mock_once().mount().await;
575    ///
576    /// let room = mock_server
577    ///     .sync_joined_room(&client, room_id!("!room_id:localhost"))
578    ///     .await;
579    ///
580    /// room.redact(event_id, None, None)
581    ///     .await
582    ///     .expect("We should be able to redact events in the room");
583    /// # anyhow::Ok(()) });
584    /// ```
585    pub fn mock_room_redact(&self) -> MockEndpoint<'_, RoomRedactEndpoint> {
586        let mock = Mock::given(method("PUT"))
587            .and(path_regex(r"^/_matrix/client/v3/rooms/.*/redact/.*?/.*?"));
588        self.mock_endpoint(mock, RoomRedactEndpoint).expect_default_access_token()
589    }
590
591    /// Creates a prebuilt mock for retrieving an event with /room/.../event.
592    pub fn mock_room_event(&self) -> MockEndpoint<'_, RoomEventEndpoint> {
593        let mock = Mock::given(method("GET"));
594        self.mock_endpoint(mock, RoomEventEndpoint { room: None, match_event_id: false })
595            .expect_default_access_token()
596    }
597
598    /// Creates a prebuilt mock for retrieving an event with /room/.../context.
599    pub fn mock_room_event_context(&self) -> MockEndpoint<'_, RoomEventContextEndpoint> {
600        let mock = Mock::given(method("GET"));
601        self.mock_endpoint(mock, RoomEventContextEndpoint { room: None, match_event_id: false })
602            .expect_default_access_token()
603    }
604
605    /// Create a prebuild mock for paginating room message with the `/messages`
606    /// endpoint.
607    pub fn mock_room_messages(&self) -> MockEndpoint<'_, RoomMessagesEndpoint> {
608        let mock =
609            Mock::given(method("GET")).and(path_regex(r"^/_matrix/client/v3/rooms/.*/messages$"));
610        self.mock_endpoint(mock, RoomMessagesEndpoint).expect_default_access_token()
611    }
612
613    /// Create a prebuilt mock for uploading media.
614    pub fn mock_upload(&self) -> MockEndpoint<'_, UploadEndpoint> {
615        let mock = Mock::given(method("POST")).and(path("/_matrix/media/v3/upload"));
616        self.mock_endpoint(mock, UploadEndpoint)
617    }
618
619    /// Create a prebuilt mock for resolving room aliases.
620    ///
621    /// # Examples
622    ///
623    /// ```
624    /// # tokio_test::block_on(async {
625    /// use matrix_sdk::{
626    ///     ruma::{owned_room_id, room_alias_id},
627    ///     test_utils::mocks::MatrixMockServer,
628    /// };
629    /// let mock_server = MatrixMockServer::new().await;
630    /// let client = mock_server.client_builder().build().await;
631    ///
632    /// mock_server
633    ///     .mock_room_directory_resolve_alias()
634    ///     .ok("!a:b.c", Vec::new())
635    ///     .mock_once()
636    ///     .mount()
637    ///     .await;
638    ///
639    /// let res = client
640    ///     .resolve_room_alias(room_alias_id!("#a:b.c"))
641    ///     .await
642    ///     .expect("We should be able to resolve the room alias");
643    /// assert_eq!(res.room_id, owned_room_id!("!a:b.c"));
644    /// # anyhow::Ok(()) });
645    /// ```
646    pub fn mock_room_directory_resolve_alias(&self) -> MockEndpoint<'_, ResolveRoomAliasEndpoint> {
647        let mock =
648            Mock::given(method("GET")).and(path_regex(r"/_matrix/client/v3/directory/room/.*"));
649        self.mock_endpoint(mock, ResolveRoomAliasEndpoint)
650    }
651
652    /// Create a prebuilt mock for publishing room aliases in the room
653    /// directory.
654    ///
655    /// # Examples
656    ///
657    /// ```
658    /// # tokio_test::block_on(async {
659    /// use matrix_sdk::{
660    ///     ruma::{room_alias_id, room_id},
661    ///     test_utils::mocks::MatrixMockServer,
662    /// };
663    ///
664    /// let mock_server = MatrixMockServer::new().await;
665    /// let client = mock_server.client_builder().build().await;
666    ///
667    /// mock_server
668    ///     .mock_room_directory_create_room_alias()
669    ///     .ok()
670    ///     .mock_once()
671    ///     .mount()
672    ///     .await;
673    ///
674    /// client
675    ///     .create_room_alias(room_alias_id!("#a:b.c"), room_id!("!a:b.c"))
676    ///     .await
677    ///     .expect("We should be able to create a room alias");
678    /// # anyhow::Ok(()) });
679    /// ```
680    pub fn mock_room_directory_create_room_alias(
681        &self,
682    ) -> MockEndpoint<'_, CreateRoomAliasEndpoint> {
683        let mock =
684            Mock::given(method("PUT")).and(path_regex(r"/_matrix/client/v3/directory/room/.*"));
685        self.mock_endpoint(mock, CreateRoomAliasEndpoint)
686    }
687
688    /// Create a prebuilt mock for removing room aliases from the room
689    /// directory.
690    ///
691    /// # Examples
692    ///
693    /// ```
694    /// # tokio_test::block_on(async {
695    /// use matrix_sdk::{
696    ///     ruma::room_alias_id, test_utils::mocks::MatrixMockServer,
697    /// };
698    ///
699    /// let mock_server = MatrixMockServer::new().await;
700    /// let client = mock_server.client_builder().build().await;
701    ///
702    /// mock_server
703    ///     .mock_room_directory_remove_room_alias()
704    ///     .ok()
705    ///     .mock_once()
706    ///     .mount()
707    ///     .await;
708    ///
709    /// client
710    ///     .remove_room_alias(room_alias_id!("#a:b.c"))
711    ///     .await
712    ///     .expect("We should be able to remove the room alias");
713    /// # anyhow::Ok(()) });
714    /// ```
715    pub fn mock_room_directory_remove_room_alias(
716        &self,
717    ) -> MockEndpoint<'_, RemoveRoomAliasEndpoint> {
718        let mock =
719            Mock::given(method("DELETE")).and(path_regex(r"/_matrix/client/v3/directory/room/.*"));
720        self.mock_endpoint(mock, RemoveRoomAliasEndpoint)
721    }
722
723    /// Create a prebuilt mock for listing public rooms.
724    ///
725    /// # Examples
726    ///
727    /// ```
728    /// #
729    /// tokio_test::block_on(async {
730    /// use js_int::uint;
731    /// use ruma::directory::PublicRoomsChunkInit;
732    /// use matrix_sdk::room_directory_search::RoomDirectorySearch;
733    /// use matrix_sdk::{
734    ///     ruma::{event_id, room_id},
735    ///     test_utils::mocks::MatrixMockServer,
736    /// };
737    /// let mock_server = MatrixMockServer::new().await;
738    /// let client = mock_server.client_builder().build().await;
739    /// let event_id = event_id!("$id");
740    /// let room_id = room_id!("!room_id:localhost");
741    ///
742    /// let chunk = vec![PublicRoomsChunkInit {
743    ///     num_joined_members: uint!(0),
744    ///     room_id: room_id.to_owned(),
745    ///     world_readable: true,
746    ///     guest_can_join: true,
747    /// }.into()];
748    ///
749    /// mock_server.mock_public_rooms().ok(chunk, None, None, Some(20)).mock_once().mount().await;
750    /// let mut room_directory_search = RoomDirectorySearch::new(client);
751    ///
752    /// room_directory_search.search(Some("some-alias".to_owned()), 100, None)
753    ///     .await
754    ///     .expect("Room directory search failed");
755    ///
756    /// let (results, _) = room_directory_search.results();
757    /// assert_eq!(results.len(), 1);
758    /// assert_eq!(results.get(0).unwrap().room_id, room_id.to_owned());
759    /// # });
760    /// ```
761    pub fn mock_public_rooms(&self) -> MockEndpoint<'_, PublicRoomsEndpoint> {
762        let mock = Mock::given(method("POST")).and(path_regex(r"/_matrix/client/v3/publicRooms"));
763        self.mock_endpoint(mock, PublicRoomsEndpoint)
764    }
765
766    /// Create a prebuilt mock for setting a room's visibility in the room
767    /// directory.
768    ///
769    /// # Examples
770    ///
771    /// ```
772    /// # tokio_test::block_on(async {
773    /// use matrix_sdk::{ruma::room_id, test_utils::mocks::MatrixMockServer};
774    /// use ruma::api::client::room::Visibility;
775    ///
776    /// let mock_server = MatrixMockServer::new().await;
777    /// let client = mock_server.client_builder().build().await;
778    ///
779    /// mock_server
780    ///     .mock_room_directory_set_room_visibility()
781    ///     .ok()
782    ///     .mock_once()
783    ///     .mount()
784    ///     .await;
785    ///
786    /// let room = mock_server
787    ///     .sync_joined_room(&client, room_id!("!room_id:localhost"))
788    ///     .await;
789    ///
790    /// room.privacy_settings()
791    ///     .update_room_visibility(Visibility::Private)
792    ///     .await
793    ///     .expect("We should be able to update the room's visibility");
794    /// # anyhow::Ok(()) });
795    /// ```
796    pub fn mock_room_directory_set_room_visibility(
797        &self,
798    ) -> MockEndpoint<'_, SetRoomVisibilityEndpoint> {
799        let mock = Mock::given(method("PUT"))
800            .and(path_regex(r"^/_matrix/client/v3/directory/list/room/.*$"));
801        self.mock_endpoint(mock, SetRoomVisibilityEndpoint)
802    }
803
804    /// Create a prebuilt mock for getting a room's visibility in the room
805    /// directory.
806    ///
807    /// # Examples
808    ///
809    /// ```
810    /// # tokio_test::block_on(async {
811    /// use matrix_sdk::{ruma::room_id, test_utils::mocks::MatrixMockServer};
812    /// use ruma::api::client::room::Visibility;
813    ///
814    /// let mock_server = MatrixMockServer::new().await;
815    /// let client = mock_server.client_builder().build().await;
816    ///
817    /// mock_server
818    ///     .mock_room_directory_get_room_visibility()
819    ///     .ok(Visibility::Public)
820    ///     .mock_once()
821    ///     .mount()
822    ///     .await;
823    ///
824    /// let room = mock_server
825    ///     .sync_joined_room(&client, room_id!("!room_id:localhost"))
826    ///     .await;
827    ///
828    /// let visibility = room
829    ///     .privacy_settings()
830    ///     .get_room_visibility()
831    ///     .await
832    ///     .expect("We should be able to get the room's visibility");
833    /// assert_eq!(visibility, Visibility::Public);
834    /// # anyhow::Ok(()) });
835    /// ```
836    pub fn mock_room_directory_get_room_visibility(
837        &self,
838    ) -> MockEndpoint<'_, GetRoomVisibilityEndpoint> {
839        let mock = Mock::given(method("GET"))
840            .and(path_regex(r"^/_matrix/client/v3/directory/list/room/.*$"));
841        self.mock_endpoint(mock, GetRoomVisibilityEndpoint)
842    }
843
844    /// Create a prebuilt mock for fetching information about key storage
845    /// backups.
846    ///
847    /// # Examples
848    ///
849    /// ```
850    /// # #[cfg(feature = "e2e-encryption")]
851    /// # {
852    /// # tokio_test::block_on(async {
853    /// use matrix_sdk::test_utils::mocks::MatrixMockServer;
854    ///
855    /// let mock_server = MatrixMockServer::new().await;
856    /// let client = mock_server.client_builder().build().await;
857    ///
858    /// mock_server.mock_room_keys_version().exists().expect(1).mount().await;
859    ///
860    /// let exists =
861    ///     client.encryption().backups().fetch_exists_on_server().await.unwrap();
862    ///
863    /// assert!(exists);
864    /// # });
865    /// # }
866    /// ```
867    pub fn mock_room_keys_version(&self) -> MockEndpoint<'_, RoomKeysVersionEndpoint> {
868        let mock =
869            Mock::given(method("GET")).and(path_regex(r"_matrix/client/v3/room_keys/version"));
870        self.mock_endpoint(mock, RoomKeysVersionEndpoint).expect_default_access_token()
871    }
872
873    /// Create a prebuilt mock for adding key storage backups via POST
874    pub fn mock_add_room_keys_version(&self) -> MockEndpoint<'_, AddRoomKeysVersionEndpoint> {
875        let mock =
876            Mock::given(method("POST")).and(path_regex(r"_matrix/client/v3/room_keys/version"));
877        self.mock_endpoint(mock, AddRoomKeysVersionEndpoint).expect_default_access_token()
878    }
879
880    /// Create a prebuilt mock for adding key storage backups via POST
881    pub fn mock_delete_room_keys_version(&self) -> MockEndpoint<'_, DeleteRoomKeysVersionEndpoint> {
882        let mock = Mock::given(method("DELETE"))
883            .and(path_regex(r"_matrix/client/v3/room_keys/version/[^/]*"));
884        self.mock_endpoint(mock, DeleteRoomKeysVersionEndpoint).expect_default_access_token()
885    }
886
887    /// Creates a prebuilt mock for the `/sendToDevice` endpoint.
888    ///
889    /// This mock can be used to simulate sending to-device messages in tests.
890    /// # Examples
891    ///
892    /// ```
893    /// # #[cfg(feature = "e2e-encryption")]
894    /// # {
895    /// # tokio_test::block_on(async {
896    /// use std::collections::BTreeMap;
897    /// use matrix_sdk::{
898    ///     ruma::{
899    ///         events::{AnyToDeviceEventContent, dummy::ToDeviceDummyEventContent},
900    ///         serde::Raw,
901    ///         api::client::to_device::send_event_to_device::v3::Request as ToDeviceRequest,
902    ///         to_device::DeviceIdOrAllDevices,
903    ///         owned_user_id, owned_device_id
904    ///     },
905    ///     test_utils::mocks::MatrixMockServer,
906    /// };
907    /// use serde_json::json;
908    ///
909    /// let mock_server = MatrixMockServer::new().await;
910    /// let client = mock_server.client_builder().build().await;
911    ///
912    /// mock_server.mock_send_to_device().ok().mock_once().mount().await;
913    ///
914    /// let request = ToDeviceRequest::new_raw(
915    ///     "m.custom.event".into(),
916    ///     "txn_id".into(),
917    ///     BTreeMap::from([(
918    ///         owned_user_id!("@alice:localhost"),
919    ///         BTreeMap::from([(
920    ///             DeviceIdOrAllDevices::AllDevices,
921    ///             Raw::new(&AnyToDeviceEventContent::Dummy(ToDeviceDummyEventContent {})).unwrap(),
922    ///         )])
923    ///     )]),
924    /// );
925    ///
926    /// client
927    ///     .send(request)
928    ///     .await
929    ///     .expect("We should be able to send a to-device message");
930    /// # anyhow::Ok(()) });
931    /// # }
932    /// ```
933    pub fn mock_send_to_device(&self) -> MockEndpoint<'_, SendToDeviceEndpoint> {
934        let mock =
935            Mock::given(method("PUT")).and(path_regex(r"^/_matrix/client/v3/sendToDevice/.*/.*"));
936        self.mock_endpoint(mock, SendToDeviceEndpoint).expect_default_access_token()
937    }
938
939    /// Create a prebuilt mock for getting the room members in a room.
940    ///
941    /// # Examples
942    ///
943    /// ```
944    /// # tokio_test::block_on(async {
945    /// use matrix_sdk::{
946    ///     ruma::{event_id, room_id},
947    ///     test_utils::mocks::MatrixMockServer,
948    /// };
949    /// use matrix_sdk_base::RoomMemberships;
950    /// use matrix_sdk_test::event_factory::EventFactory;
951    /// use ruma::{
952    ///     events::room::member::{MembershipState, RoomMemberEventContent},
953    ///     user_id,
954    /// };
955    /// let mock_server = MatrixMockServer::new().await;
956    /// let client = mock_server.client_builder().build().await;
957    /// let event_id = event_id!("$id");
958    /// let room_id = room_id!("!room_id:localhost");
959    ///
960    /// let f = EventFactory::new().room(room_id);
961    /// let alice_user_id = user_id!("@alice:b.c");
962    /// let alice_knock_event = f
963    ///     .event(RoomMemberEventContent::new(MembershipState::Knock))
964    ///     .event_id(event_id)
965    ///     .sender(alice_user_id)
966    ///     .state_key(alice_user_id)
967    ///     .into_raw();
968    ///
969    /// mock_server
970    ///     .mock_get_members()
971    ///     .ok(vec![alice_knock_event])
972    ///     .mock_once()
973    ///     .mount()
974    ///     .await;
975    /// let room = mock_server.sync_joined_room(&client, room_id).await;
976    ///
977    /// let members = room.members(RoomMemberships::all()).await.unwrap();
978    /// assert_eq!(members.len(), 1);
979    /// # });
980    /// ```
981    pub fn mock_get_members(&self) -> MockEndpoint<'_, GetRoomMembersEndpoint> {
982        let mock =
983            Mock::given(method("GET")).and(path_regex(r"^/_matrix/client/v3/rooms/.*/members$"));
984        self.mock_endpoint(mock, GetRoomMembersEndpoint)
985    }
986
987    /// Creates a prebuilt mock for inviting a user to a room by its id.
988    ///
989    /// # Examples
990    ///
991    /// ```
992    /// # use ruma::user_id;
993    /// tokio_test::block_on(async {
994    /// use matrix_sdk::{
995    ///     ruma::room_id,
996    ///     test_utils::mocks::MatrixMockServer,
997    /// };
998    ///
999    /// let mock_server = MatrixMockServer::new().await;
1000    /// let client = mock_server.client_builder().build().await;
1001    ///
1002    /// mock_server.mock_invite_user_by_id().ok().mock_once().mount().await;
1003    ///
1004    /// let room = mock_server
1005    ///     .sync_joined_room(&client, room_id!("!room_id:localhost"))
1006    ///     .await;
1007    ///
1008    /// room.invite_user_by_id(user_id!("@alice:localhost")).await.unwrap();
1009    /// # anyhow::Ok(()) });
1010    /// ```
1011    pub fn mock_invite_user_by_id(&self) -> MockEndpoint<'_, InviteUserByIdEndpoint> {
1012        let mock =
1013            Mock::given(method("POST")).and(path_regex(r"^/_matrix/client/v3/rooms/.*/invite$"));
1014        self.mock_endpoint(mock, InviteUserByIdEndpoint)
1015    }
1016
1017    /// Creates a prebuilt mock for kicking a user from a room.
1018    ///
1019    /// # Examples
1020    ///
1021    /// ```
1022    /// # use ruma::user_id;
1023    /// tokio_test::block_on(async {
1024    /// use matrix_sdk::{
1025    ///     ruma::room_id,
1026    ///     test_utils::mocks::MatrixMockServer,
1027    /// };
1028    ///
1029    /// let mock_server = MatrixMockServer::new().await;
1030    /// let client = mock_server.client_builder().build().await;
1031    ///
1032    /// mock_server.mock_kick_user().ok().mock_once().mount().await;
1033    ///
1034    /// let room = mock_server
1035    ///     .sync_joined_room(&client, room_id!("!room_id:localhost"))
1036    ///     .await;
1037    ///
1038    /// room.kick_user(user_id!("@alice:localhost"), None).await.unwrap();
1039    /// # anyhow::Ok(()) });
1040    /// ```
1041    pub fn mock_kick_user(&self) -> MockEndpoint<'_, KickUserEndpoint> {
1042        let mock =
1043            Mock::given(method("POST")).and(path_regex(r"^/_matrix/client/v3/rooms/.*/kick"));
1044        self.mock_endpoint(mock, KickUserEndpoint)
1045    }
1046
1047    /// Creates a prebuilt mock for banning a user from a room.
1048    ///
1049    /// # Examples
1050    ///
1051    /// ```
1052    /// # use ruma::user_id;
1053    /// tokio_test::block_on(async {
1054    /// use matrix_sdk::{
1055    ///     ruma::room_id,
1056    ///     test_utils::mocks::MatrixMockServer,
1057    /// };
1058    ///
1059    /// let mock_server = MatrixMockServer::new().await;
1060    /// let client = mock_server.client_builder().build().await;
1061    ///
1062    /// mock_server.mock_ban_user().ok().mock_once().mount().await;
1063    ///
1064    /// let room = mock_server
1065    ///     .sync_joined_room(&client, room_id!("!room_id:localhost"))
1066    ///     .await;
1067    ///
1068    /// room.ban_user(user_id!("@alice:localhost"), None).await.unwrap();
1069    /// # anyhow::Ok(()) });
1070    /// ```
1071    pub fn mock_ban_user(&self) -> MockEndpoint<'_, BanUserEndpoint> {
1072        let mock = Mock::given(method("POST")).and(path_regex(r"^/_matrix/client/v3/rooms/.*/ban"));
1073        self.mock_endpoint(mock, BanUserEndpoint)
1074    }
1075
1076    /// Creates a prebuilt mock for the `/_matrix/client/versions` endpoint.
1077    pub fn mock_versions(&self) -> MockEndpoint<'_, VersionsEndpoint> {
1078        let mock = Mock::given(method("GET")).and(path_regex(r"^/_matrix/client/versions"));
1079        self.mock_endpoint(mock, VersionsEndpoint::default())
1080    }
1081
1082    /// Creates a prebuilt mock for the room summary endpoint [MSC3266](https://github.com/matrix-org/matrix-spec-proposals/pull/3266).
1083    pub fn mock_room_summary(&self) -> MockEndpoint<'_, RoomSummaryEndpoint> {
1084        let mock = Mock::given(method("GET"))
1085            .and(path_regex(r"^/_matrix/client/unstable/im.nheko.summary/rooms/.*/summary"));
1086        self.mock_endpoint(mock, RoomSummaryEndpoint)
1087    }
1088
1089    /// Creates a prebuilt mock for the endpoint used to set a room's pinned
1090    /// events.
1091    pub fn mock_set_room_pinned_events(&self) -> MockEndpoint<'_, SetRoomPinnedEventsEndpoint> {
1092        let mock = Mock::given(method("PUT"))
1093            .and(path_regex(r"^/_matrix/client/v3/rooms/.*/state/m.room.pinned_events/.*?"));
1094        self.mock_endpoint(mock, SetRoomPinnedEventsEndpoint).expect_default_access_token()
1095    }
1096
1097    /// Creates a prebuilt mock for the endpoint used to get information about
1098    /// the owner of the given access token.
1099    ///
1100    /// If no access token is provided, the access token to match is `"1234"`,
1101    /// which matches the default value in the mock data.
1102    pub fn mock_who_am_i(&self) -> MockEndpoint<'_, WhoAmIEndpoint> {
1103        let mock =
1104            Mock::given(method("GET")).and(path_regex(r"^/_matrix/client/v3/account/whoami"));
1105        self.mock_endpoint(mock, WhoAmIEndpoint).expect_default_access_token()
1106    }
1107
1108    /// Creates a prebuilt mock for the endpoint used to publish end-to-end
1109    /// encryption keys.
1110    pub fn mock_upload_keys(&self) -> MockEndpoint<'_, UploadKeysEndpoint> {
1111        let mock = Mock::given(method("POST")).and(path_regex(r"^/_matrix/client/v3/keys/upload"));
1112        self.mock_endpoint(mock, UploadKeysEndpoint).expect_default_access_token()
1113    }
1114
1115    /// Creates a prebuilt mock for the endpoint used to query end-to-end
1116    /// encryption keys.
1117    pub fn mock_query_keys(&self) -> MockEndpoint<'_, QueryKeysEndpoint> {
1118        let mock = Mock::given(method("POST")).and(path_regex(r"^/_matrix/client/v3/keys/query"));
1119        self.mock_endpoint(mock, QueryKeysEndpoint).expect_default_access_token()
1120    }
1121
1122    /// Creates a prebuilt mock for the endpoint used to discover the URL of a
1123    /// homeserver.
1124    pub fn mock_well_known(&self) -> MockEndpoint<'_, WellKnownEndpoint> {
1125        let mock = Mock::given(method("GET")).and(path_regex(r"^/.well-known/matrix/client"));
1126        self.mock_endpoint(mock, WellKnownEndpoint)
1127    }
1128
1129    /// Creates a prebuilt mock for the endpoint used to publish cross-signing
1130    /// keys.
1131    pub fn mock_upload_cross_signing_keys(
1132        &self,
1133    ) -> MockEndpoint<'_, UploadCrossSigningKeysEndpoint> {
1134        let mock = Mock::given(method("POST"))
1135            .and(path_regex(r"^/_matrix/client/v3/keys/device_signing/upload"));
1136        self.mock_endpoint(mock, UploadCrossSigningKeysEndpoint).expect_default_access_token()
1137    }
1138
1139    /// Creates a prebuilt mock for the endpoint used to publish cross-signing
1140    /// signatures.
1141    pub fn mock_upload_cross_signing_signatures(
1142        &self,
1143    ) -> MockEndpoint<'_, UploadCrossSigningSignaturesEndpoint> {
1144        let mock = Mock::given(method("POST"))
1145            .and(path_regex(r"^/_matrix/client/v3/keys/signatures/upload"));
1146        self.mock_endpoint(mock, UploadCrossSigningSignaturesEndpoint).expect_default_access_token()
1147    }
1148
1149    /// Creates a prebuilt mock for the endpoint used to leave a room.
1150    pub fn mock_room_leave(&self) -> MockEndpoint<'_, RoomLeaveEndpoint> {
1151        let mock =
1152            Mock::given(method("POST")).and(path_regex(r"^/_matrix/client/v3/rooms/.*/leave"));
1153        self.mock_endpoint(mock, RoomLeaveEndpoint).expect_default_access_token()
1154    }
1155
1156    /// Creates a prebuilt mock for the endpoint used to forget a room.
1157    pub fn mock_room_forget(&self) -> MockEndpoint<'_, RoomForgetEndpoint> {
1158        let mock =
1159            Mock::given(method("POST")).and(path_regex(r"^/_matrix/client/v3/rooms/.*/forget"));
1160        self.mock_endpoint(mock, RoomForgetEndpoint).expect_default_access_token()
1161    }
1162
1163    /// Create a prebuilt mock for the endpoint use to log out a session.
1164    pub fn mock_logout(&self) -> MockEndpoint<'_, LogoutEndpoint> {
1165        let mock = Mock::given(method("POST")).and(path("/_matrix/client/v3/logout"));
1166        self.mock_endpoint(mock, LogoutEndpoint).expect_default_access_token()
1167    }
1168
1169    /// Create a prebuilt mock for the endpoint used to get the list of thread
1170    /// roots.
1171    pub fn mock_room_threads(&self) -> MockEndpoint<'_, RoomThreadsEndpoint> {
1172        let mock =
1173            Mock::given(method("GET")).and(path_regex(r"^/_matrix/client/v1/rooms/.*/threads$"));
1174        self.mock_endpoint(mock, RoomThreadsEndpoint).expect_default_access_token()
1175    }
1176
1177    /// Create a prebuilt mock for the endpoint used to get the related events.
1178    pub fn mock_room_relations(&self) -> MockEndpoint<'_, RoomRelationsEndpoint> {
1179        // Routing happens in the final method ok(), since it can get complicated.
1180        let mock = Mock::given(method("GET"));
1181        self.mock_endpoint(mock, RoomRelationsEndpoint::default()).expect_default_access_token()
1182    }
1183
1184    /// Create a prebuilt mock for the endpoint used to get the global account
1185    /// data.
1186    ///
1187    /// # Examples
1188    ///
1189    /// ```
1190    /// tokio_test::block_on(async {
1191    /// use js_int::uint;
1192    /// use matrix_sdk::test_utils::mocks::MatrixMockServer;
1193    ///
1194    /// let mock_server = MatrixMockServer::new().await;
1195    /// let client = mock_server.client_builder().build().await;
1196    ///
1197    /// mock_server.mock_get_recent_emojis().ok(
1198    ///     client.user_id().unwrap(),
1199    ///     vec![(":)".to_string(), uint!(1))]
1200    /// )
1201    /// .mock_once()
1202    /// .mount()
1203    /// .await;
1204    ///
1205    /// client.account().fetch_media_preview_config_event_content().await.unwrap();
1206    ///
1207    /// # anyhow::Ok(()) });
1208    /// ```
1209    #[cfg(feature = "experimental-element-recent-emojis")]
1210    pub fn mock_get_recent_emojis(&self) -> MockEndpoint<'_, GetRecentEmojisEndpoint> {
1211        let mock = Mock::given(method("GET"));
1212        self.mock_endpoint(mock, GetRecentEmojisEndpoint).expect_default_access_token()
1213    }
1214
1215    /// Create a prebuilt mock for the endpoint that updates the global account
1216    /// data.
1217    ///
1218    /// # Examples
1219    ///
1220    /// ```
1221    /// tokio_test::block_on(async {
1222    /// use js_int::uint;
1223    /// use matrix_sdk::test_utils::mocks::MatrixMockServer;
1224    /// use ruma::user_id;
1225    ///
1226    /// let mock_server = MatrixMockServer::new().await;
1227    /// let client = mock_server.client_builder().build().await;
1228    /// let user_id = client.user_id().unwrap();
1229    ///
1230    /// mock.server.mock_get_recent_emojis()
1231    /// .ok(user_id, vec![(":D".to_string(), uint!(1))])
1232    /// .mock_once()
1233    /// .mount()
1234    /// .await;
1235    /// mock_server.mock_add_recent_emojis()
1236    /// .ok(user_id)
1237    /// .mock_once()
1238    /// .mount()
1239    /// .await;
1240    /// // Calls both get and update recent emoji endpoints, with an update value
1241    /// client.account().add_recent_emoji(":D").await.unwrap();
1242    ///
1243    /// # anyhow::Ok(()) });
1244    /// ```
1245    #[cfg(feature = "experimental-element-recent-emojis")]
1246    pub fn mock_add_recent_emojis(&self) -> MockEndpoint<'_, UpdateRecentEmojisEndpoint> {
1247        let mock = Mock::given(method("PUT"));
1248        self.mock_endpoint(mock, UpdateRecentEmojisEndpoint::new()).expect_default_access_token()
1249    }
1250
1251    /// Create a prebuilt mock for the endpoint used to get the default secret
1252    /// storage key.
1253    ///
1254    /// # Examples
1255    ///
1256    /// ```
1257    /// tokio_test::block_on(async {
1258    /// use js_int::uint;
1259    /// use matrix_sdk::{
1260    ///     encryption::secret_storage::SecretStorage,
1261    ///     test_utils::mocks::MatrixMockServer,
1262    /// };
1263    ///
1264    /// let mock_server = MatrixMockServer::new().await;
1265    /// let client = mock_server.client_builder().build().await;
1266    ///
1267    /// mock_server.mock_get_default_secret_storage_key().ok(
1268    ///     client.user_id().unwrap(),
1269    ///     "abc", // key ID of default secret storage key
1270    /// )
1271    ///     .mount()
1272    ///     .await;
1273    ///
1274    /// client.encryption()
1275    ///     .secret_storage()
1276    ///     .fetch_default_key_id()
1277    ///     .await
1278    ///     .unwrap();
1279    ///
1280    /// # anyhow::Ok(()) });
1281    /// ```
1282    #[cfg(feature = "e2e-encryption")]
1283    pub fn mock_get_default_secret_storage_key(
1284        &self,
1285    ) -> MockEndpoint<'_, GetDefaultSecretStorageKeyEndpoint> {
1286        let mock = Mock::given(method("GET"));
1287        self.mock_endpoint(mock, GetDefaultSecretStorageKeyEndpoint).expect_default_access_token()
1288    }
1289
1290    /// Create a prebuilt mock for the endpoint used to get a secret storage
1291    /// key.
1292    ///
1293    /// # Examples
1294    ///
1295    /// ```
1296    /// tokio_test::block_on(async {
1297    /// use js_int::uint;
1298    /// use ruma::events::secret_storage::key;
1299    /// use ruma::serde::Base64;
1300    /// use matrix_sdk::{
1301    ///     encryption::secret_storage::SecretStorage,
1302    ///     test_utils::mocks::MatrixMockServer,
1303    /// };
1304    ///
1305    /// let mock_server = MatrixMockServer::new().await;
1306    /// let client = mock_server.client_builder().build().await;
1307    ///
1308    /// mock_server.mock_get_default_secret_storage_key().ok(
1309    ///     client.user_id().unwrap(),
1310    ///     "abc",
1311    /// )
1312    ///     .mount()
1313    ///     .await;
1314    /// mock_server.mock_get_secret_storage_key().ok(
1315    ///     client.user_id().unwrap(),
1316    ///     &key::SecretStorageKeyEventContent::new(
1317    ///         "abc".into(),
1318    ///         key::SecretStorageEncryptionAlgorithm::V1AesHmacSha2(key::SecretStorageV1AesHmacSha2Properties::new(
1319    ///             Some(Base64::parse("xv5b6/p3ExEw++wTyfSHEg==").unwrap()),
1320    ///             Some(Base64::parse("ujBBbXahnTAMkmPUX2/0+VTfUh63pGyVRuBcDMgmJC8=").unwrap()),
1321    ///         )),
1322    ///     ),
1323    /// )
1324    ///     .mount()
1325    ///     .await;
1326    ///
1327    /// client.encryption()
1328    ///     .secret_storage()
1329    ///     .open_secret_store("EsTj 3yST y93F SLpB jJsz eAXc 2XzA ygD3 w69H fGaN TKBj jXEd")
1330    ///     .await
1331    ///     .unwrap();
1332    ///
1333    /// # anyhow::Ok(()) });
1334    /// ```
1335    #[cfg(feature = "e2e-encryption")]
1336    pub fn mock_get_secret_storage_key(&self) -> MockEndpoint<'_, GetSecretStorageKeyEndpoint> {
1337        let mock = Mock::given(method("GET"));
1338        self.mock_endpoint(mock, GetSecretStorageKeyEndpoint).expect_default_access_token()
1339    }
1340
1341    /// Create a prebuilt mock for the endpoint used to get the default secret
1342    /// storage key.
1343    ///
1344    /// # Examples
1345    ///
1346    /// ```
1347    /// tokio_test::block_on(async {
1348    /// use js_int::uint;
1349    /// use serde_json::json;
1350    /// use ruma::events::GlobalAccountDataEventType;
1351    /// use matrix_sdk::test_utils::mocks::MatrixMockServer;
1352    ///
1353    /// let mock_server = MatrixMockServer::new().await;
1354    /// let client = mock_server.client_builder().build().await;
1355    ///
1356    /// mock_server.mock_get_master_signing_key().ok(
1357    ///     client.user_id().unwrap(),
1358    ///     json!({})
1359    /// )
1360    /// .mount()
1361    /// .await;
1362    ///
1363    /// client.account()
1364    ///     .fetch_account_data(GlobalAccountDataEventType::from("m.cross_signing.master".to_owned()))
1365    ///     .await
1366    ///     .unwrap();
1367    ///
1368    /// # anyhow::Ok(()) });
1369    /// ```
1370    #[cfg(feature = "e2e-encryption")]
1371    pub fn mock_get_master_signing_key(&self) -> MockEndpoint<'_, GetMasterSigningKeyEndpoint> {
1372        let mock = Mock::given(method("GET"));
1373        self.mock_endpoint(mock, GetMasterSigningKeyEndpoint).expect_default_access_token()
1374    }
1375
1376    /// Create a prebuilt mock for the endpoint used to send a single receipt.
1377    pub fn mock_send_receipt(
1378        &self,
1379        receipt_type: ReceiptType,
1380    ) -> MockEndpoint<'_, ReceiptEndpoint> {
1381        let mock = Mock::given(method("POST"))
1382            .and(path_regex(format!("^/_matrix/client/v3/rooms/.*/receipt/{receipt_type}/")));
1383        self.mock_endpoint(mock, ReceiptEndpoint).expect_default_access_token()
1384    }
1385
1386    /// Create a prebuilt mock for the endpoint used to send multiple receipts.
1387    pub fn mock_send_read_markers(&self) -> MockEndpoint<'_, ReadMarkersEndpoint> {
1388        let mock = Mock::given(method("POST"))
1389            .and(path_regex(r"^/_matrix/client/v3/rooms/.*/read_markers"));
1390        self.mock_endpoint(mock, ReadMarkersEndpoint).expect_default_access_token()
1391    }
1392
1393    /// Create a prebuilt mock for the endpoint used to set room account data.
1394    pub fn mock_set_room_account_data(
1395        &self,
1396        data_type: RoomAccountDataEventType,
1397    ) -> MockEndpoint<'_, RoomAccountDataEndpoint> {
1398        let mock = Mock::given(method("PUT")).and(path_regex(format!(
1399            "^/_matrix/client/v3/user/.*/rooms/.*/account_data/{data_type}"
1400        )));
1401        self.mock_endpoint(mock, RoomAccountDataEndpoint).expect_default_access_token()
1402    }
1403
1404    /// Create a prebuilt mock for the endpoint used to get the media config of
1405    /// the homeserver that requires authentication.
1406    pub fn mock_authenticated_media_config(
1407        &self,
1408    ) -> MockEndpoint<'_, AuthenticatedMediaConfigEndpoint> {
1409        let mock = Mock::given(method("GET")).and(path("/_matrix/client/v1/media/config"));
1410        self.mock_endpoint(mock, AuthenticatedMediaConfigEndpoint)
1411    }
1412
1413    /// Create a prebuilt mock for the endpoint used to get the media config of
1414    /// the homeserver without requiring authentication.
1415    pub fn mock_media_config(&self) -> MockEndpoint<'_, MediaConfigEndpoint> {
1416        let mock = Mock::given(method("GET")).and(path("/_matrix/media/v3/config"));
1417        self.mock_endpoint(mock, MediaConfigEndpoint)
1418    }
1419
1420    /// Create a prebuilt mock for the endpoint used to log into a session.
1421    pub fn mock_login(&self) -> MockEndpoint<'_, LoginEndpoint> {
1422        let mock = Mock::given(method("POST")).and(path("/_matrix/client/v3/login"));
1423        self.mock_endpoint(mock, LoginEndpoint)
1424    }
1425
1426    /// Create a prebuilt mock for the endpoint used to list the devices of a
1427    /// user.
1428    pub fn mock_devices(&self) -> MockEndpoint<'_, DevicesEndpoint> {
1429        let mock = Mock::given(method("GET")).and(path("/_matrix/client/v3/devices"));
1430        self.mock_endpoint(mock, DevicesEndpoint).expect_default_access_token()
1431    }
1432
1433    /// Create a prebuilt mock for the endpoint used to query a single device.
1434    pub fn mock_get_device(&self) -> MockEndpoint<'_, GetDeviceEndpoint> {
1435        let mock = Mock::given(method("GET")).and(path_regex("/_matrix/client/v3/devices/.*"));
1436        self.mock_endpoint(mock, GetDeviceEndpoint).expect_default_access_token()
1437    }
1438
1439    /// Create a prebuilt mock for the endpoint used to search in the user
1440    /// directory.
1441    pub fn mock_user_directory(&self) -> MockEndpoint<'_, UserDirectoryEndpoint> {
1442        let mock = Mock::given(method("POST"))
1443            .and(path("/_matrix/client/v3/user_directory/search"))
1444            .and(body_json(&*test_json::search_users::SEARCH_USERS_REQUEST));
1445        self.mock_endpoint(mock, UserDirectoryEndpoint).expect_default_access_token()
1446    }
1447
1448    /// Create a prebuilt mock for the endpoint used to create a new room.
1449    pub fn mock_create_room(&self) -> MockEndpoint<'_, CreateRoomEndpoint> {
1450        let mock = Mock::given(method("POST")).and(path("/_matrix/client/v3/createRoom"));
1451        self.mock_endpoint(mock, CreateRoomEndpoint).expect_default_access_token()
1452    }
1453
1454    /// Create a prebuilt mock for the endpoint used to upgrade a room.
1455    pub fn mock_upgrade_room(&self) -> MockEndpoint<'_, UpgradeRoomEndpoint> {
1456        let mock =
1457            Mock::given(method("POST")).and(path_regex("/_matrix/client/v3/rooms/.*/upgrade"));
1458        self.mock_endpoint(mock, UpgradeRoomEndpoint).expect_default_access_token()
1459    }
1460
1461    /// Create a prebuilt mock for the endpoint used to pre-allocate a MXC URI
1462    /// for a media file.
1463    pub fn mock_media_allocate(&self) -> MockEndpoint<'_, MediaAllocateEndpoint> {
1464        let mock = Mock::given(method("POST")).and(path("/_matrix/media/v1/create"));
1465        self.mock_endpoint(mock, MediaAllocateEndpoint)
1466    }
1467
1468    /// Create a prebuilt mock for the endpoint used to upload a media file with
1469    /// a pre-allocated MXC URI.
1470    pub fn mock_media_allocated_upload(
1471        &self,
1472        server_name: &str,
1473        media_id: &str,
1474    ) -> MockEndpoint<'_, MediaAllocatedUploadEndpoint> {
1475        let mock = Mock::given(method("PUT"))
1476            .and(path(format!("/_matrix/media/v3/upload/{server_name}/{media_id}")));
1477        self.mock_endpoint(mock, MediaAllocatedUploadEndpoint)
1478    }
1479
1480    /// Create a prebuilt mock for the endpoint used to download a media file
1481    /// without requiring authentication.
1482    pub fn mock_media_download(&self) -> MockEndpoint<'_, MediaDownloadEndpoint> {
1483        let mock = Mock::given(method("GET")).and(path_regex("^/_matrix/media/v3/download/"));
1484        self.mock_endpoint(mock, MediaDownloadEndpoint)
1485    }
1486
1487    /// Create a prebuilt mock for the endpoint used to download a thumbnail of
1488    /// a media file without requiring authentication.
1489    pub fn mock_media_thumbnail(
1490        &self,
1491        resize_method: Method,
1492        width: u16,
1493        height: u16,
1494        animated: bool,
1495    ) -> MockEndpoint<'_, MediaThumbnailEndpoint> {
1496        let mock = Mock::given(method("GET"))
1497            .and(path_regex("^/_matrix/media/v3/thumbnail/"))
1498            .and(query_param("method", resize_method.as_str()))
1499            .and(query_param("width", width.to_string()))
1500            .and(query_param("height", height.to_string()))
1501            .and(query_param("animated", animated.to_string()));
1502        self.mock_endpoint(mock, MediaThumbnailEndpoint)
1503    }
1504
1505    /// Create a prebuilt mock for the endpoint used to download a media file
1506    /// that requires authentication.
1507    pub fn mock_authed_media_download(&self) -> MockEndpoint<'_, AuthedMediaDownloadEndpoint> {
1508        let mock =
1509            Mock::given(method("GET")).and(path_regex("^/_matrix/client/v1/media/download/"));
1510        self.mock_endpoint(mock, AuthedMediaDownloadEndpoint).expect_default_access_token()
1511    }
1512
1513    /// Create a prebuilt mock for the endpoint used to download a thumbnail of
1514    /// a media file that requires authentication.
1515    pub fn mock_authed_media_thumbnail(
1516        &self,
1517        resize_method: Method,
1518        width: u16,
1519        height: u16,
1520        animated: bool,
1521    ) -> MockEndpoint<'_, AuthedMediaThumbnailEndpoint> {
1522        let mock = Mock::given(method("GET"))
1523            .and(path_regex("^/_matrix/client/v1/media/thumbnail/"))
1524            .and(query_param("method", resize_method.as_str()))
1525            .and(query_param("width", width.to_string()))
1526            .and(query_param("height", height.to_string()))
1527            .and(query_param("animated", animated.to_string()));
1528        self.mock_endpoint(mock, AuthedMediaThumbnailEndpoint).expect_default_access_token()
1529    }
1530
1531    /// Create a prebuilt mock for the endpoint used to get a single thread
1532    /// subscription status in a given room.
1533    pub fn mock_room_get_thread_subscription(
1534        &self,
1535    ) -> MockEndpoint<'_, RoomGetThreadSubscriptionEndpoint> {
1536        let mock = Mock::given(method("GET"));
1537        self.mock_endpoint(mock, RoomGetThreadSubscriptionEndpoint::default())
1538            .expect_default_access_token()
1539    }
1540
1541    /// Create a prebuilt mock for the endpoint used to define a thread
1542    /// subscription in a given room.
1543    pub fn mock_room_put_thread_subscription(
1544        &self,
1545    ) -> MockEndpoint<'_, RoomPutThreadSubscriptionEndpoint> {
1546        let mock = Mock::given(method("PUT"));
1547        self.mock_endpoint(mock, RoomPutThreadSubscriptionEndpoint::default())
1548            .expect_default_access_token()
1549    }
1550
1551    /// Create a prebuilt mock for the endpoint used to delete a thread
1552    /// subscription in a given room.
1553    pub fn mock_room_delete_thread_subscription(
1554        &self,
1555    ) -> MockEndpoint<'_, RoomDeleteThreadSubscriptionEndpoint> {
1556        let mock = Mock::given(method("DELETE"));
1557        self.mock_endpoint(mock, RoomDeleteThreadSubscriptionEndpoint::default())
1558            .expect_default_access_token()
1559    }
1560
1561    /// Create a prebuilt mock for the endpoint used to enable a push rule.
1562    pub fn mock_enable_push_rule(
1563        &self,
1564        kind: RuleKind,
1565        rule_id: impl AsRef<str>,
1566    ) -> MockEndpoint<'_, EnablePushRuleEndpoint> {
1567        let rule_id = rule_id.as_ref();
1568        let mock = Mock::given(method("PUT")).and(path_regex(format!(
1569            "^/_matrix/client/v3/pushrules/global/{kind}/{rule_id}/enabled",
1570        )));
1571        self.mock_endpoint(mock, EnablePushRuleEndpoint).expect_default_access_token()
1572    }
1573
1574    /// Create a prebuilt mock for the endpoint used to set push rules actions.
1575    pub fn mock_set_push_rules_actions(
1576        &self,
1577        kind: RuleKind,
1578        rule_id: PushRuleIdSpec<'_>,
1579    ) -> MockEndpoint<'_, SetPushRulesActionsEndpoint> {
1580        let rule_id = rule_id.to_path();
1581        let mock = Mock::given(method("PUT")).and(path_regex(format!(
1582            "^/_matrix/client/v3/pushrules/global/{kind}/{rule_id}/actions",
1583        )));
1584        self.mock_endpoint(mock, SetPushRulesActionsEndpoint).expect_default_access_token()
1585    }
1586
1587    /// Create a prebuilt mock for the endpoint used to set push rules.
1588    pub fn mock_set_push_rules(
1589        &self,
1590        kind: RuleKind,
1591        rule_id: PushRuleIdSpec<'_>,
1592    ) -> MockEndpoint<'_, SetPushRulesEndpoint> {
1593        let rule_id = rule_id.to_path();
1594        let mock = Mock::given(method("PUT"))
1595            .and(path_regex(format!("^/_matrix/client/v3/pushrules/global/{kind}/{rule_id}$",)));
1596        self.mock_endpoint(mock, SetPushRulesEndpoint).expect_default_access_token()
1597    }
1598
1599    /// Create a prebuilt mock for the endpoint used to delete push rules.
1600    pub fn mock_delete_push_rules(
1601        &self,
1602        kind: RuleKind,
1603        rule_id: PushRuleIdSpec<'_>,
1604    ) -> MockEndpoint<'_, DeletePushRulesEndpoint> {
1605        let rule_id = rule_id.to_path();
1606        let mock = Mock::given(method("DELETE"))
1607            .and(path_regex(format!("^/_matrix/client/v3/pushrules/global/{kind}/{rule_id}$",)));
1608        self.mock_endpoint(mock, DeletePushRulesEndpoint).expect_default_access_token()
1609    }
1610
1611    /// Create a prebuilt mock for the federation version endpoint.
1612    pub fn mock_federation_version(&self) -> MockEndpoint<'_, FederationVersionEndpoint> {
1613        let mock = Mock::given(method("GET")).and(path("/_matrix/federation/v1/version"));
1614        self.mock_endpoint(mock, FederationVersionEndpoint)
1615    }
1616
1617    /// Create a prebuilt mock for the endpoint used to get all thread
1618    /// subscriptions across all rooms.
1619    pub fn mock_get_thread_subscriptions(
1620        &self,
1621    ) -> MockEndpoint<'_, GetThreadSubscriptionsEndpoint> {
1622        let mock = Mock::given(method("GET"))
1623            .and(path_regex(r"^/_matrix/client/unstable/io.element.msc4308/thread_subscriptions$"));
1624        self.mock_endpoint(mock, GetThreadSubscriptionsEndpoint::default())
1625            .expect_default_access_token()
1626    }
1627
1628    /// Create a prebuilt mock for the endpoint used to retrieve a space tree
1629    pub fn mock_get_hierarchy(&self) -> MockEndpoint<'_, GetHierarchyEndpoint> {
1630        let mock =
1631            Mock::given(method("GET")).and(path_regex(r"^/_matrix/client/v1/rooms/.*/hierarchy"));
1632        self.mock_endpoint(mock, GetHierarchyEndpoint).expect_default_access_token()
1633    }
1634
1635    /// Create a prebuilt mock for the endpoint used to set a space child.
1636    pub fn mock_set_space_child(&self) -> MockEndpoint<'_, SetSpaceChildEndpoint> {
1637        let mock = Mock::given(method("PUT"))
1638            .and(path_regex(r"^/_matrix/client/v3/rooms/.*/state/m.space.child/.*?"));
1639        self.mock_endpoint(mock, SetSpaceChildEndpoint).expect_default_access_token()
1640    }
1641
1642    /// Create a prebuilt mock for the endpoint used to set a space parent.
1643    pub fn mock_set_space_parent(&self) -> MockEndpoint<'_, SetSpaceParentEndpoint> {
1644        let mock = Mock::given(method("PUT"))
1645            .and(path_regex(r"^/_matrix/client/v3/rooms/.*/state/m.space.parent"));
1646        self.mock_endpoint(mock, SetSpaceParentEndpoint).expect_default_access_token()
1647    }
1648
1649    /// Create a prebuilt mock for the endpoint used to get a profile field.
1650    pub fn mock_get_profile_field(
1651        &self,
1652        user_id: &UserId,
1653        field: ProfileFieldName,
1654    ) -> MockEndpoint<'_, GetProfileFieldEndpoint> {
1655        let mock = Mock::given(method("GET"))
1656            .and(path(format!("/_matrix/client/v3/profile/{user_id}/{field}")));
1657        self.mock_endpoint(mock, GetProfileFieldEndpoint { field })
1658    }
1659
1660    /// Create a prebuilt mock for the endpoint used to set a profile field.
1661    pub fn mock_set_profile_field(
1662        &self,
1663        user_id: &UserId,
1664        field: ProfileFieldName,
1665    ) -> MockEndpoint<'_, SetProfileFieldEndpoint> {
1666        let mock = Mock::given(method("PUT"))
1667            .and(path(format!("/_matrix/client/v3/profile/{user_id}/{field}")));
1668        self.mock_endpoint(mock, SetProfileFieldEndpoint).expect_default_access_token()
1669    }
1670
1671    /// Create a prebuilt mock for the endpoint used to delete a profile field.
1672    pub fn mock_delete_profile_field(
1673        &self,
1674        user_id: &UserId,
1675        field: ProfileFieldName,
1676    ) -> MockEndpoint<'_, DeleteProfileFieldEndpoint> {
1677        let mock = Mock::given(method("DELETE"))
1678            .and(path(format!("/_matrix/client/v3/profile/{user_id}/{field}")));
1679        self.mock_endpoint(mock, DeleteProfileFieldEndpoint).expect_default_access_token()
1680    }
1681
1682    /// Create a prebuilt mock for the endpoint used to get a profile.
1683    pub fn mock_get_profile(&self, user_id: &UserId) -> MockEndpoint<'_, GetProfileEndpoint> {
1684        let mock =
1685            Mock::given(method("GET")).and(path(format!("/_matrix/client/v3/profile/{user_id}")));
1686        self.mock_endpoint(mock, GetProfileEndpoint)
1687    }
1688}
1689
1690/// A specification for a push rule ID.
1691pub enum PushRuleIdSpec<'a> {
1692    /// A precise rule ID.
1693    Some(&'a str),
1694    /// Any rule ID should match.
1695    Any,
1696}
1697
1698impl<'a> PushRuleIdSpec<'a> {
1699    /// Convert this [`PushRuleIdSpec`] to a path.
1700    pub fn to_path(&self) -> &str {
1701        match self {
1702            PushRuleIdSpec::Some(id) => id,
1703            PushRuleIdSpec::Any => "[^/]*",
1704        }
1705    }
1706}
1707
1708/// Parameter to [`MatrixMockServer::sync_room`].
1709pub enum AnyRoomBuilder {
1710    /// A room we've been invited to.
1711    Invited(InvitedRoomBuilder),
1712    /// A room we've joined.
1713    Joined(JoinedRoomBuilder),
1714    /// A room we've left.
1715    Left(LeftRoomBuilder),
1716    /// A room we've knocked to.
1717    Knocked(KnockedRoomBuilder),
1718}
1719
1720impl AnyRoomBuilder {
1721    /// Get the [`RoomId`] of the room this [`AnyRoomBuilder`] will create.
1722    fn room_id(&self) -> &RoomId {
1723        match self {
1724            AnyRoomBuilder::Invited(r) => r.room_id(),
1725            AnyRoomBuilder::Joined(r) => r.room_id(),
1726            AnyRoomBuilder::Left(r) => r.room_id(),
1727            AnyRoomBuilder::Knocked(r) => r.room_id(),
1728        }
1729    }
1730}
1731
1732impl From<InvitedRoomBuilder> for AnyRoomBuilder {
1733    fn from(val: InvitedRoomBuilder) -> AnyRoomBuilder {
1734        AnyRoomBuilder::Invited(val)
1735    }
1736}
1737
1738impl From<JoinedRoomBuilder> for AnyRoomBuilder {
1739    fn from(val: JoinedRoomBuilder) -> AnyRoomBuilder {
1740        AnyRoomBuilder::Joined(val)
1741    }
1742}
1743
1744impl From<LeftRoomBuilder> for AnyRoomBuilder {
1745    fn from(val: LeftRoomBuilder) -> AnyRoomBuilder {
1746        AnyRoomBuilder::Left(val)
1747    }
1748}
1749
1750impl From<KnockedRoomBuilder> for AnyRoomBuilder {
1751    fn from(val: KnockedRoomBuilder) -> AnyRoomBuilder {
1752        AnyRoomBuilder::Knocked(val)
1753    }
1754}
1755
1756/// The [path percent-encode set] as defined in the WHATWG URL standard + `/`
1757/// since we always encode single segments of the path.
1758///
1759/// [path percent-encode set]: https://url.spec.whatwg.org/#path-percent-encode-set
1760///
1761/// Copied from Ruma:
1762/// https://github.com/ruma/ruma/blob/e4cb409ff3aaa16f31a7fe1e61fee43b2d144f7b/crates/ruma-common/src/percent_encode.rs#L7
1763const PATH_PERCENT_ENCODE_SET: &AsciiSet = &CONTROLS
1764    .add(b' ')
1765    .add(b'"')
1766    .add(b'#')
1767    .add(b'<')
1768    .add(b'>')
1769    .add(b'?')
1770    .add(b'`')
1771    .add(b'{')
1772    .add(b'}')
1773    .add(b'/');
1774
1775fn percent_encoded_path(path: &str) -> String {
1776    percent_encoding::utf8_percent_encode(path, PATH_PERCENT_ENCODE_SET).to_string()
1777}
1778
1779/// A wrapper for a [`Mock`] as well as a [`MockServer`], allowing us to call
1780/// [`Mock::mount`] or [`Mock::mount_as_scoped`] without having to pass the
1781/// [`MockServer`] reference (i.e. call `mount()` instead of `mount(&server)`).
1782pub struct MatrixMock<'a> {
1783    pub(super) mock: Mock,
1784    pub(super) server: &'a MockServer,
1785}
1786
1787impl MatrixMock<'_> {
1788    /// Set an expectation on the number of times this [`MatrixMock`] should
1789    /// match in the current test case.
1790    ///
1791    /// Expectations are verified when the server is shutting down: if
1792    /// the expectation is not satisfied, the [`MatrixMockServer`] will panic
1793    /// and the `error_message` is shown.
1794    ///
1795    /// By default, no expectation is set for [`MatrixMock`]s.
1796    pub fn expect<T: Into<Times>>(self, num_calls: T) -> Self {
1797        Self { mock: self.mock.expect(num_calls), ..self }
1798    }
1799
1800    /// Assign a name to your mock.
1801    ///
1802    /// The mock name will be used in error messages (e.g. if the mock
1803    /// expectation is not satisfied) and debug logs to help you identify
1804    /// what failed.
1805    pub fn named(self, name: impl Into<String>) -> Self {
1806        Self { mock: self.mock.named(name), ..self }
1807    }
1808
1809    /// Respond to a response of this endpoint exactly once.
1810    ///
1811    /// After it's been called, subsequent responses will hit the next handler
1812    /// or a 404.
1813    ///
1814    /// Also verifies that it's been called once.
1815    pub fn mock_once(self) -> Self {
1816        Self { mock: self.mock.up_to_n_times(1).expect(1), ..self }
1817    }
1818
1819    /// Makes sure the endpoint is never reached.
1820    pub fn never(self) -> Self {
1821        Self { mock: self.mock.expect(0), ..self }
1822    }
1823
1824    /// Specify an upper limit to the number of times you would like this
1825    /// [`MatrixMock`] to respond to incoming requests that satisfy the
1826    /// conditions imposed by your matchers.
1827    pub fn up_to_n_times(self, num: u64) -> Self {
1828        Self { mock: self.mock.up_to_n_times(num), ..self }
1829    }
1830
1831    /// Mount a [`MatrixMock`] on the attached server.
1832    ///
1833    /// The [`MatrixMock`] will remain active until the [`MatrixMockServer`] is
1834    /// shut down. If you want to control or limit how long your
1835    /// [`MatrixMock`] stays active, check out [`Self::mount_as_scoped`].
1836    pub async fn mount(self) {
1837        self.mock.mount(self.server).await;
1838    }
1839
1840    /// Mount a [`MatrixMock`] as **scoped** on the attached server.
1841    ///
1842    /// When using [`Self::mount`], your [`MatrixMock`]s will be active until
1843    /// the [`MatrixMockServer`] is shut down.
1844    ///
1845    /// When using `mount_as_scoped`, your [`MatrixMock`]s will be active as
1846    /// long as the returned [`MockGuard`] is not dropped.
1847    ///
1848    /// When the returned [`MockGuard`] is dropped, [`MatrixMockServer`] will
1849    /// verify that the expectations set on the scoped [`MatrixMock`] were
1850    /// verified - if not, it will panic.
1851    pub async fn mount_as_scoped(self) -> MockGuard {
1852        self.mock.mount_as_scoped(self.server).await
1853    }
1854}
1855
1856/// Generic mocked endpoint, with useful common helpers.
1857pub struct MockEndpoint<'a, T> {
1858    server: &'a MockServer,
1859    mock: MockBuilder,
1860    endpoint: T,
1861    expected_access_token: ExpectedAccessToken,
1862}
1863
1864impl<'a, T> MockEndpoint<'a, T> {
1865    fn new(server: &'a MockServer, mock: MockBuilder, endpoint: T) -> Self {
1866        Self { server, mock, endpoint, expected_access_token: ExpectedAccessToken::Ignore }
1867    }
1868
1869    /// Expect authentication with the default access token on this endpoint.
1870    pub fn expect_default_access_token(mut self) -> Self {
1871        self.expected_access_token = ExpectedAccessToken::Default;
1872        self
1873    }
1874
1875    /// Expect authentication with the given access token on this endpoint.
1876    pub fn expect_access_token(mut self, access_token: &'static str) -> Self {
1877        self.expected_access_token = ExpectedAccessToken::Custom(access_token);
1878        self
1879    }
1880
1881    /// Expect authentication with any access token on this endpoint, regardless
1882    /// of its value.
1883    ///
1884    /// This is useful if we don't want to track the value of the access token.
1885    pub fn expect_any_access_token(mut self) -> Self {
1886        self.expected_access_token = ExpectedAccessToken::Any;
1887        self
1888    }
1889
1890    /// Expect no authentication on this endpoint.
1891    ///
1892    /// This means that the endpoint will not match if an `AUTHENTICATION`
1893    /// header is present.
1894    pub fn expect_missing_access_token(mut self) -> Self {
1895        self.expected_access_token = ExpectedAccessToken::Missing;
1896        self
1897    }
1898
1899    /// Ignore the access token on this endpoint.
1900    ///
1901    /// This should be used to override the default behavior of an endpoint that
1902    /// requires access tokens.
1903    pub fn ignore_access_token(mut self) -> Self {
1904        self.expected_access_token = ExpectedAccessToken::Ignore;
1905        self
1906    }
1907
1908    /// Specify how to respond to a query (viz., like
1909    /// [`MockBuilder::respond_with`] does), when other predefined responses
1910    /// aren't sufficient.
1911    ///
1912    /// # Examples
1913    ///
1914    /// ```
1915    /// # tokio_test::block_on(async {
1916    /// use matrix_sdk::{ruma::{room_id, event_id}, test_utils::mocks::MatrixMockServer};
1917    /// use serde_json::json;
1918    /// use wiremock::ResponseTemplate;
1919    ///
1920    /// let mock_server = MatrixMockServer::new().await;
1921    /// let client = mock_server.client_builder().build().await;
1922    ///
1923    /// mock_server.mock_room_state_encryption().plain().mount().await;
1924    ///
1925    /// let room = mock_server
1926    ///     .sync_joined_room(&client, room_id!("!room_id:localhost"))
1927    ///     .await;
1928    ///
1929    /// let event_id = event_id!("$some_id");
1930    /// mock_server
1931    ///     .mock_room_send()
1932    ///     .respond_with(
1933    ///         ResponseTemplate::new(429)
1934    ///             .insert_header("Retry-After", "100")
1935    ///             .set_body_json(json!({
1936    ///                 "errcode": "M_LIMIT_EXCEEDED",
1937    ///                 "custom_field": "with custom data",
1938    ///     })))
1939    ///     .expect(1)
1940    ///     .mount()
1941    ///     .await;
1942    ///
1943    /// room
1944    ///     .send_raw("m.room.message", json!({ "body": "Hello world" }))
1945    ///     .await
1946    ///     .expect_err("The sending of the event should fail");
1947    /// # anyhow::Ok(()) });
1948    /// ```
1949    pub fn respond_with<R: Respond + 'static>(self, func: R) -> MatrixMock<'a> {
1950        let mock = self.mock.and(self.expected_access_token).respond_with(func);
1951        MatrixMock { mock, server: self.server }
1952    }
1953
1954    /// Returns a send endpoint that emulates a transient failure, i.e responds
1955    /// with error 500.
1956    ///
1957    /// # Examples
1958    /// ```
1959    /// # tokio_test::block_on(async {
1960    /// use matrix_sdk::{ruma::{room_id, event_id}, test_utils::mocks::MatrixMockServer};
1961    /// use serde_json::json;
1962    ///
1963    /// let mock_server = MatrixMockServer::new().await;
1964    /// let client = mock_server.client_builder().build().await;
1965    ///
1966    /// mock_server.mock_room_state_encryption().plain().mount().await;
1967    ///
1968    /// let room = mock_server
1969    ///     .sync_joined_room(&client, room_id!("!room_id:localhost"))
1970    ///     .await;
1971    ///
1972    /// mock_server
1973    ///     .mock_room_send()
1974    ///     .error500()
1975    ///     .expect(1)
1976    ///     .mount()
1977    ///     .await;
1978    ///
1979    /// room
1980    ///     .send_raw("m.room.message", json!({ "body": "Hello world" }))
1981    ///     .await.expect_err("The sending of the event should have failed");
1982    /// # anyhow::Ok(()) });
1983    /// ```
1984    pub fn error500(self) -> MatrixMock<'a> {
1985        self.respond_with(ResponseTemplate::new(500))
1986    }
1987
1988    /// Returns a mocked endpoint that emulates an unimplemented endpoint, i.e
1989    /// responds with a 404 HTTP status code and an `M_UNRECOGNIZED` Matrix
1990    /// error code.
1991    ///
1992    /// Note that the default behavior of the mock server is to return a 404
1993    /// status code for endpoints that are not mocked with an empty response.
1994    ///
1995    /// This can be useful to check if an endpoint is called, even if it is not
1996    /// implemented by the server.
1997    pub fn error_unrecognized(self) -> MatrixMock<'a> {
1998        self.respond_with(ResponseTemplate::new(404).set_body_json(json!({
1999            "errcode": "M_UNRECOGNIZED",
2000            "error": "Unrecognized request",
2001        })))
2002    }
2003
2004    /// Returns a mocked endpoint that emulates an unknown token error, i.e
2005    /// responds with a 401 HTTP status code and an `M_UNKNOWN_TOKEN` Matrix
2006    /// error code.
2007    pub fn error_unknown_token(self, soft_logout: bool) -> MatrixMock<'a> {
2008        self.respond_with(ResponseTemplate::new(401).set_body_json(json!({
2009            "errcode": "M_UNKNOWN_TOKEN",
2010            "error": "Unrecognized access token",
2011            "soft_logout": soft_logout,
2012        })))
2013    }
2014
2015    /// Internal helper to return an `{ event_id }` JSON struct along with a 200
2016    /// ok response.
2017    fn ok_with_event_id(self, event_id: OwnedEventId) -> MatrixMock<'a> {
2018        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({ "event_id": event_id })))
2019    }
2020
2021    /// Internal helper to return a 200 OK response with an empty JSON object in
2022    /// the body.
2023    fn ok_empty_json(self) -> MatrixMock<'a> {
2024        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({})))
2025    }
2026
2027    /// Returns an endpoint that emulates a permanent failure error (e.g. event
2028    /// is too large).
2029    ///
2030    /// # Examples
2031    /// ```
2032    /// # tokio_test::block_on(async {
2033    /// use matrix_sdk::{ruma::{room_id, event_id}, test_utils::mocks::MatrixMockServer};
2034    /// use serde_json::json;
2035    ///
2036    /// let mock_server = MatrixMockServer::new().await;
2037    /// let client = mock_server.client_builder().build().await;
2038    ///
2039    /// mock_server.mock_room_state_encryption().plain().mount().await;
2040    ///
2041    /// let room = mock_server
2042    ///     .sync_joined_room(&client, room_id!("!room_id:localhost"))
2043    ///     .await;
2044    ///
2045    /// mock_server
2046    ///     .mock_room_send()
2047    ///     .error_too_large()
2048    ///     .expect(1)
2049    ///     .mount()
2050    ///     .await;
2051    ///
2052    /// room
2053    ///     .send_raw("m.room.message", json!({ "body": "Hello world" }))
2054    ///     .await.expect_err("The sending of the event should have failed");
2055    /// # anyhow::Ok(()) });
2056    /// ```
2057    pub fn error_too_large(self) -> MatrixMock<'a> {
2058        self.respond_with(ResponseTemplate::new(413).set_body_json(json!({
2059            // From https://spec.matrix.org/v1.10/client-server-api/#standard-error-response
2060            "errcode": "M_TOO_LARGE",
2061        })))
2062    }
2063}
2064
2065/// The access token to expect on an endpoint.
2066enum ExpectedAccessToken {
2067    /// Ignore any access token or lack thereof.
2068    Ignore,
2069
2070    /// We expect the default access token.
2071    Default,
2072
2073    /// We expect the given access token.
2074    Custom(&'static str),
2075
2076    /// We expect any access token.
2077    Any,
2078
2079    /// We expect that there is no access token.
2080    Missing,
2081}
2082
2083impl ExpectedAccessToken {
2084    /// Get the access token from the given request.
2085    fn access_token(request: &Request) -> Option<&str> {
2086        request
2087            .headers
2088            .get(&http::header::AUTHORIZATION)?
2089            .to_str()
2090            .ok()?
2091            .strip_prefix("Bearer ")
2092            .filter(|token| !token.is_empty())
2093    }
2094}
2095
2096impl wiremock::Match for ExpectedAccessToken {
2097    fn matches(&self, request: &Request) -> bool {
2098        match self {
2099            Self::Ignore => true,
2100            Self::Default => Self::access_token(request) == Some("1234"),
2101            Self::Custom(token) => Self::access_token(request) == Some(token),
2102            Self::Any => Self::access_token(request).is_some(),
2103            Self::Missing => request.headers.get(&http::header::AUTHORIZATION).is_none(),
2104        }
2105    }
2106}
2107
2108/// A prebuilt mock for sending a message like event in a room.
2109pub struct RoomSendEndpoint;
2110
2111impl<'a> MockEndpoint<'a, RoomSendEndpoint> {
2112    /// Ensures that the body of the request is a superset of the provided
2113    /// `body` parameter.
2114    ///
2115    /// # Examples
2116    /// ```
2117    /// # tokio_test::block_on(async {
2118    /// use matrix_sdk::{
2119    ///     ruma::{room_id, event_id, events::room::message::RoomMessageEventContent},
2120    ///     test_utils::mocks::MatrixMockServer
2121    /// };
2122    /// use serde_json::json;
2123    ///
2124    /// let mock_server = MatrixMockServer::new().await;
2125    /// let client = mock_server.client_builder().build().await;
2126    ///
2127    /// mock_server.mock_room_state_encryption().plain().mount().await;
2128    ///
2129    /// let room = mock_server
2130    ///     .sync_joined_room(&client, room_id!("!room_id:localhost"))
2131    ///     .await;
2132    ///
2133    /// let event_id = event_id!("$some_id");
2134    /// mock_server
2135    ///     .mock_room_send()
2136    ///     .body_matches_partial_json(json!({
2137    ///         "body": "Hello world",
2138    ///     }))
2139    ///     .ok(event_id)
2140    ///     .expect(1)
2141    ///     .mount()
2142    ///     .await;
2143    ///
2144    /// let content = RoomMessageEventContent::text_plain("Hello world");
2145    /// let result = room.send(content).await?;
2146    ///
2147    /// assert_eq!(
2148    ///     event_id,
2149    ///     result.response.event_id,
2150    ///     "The event ID we mocked should match the one we received when we sent the event"
2151    /// );
2152    /// # anyhow::Ok(()) });
2153    /// ```
2154    pub fn body_matches_partial_json(self, body: Value) -> Self {
2155        Self { mock: self.mock.and(body_partial_json(body)), ..self }
2156    }
2157
2158    /// Ensures that the send endpoint request uses a specific event type.
2159    ///
2160    /// # Examples
2161    ///
2162    /// see also [`MatrixMockServer::mock_room_send`] for more context.
2163    ///
2164    /// ```
2165    /// # tokio_test::block_on(async {
2166    /// use matrix_sdk::{ruma::{room_id, event_id}, test_utils::mocks::MatrixMockServer};
2167    /// use serde_json::json;
2168    ///
2169    /// let mock_server = MatrixMockServer::new().await;
2170    /// let client = mock_server.client_builder().build().await;
2171    ///
2172    /// mock_server.mock_room_state_encryption().plain().mount().await;
2173    ///
2174    /// let room = mock_server
2175    ///     .sync_joined_room(&client, room_id!("!room_id:localhost"))
2176    ///     .await;
2177    ///
2178    /// let event_id = event_id!("$some_id");
2179    /// mock_server
2180    ///     .mock_room_send()
2181    ///     .for_type("m.room.message".into())
2182    ///     .ok(event_id)
2183    ///     .expect(1)
2184    ///     .mount()
2185    ///     .await;
2186    ///
2187    /// let response_not_mocked = room.send_raw("m.room.reaction", json!({ "body": "Hello world" })).await;
2188    /// // The `m.room.reaction` event type should not be mocked by the server.
2189    /// assert!(response_not_mocked.is_err());
2190    ///
2191    /// let result = room.send_raw("m.room.message", json!({ "body": "Hello world" })).await?;
2192    /// // The `m.room.message` event type should be mocked by the server.
2193    /// assert_eq!(
2194    ///     event_id,
2195    ///     result.response.event_id,
2196    ///     "The event ID we mocked should match the one we received when we sent the event"
2197    /// );
2198    /// # anyhow::Ok(()) });
2199    /// ```
2200    pub fn for_type(self, event_type: MessageLikeEventType) -> Self {
2201        Self {
2202            // Note: we already defined a path when constructing the mock builder, but this one
2203            // ought to be more specialized.
2204            mock: self
2205                .mock
2206                .and(path_regex(format!(r"^/_matrix/client/v3/rooms/.*/send/{event_type}",))),
2207            ..self
2208        }
2209    }
2210
2211    /// Ensures the event was sent as a delayed event.
2212    ///
2213    /// See also [the MSC](https://github.com/matrix-org/matrix-spec-proposals/pull/4140).
2214    ///
2215    /// Note: works with *any* room.
2216    ///
2217    /// # Examples
2218    ///
2219    /// see also [`MatrixMockServer::mock_room_send`] for more context.
2220    ///
2221    /// ```
2222    /// # tokio_test::block_on(async {
2223    /// use matrix_sdk::{
2224    ///     ruma::{
2225    ///         api::client::delayed_events::{delayed_message_event, DelayParameters},
2226    ///         events::{message::MessageEventContent, AnyMessageLikeEventContent},
2227    ///         room_id,
2228    ///         time::Duration,
2229    ///         TransactionId,
2230    ///     },
2231    ///     test_utils::mocks::MatrixMockServer,
2232    /// };
2233    /// use serde_json::json;
2234    /// use wiremock::ResponseTemplate;
2235    ///
2236    /// let mock_server = MatrixMockServer::new().await;
2237    /// let client = mock_server.client_builder().build().await;
2238    ///
2239    /// mock_server.mock_room_state_encryption().plain().mount().await;
2240    ///
2241    /// let room = mock_server.sync_joined_room(&client, room_id!("!room_id:localhost")).await;
2242    ///
2243    /// mock_server
2244    ///     .mock_room_send()
2245    ///     .match_delayed_event(Duration::from_millis(500))
2246    ///     .respond_with(ResponseTemplate::new(200).set_body_json(json!({"delay_id":"$some_id"})))
2247    ///     .mock_once()
2248    ///     .mount()
2249    ///     .await;
2250    ///
2251    /// let response_not_mocked =
2252    ///     room.send_raw("m.room.message", json!({ "body": "Hello world" })).await;
2253    ///
2254    /// // A non delayed event should not be mocked by the server.
2255    /// assert!(response_not_mocked.is_err());
2256    ///
2257    /// let r = delayed_message_event::unstable::Request::new(
2258    ///     room.room_id().to_owned(),
2259    ///     TransactionId::new(),
2260    ///     DelayParameters::Timeout { timeout: Duration::from_millis(500) },
2261    ///     &AnyMessageLikeEventContent::Message(MessageEventContent::plain("hello world")),
2262    /// )
2263    /// .unwrap();
2264    ///
2265    /// let response = room.client().send(r).await.unwrap();
2266    /// // The delayed `m.room.message` event type should be mocked by the server.
2267    /// assert_eq!("$some_id", response.delay_id);
2268    /// # anyhow::Ok(()) });
2269    /// ```
2270    pub fn match_delayed_event(self, delay: Duration) -> Self {
2271        Self {
2272            mock: self
2273                .mock
2274                .and(query_param("org.matrix.msc4140.delay", delay.as_millis().to_string())),
2275            ..self
2276        }
2277    }
2278
2279    /// Returns a send endpoint that emulates success, i.e. the event has been
2280    /// sent with the given event id.
2281    ///
2282    /// # Examples
2283    /// ```
2284    /// # tokio_test::block_on(async {
2285    /// use matrix_sdk::{ruma::{room_id, event_id}, test_utils::mocks::MatrixMockServer};
2286    /// use serde_json::json;
2287    ///
2288    /// let mock_server = MatrixMockServer::new().await;
2289    /// let client = mock_server.client_builder().build().await;
2290    ///
2291    /// mock_server.mock_room_state_encryption().plain().mount().await;
2292    ///
2293    /// let room = mock_server
2294    ///     .sync_joined_room(&client, room_id!("!room_id:localhost"))
2295    ///     .await;
2296    ///
2297    /// let event_id = event_id!("$some_id");
2298    /// let send_guard = mock_server
2299    ///     .mock_room_send()
2300    ///     .ok(event_id)
2301    ///     .expect(1)
2302    ///     .mount_as_scoped()
2303    ///     .await;
2304    ///
2305    /// let result = room.send_raw("m.room.message", json!({ "body": "Hello world" })).await?;
2306    ///
2307    /// assert_eq!(
2308    ///     event_id,
2309    ///     result.response.event_id,
2310    ///     "The event ID we mocked should match the one we received when we sent the event"
2311    /// );
2312    /// # anyhow::Ok(()) });
2313    /// ```
2314    pub fn ok(self, returned_event_id: impl Into<OwnedEventId>) -> MatrixMock<'a> {
2315        self.ok_with_event_id(returned_event_id.into())
2316    }
2317
2318    /// Returns a send endpoint that emulates success, i.e. the event has been
2319    /// sent with the given event id.
2320    ///
2321    /// The sent event is captured and can be accessed using the returned
2322    /// [`Receiver`]. The [`Receiver`] is valid only for a send call. The given
2323    /// `event_sender` are added to the event JSON.
2324    ///
2325    /// # Examples
2326    ///
2327    /// ```no_run
2328    /// # tokio_test::block_on(async {
2329    /// use matrix_sdk::{
2330    ///     ruma::{
2331    ///         event_id, events::room::message::RoomMessageEventContent, room_id,
2332    ///     },
2333    ///     test_utils::mocks::MatrixMockServer,
2334    /// };
2335    /// use matrix_sdk_test::JoinedRoomBuilder;
2336    ///
2337    /// let room_id = room_id!("!room_id:localhost");
2338    /// let event_id = event_id!("$some_id");
2339    ///
2340    /// let server = MatrixMockServer::new().await;
2341    /// let client = server.client_builder().build().await;
2342    ///
2343    /// let user_id = client.user_id().expect("We should have a user ID by now");
2344    ///
2345    /// let (receiver, mock) =
2346    ///     server.mock_room_send().ok_with_capture(event_id, user_id);
2347    ///
2348    /// server
2349    ///     .mock_sync()
2350    ///     .ok_and_run(&client, |builder| {
2351    ///         builder.add_joined_room(JoinedRoomBuilder::new(room_id));
2352    ///     })
2353    ///     .await;
2354    ///
2355    /// // Mock any additional endpoints that might be needed to send the message.
2356    ///
2357    /// let room = client
2358    ///     .get_room(room_id)
2359    ///     .expect("We should have access to our room now");
2360    ///
2361    /// let event_id = room
2362    ///     .send(RoomMessageEventContent::text_plain("It's a secret to everybody"))
2363    ///     .await
2364    ///     .expect("We should be able to send an initial message")
2365    ///     .response
2366    ///     .event_id;
2367    ///
2368    /// let event = receiver.await?;
2369    /// # anyhow::Ok(()) });
2370    /// ```
2371    pub fn ok_with_capture(
2372        self,
2373        returned_event_id: impl Into<OwnedEventId>,
2374        event_sender: impl Into<OwnedUserId>,
2375    ) -> (Receiver<Raw<AnySyncTimelineEvent>>, MatrixMock<'a>) {
2376        let event_id = returned_event_id.into();
2377        let event_sender = event_sender.into();
2378
2379        let (sender, receiver) = oneshot::channel();
2380        let sender = Arc::new(Mutex::new(Some(sender)));
2381
2382        let ret = self.respond_with(move |request: &Request| {
2383            if let Some(sender) = sender.lock().unwrap().take() {
2384                let uri = &request.url;
2385                let path_segments = uri.path_segments();
2386                let maybe_event_type = path_segments.and_then(|mut s| s.nth_back(1));
2387                let event_type = maybe_event_type
2388                    .as_ref()
2389                    .map(|&e| e.to_owned())
2390                    .unwrap_or("m.room.message".to_owned());
2391
2392                let body: Value =
2393                    request.body_json().expect("The received body should be valid JSON");
2394
2395                let event = json!({
2396                    "event_id": event_id.clone(),
2397                    "sender": event_sender,
2398                    "type": event_type,
2399                    "origin_server_ts": MilliSecondsSinceUnixEpoch::now(),
2400                    "content": body,
2401                });
2402
2403                let event: Raw<AnySyncTimelineEvent> = from_value(event)
2404                    .expect("We should be able to create a raw event from the content");
2405
2406                sender.send(event).expect("We should be able to send the event to the receiver");
2407            }
2408
2409            ResponseTemplate::new(200).set_body_json(json!({ "event_id": event_id.clone() }))
2410        });
2411
2412        (receiver, ret)
2413    }
2414}
2415
2416/// A prebuilt mock for sending a state event in a room.
2417#[derive(Default)]
2418pub struct RoomSendStateEndpoint {
2419    state_key: Option<String>,
2420    event_type: Option<StateEventType>,
2421}
2422
2423impl<'a> MockEndpoint<'a, RoomSendStateEndpoint> {
2424    fn generate_path_regexp(endpoint: &RoomSendStateEndpoint) -> String {
2425        format!(
2426            r"^/_matrix/client/v3/rooms/.*/state/{}/{}",
2427            endpoint.event_type.as_ref().map_or_else(|| ".*".to_owned(), |t| t.to_string()),
2428            endpoint.state_key.as_ref().map_or_else(|| ".*".to_owned(), |k| k.to_string())
2429        )
2430    }
2431
2432    /// Ensures that the body of the request is a superset of the provided
2433    /// `body` parameter.
2434    ///
2435    /// # Examples
2436    /// ```
2437    /// # tokio_test::block_on(async {
2438    /// use matrix_sdk::{
2439    ///     ruma::{
2440    ///         room_id, event_id,
2441    ///         events::room::power_levels::RoomPowerLevelsEventContent,
2442    ///         room_version_rules::AuthorizationRules
2443    ///     },
2444    ///     test_utils::mocks::MatrixMockServer
2445    /// };
2446    /// use serde_json::json;
2447    ///
2448    /// let mock_server = MatrixMockServer::new().await;
2449    /// let client = mock_server.client_builder().build().await;
2450    ///
2451    /// mock_server.mock_room_state_encryption().plain().mount().await;
2452    ///
2453    /// let room = mock_server
2454    ///     .sync_joined_room(&client, room_id!("!room_id:localhost"))
2455    ///     .await;
2456    ///
2457    /// let event_id = event_id!("$some_id");
2458    /// mock_server
2459    ///     .mock_room_send_state()
2460    ///     .body_matches_partial_json(json!({
2461    ///         "redact": 51,
2462    ///     }))
2463    ///     .ok(event_id)
2464    ///     .expect(1)
2465    ///     .mount()
2466    ///     .await;
2467    ///
2468    /// let mut content = RoomPowerLevelsEventContent::new(&AuthorizationRules::V1);
2469    /// // Update the power level to a non default value.
2470    /// // Otherwise it will be skipped from serialization.
2471    /// content.redact = 51.into();
2472    ///
2473    /// let response = room.send_state_event(content).await?;
2474    ///
2475    /// assert_eq!(
2476    ///     event_id,
2477    ///     response.event_id,
2478    ///     "The event ID we mocked should match the one we received when we sent the event"
2479    /// );
2480    /// # anyhow::Ok(()) });
2481    /// ```
2482    pub fn body_matches_partial_json(self, body: Value) -> Self {
2483        Self { mock: self.mock.and(body_partial_json(body)), ..self }
2484    }
2485
2486    /// Ensures that the send endpoint request uses a specific event type.
2487    ///
2488    /// Note: works with *any* room.
2489    ///
2490    /// # Examples
2491    ///
2492    /// see also [`MatrixMockServer::mock_room_send`] for more context.
2493    ///
2494    /// ```
2495    /// # tokio_test::block_on(async {
2496    /// use matrix_sdk::{
2497    ///     ruma::{
2498    ///         event_id,
2499    ///         events::room::{
2500    ///             create::RoomCreateEventContent, power_levels::RoomPowerLevelsEventContent,
2501    ///         },
2502    ///         events::StateEventType,
2503    ///         room_id,
2504    ///         room_version_rules::AuthorizationRules,
2505    ///     },
2506    ///     test_utils::mocks::MatrixMockServer,
2507    /// };
2508    ///
2509    /// let mock_server = MatrixMockServer::new().await;
2510    /// let client = mock_server.client_builder().build().await;
2511    ///
2512    /// mock_server.mock_room_state_encryption().plain().mount().await;
2513    ///
2514    /// let room = mock_server.sync_joined_room(&client, room_id!("!room_id:localhost")).await;
2515    ///
2516    /// let event_id = event_id!("$some_id");
2517    ///
2518    /// mock_server
2519    ///     .mock_room_send_state()
2520    ///     .for_type(StateEventType::RoomPowerLevels)
2521    ///     .ok(event_id)
2522    ///     .expect(1)
2523    ///     .mount()
2524    ///     .await;
2525    ///
2526    /// let response_not_mocked = room.send_state_event(RoomCreateEventContent::new_v11()).await;
2527    /// // The `m.room.reaction` event type should not be mocked by the server.
2528    /// assert!(response_not_mocked.is_err());
2529    ///
2530    /// let response = room.send_state_event(RoomPowerLevelsEventContent::new(&AuthorizationRules::V1)).await?;
2531    /// // The `m.room.message` event type should be mocked by the server.
2532    /// assert_eq!(
2533    ///     event_id, response.event_id,
2534    ///     "The event ID we mocked should match the one we received when we sent the event"
2535    /// );
2536    ///
2537    /// # anyhow::Ok(()) });
2538    /// ```
2539    pub fn for_type(mut self, event_type: StateEventType) -> Self {
2540        self.endpoint.event_type = Some(event_type);
2541        // Note: we may have already defined a path, but this one ought to be more
2542        // specialized (unless for_key/for_type were called multiple times).
2543        Self { mock: self.mock.and(path_regex(Self::generate_path_regexp(&self.endpoint))), ..self }
2544    }
2545
2546    /// Ensures the event was sent as a delayed event.
2547    ///
2548    /// See also [the MSC](https://github.com/matrix-org/matrix-spec-proposals/pull/4140).
2549    ///
2550    /// Note: works with *any* room.
2551    ///
2552    /// # Examples
2553    ///
2554    /// see also [`MatrixMockServer::mock_room_send`] for more context.
2555    ///
2556    /// ```
2557    /// # tokio_test::block_on(async {
2558    /// use matrix_sdk::{
2559    ///     ruma::{
2560    ///         api::client::delayed_events::{delayed_state_event, DelayParameters},
2561    ///         events::{room::create::RoomCreateEventContent, AnyStateEventContent},
2562    ///         room_id,
2563    ///         time::Duration,
2564    ///     },
2565    ///     test_utils::mocks::MatrixMockServer,
2566    /// };
2567    /// use wiremock::ResponseTemplate;
2568    /// use serde_json::json;
2569    ///
2570    /// let mock_server = MatrixMockServer::new().await;
2571    /// let client = mock_server.client_builder().build().await;
2572    ///
2573    /// mock_server.mock_room_state_encryption().plain().mount().await;
2574    ///
2575    /// let room = mock_server.sync_joined_room(&client, room_id!("!room_id:localhost")).await;
2576    ///
2577    /// mock_server
2578    ///     .mock_room_send_state()
2579    ///     .match_delayed_event(Duration::from_millis(500))
2580    ///     .respond_with(ResponseTemplate::new(200).set_body_json(json!({"delay_id":"$some_id"})))
2581    ///     .mock_once()
2582    ///     .mount()
2583    ///     .await;
2584    ///
2585    /// let response_not_mocked = room.send_state_event(RoomCreateEventContent::new_v11()).await;
2586    /// // A non delayed event should not be mocked by the server.
2587    /// assert!(response_not_mocked.is_err());
2588    ///
2589    /// let r = delayed_state_event::unstable::Request::new(
2590    ///     room.room_id().to_owned(),
2591    ///     "".to_owned(),
2592    ///     DelayParameters::Timeout { timeout: Duration::from_millis(500) },
2593    ///     &AnyStateEventContent::RoomCreate(RoomCreateEventContent::new_v11()),
2594    /// )
2595    /// .unwrap();
2596    /// let response = room.client().send(r).await.unwrap();
2597    /// // The delayed `m.room.message` event type should be mocked by the server.
2598    /// assert_eq!("$some_id", response.delay_id);
2599    ///
2600    /// # anyhow::Ok(()) });
2601    /// ```
2602    pub fn match_delayed_event(self, delay: Duration) -> Self {
2603        Self {
2604            mock: self
2605                .mock
2606                .and(query_param("org.matrix.msc4140.delay", delay.as_millis().to_string())),
2607            ..self
2608        }
2609    }
2610
2611    ///
2612    /// ```
2613    /// # tokio_test::block_on(async {
2614    /// use matrix_sdk::{
2615    ///     ruma::{
2616    ///         event_id,
2617    ///         events::{call::member::CallMemberEventContent, AnyStateEventContent},
2618    ///         room_id,
2619    ///     },
2620    ///     test_utils::mocks::MatrixMockServer,
2621    /// };
2622    ///
2623    /// let mock_server = MatrixMockServer::new().await;
2624    /// let client = mock_server.client_builder().build().await;
2625    ///
2626    /// mock_server.mock_room_state_encryption().plain().mount().await;
2627    ///
2628    /// let room = mock_server.sync_joined_room(&client, room_id!("!room_id:localhost")).await;
2629    ///
2630    /// let event_id = event_id!("$some_id");
2631    ///
2632    /// mock_server
2633    ///     .mock_room_send_state()
2634    ///     .for_key("my_key".to_owned())
2635    ///     .ok(event_id)
2636    ///     .expect(1)
2637    ///     .mount()
2638    ///     .await;
2639    ///
2640    /// let response_not_mocked = room
2641    ///     .send_state_event_for_key(
2642    ///         "",
2643    ///         AnyStateEventContent::CallMember(CallMemberEventContent::new_empty(None)),
2644    ///     )
2645    ///     .await;
2646    /// // The `m.room.reaction` event type should not be mocked by the server.
2647    /// assert!(response_not_mocked.is_err());
2648    ///
2649    /// let response = room
2650    ///     .send_state_event_for_key(
2651    ///         "my_key",
2652    ///         AnyStateEventContent::CallMember(CallMemberEventContent::new_empty(None)),
2653    ///     )
2654    ///     .await
2655    ///     .unwrap();
2656    ///
2657    /// // The `m.room.message` event type should be mocked by the server.
2658    /// assert_eq!(
2659    ///     event_id, response.event_id,
2660    ///     "The event ID we mocked should match the one we received when we sent the event"
2661    /// );
2662    /// # anyhow::Ok(()) });
2663    /// ```
2664    pub fn for_key(mut self, state_key: String) -> Self {
2665        self.endpoint.state_key = Some(state_key);
2666        // Note: we may have already defined a path, but this one ought to be more
2667        // specialized (unless for_key/for_type were called multiple times).
2668        Self { mock: self.mock.and(path_regex(Self::generate_path_regexp(&self.endpoint))), ..self }
2669    }
2670
2671    /// Returns a send endpoint that emulates success, i.e. the event has been
2672    /// sent with the given event id.
2673    ///
2674    /// # Examples
2675    /// ```
2676    /// # tokio_test::block_on(async {
2677    /// use matrix_sdk::{ruma::{room_id, event_id}, test_utils::mocks::MatrixMockServer};
2678    /// use serde_json::json;
2679    ///
2680    /// let mock_server = MatrixMockServer::new().await;
2681    /// let client = mock_server.client_builder().build().await;
2682    ///
2683    /// mock_server.mock_room_state_encryption().plain().mount().await;
2684    ///
2685    /// let room = mock_server
2686    ///     .sync_joined_room(&client, room_id!("!room_id:localhost"))
2687    ///     .await;
2688    ///
2689    /// let event_id = event_id!("$some_id");
2690    /// let send_guard = mock_server
2691    ///     .mock_room_send_state()
2692    ///     .ok(event_id)
2693    ///     .expect(1)
2694    ///     .mount_as_scoped()
2695    ///     .await;
2696    ///
2697    /// let response = room.send_state_event_raw("m.room.message", "my_key", json!({ "body": "Hello world" })).await?;
2698    ///
2699    /// assert_eq!(
2700    ///     event_id,
2701    ///     response.event_id,
2702    ///     "The event ID we mocked should match the one we received when we sent the event"
2703    /// );
2704    /// # anyhow::Ok(()) });
2705    /// ```
2706    pub fn ok(self, returned_event_id: impl Into<OwnedEventId>) -> MatrixMock<'a> {
2707        self.ok_with_event_id(returned_event_id.into())
2708    }
2709}
2710
2711/// A prebuilt mock for running sync v2.
2712pub struct SyncEndpoint {
2713    sync_response_builder: Arc<Mutex<SyncResponseBuilder>>,
2714}
2715
2716impl<'a> MockEndpoint<'a, SyncEndpoint> {
2717    /// Expect the given timeout, or lack thereof, in the request.
2718    pub fn timeout(mut self, timeout: Option<Duration>) -> Self {
2719        if let Some(timeout) = timeout {
2720            self.mock = self.mock.and(query_param("timeout", timeout.as_millis().to_string()));
2721        } else {
2722            self.mock = self.mock.and(query_param_is_missing("timeout"));
2723        }
2724
2725        self
2726    }
2727
2728    /// Mocks the sync endpoint, using the given function to generate the
2729    /// response.
2730    pub fn ok<F: FnOnce(&mut SyncResponseBuilder)>(self, func: F) -> MatrixMock<'a> {
2731        let json_response = {
2732            let mut builder = self.endpoint.sync_response_builder.lock().unwrap();
2733            func(&mut builder);
2734            builder.build_json_sync_response()
2735        };
2736
2737        self.respond_with(ResponseTemplate::new(200).set_body_json(json_response))
2738    }
2739
2740    /// Temporarily mocks the sync with the given endpoint and runs a client
2741    /// sync with it.
2742    ///
2743    /// After calling this function, the sync endpoint isn't mocked anymore.
2744    ///
2745    /// # Examples
2746    ///
2747    /// ```
2748    /// # tokio_test::block_on(async {
2749    /// use matrix_sdk::{ruma::room_id, test_utils::mocks::MatrixMockServer};
2750    /// use matrix_sdk_test::JoinedRoomBuilder;
2751    ///
2752    /// // First create the mock server and client pair.
2753    /// let mock_server = MatrixMockServer::new().await;
2754    /// let client = mock_server.client_builder().build().await;
2755    /// let room_id = room_id!("!room_id:localhost");
2756    ///
2757    /// // Let's emulate what `MatrixMockServer::sync_joined_room()` does.
2758    /// mock_server
2759    ///     .mock_sync()
2760    ///     .ok_and_run(&client, |builder| {
2761    ///         builder.add_joined_room(JoinedRoomBuilder::new(room_id));
2762    ///     })
2763    ///     .await;
2764    ///
2765    /// let room = client
2766    ///     .get_room(room_id)
2767    ///     .expect("The room should be available after we mocked the sync");
2768    /// # anyhow::Ok(()) });
2769    /// ```
2770    pub async fn ok_and_run<F: FnOnce(&mut SyncResponseBuilder)>(self, client: &Client, func: F) {
2771        let _scope = self.ok(func).mount_as_scoped().await;
2772
2773        let _response = client.sync_once(Default::default()).await.unwrap();
2774    }
2775}
2776
2777/// A prebuilt mock for reading the encryption state of a room.
2778pub struct EncryptionStateEndpoint;
2779
2780impl<'a> MockEndpoint<'a, EncryptionStateEndpoint> {
2781    /// Marks the room as encrypted.
2782    ///
2783    /// # Examples
2784    ///
2785    /// ```
2786    /// # tokio_test::block_on(async {
2787    /// use matrix_sdk::{ruma::room_id, test_utils::mocks::MatrixMockServer};
2788    ///
2789    /// let mock_server = MatrixMockServer::new().await;
2790    /// let client = mock_server.client_builder().build().await;
2791    ///
2792    /// mock_server.mock_room_state_encryption().encrypted().mount().await;
2793    ///
2794    /// let room = mock_server
2795    ///     .sync_joined_room(&client, room_id!("!room_id:localhost"))
2796    ///     .await;
2797    ///
2798    /// assert!(
2799    ///     room.latest_encryption_state().await?.is_encrypted(),
2800    ///     "The room should be marked as encrypted."
2801    /// );
2802    /// # anyhow::Ok(()) });
2803    /// ```
2804    pub fn encrypted(self) -> MatrixMock<'a> {
2805        self.respond_with(
2806            ResponseTemplate::new(200)
2807                .set_body_json(EventFactory::new().room_encryption().into_content()),
2808        )
2809    }
2810
2811    /// Marks the room as encrypted, opting into experimental state event
2812    /// encryption.
2813    ///
2814    /// # Examples
2815    ///
2816    /// ```
2817    /// # tokio_test::block_on(async {
2818    /// use matrix_sdk::{ruma::room_id, test_utils::mocks::MatrixMockServer};
2819    ///
2820    /// let mock_server = MatrixMockServer::new().await;
2821    /// let client = mock_server.client_builder().build().await;
2822    ///
2823    /// mock_server.mock_room_state_encryption().state_encrypted().mount().await;
2824    ///
2825    /// let room = mock_server
2826    ///     .sync_joined_room(&client, room_id!("!room_id:localhost"))
2827    ///     .await;
2828    ///
2829    /// assert!(
2830    ///     room.latest_encryption_state().await?.is_state_encrypted(),
2831    ///     "The room should be marked as state encrypted."
2832    /// );
2833    /// # anyhow::Ok(()) });
2834    #[cfg(feature = "experimental-encrypted-state-events")]
2835    pub fn state_encrypted(self) -> MatrixMock<'a> {
2836        self.respond_with(ResponseTemplate::new(200).set_body_json(
2837            EventFactory::new().room_encryption_with_state_encryption().into_content(),
2838        ))
2839    }
2840
2841    /// Marks the room as not encrypted.
2842    ///
2843    /// # Examples
2844    ///
2845    /// ```
2846    /// # tokio_test::block_on(async {
2847    /// use matrix_sdk::{ruma::room_id, test_utils::mocks::MatrixMockServer};
2848    ///
2849    /// let mock_server = MatrixMockServer::new().await;
2850    /// let client = mock_server.client_builder().build().await;
2851    ///
2852    /// mock_server.mock_room_state_encryption().plain().mount().await;
2853    ///
2854    /// let room = mock_server
2855    ///     .sync_joined_room(&client, room_id!("!room_id:localhost"))
2856    ///     .await;
2857    ///
2858    /// assert!(
2859    ///     !room.latest_encryption_state().await?.is_encrypted(),
2860    ///     "The room should not be marked as encrypted."
2861    /// );
2862    /// # anyhow::Ok(()) });
2863    /// ```
2864    pub fn plain(self) -> MatrixMock<'a> {
2865        self.respond_with(ResponseTemplate::new(404).set_body_json(&*test_json::NOT_FOUND))
2866    }
2867}
2868
2869/// A prebuilt mock for setting the encryption state of a room.
2870pub struct SetEncryptionStateEndpoint;
2871
2872impl<'a> MockEndpoint<'a, SetEncryptionStateEndpoint> {
2873    /// Returns a mock for a successful setting of the encryption state event.
2874    pub fn ok(self, returned_event_id: impl Into<OwnedEventId>) -> MatrixMock<'a> {
2875        self.ok_with_event_id(returned_event_id.into())
2876    }
2877}
2878
2879/// A prebuilt mock for redacting an event in a room.
2880pub struct RoomRedactEndpoint;
2881
2882impl<'a> MockEndpoint<'a, RoomRedactEndpoint> {
2883    /// Returns a redact endpoint that emulates success, i.e. the redaction
2884    /// event has been sent with the given event id.
2885    pub fn ok(self, returned_event_id: impl Into<OwnedEventId>) -> MatrixMock<'a> {
2886        self.ok_with_event_id(returned_event_id.into())
2887    }
2888}
2889
2890/// A prebuilt mock for getting a single event in a room.
2891pub struct RoomEventEndpoint {
2892    room: Option<OwnedRoomId>,
2893    match_event_id: bool,
2894}
2895
2896impl<'a> MockEndpoint<'a, RoomEventEndpoint> {
2897    /// Limits the scope of this mock to a specific room.
2898    pub fn room(mut self, room: impl Into<OwnedRoomId>) -> Self {
2899        self.endpoint.room = Some(room.into());
2900        self
2901    }
2902
2903    /// Whether the mock checks for the event id from the event.
2904    pub fn match_event_id(mut self) -> Self {
2905        self.endpoint.match_event_id = true;
2906        self
2907    }
2908
2909    /// Returns a redact endpoint that emulates success, i.e. the redaction
2910    /// event has been sent with the given event id.
2911    pub fn ok(self, event: TimelineEvent) -> MatrixMock<'a> {
2912        let event_path = if self.endpoint.match_event_id {
2913            let event_id = event.kind.event_id().expect("an event id is required");
2914            // The event id should begin with `$`, which would be taken as the end of the
2915            // regex so we need to escape it
2916            event_id.as_str().replace("$", "\\$")
2917        } else {
2918            // Event is at the end, so no need to add anything.
2919            "".to_owned()
2920        };
2921
2922        let room_path = self.endpoint.room.map_or_else(|| ".*".to_owned(), |room| room.to_string());
2923
2924        let mock = self
2925            .mock
2926            .and(path_regex(format!(r"^/_matrix/client/v3/rooms/{room_path}/event/{event_path}")))
2927            .respond_with(ResponseTemplate::new(200).set_body_json(event.into_raw().json()));
2928        MatrixMock { server: self.server, mock }
2929    }
2930}
2931
2932/// A builder pattern for the response to a [`RoomEventContextEndpoint`]
2933/// request.
2934pub struct RoomContextResponseTemplate {
2935    event: TimelineEvent,
2936    events_before: Vec<TimelineEvent>,
2937    events_after: Vec<TimelineEvent>,
2938    start: Option<String>,
2939    end: Option<String>,
2940    state_events: Vec<Raw<AnyStateEvent>>,
2941}
2942
2943impl RoomContextResponseTemplate {
2944    /// Creates a new context response with the given focused event.
2945    pub fn new(event: TimelineEvent) -> Self {
2946        Self {
2947            event,
2948            events_before: Vec::new(),
2949            events_after: Vec::new(),
2950            start: None,
2951            end: None,
2952            state_events: Vec::new(),
2953        }
2954    }
2955
2956    /// Add some events before the target event.
2957    pub fn events_before(mut self, events: Vec<TimelineEvent>) -> Self {
2958        self.events_before = events;
2959        self
2960    }
2961
2962    /// Add some events after the target event.
2963    pub fn events_after(mut self, events: Vec<TimelineEvent>) -> Self {
2964        self.events_after = events;
2965        self
2966    }
2967
2968    /// Set the start token that could be used for paginating backwards.
2969    pub fn start(mut self, start: impl Into<String>) -> Self {
2970        self.start = Some(start.into());
2971        self
2972    }
2973
2974    /// Set the end token that could be used for paginating forwards.
2975    pub fn end(mut self, end: impl Into<String>) -> Self {
2976        self.end = Some(end.into());
2977        self
2978    }
2979
2980    /// Pass some extra state events to this response.
2981    pub fn state_events(mut self, state_events: Vec<Raw<AnyStateEvent>>) -> Self {
2982        self.state_events = state_events;
2983        self
2984    }
2985}
2986
2987/// A prebuilt mock for getting a single event with its context in a room.
2988pub struct RoomEventContextEndpoint {
2989    room: Option<OwnedRoomId>,
2990    match_event_id: bool,
2991}
2992
2993impl<'a> MockEndpoint<'a, RoomEventContextEndpoint> {
2994    /// Limits the scope of this mock to a specific room.
2995    pub fn room(mut self, room: impl Into<OwnedRoomId>) -> Self {
2996        self.endpoint.room = Some(room.into());
2997        self
2998    }
2999
3000    /// Whether the mock checks for the event id from the event.
3001    pub fn match_event_id(mut self) -> Self {
3002        self.endpoint.match_event_id = true;
3003        self
3004    }
3005
3006    /// Returns an endpoint that emulates a successful response.
3007    pub fn ok(self, response: RoomContextResponseTemplate) -> MatrixMock<'a> {
3008        let event_path = if self.endpoint.match_event_id {
3009            let event_id = response.event.event_id().expect("an event id is required");
3010            // The event id should begin with `$`, which would be taken as the end of the
3011            // regex so we need to escape it
3012            event_id.as_str().replace("$", "\\$")
3013        } else {
3014            // Event is at the end, so no need to add anything.
3015            "".to_owned()
3016        };
3017
3018        let room_path = self.endpoint.room.map_or_else(|| ".*".to_owned(), |room| room.to_string());
3019
3020        let mock = self
3021            .mock
3022            .and(path_regex(format!(r"^/_matrix/client/v3/rooms/{room_path}/context/{event_path}")))
3023            .respond_with(ResponseTemplate::new(200).set_body_json(json!({
3024                "event": response.event.into_raw().json(),
3025                "events_before": response.events_before.into_iter().map(|event| event.into_raw().json().to_owned()).collect::<Vec<_>>(),
3026                "events_after": response.events_after.into_iter().map(|event| event.into_raw().json().to_owned()).collect::<Vec<_>>(),
3027                "end": response.end,
3028                "start": response.start,
3029                "state": response.state_events,
3030            })));
3031        MatrixMock { server: self.server, mock }
3032    }
3033}
3034
3035/// A prebuilt mock for the `/messages` endpoint.
3036pub struct RoomMessagesEndpoint;
3037
3038/// A prebuilt mock for getting a room messages in a room.
3039impl<'a> MockEndpoint<'a, RoomMessagesEndpoint> {
3040    /// Expects an optional limit to be set on the request.
3041    pub fn match_limit(self, limit: u32) -> Self {
3042        Self { mock: self.mock.and(query_param("limit", limit.to_string())), ..self }
3043    }
3044
3045    /// Expects an optional `from` to be set on the request.
3046    pub fn match_from(self, from: &str) -> Self {
3047        Self { mock: self.mock.and(query_param("from", from)), ..self }
3048    }
3049
3050    /// Returns a messages endpoint that emulates success, i.e. the messages
3051    /// provided as `response` could be retrieved.
3052    ///
3053    /// Note: pass `chunk` in the correct order: topological for forward
3054    /// pagination, reverse topological for backwards pagination.
3055    pub fn ok(self, response: RoomMessagesResponseTemplate) -> MatrixMock<'a> {
3056        let mut template = ResponseTemplate::new(200).set_body_json(json!({
3057            "start": response.start,
3058            "end": response.end,
3059            "chunk": response.chunk,
3060            "state": response.state,
3061        }));
3062
3063        if let Some(delay) = response.delay {
3064            template = template.set_delay(delay);
3065        }
3066
3067        self.respond_with(template)
3068    }
3069}
3070
3071/// A response to a [`RoomMessagesEndpoint`] query.
3072pub struct RoomMessagesResponseTemplate {
3073    /// The start token for this /messages query.
3074    pub start: String,
3075    /// The end token for this /messages query (previous batch for back
3076    /// paginations, next batch for forward paginations).
3077    pub end: Option<String>,
3078    /// The set of timeline events returned by this query.
3079    pub chunk: Vec<Raw<AnyTimelineEvent>>,
3080    /// The set of state events returned by this query.
3081    pub state: Vec<Raw<AnyStateEvent>>,
3082    /// Optional delay to respond to the query.
3083    pub delay: Option<Duration>,
3084}
3085
3086impl RoomMessagesResponseTemplate {
3087    /// Fill the events returned as part of this response.
3088    pub fn events(mut self, chunk: Vec<impl Into<Raw<AnyTimelineEvent>>>) -> Self {
3089        self.chunk = chunk.into_iter().map(Into::into).collect();
3090        self
3091    }
3092
3093    /// Fill the end token.
3094    pub fn end_token(mut self, token: impl Into<String>) -> Self {
3095        self.end = Some(token.into());
3096        self
3097    }
3098
3099    /// Respond with a given delay to the query.
3100    pub fn with_delay(mut self, delay: Duration) -> Self {
3101        self.delay = Some(delay);
3102        self
3103    }
3104}
3105
3106impl Default for RoomMessagesResponseTemplate {
3107    fn default() -> Self {
3108        Self {
3109            start: "start-token-unused".to_owned(),
3110            end: Default::default(),
3111            chunk: Default::default(),
3112            state: Default::default(),
3113            delay: None,
3114        }
3115    }
3116}
3117
3118/// A prebuilt mock for uploading media.
3119pub struct UploadEndpoint;
3120
3121impl<'a> MockEndpoint<'a, UploadEndpoint> {
3122    /// Expect that the content type matches what's given here.
3123    pub fn expect_mime_type(self, content_type: &str) -> Self {
3124        Self { mock: self.mock.and(header("content-type", content_type)), ..self }
3125    }
3126
3127    /// Returns a upload endpoint that emulates success, i.e. the media has been
3128    /// uploaded to the media server and can be accessed using the given
3129    /// event has been sent with the given [`MxcUri`].
3130    ///
3131    /// The uploaded content is captured and can be accessed using the returned
3132    /// [`Receiver`]. The [`Receiver`] is valid only for a single media
3133    /// upload.
3134    ///
3135    /// # Examples
3136    ///
3137    /// ```no_run
3138    /// # tokio_test::block_on(async {
3139    /// use matrix_sdk::{
3140    ///     ruma::{event_id, mxc_uri, room_id},
3141    ///     test_utils::mocks::MatrixMockServer,
3142    /// };
3143    ///
3144    /// let mxid = mxc_uri!("mxc://localhost/12345");
3145    ///
3146    /// let server = MatrixMockServer::new().await;
3147    /// let (receiver, upload_mock) = server.mock_upload().ok_with_capture(mxid);
3148    /// let client = server.client_builder().build().await;
3149    ///
3150    /// client.media().upload(&mime::TEXT_PLAIN, vec![1, 2, 3, 4, 5], None).await?;
3151    ///
3152    /// let uploaded = receiver.await?;
3153    ///
3154    /// assert_eq!(uploaded, vec![1, 2, 3, 4, 5]);
3155    /// # anyhow::Ok(()) });
3156    /// ```
3157    pub fn ok_with_capture(self, mxc_id: &MxcUri) -> (Receiver<Vec<u8>>, MatrixMock<'a>) {
3158        let (sender, receiver) = oneshot::channel();
3159        let sender = Arc::new(Mutex::new(Some(sender)));
3160        let response_body = json!({"content_uri": mxc_id});
3161
3162        let ret = self.respond_with(move |request: &Request| {
3163            let maybe_sender = sender.lock().unwrap().take();
3164
3165            if let Some(sender) = maybe_sender {
3166                let body = request.body.clone();
3167                let _ = sender.send(body);
3168            }
3169
3170            ResponseTemplate::new(200).set_body_json(response_body.clone())
3171        });
3172
3173        (receiver, ret)
3174    }
3175
3176    /// Returns a upload endpoint that emulates success, i.e. the media has been
3177    /// uploaded to the media server and can be accessed using the given
3178    /// event has been sent with the given [`MxcUri`].
3179    pub fn ok(self, mxc_id: &MxcUri) -> MatrixMock<'a> {
3180        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
3181            "content_uri": mxc_id
3182        })))
3183    }
3184}
3185
3186/// A prebuilt mock for resolving a room alias.
3187pub struct ResolveRoomAliasEndpoint;
3188
3189impl<'a> MockEndpoint<'a, ResolveRoomAliasEndpoint> {
3190    /// Sets up the endpoint to only intercept requests for the given room
3191    /// alias.
3192    pub fn for_alias(self, alias: impl Into<String>) -> Self {
3193        let alias = alias.into();
3194        Self {
3195            mock: self.mock.and(path_regex(format!(
3196                r"^/_matrix/client/v3/directory/room/{}",
3197                percent_encoded_path(&alias)
3198            ))),
3199            ..self
3200        }
3201    }
3202
3203    /// Returns a data endpoint with a resolved room alias.
3204    pub fn ok(self, room_id: &str, servers: Vec<String>) -> MatrixMock<'a> {
3205        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
3206            "room_id": room_id,
3207            "servers": servers,
3208        })))
3209    }
3210
3211    /// Returns a data endpoint for a room alias that does not exit.
3212    pub fn not_found(self) -> MatrixMock<'a> {
3213        self.respond_with(ResponseTemplate::new(404).set_body_json(json!({
3214          "errcode": "M_NOT_FOUND",
3215          "error": "Room alias not found."
3216        })))
3217    }
3218}
3219
3220/// A prebuilt mock for creating a room alias.
3221pub struct CreateRoomAliasEndpoint;
3222
3223impl<'a> MockEndpoint<'a, CreateRoomAliasEndpoint> {
3224    /// Returns a data endpoint for creating a room alias.
3225    pub fn ok(self) -> MatrixMock<'a> {
3226        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({})))
3227    }
3228}
3229
3230/// A prebuilt mock for removing a room alias.
3231pub struct RemoveRoomAliasEndpoint;
3232
3233impl<'a> MockEndpoint<'a, RemoveRoomAliasEndpoint> {
3234    /// Returns a data endpoint for removing a room alias.
3235    pub fn ok(self) -> MatrixMock<'a> {
3236        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({})))
3237    }
3238}
3239
3240/// A prebuilt mock for paginating the public room list.
3241pub struct PublicRoomsEndpoint;
3242
3243impl<'a> MockEndpoint<'a, PublicRoomsEndpoint> {
3244    /// Returns a data endpoint for paginating the public room list.
3245    pub fn ok(
3246        self,
3247        chunk: Vec<PublicRoomsChunk>,
3248        next_batch: Option<String>,
3249        prev_batch: Option<String>,
3250        total_room_count_estimate: Option<u64>,
3251    ) -> MatrixMock<'a> {
3252        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
3253            "chunk": chunk,
3254            "next_batch": next_batch,
3255            "prev_batch": prev_batch,
3256            "total_room_count_estimate": total_room_count_estimate,
3257        })))
3258    }
3259
3260    /// Returns a data endpoint for paginating the public room list with several
3261    /// `via` params.
3262    ///
3263    /// Each `via` param must be in the `server_map` parameter, otherwise it'll
3264    /// fail.
3265    pub fn ok_with_via_params(
3266        self,
3267        server_map: BTreeMap<OwnedServerName, Vec<PublicRoomsChunk>>,
3268    ) -> MatrixMock<'a> {
3269        self.respond_with(move |req: &Request| {
3270            #[derive(Deserialize)]
3271            struct PartialRequest {
3272                server: Option<OwnedServerName>,
3273            }
3274
3275            let (_, server) = req
3276                .url
3277                .query_pairs()
3278                .into_iter()
3279                .find(|(key, _)| key == "server")
3280                .expect("Server param not found in request URL");
3281            let server = ServerName::parse(server).expect("Couldn't parse server name");
3282            let chunk = server_map.get(&server).expect("Chunk for the server param not found");
3283            ResponseTemplate::new(200).set_body_json(json!({
3284                "chunk": chunk,
3285                "total_room_count_estimate": chunk.len(),
3286            }))
3287        })
3288    }
3289}
3290
3291/// A prebuilt mock for getting the room's visibility in the room directory.
3292pub struct GetRoomVisibilityEndpoint;
3293
3294impl<'a> MockEndpoint<'a, GetRoomVisibilityEndpoint> {
3295    /// Returns an endpoint that get the room's public visibility.
3296    pub fn ok(self, visibility: Visibility) -> MatrixMock<'a> {
3297        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
3298            "visibility": visibility,
3299        })))
3300    }
3301}
3302
3303/// A prebuilt mock for setting the room's visibility in the room directory.
3304pub struct SetRoomVisibilityEndpoint;
3305
3306impl<'a> MockEndpoint<'a, SetRoomVisibilityEndpoint> {
3307    /// Returns an endpoint that updates the room's visibility.
3308    pub fn ok(self) -> MatrixMock<'a> {
3309        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({})))
3310    }
3311}
3312
3313/// A prebuilt mock for `GET room_keys/version`: storage ("backup") of room
3314/// keys.
3315pub struct RoomKeysVersionEndpoint;
3316
3317impl<'a> MockEndpoint<'a, RoomKeysVersionEndpoint> {
3318    /// Returns an endpoint that says there is a single room keys backup
3319    pub fn exists(self) -> MatrixMock<'a> {
3320        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
3321            "algorithm": "m.megolm_backup.v1.curve25519-aes-sha2",
3322            "auth_data": {
3323                "public_key": "abcdefg",
3324                "signatures": {},
3325            },
3326            "count": 42,
3327            "etag": "anopaquestring",
3328            "version": "1",
3329        })))
3330    }
3331
3332    /// Returns an endpoint that says there is no room keys backup
3333    pub fn none(self) -> MatrixMock<'a> {
3334        self.respond_with(ResponseTemplate::new(404).set_body_json(json!({
3335            "errcode": "M_NOT_FOUND",
3336            "error": "No current backup version"
3337        })))
3338    }
3339
3340    /// Returns an endpoint that 429 errors when we get it
3341    pub fn error429(self) -> MatrixMock<'a> {
3342        self.respond_with(ResponseTemplate::new(429).set_body_json(json!({
3343            "errcode": "M_LIMIT_EXCEEDED",
3344            "error": "Too many requests",
3345            "retry_after_ms": 2000
3346        })))
3347    }
3348
3349    /// Returns an endpoint that 404 errors when we get it
3350    pub fn error404(self) -> MatrixMock<'a> {
3351        self.respond_with(ResponseTemplate::new(404))
3352    }
3353}
3354
3355/// A prebuilt mock for `POST room_keys/version`: adding room key backups.
3356pub struct AddRoomKeysVersionEndpoint;
3357
3358impl<'a> MockEndpoint<'a, AddRoomKeysVersionEndpoint> {
3359    /// Returns an endpoint that may be used to add room key backups
3360    pub fn ok(self) -> MatrixMock<'a> {
3361        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
3362          "version": "1"
3363        })))
3364        .named("POST for the backup creation")
3365    }
3366}
3367
3368/// A prebuilt mock for `DELETE room_keys/version/xxx`: deleting room key
3369/// backups.
3370pub struct DeleteRoomKeysVersionEndpoint;
3371
3372impl<'a> MockEndpoint<'a, DeleteRoomKeysVersionEndpoint> {
3373    /// Returns an endpoint that allows deleting room key backups
3374    pub fn ok(self) -> MatrixMock<'a> {
3375        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({})))
3376            .named("DELETE for the backup deletion")
3377    }
3378}
3379
3380/// A prebuilt mock for the `/sendToDevice` endpoint.
3381///
3382/// This mock can be used to simulate sending to-device messages in tests.
3383pub struct SendToDeviceEndpoint;
3384impl<'a> MockEndpoint<'a, SendToDeviceEndpoint> {
3385    /// Returns a successful response with default data.
3386    pub fn ok(self) -> MatrixMock<'a> {
3387        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({})))
3388    }
3389}
3390
3391/// A prebuilt mock for `GET /members` request.
3392pub struct GetRoomMembersEndpoint;
3393
3394impl<'a> MockEndpoint<'a, GetRoomMembersEndpoint> {
3395    /// Returns a successful get members request with a list of members.
3396    pub fn ok(self, members: Vec<Raw<RoomMemberEvent>>) -> MatrixMock<'a> {
3397        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
3398            "chunk": members,
3399        })))
3400    }
3401}
3402
3403/// A prebuilt mock for `POST /invite` request.
3404pub struct InviteUserByIdEndpoint;
3405
3406impl<'a> MockEndpoint<'a, InviteUserByIdEndpoint> {
3407    /// Returns a successful invite user by id request.
3408    pub fn ok(self) -> MatrixMock<'a> {
3409        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({})))
3410    }
3411}
3412
3413/// A prebuilt mock for `POST /kick` request.
3414pub struct KickUserEndpoint;
3415
3416impl<'a> MockEndpoint<'a, KickUserEndpoint> {
3417    /// Returns a successful kick user request.
3418    pub fn ok(self) -> MatrixMock<'a> {
3419        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({})))
3420    }
3421}
3422
3423/// A prebuilt mock for `POST /ban` request.
3424pub struct BanUserEndpoint;
3425
3426impl<'a> MockEndpoint<'a, BanUserEndpoint> {
3427    /// Returns a successful ban user request.
3428    pub fn ok(self) -> MatrixMock<'a> {
3429        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({})))
3430    }
3431}
3432
3433/// A prebuilt mock for `GET /versions` request.
3434pub struct VersionsEndpoint {
3435    versions: Vec<&'static str>,
3436    features: BTreeMap<&'static str, bool>,
3437}
3438
3439impl VersionsEndpoint {
3440    // Get a JSON array of commonly supported versions.
3441    fn commonly_supported_versions() -> Vec<&'static str> {
3442        vec![
3443            "r0.0.1", "r0.2.0", "r0.3.0", "r0.4.0", "r0.5.0", "r0.6.0", "r0.6.1", "v1.1", "v1.2",
3444            "v1.3", "v1.4", "v1.5", "v1.6", "v1.7", "v1.8", "v1.9", "v1.10", "v1.11",
3445        ]
3446    }
3447}
3448
3449impl Default for VersionsEndpoint {
3450    fn default() -> Self {
3451        Self { versions: Self::commonly_supported_versions(), features: BTreeMap::new() }
3452    }
3453}
3454
3455impl<'a> MockEndpoint<'a, VersionsEndpoint> {
3456    /// Returns a successful `/_matrix/client/versions` request.
3457    ///
3458    /// The response will return some commonly supported versions.
3459    pub fn ok(mut self) -> MatrixMock<'a> {
3460        let features = std::mem::take(&mut self.endpoint.features);
3461        let versions = std::mem::take(&mut self.endpoint.versions);
3462        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
3463            "unstable_features": features,
3464            "versions": versions
3465        })))
3466    }
3467
3468    /// Set the supported flag for the given unstable feature in the response of
3469    /// this endpoint.
3470    pub fn with_feature(mut self, feature: &'static str, supported: bool) -> Self {
3471        self.endpoint.features.insert(feature, supported);
3472        self
3473    }
3474
3475    /// Indicate that push for encrypted events is supported by this homeserver.
3476    pub fn with_push_encrypted_events(self) -> Self {
3477        self.with_feature("org.matrix.msc4028", true)
3478    }
3479
3480    /// Indicate that thread subscriptions are supported by this homeserver.
3481    pub fn with_thread_subscriptions(self) -> Self {
3482        self.with_feature("org.matrix.msc4306", true)
3483    }
3484
3485    /// Indicate that simplified sliding sync is supported by this homeserver.
3486    pub fn with_simplified_sliding_sync(self) -> Self {
3487        self.with_feature("org.matrix.simplified_msc3575", true)
3488    }
3489
3490    /// Set the supported versions in the response of this endpoint.
3491    pub fn with_versions(mut self, versions: Vec<&'static str>) -> Self {
3492        self.endpoint.versions = versions;
3493        self
3494    }
3495}
3496
3497/// A prebuilt mock for the room summary endpoint.
3498pub struct RoomSummaryEndpoint;
3499
3500impl<'a> MockEndpoint<'a, RoomSummaryEndpoint> {
3501    /// Returns a successful response with some default data for the given room
3502    /// id.
3503    pub fn ok(self, room_id: &RoomId) -> MatrixMock<'a> {
3504        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
3505            "room_id": room_id,
3506            "guest_can_join": true,
3507            "num_joined_members": 1,
3508            "world_readable": true,
3509            "join_rule": "public",
3510        })))
3511    }
3512}
3513
3514/// A prebuilt mock to set a room's pinned events.
3515pub struct SetRoomPinnedEventsEndpoint;
3516
3517impl<'a> MockEndpoint<'a, SetRoomPinnedEventsEndpoint> {
3518    /// Returns a successful response with a given event id.
3519    /// id.
3520    pub fn ok(self, event_id: OwnedEventId) -> MatrixMock<'a> {
3521        self.ok_with_event_id(event_id)
3522    }
3523
3524    /// Returns an error response with a generic error code indicating the
3525    /// client is not authorized to set pinned events.
3526    pub fn unauthorized(self) -> MatrixMock<'a> {
3527        self.respond_with(ResponseTemplate::new(400))
3528    }
3529}
3530
3531/// A prebuilt mock for `GET /account/whoami` request.
3532pub struct WhoAmIEndpoint;
3533
3534impl<'a> MockEndpoint<'a, WhoAmIEndpoint> {
3535    /// Returns a successful response with the default device ID.
3536    pub fn ok(self) -> MatrixMock<'a> {
3537        self.ok_with_device_id(device_id!("D3V1C31D"))
3538    }
3539
3540    /// Returns a successful response with the given device ID.
3541    pub fn ok_with_device_id(self, device_id: &DeviceId) -> MatrixMock<'a> {
3542        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
3543            "user_id": "@joe:example.org",
3544            "device_id": device_id,
3545        })))
3546    }
3547}
3548
3549/// A prebuilt mock for `POST /keys/upload` request.
3550pub struct UploadKeysEndpoint;
3551
3552impl<'a> MockEndpoint<'a, UploadKeysEndpoint> {
3553    /// Returns a successful response with counts of 10 curve25519 keys and 20
3554    /// signed curve25519 keys.
3555    pub fn ok(self) -> MatrixMock<'a> {
3556        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
3557            "one_time_key_counts": {
3558                "curve25519": 10,
3559                "signed_curve25519": 20,
3560            },
3561        })))
3562    }
3563}
3564
3565/// A prebuilt mock for `POST /keys/query` request.
3566pub struct QueryKeysEndpoint;
3567
3568impl<'a> MockEndpoint<'a, QueryKeysEndpoint> {
3569    /// Returns a successful empty response.
3570    pub fn ok(self) -> MatrixMock<'a> {
3571        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({})))
3572    }
3573}
3574
3575/// A prebuilt mock for `GET /.well-known/matrix/client` request.
3576pub struct WellKnownEndpoint;
3577
3578impl<'a> MockEndpoint<'a, WellKnownEndpoint> {
3579    /// Returns a successful response with the URL for this homeserver.
3580    pub fn ok(self) -> MatrixMock<'a> {
3581        let server_uri = self.server.uri();
3582        self.ok_with_homeserver_url(&server_uri)
3583    }
3584
3585    /// Returns a successful response with the given homeserver URL.
3586    pub fn ok_with_homeserver_url(self, homeserver_url: &str) -> MatrixMock<'a> {
3587        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
3588            "m.homeserver": {
3589                "base_url": homeserver_url,
3590            },
3591            "m.rtc_foci": [
3592                {
3593                    "type": "livekit",
3594                    "livekit_service_url": "https://livekit.example.com",
3595                },
3596            ],
3597        })))
3598    }
3599
3600    /// Returns a 404 error response.
3601    pub fn error404(self) -> MatrixMock<'a> {
3602        self.respond_with(ResponseTemplate::new(404))
3603    }
3604}
3605
3606/// A prebuilt mock for `POST /keys/device_signing/upload` request.
3607pub struct UploadCrossSigningKeysEndpoint;
3608
3609impl<'a> MockEndpoint<'a, UploadCrossSigningKeysEndpoint> {
3610    /// Returns a successful empty response.
3611    pub fn ok(self) -> MatrixMock<'a> {
3612        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({})))
3613    }
3614
3615    /// Returns an error response with a UIAA stage that failed to authenticate
3616    /// because of an invalid password.
3617    pub fn uiaa_invalid_password(self) -> MatrixMock<'a> {
3618        self.respond_with(ResponseTemplate::new(401).set_body_json(json!({
3619            "errcode": "M_FORBIDDEN",
3620            "error": "Invalid password",
3621            "flows": [
3622                {
3623                    "stages": [
3624                        "m.login.password"
3625                    ]
3626                }
3627            ],
3628            "params": {},
3629            "session": "oFIJVvtEOCKmRUTYKTYIIPHL"
3630        })))
3631    }
3632
3633    /// Returns an error response with a UIAA stage.
3634    pub fn uiaa(self) -> MatrixMock<'a> {
3635        self.respond_with(ResponseTemplate::new(401).set_body_json(json!({
3636            "flows": [
3637                {
3638                    "stages": [
3639                        "m.login.password"
3640                    ]
3641                }
3642            ],
3643            "params": {},
3644            "session": "oFIJVvtEOCKmRUTYKTYIIPHL"
3645        })))
3646    }
3647
3648    /// Returns an error response with an unstable OAuth 2.0 UIAA stage.
3649    pub fn uiaa_unstable_oauth(self) -> MatrixMock<'a> {
3650        let server_uri = self.server.uri();
3651        self.respond_with(ResponseTemplate::new(401).set_body_json(json!({
3652            "session": "dummy",
3653            "flows": [{
3654                "stages": [ "org.matrix.cross_signing_reset" ]
3655            }],
3656            "params": {
3657                "org.matrix.cross_signing_reset": {
3658                    "url": format!("{server_uri}/account/?action=org.matrix.cross_signing_reset"),
3659                }
3660            },
3661            "msg": "To reset your end-to-end encryption cross-signing identity, you first need to approve it and then try again."
3662        })))
3663    }
3664
3665    /// Returns an error response with a stable OAuth 2.0 UIAA stage.
3666    pub fn uiaa_stable_oauth(self) -> MatrixMock<'a> {
3667        let server_uri = self.server.uri();
3668        self.respond_with(ResponseTemplate::new(401).set_body_json(json!({
3669            "session": "dummy",
3670            "flows": [{
3671                "stages": [ "m.oauth" ]
3672            }],
3673            "params": {
3674                "m.oauth": {
3675                    "url": format!("{server_uri}/account/?action=org.matrix.cross_signing_reset"),
3676                }
3677            },
3678            "msg": "To reset your end-to-end encryption cross-signing identity, you first need to approve it and then try again."
3679        })))
3680    }
3681}
3682
3683/// A prebuilt mock for `POST /keys/signatures/upload` request.
3684pub struct UploadCrossSigningSignaturesEndpoint;
3685
3686impl<'a> MockEndpoint<'a, UploadCrossSigningSignaturesEndpoint> {
3687    /// Returns a successful empty response.
3688    pub fn ok(self) -> MatrixMock<'a> {
3689        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({})))
3690    }
3691}
3692
3693/// A prebuilt mock for the room leave endpoint.
3694pub struct RoomLeaveEndpoint;
3695
3696impl<'a> MockEndpoint<'a, RoomLeaveEndpoint> {
3697    /// Returns a successful response with some default data for the given room
3698    /// id.
3699    pub fn ok(self, room_id: &RoomId) -> MatrixMock<'a> {
3700        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
3701            "room_id": room_id,
3702        })))
3703    }
3704
3705    /// Returns a `M_FORBIDDEN` response.
3706    pub fn forbidden(self) -> MatrixMock<'a> {
3707        self.respond_with(ResponseTemplate::new(403).set_body_json(json!({
3708            "errcode": "M_FORBIDDEN",
3709            "error": "sowwy",
3710        })))
3711    }
3712}
3713
3714/// A prebuilt mock for the room forget endpoint.
3715pub struct RoomForgetEndpoint;
3716
3717impl<'a> MockEndpoint<'a, RoomForgetEndpoint> {
3718    /// Returns a successful response with some default data for the given room
3719    /// id.
3720    pub fn ok(self) -> MatrixMock<'a> {
3721        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({})))
3722    }
3723}
3724
3725/// A prebuilt mock for `POST /logout` request.
3726pub struct LogoutEndpoint;
3727
3728impl<'a> MockEndpoint<'a, LogoutEndpoint> {
3729    /// Returns a successful empty response.
3730    pub fn ok(self) -> MatrixMock<'a> {
3731        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({})))
3732    }
3733}
3734
3735/// A prebuilt mock for a `GET /rooms/{roomId}/threads` request.
3736pub struct RoomThreadsEndpoint;
3737
3738impl<'a> MockEndpoint<'a, RoomThreadsEndpoint> {
3739    /// Expects an optional `from` to be set on the request.
3740    pub fn match_from(self, from: &str) -> Self {
3741        Self { mock: self.mock.and(query_param("from", from)), ..self }
3742    }
3743
3744    /// Returns a successful response with some optional events and previous
3745    /// batch token.
3746    pub fn ok(
3747        self,
3748        chunk: Vec<Raw<AnyTimelineEvent>>,
3749        next_batch: Option<String>,
3750    ) -> MatrixMock<'a> {
3751        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
3752            "chunk": chunk,
3753            "next_batch": next_batch
3754        })))
3755    }
3756}
3757
3758/// A prebuilt mock for a `GET /rooms/{roomId}/relations/{eventId}` family of
3759/// requests.
3760#[derive(Default)]
3761pub struct RoomRelationsEndpoint {
3762    event_id: Option<OwnedEventId>,
3763    spec: Option<IncludeRelations>,
3764}
3765
3766impl<'a> MockEndpoint<'a, RoomRelationsEndpoint> {
3767    /// Expects an optional `from` to be set on the request.
3768    pub fn match_from(self, from: &str) -> Self {
3769        Self { mock: self.mock.and(query_param("from", from)), ..self }
3770    }
3771
3772    /// Expects an optional `limit` to be set on the request.
3773    pub fn match_limit(self, limit: u32) -> Self {
3774        Self { mock: self.mock.and(query_param("limit", limit.to_string())), ..self }
3775    }
3776
3777    /// Match the given subrequest, according to the given specification.
3778    pub fn match_subrequest(mut self, spec: IncludeRelations) -> Self {
3779        self.endpoint.spec = Some(spec);
3780        self
3781    }
3782
3783    /// Expects the request to match a specific event id.
3784    pub fn match_target_event(mut self, event_id: OwnedEventId) -> Self {
3785        self.endpoint.event_id = Some(event_id);
3786        self
3787    }
3788
3789    /// Returns a successful response with some optional events and pagination
3790    /// tokens.
3791    pub fn ok(mut self, response: RoomRelationsResponseTemplate) -> MatrixMock<'a> {
3792        // Escape the leading $ to not confuse the regular expression engine.
3793        let event_spec = self
3794            .endpoint
3795            .event_id
3796            .take()
3797            .map(|event_id| event_id.as_str().replace("$", "\\$"))
3798            .unwrap_or_else(|| ".*".to_owned());
3799
3800        match self.endpoint.spec.take() {
3801            Some(IncludeRelations::RelationsOfType(rel_type)) => {
3802                self.mock = self.mock.and(path_regex(format!(
3803                    r"^/_matrix/client/v1/rooms/.*/relations/{event_spec}/{rel_type}$"
3804                )));
3805            }
3806            Some(IncludeRelations::RelationsOfTypeAndEventType(rel_type, event_type)) => {
3807                self.mock = self.mock.and(path_regex(format!(
3808                    r"^/_matrix/client/v1/rooms/.*/relations/{event_spec}/{rel_type}/{event_type}$"
3809                )));
3810            }
3811            _ => {
3812                self.mock = self.mock.and(path_regex(format!(
3813                    r"^/_matrix/client/v1/rooms/.*/relations/{event_spec}",
3814                )));
3815            }
3816        }
3817
3818        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
3819            "chunk": response.chunk,
3820            "next_batch": response.next_batch,
3821            "prev_batch": response.prev_batch,
3822            "recursion_depth": response.recursion_depth,
3823        })))
3824    }
3825}
3826
3827/// Helper function to set up a [`MockBuilder`] so it intercepts the account
3828/// data URLs.
3829fn global_account_data_mock_builder(
3830    builder: MockBuilder,
3831    user_id: &UserId,
3832    event_type: GlobalAccountDataEventType,
3833) -> MockBuilder {
3834    builder
3835        .and(path_regex(format!(r"^/_matrix/client/v3/user/{user_id}/account_data/{event_type}",)))
3836}
3837
3838/// A prebuilt mock for a `GET
3839/// /_matrix/client/v3/user/{userId}/account_data/io.element.recent_emoji`
3840/// request, which fetches the recently used emojis in the account data.
3841#[cfg(feature = "experimental-element-recent-emojis")]
3842pub struct GetRecentEmojisEndpoint;
3843
3844#[cfg(feature = "experimental-element-recent-emojis")]
3845impl<'a> MockEndpoint<'a, GetRecentEmojisEndpoint> {
3846    /// Returns a mock for a successful fetch of the recently used emojis in the
3847    /// account data.
3848    pub fn ok(self, user_id: &UserId, emojis: Vec<(String, UInt)>) -> MatrixMock<'a> {
3849        let mock =
3850            global_account_data_mock_builder(self.mock, user_id, "io.element.recent_emoji".into())
3851                .respond_with(
3852                    ResponseTemplate::new(200).set_body_json(json!({ "recent_emoji": emojis })),
3853                );
3854        MatrixMock { server: self.server, mock }
3855    }
3856}
3857
3858/// A prebuilt mock for a `PUT
3859/// /_matrix/client/v3/user/{userId}/account_data/io.element.recent_emoji`
3860/// request, which updates the recently used emojis in the account data.
3861#[cfg(feature = "experimental-element-recent-emojis")]
3862pub struct UpdateRecentEmojisEndpoint {
3863    pub(crate) request_body: Option<Vec<(String, UInt)>>,
3864}
3865
3866#[cfg(feature = "experimental-element-recent-emojis")]
3867impl UpdateRecentEmojisEndpoint {
3868    /// Creates a new instance of the recent update recent emojis mock endpoint.
3869    fn new() -> Self {
3870        Self { request_body: None }
3871    }
3872}
3873
3874#[cfg(feature = "experimental-element-recent-emojis")]
3875impl<'a> MockEndpoint<'a, UpdateRecentEmojisEndpoint> {
3876    /// Returns a mock that will check the body of the request, making sure its
3877    /// contents match the provided list of emojis.
3878    pub fn match_emojis_in_request_body(self, emojis: Vec<(String, UInt)>) -> Self {
3879        Self::new(
3880            self.server,
3881            self.mock.and(body_json(json!(RecentEmojisContent::new(emojis)))),
3882            self.endpoint,
3883        )
3884    }
3885
3886    /// Returns a mock for a successful update of the recent emojis account data
3887    /// event. The request body contents should match the provided emoji
3888    /// list.
3889    #[cfg(feature = "experimental-element-recent-emojis")]
3890    pub fn ok(self, user_id: &UserId) -> MatrixMock<'a> {
3891        let mock =
3892            global_account_data_mock_builder(self.mock, user_id, "io.element.recent_emoji".into())
3893                .respond_with(ResponseTemplate::new(200).set_body_json(()));
3894        MatrixMock { server: self.server, mock }
3895    }
3896}
3897
3898/// A prebuilt mock for a `GET
3899/// /_matrix/client/v3/user/{userId}/account_data/m.secret_storage.default_key`
3900/// request, which fetches the ID of the default secret storage key.
3901#[cfg(feature = "e2e-encryption")]
3902pub struct GetDefaultSecretStorageKeyEndpoint;
3903
3904#[cfg(feature = "e2e-encryption")]
3905impl<'a> MockEndpoint<'a, GetDefaultSecretStorageKeyEndpoint> {
3906    /// Returns a mock for a successful fetch of the default secret storage key.
3907    pub fn ok(self, user_id: &UserId, key_id: &str) -> MatrixMock<'a> {
3908        let mock = global_account_data_mock_builder(
3909            self.mock,
3910            user_id,
3911            GlobalAccountDataEventType::SecretStorageDefaultKey,
3912        )
3913        .respond_with(ResponseTemplate::new(200).set_body_json(json!({
3914            "key": key_id
3915        })));
3916        MatrixMock { server: self.server, mock }
3917    }
3918}
3919
3920/// A prebuilt mock for a `GET
3921/// /_matrix/client/v3/user/{userId}/account_data/m.secret_storage.key.{keyId}`
3922/// request, which fetches information about a secret storage key.
3923#[cfg(feature = "e2e-encryption")]
3924pub struct GetSecretStorageKeyEndpoint;
3925
3926#[cfg(feature = "e2e-encryption")]
3927impl<'a> MockEndpoint<'a, GetSecretStorageKeyEndpoint> {
3928    /// Returns a mock for a successful fetch of the secret storage key
3929    pub fn ok(
3930        self,
3931        user_id: &UserId,
3932        secret_storage_key_event_content: &ruma::events::secret_storage::key::SecretStorageKeyEventContent,
3933    ) -> MatrixMock<'a> {
3934        let mock = global_account_data_mock_builder(
3935            self.mock,
3936            user_id,
3937            GlobalAccountDataEventType::SecretStorageKey(
3938                secret_storage_key_event_content.key_id.clone(),
3939            ),
3940        )
3941        .respond_with(ResponseTemplate::new(200).set_body_json(secret_storage_key_event_content));
3942        MatrixMock { server: self.server, mock }
3943    }
3944}
3945
3946/// A prebuilt mock for a `GET
3947/// /_matrix/client/v3/user/{userId}/account_data/m.cross_signing.master`
3948/// request, which fetches information about the master signing key.
3949#[cfg(feature = "e2e-encryption")]
3950pub struct GetMasterSigningKeyEndpoint;
3951
3952#[cfg(feature = "e2e-encryption")]
3953impl<'a> MockEndpoint<'a, GetMasterSigningKeyEndpoint> {
3954    /// Returns a mock for a successful fetch of the master signing key
3955    pub fn ok<B: Serialize>(self, user_id: &UserId, key_json: B) -> MatrixMock<'a> {
3956        let mock = global_account_data_mock_builder(
3957            self.mock,
3958            user_id,
3959            GlobalAccountDataEventType::from("m.cross_signing.master".to_owned()),
3960        )
3961        .respond_with(ResponseTemplate::new(200).set_body_json(key_json));
3962        MatrixMock { server: self.server, mock }
3963    }
3964}
3965
3966/// A response to a [`RoomRelationsEndpoint`] query.
3967#[derive(Default)]
3968pub struct RoomRelationsResponseTemplate {
3969    /// The set of timeline events returned by this query.
3970    pub chunk: Vec<Raw<AnyTimelineEvent>>,
3971
3972    /// An opaque string representing a pagination token, which semantics depend
3973    /// on the direction used in the request.
3974    pub next_batch: Option<String>,
3975
3976    /// An opaque string representing a pagination token, which semantics depend
3977    /// on the direction used in the request.
3978    pub prev_batch: Option<String>,
3979
3980    /// If `recurse` was set on the request, the depth to which the server
3981    /// recursed.
3982    ///
3983    /// If `recurse` was not set, this field must be absent.
3984    pub recursion_depth: Option<u32>,
3985}
3986
3987impl RoomRelationsResponseTemplate {
3988    /// Fill the events returned as part of this response.
3989    pub fn events(mut self, chunk: Vec<impl Into<Raw<AnyTimelineEvent>>>) -> Self {
3990        self.chunk = chunk.into_iter().map(Into::into).collect();
3991        self
3992    }
3993
3994    /// Fill the `next_batch` token returned as part of this response.
3995    pub fn next_batch(mut self, token: impl Into<String>) -> Self {
3996        self.next_batch = Some(token.into());
3997        self
3998    }
3999
4000    /// Fill the `prev_batch` token returned as part of this response.
4001    pub fn prev_batch(mut self, token: impl Into<String>) -> Self {
4002        self.prev_batch = Some(token.into());
4003        self
4004    }
4005
4006    /// Fill the recursion depth returned in this response.
4007    pub fn recursion_depth(mut self, depth: u32) -> Self {
4008        self.recursion_depth = Some(depth);
4009        self
4010    }
4011}
4012
4013/// A prebuilt mock for `POST /rooms/{roomId}/receipt/{receiptType}/{eventId}`
4014/// request.
4015pub struct ReceiptEndpoint;
4016
4017impl<'a> MockEndpoint<'a, ReceiptEndpoint> {
4018    /// Returns a successful empty response.
4019    pub fn ok(self) -> MatrixMock<'a> {
4020        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({})))
4021    }
4022
4023    /// Ensures that the body of the request is a superset of the provided
4024    /// `body` parameter.
4025    pub fn body_matches_partial_json(self, body: Value) -> Self {
4026        Self { mock: self.mock.and(body_partial_json(body)), ..self }
4027    }
4028
4029    /// Ensures that the body of the request is the exact provided `body`
4030    /// parameter.
4031    pub fn body_json(self, body: Value) -> Self {
4032        Self { mock: self.mock.and(body_json(body)), ..self }
4033    }
4034
4035    /// Ensures that the request matches a specific receipt thread.
4036    pub fn match_thread(self, thread: ReceiptThread) -> Self {
4037        if let Some(thread_str) = thread.as_str() {
4038            self.body_matches_partial_json(json!({
4039                "thread_id": thread_str
4040            }))
4041        } else {
4042            self
4043        }
4044    }
4045
4046    /// Ensures that the request matches a specific event id.
4047    pub fn match_event_id(self, event_id: &EventId) -> Self {
4048        Self {
4049            mock: self.mock.and(path_regex(format!(
4050                r"^/_matrix/client/v3/rooms/.*/receipt/.*/{}$",
4051                event_id.as_str().replace("$", "\\$")
4052            ))),
4053            ..self
4054        }
4055    }
4056}
4057
4058/// A prebuilt mock for `POST /rooms/{roomId}/read_markers` request.
4059pub struct ReadMarkersEndpoint;
4060
4061impl<'a> MockEndpoint<'a, ReadMarkersEndpoint> {
4062    /// Returns a successful empty response.
4063    pub fn ok(self) -> MatrixMock<'a> {
4064        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({})))
4065    }
4066}
4067
4068/// A prebuilt mock for `PUT /user/{userId}/rooms/{roomId}/account_data/{type}`
4069/// request.
4070pub struct RoomAccountDataEndpoint;
4071
4072impl<'a> MockEndpoint<'a, RoomAccountDataEndpoint> {
4073    /// Returns a successful empty response.
4074    pub fn ok(self) -> MatrixMock<'a> {
4075        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({})))
4076    }
4077}
4078
4079/// A prebuilt mock for `GET /_matrix/client/v1/media/config` request.
4080pub struct AuthenticatedMediaConfigEndpoint;
4081
4082impl<'a> MockEndpoint<'a, AuthenticatedMediaConfigEndpoint> {
4083    /// Returns a successful response with the provided max upload size.
4084    pub fn ok(self, max_upload_size: UInt) -> MatrixMock<'a> {
4085        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
4086            "m.upload.size": max_upload_size,
4087        })))
4088    }
4089
4090    /// Returns a successful response with a maxed out max upload size.
4091    pub fn ok_default(self) -> MatrixMock<'a> {
4092        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
4093            "m.upload.size": UInt::MAX,
4094        })))
4095    }
4096}
4097
4098/// A prebuilt mock for `GET /_matrix/media/v3/config` request.
4099pub struct MediaConfigEndpoint;
4100
4101impl<'a> MockEndpoint<'a, MediaConfigEndpoint> {
4102    /// Returns a successful response with the provided max upload size.
4103    pub fn ok(self, max_upload_size: UInt) -> MatrixMock<'a> {
4104        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
4105            "m.upload.size": max_upload_size,
4106        })))
4107    }
4108}
4109
4110/// A prebuilt mock for `POST /login` requests.
4111pub struct LoginEndpoint;
4112
4113impl<'a> MockEndpoint<'a, LoginEndpoint> {
4114    /// Returns a successful response.
4115    pub fn ok(self) -> MatrixMock<'a> {
4116        self.respond_with(ResponseTemplate::new(200).set_body_json(&*test_json::LOGIN))
4117    }
4118
4119    /// Returns a given response on POST /login requests
4120    ///
4121    /// # Arguments
4122    ///
4123    /// * `response` - The response that the mock server sends on POST /login
4124    ///   requests.
4125    ///
4126    /// # Returns
4127    ///
4128    /// Returns a [`MatrixMock`] which can be mounted.
4129    ///
4130    /// # Examples
4131    ///
4132    /// ```
4133    /// use matrix_sdk::test_utils::mocks::{
4134    ///     LoginResponseTemplate200, MatrixMockServer,
4135    /// };
4136    /// use matrix_sdk_test::async_test;
4137    /// use ruma::{device_id, time::Duration, user_id};
4138    ///
4139    /// #[async_test]
4140    /// async fn test_ok_with() {
4141    ///     let server = MatrixMockServer::new().await;
4142    ///     server
4143    ///         .mock_login()
4144    ///         .ok_with(LoginResponseTemplate200::new(
4145    ///             "qwerty",
4146    ///             device_id!("DEADBEEF"),
4147    ///             user_id!("@cheeky_monkey:matrix.org"),
4148    ///         ))
4149    ///         .mount()
4150    ///         .await;
4151    ///
4152    ///     let client = server.client_builder().unlogged().build().await;
4153    ///
4154    ///     let result = client
4155    ///         .matrix_auth()
4156    ///         .login_username("example", "wordpass")
4157    ///         .send()
4158    ///         .await
4159    ///         .unwrap();
4160    ///
4161    ///     assert!(
4162    ///         result.access_tokesn.unwrap() == "qwerty",
4163    ///         "wrong access token in response"
4164    ///     );
4165    ///     assert!(
4166    ///         result.device_id.unwrap() == "DEADBEEF",
4167    ///         "wrong device id in response"
4168    ///     );
4169    ///     assert!(
4170    ///         result.user_id.unwrap() == "@cheeky_monkey:matrix.org",
4171    ///         "wrong user id in response"
4172    ///     );
4173    /// }
4174    /// ```
4175    pub fn ok_with(self, response: LoginResponseTemplate200) -> MatrixMock<'a> {
4176        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
4177            "access_token": response.access_token,
4178            "device_id": response.device_id,
4179            "user_id": response.user_id,
4180            "expires_in": response.expires_in.map(|duration| { duration.as_millis() }),
4181            "refresh_token": response.refresh_token,
4182            "well_known": response.well_known.map(|vals| {
4183                json!({
4184                    "m.homeserver": {
4185                        "base_url": vals.homeserver_url
4186                    },
4187                    "m.identity_server": vals.identity_url.map(|url| {
4188                        json!({
4189                            "base_url": url
4190                        })
4191                    })
4192                })
4193            }),
4194        })))
4195    }
4196
4197    /// Ensures that the body of the request is a superset of the provided
4198    /// `body` parameter.
4199    pub fn body_matches_partial_json(self, body: Value) -> Self {
4200        Self { mock: self.mock.and(body_partial_json(body)), ..self }
4201    }
4202}
4203
4204#[derive(Default)]
4205struct LoginResponseWellKnown {
4206    /// Required if well_known is used: The base URL for the homeserver for
4207    /// client-server connections.
4208    homeserver_url: String,
4209
4210    /// Required if well_known and m.identity_server are used: The base URL for
4211    /// the identity server for client-server connections.
4212    identity_url: Option<String>,
4213}
4214
4215/// A response to a [`LoginEndpoint`] query with status code 200.
4216#[derive(Default)]
4217pub struct LoginResponseTemplate200 {
4218    /// Required: An access token for the account. This access token can then be
4219    /// used to authorize other requests.
4220    access_token: Option<String>,
4221
4222    /// Required: ID of the logged-in device. Will be the same as the
4223    /// corresponding parameter in the request, if one was specified.
4224    device_id: Option<OwnedDeviceId>,
4225
4226    /// The lifetime of the access token, in milliseconds. Once the access token
4227    /// has expired a new access token can be obtained by using the provided
4228    /// refresh token. If no refresh token is provided, the client will need
4229    /// to re-log in to obtain a new access token. If not given, the client
4230    /// can assume that the access token will not expire.
4231    expires_in: Option<Duration>,
4232
4233    /// A refresh token for the account. This token can be used to obtain a new
4234    /// access token when it expires by calling the /refresh endpoint.
4235    refresh_token: Option<String>,
4236
4237    /// Required: The fully-qualified Matrix ID for the account.
4238    user_id: Option<OwnedUserId>,
4239
4240    /// Optional client configuration provided by the server.
4241    well_known: Option<LoginResponseWellKnown>,
4242}
4243
4244impl LoginResponseTemplate200 {
4245    /// Constructor for empty response
4246    pub fn new<T1: Into<OwnedDeviceId>, T2: Into<OwnedUserId>>(
4247        access_token: &str,
4248        device_id: T1,
4249        user_id: T2,
4250    ) -> Self {
4251        Self {
4252            access_token: Some(access_token.to_owned()),
4253            device_id: Some(device_id.into()),
4254            user_id: Some(user_id.into()),
4255            ..Default::default()
4256        }
4257    }
4258
4259    /// sets expires_in
4260    pub fn expires_in(mut self, value: Duration) -> Self {
4261        self.expires_in = Some(value);
4262        self
4263    }
4264
4265    /// sets refresh_token
4266    pub fn refresh_token(mut self, value: &str) -> Self {
4267        self.refresh_token = Some(value.to_owned());
4268        self
4269    }
4270
4271    /// sets well_known which takes a homeserver_url and an optional
4272    /// identity_url
4273    pub fn well_known(mut self, homeserver_url: String, identity_url: Option<String>) -> Self {
4274        self.well_known = Some(LoginResponseWellKnown { homeserver_url, identity_url });
4275        self
4276    }
4277}
4278
4279/// A prebuilt mock for `GET /devices` requests.
4280pub struct DevicesEndpoint;
4281
4282impl<'a> MockEndpoint<'a, DevicesEndpoint> {
4283    /// Returns a successful response.
4284    pub fn ok(self) -> MatrixMock<'a> {
4285        self.respond_with(ResponseTemplate::new(200).set_body_json(&*test_json::DEVICES))
4286    }
4287}
4288
4289/// A prebuilt mock for `GET /devices/{deviceId}` requests.
4290pub struct GetDeviceEndpoint;
4291
4292impl<'a> MockEndpoint<'a, GetDeviceEndpoint> {
4293    /// Returns a successful response.
4294    pub fn ok(self) -> MatrixMock<'a> {
4295        self.respond_with(ResponseTemplate::new(200).set_body_json(&*test_json::DEVICE))
4296    }
4297}
4298
4299/// A prebuilt mock for `POST /user_directory/search` requests.
4300pub struct UserDirectoryEndpoint;
4301
4302impl<'a> MockEndpoint<'a, UserDirectoryEndpoint> {
4303    /// Returns a successful response.
4304    pub fn ok(self) -> MatrixMock<'a> {
4305        self.respond_with(
4306            ResponseTemplate::new(200)
4307                .set_body_json(&*test_json::search_users::SEARCH_USERS_RESPONSE),
4308        )
4309    }
4310}
4311
4312/// A prebuilt mock for `POST /createRoom` requests.
4313pub struct CreateRoomEndpoint;
4314
4315impl<'a> MockEndpoint<'a, CreateRoomEndpoint> {
4316    /// Returns a successful response.
4317    pub fn ok(self) -> MatrixMock<'a> {
4318        self.respond_with(
4319            ResponseTemplate::new(200).set_body_json(json!({ "room_id": "!room:example.org"})),
4320        )
4321    }
4322}
4323
4324/// A prebuilt mock for `POST /rooms/{roomId}/upgrade` requests.
4325pub struct UpgradeRoomEndpoint;
4326
4327impl<'a> MockEndpoint<'a, UpgradeRoomEndpoint> {
4328    /// Returns a successful response with desired replacement_room ID.
4329    pub fn ok_with(self, new_room_id: &RoomId) -> MatrixMock<'a> {
4330        self.respond_with(
4331            ResponseTemplate::new(200)
4332                .set_body_json(json!({ "replacement_room": new_room_id.as_str()})),
4333        )
4334    }
4335}
4336
4337/// A prebuilt mock for `POST /media/v1/create` requests.
4338pub struct MediaAllocateEndpoint;
4339
4340impl<'a> MockEndpoint<'a, MediaAllocateEndpoint> {
4341    /// Returns a successful response.
4342    pub fn ok(self) -> MatrixMock<'a> {
4343        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
4344          "content_uri": "mxc://example.com/AQwafuaFswefuhsfAFAgsw"
4345        })))
4346    }
4347}
4348
4349/// A prebuilt mock for `PUT /media/v3/upload/{server_name}/{media_id}`
4350/// requests.
4351pub struct MediaAllocatedUploadEndpoint;
4352
4353impl<'a> MockEndpoint<'a, MediaAllocatedUploadEndpoint> {
4354    /// Returns a successful response.
4355    pub fn ok(self) -> MatrixMock<'a> {
4356        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({})))
4357    }
4358}
4359
4360/// A prebuilt mock for `GET /media/v3/download` requests.
4361pub struct MediaDownloadEndpoint;
4362
4363impl<'a> MockEndpoint<'a, MediaDownloadEndpoint> {
4364    /// Returns a successful response with a plain text content.
4365    pub fn ok_plain_text(self) -> MatrixMock<'a> {
4366        self.respond_with(ResponseTemplate::new(200).set_body_string("Hello, World!"))
4367    }
4368
4369    /// Returns a successful response with a fake image content.
4370    pub fn ok_image(self) -> MatrixMock<'a> {
4371        self.respond_with(
4372            ResponseTemplate::new(200).set_body_raw(b"binaryjpegfullimagedata", "image/jpeg"),
4373        )
4374    }
4375}
4376
4377/// A prebuilt mock for `GET /media/v3/thumbnail` requests.
4378pub struct MediaThumbnailEndpoint;
4379
4380impl<'a> MockEndpoint<'a, MediaThumbnailEndpoint> {
4381    /// Returns a successful response with a fake image content.
4382    pub fn ok(self) -> MatrixMock<'a> {
4383        self.respond_with(
4384            ResponseTemplate::new(200).set_body_raw(b"binaryjpegthumbnaildata", "image/jpeg"),
4385        )
4386    }
4387}
4388
4389/// A prebuilt mock for `GET /client/v1/media/download` requests.
4390pub struct AuthedMediaDownloadEndpoint;
4391
4392impl<'a> MockEndpoint<'a, AuthedMediaDownloadEndpoint> {
4393    /// Returns a successful response with a plain text content.
4394    pub fn ok_plain_text(self) -> MatrixMock<'a> {
4395        self.respond_with(ResponseTemplate::new(200).set_body_string("Hello, World!"))
4396    }
4397
4398    /// Returns a successful response with the given bytes.
4399    pub fn ok_bytes(self, bytes: Vec<u8>) -> MatrixMock<'a> {
4400        self.respond_with(
4401            ResponseTemplate::new(200).set_body_raw(bytes, "application/octet-stream"),
4402        )
4403    }
4404
4405    /// Returns a successful response with a fake image content.
4406    pub fn ok_image(self) -> MatrixMock<'a> {
4407        self.respond_with(
4408            ResponseTemplate::new(200).set_body_raw(b"binaryjpegfullimagedata", "image/jpeg"),
4409        )
4410    }
4411}
4412
4413/// A prebuilt mock for `GET /client/v1/media/thumbnail` requests.
4414pub struct AuthedMediaThumbnailEndpoint;
4415
4416impl<'a> MockEndpoint<'a, AuthedMediaThumbnailEndpoint> {
4417    /// Returns a successful response with a fake image content.
4418    pub fn ok(self) -> MatrixMock<'a> {
4419        self.respond_with(
4420            ResponseTemplate::new(200).set_body_raw(b"binaryjpegthumbnaildata", "image/jpeg"),
4421        )
4422    }
4423}
4424
4425/// A prebuilt mock for `GET /client/v3/rooms/{room_id}/join` requests.
4426pub struct JoinRoomEndpoint {
4427    room_id: OwnedRoomId,
4428}
4429
4430impl<'a> MockEndpoint<'a, JoinRoomEndpoint> {
4431    /// Returns a successful response using the provided [`RoomId`].
4432    pub fn ok(self) -> MatrixMock<'a> {
4433        let room_id = self.endpoint.room_id.to_owned();
4434
4435        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
4436            "room_id": room_id,
4437        })))
4438    }
4439}
4440
4441#[derive(Default)]
4442struct ThreadSubscriptionMatchers {
4443    /// Optional room id to match in the query.
4444    room_id: Option<OwnedRoomId>,
4445    /// Optional thread root event id to match in the query.
4446    thread_root: Option<OwnedEventId>,
4447}
4448
4449impl ThreadSubscriptionMatchers {
4450    /// Match the request parameter against a specific room id.
4451    fn match_room_id(mut self, room_id: OwnedRoomId) -> Self {
4452        self.room_id = Some(room_id);
4453        self
4454    }
4455
4456    /// Match the request parameter against a specific thread root event id.
4457    fn match_thread_id(mut self, thread_root: OwnedEventId) -> Self {
4458        self.thread_root = Some(thread_root);
4459        self
4460    }
4461
4462    /// Compute the final URI for the thread subscription endpoint.
4463    fn endpoint_regexp_uri(&self) -> String {
4464        if self.room_id.is_some() || self.thread_root.is_some() {
4465            format!(
4466                "^/_matrix/client/unstable/io.element.msc4306/rooms/{}/thread/{}/subscription$",
4467                self.room_id.as_deref().map(|s| s.as_str()).unwrap_or(".*"),
4468                self.thread_root.as_deref().map(|s| s.as_str()).unwrap_or(".*").replace("$", "\\$")
4469            )
4470        } else {
4471            "^/_matrix/client/unstable/io.element.msc4306/rooms/.*/thread/.*/subscription$"
4472                .to_owned()
4473        }
4474    }
4475}
4476
4477/// A prebuilt mock for `GET
4478/// /client/*/rooms/{room_id}/threads/{thread_root}/subscription`
4479#[derive(Default)]
4480pub struct RoomGetThreadSubscriptionEndpoint {
4481    matchers: ThreadSubscriptionMatchers,
4482}
4483
4484impl<'a> MockEndpoint<'a, RoomGetThreadSubscriptionEndpoint> {
4485    /// Returns a successful response for the given thread subscription.
4486    pub fn ok(mut self, automatic: bool) -> MatrixMock<'a> {
4487        self.mock = self.mock.and(path_regex(self.endpoint.matchers.endpoint_regexp_uri()));
4488        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
4489            "automatic": automatic
4490        })))
4491    }
4492
4493    /// Match the request parameter against a specific room id.
4494    pub fn match_room_id(mut self, room_id: OwnedRoomId) -> Self {
4495        self.endpoint.matchers = self.endpoint.matchers.match_room_id(room_id);
4496        self
4497    }
4498    /// Match the request parameter against a specific thread root event id.
4499    pub fn match_thread_id(mut self, thread_root: OwnedEventId) -> Self {
4500        self.endpoint.matchers = self.endpoint.matchers.match_thread_id(thread_root);
4501        self
4502    }
4503}
4504
4505/// A prebuilt mock for `PUT
4506/// /client/*/rooms/{room_id}/threads/{thread_root}/subscription`
4507#[derive(Default)]
4508pub struct RoomPutThreadSubscriptionEndpoint {
4509    matchers: ThreadSubscriptionMatchers,
4510}
4511
4512impl<'a> MockEndpoint<'a, RoomPutThreadSubscriptionEndpoint> {
4513    /// Returns a successful response for the given setting of thread
4514    /// subscription.
4515    pub fn ok(mut self) -> MatrixMock<'a> {
4516        self.mock = self.mock.and(path_regex(self.endpoint.matchers.endpoint_regexp_uri()));
4517        self.respond_with(ResponseTemplate::new(200))
4518    }
4519
4520    /// Returns that the server skipped an automated thread subscription,
4521    /// because the user unsubscribed to the thread after the event id passed in
4522    /// the automatic subscription.
4523    pub fn conflicting_unsubscription(mut self) -> MatrixMock<'a> {
4524        self.mock = self.mock.and(path_regex(self.endpoint.matchers.endpoint_regexp_uri()));
4525        self.respond_with(ResponseTemplate::new(409).set_body_json(json!({
4526            "errcode": "IO.ELEMENT.MSC4306.M_CONFLICTING_UNSUBSCRIPTION",
4527            "error": "the user unsubscribed after the subscription event id"
4528        })))
4529    }
4530
4531    /// Match the request parameter against a specific room id.
4532    pub fn match_room_id(mut self, room_id: OwnedRoomId) -> Self {
4533        self.endpoint.matchers = self.endpoint.matchers.match_room_id(room_id);
4534        self
4535    }
4536    /// Match the request parameter against a specific thread root event id.
4537    pub fn match_thread_id(mut self, thread_root: OwnedEventId) -> Self {
4538        self.endpoint.matchers = self.endpoint.matchers.match_thread_id(thread_root);
4539        self
4540    }
4541    /// Match the request body's `automatic` field against a specific event id.
4542    pub fn match_automatic_event_id(mut self, up_to_event_id: &EventId) -> Self {
4543        self.mock = self.mock.and(body_json(json!({
4544            "automatic": up_to_event_id
4545        })));
4546        self
4547    }
4548}
4549
4550/// A prebuilt mock for `DELETE
4551/// /client/*/rooms/{room_id}/threads/{thread_root}/subscription`
4552#[derive(Default)]
4553pub struct RoomDeleteThreadSubscriptionEndpoint {
4554    matchers: ThreadSubscriptionMatchers,
4555}
4556
4557impl<'a> MockEndpoint<'a, RoomDeleteThreadSubscriptionEndpoint> {
4558    /// Returns a successful response for the deletion of a given thread
4559    /// subscription.
4560    pub fn ok(mut self) -> MatrixMock<'a> {
4561        self.mock = self.mock.and(path_regex(self.endpoint.matchers.endpoint_regexp_uri()));
4562        self.respond_with(ResponseTemplate::new(200))
4563    }
4564
4565    /// Match the request parameter against a specific room id.
4566    pub fn match_room_id(mut self, room_id: OwnedRoomId) -> Self {
4567        self.endpoint.matchers = self.endpoint.matchers.match_room_id(room_id);
4568        self
4569    }
4570    /// Match the request parameter against a specific thread root event id.
4571    pub fn match_thread_id(mut self, thread_root: OwnedEventId) -> Self {
4572        self.endpoint.matchers = self.endpoint.matchers.match_thread_id(thread_root);
4573        self
4574    }
4575}
4576
4577/// A prebuilt mock for `PUT
4578/// /_matrix/client/v3/pushrules/global/{kind}/{ruleId}/enabled`.
4579pub struct EnablePushRuleEndpoint;
4580
4581impl<'a> MockEndpoint<'a, EnablePushRuleEndpoint> {
4582    /// Returns a successful empty JSON response.
4583    pub fn ok(self) -> MatrixMock<'a> {
4584        self.ok_empty_json()
4585    }
4586}
4587
4588/// A prebuilt mock for `PUT
4589/// /_matrix/client/v3/pushrules/global/{kind}/{ruleId}/actions`.
4590pub struct SetPushRulesActionsEndpoint;
4591
4592impl<'a> MockEndpoint<'a, SetPushRulesActionsEndpoint> {
4593    /// Returns a successful empty JSON response.
4594    pub fn ok(self) -> MatrixMock<'a> {
4595        self.ok_empty_json()
4596    }
4597}
4598
4599/// A prebuilt mock for `PUT
4600/// /_matrix/client/v3/pushrules/global/{kind}/{ruleId}`.
4601pub struct SetPushRulesEndpoint;
4602
4603impl<'a> MockEndpoint<'a, SetPushRulesEndpoint> {
4604    /// Returns a successful empty JSON response.
4605    pub fn ok(self) -> MatrixMock<'a> {
4606        self.ok_empty_json()
4607    }
4608}
4609
4610/// A prebuilt mock for `DELETE
4611/// /_matrix/client/v3/pushrules/global/{kind}/{ruleId}`.
4612pub struct DeletePushRulesEndpoint;
4613
4614impl<'a> MockEndpoint<'a, DeletePushRulesEndpoint> {
4615    /// Returns a successful empty JSON response.
4616    pub fn ok(self) -> MatrixMock<'a> {
4617        self.ok_empty_json()
4618    }
4619}
4620
4621/// A prebuilt mock for the federation version endpoint.
4622pub struct FederationVersionEndpoint;
4623
4624impl<'a> MockEndpoint<'a, FederationVersionEndpoint> {
4625    /// Returns a successful response with the given server name and version.
4626    pub fn ok(self, server_name: &str, version: &str) -> MatrixMock<'a> {
4627        let response_body = json!({
4628            "server": {
4629                "name": server_name,
4630                "version": version
4631            }
4632        });
4633        self.respond_with(ResponseTemplate::new(200).set_body_json(response_body))
4634    }
4635
4636    /// Returns a successful response with empty/missing server information.
4637    pub fn ok_empty(self) -> MatrixMock<'a> {
4638        let response_body = json!({});
4639        self.respond_with(ResponseTemplate::new(200).set_body_json(response_body))
4640    }
4641}
4642
4643/// A prebuilt mock for `GET ^/_matrix/client/v3/thread_subscriptions`.
4644#[derive(Default)]
4645pub struct GetThreadSubscriptionsEndpoint {
4646    /// New thread subscriptions per (room id, thread root event id).
4647    subscribed: BTreeMap<OwnedRoomId, BTreeMap<OwnedEventId, ThreadSubscription>>,
4648    /// New thread unsubscriptions per (room id, thread root event id).
4649    unsubscribed: BTreeMap<OwnedRoomId, BTreeMap<OwnedEventId, ThreadUnsubscription>>,
4650    /// Optional delay to respond to the query.
4651    delay: Option<Duration>,
4652}
4653
4654impl<'a> MockEndpoint<'a, GetThreadSubscriptionsEndpoint> {
4655    /// Add a single thread subscription to the response.
4656    pub fn add_subscription(
4657        mut self,
4658        room_id: OwnedRoomId,
4659        thread_root: OwnedEventId,
4660        subscription: ThreadSubscription,
4661    ) -> Self {
4662        self.endpoint.subscribed.entry(room_id).or_default().insert(thread_root, subscription);
4663        self
4664    }
4665
4666    /// Add a single thread unsubscription to the response.
4667    pub fn add_unsubscription(
4668        mut self,
4669        room_id: OwnedRoomId,
4670        thread_root: OwnedEventId,
4671        unsubscription: ThreadUnsubscription,
4672    ) -> Self {
4673        self.endpoint.unsubscribed.entry(room_id).or_default().insert(thread_root, unsubscription);
4674        self
4675    }
4676
4677    /// Respond with a given delay to the query.
4678    pub fn with_delay(mut self, delay: Duration) -> Self {
4679        self.endpoint.delay = Some(delay);
4680        self
4681    }
4682
4683    /// Match the `from` query parameter to a given value.
4684    pub fn match_from(self, from: &str) -> Self {
4685        Self { mock: self.mock.and(query_param("from", from)), ..self }
4686    }
4687    /// Match the `to` query parameter to a given value.
4688    pub fn match_to(self, to: &str) -> Self {
4689        Self { mock: self.mock.and(query_param("to", to)), ..self }
4690    }
4691
4692    /// Returns a successful response with the given thread subscriptions, and
4693    /// "end" parameter to be used in the next query.
4694    pub fn ok(self, end: Option<String>) -> MatrixMock<'a> {
4695        let response_body = json!({
4696            "subscribed": self.endpoint.subscribed,
4697            "unsubscribed": self.endpoint.unsubscribed,
4698            "end": end,
4699        });
4700
4701        let mut template = ResponseTemplate::new(200).set_body_json(response_body);
4702
4703        if let Some(delay) = self.endpoint.delay {
4704            template = template.set_delay(delay);
4705        }
4706
4707        self.respond_with(template)
4708    }
4709}
4710
4711/// A prebuilt mock for `GET /client/*/rooms/{roomId}/hierarchy`
4712#[derive(Default)]
4713pub struct GetHierarchyEndpoint;
4714
4715impl<'a> MockEndpoint<'a, GetHierarchyEndpoint> {
4716    /// Returns a successful response containing the given room IDs.
4717    pub fn ok_with_room_ids(self, room_ids: Vec<&RoomId>) -> MatrixMock<'a> {
4718        let rooms = room_ids
4719            .iter()
4720            .map(|id| {
4721                json!({
4722                  "room_id": id,
4723                  "num_joined_members": 1,
4724                  "world_readable": false,
4725                  "guest_can_join": false,
4726                  "children_state": []
4727                })
4728            })
4729            .collect::<Vec<_>>();
4730
4731        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
4732            "rooms": rooms,
4733        })))
4734    }
4735
4736    /// Returns a successful response containing the given room IDs and children
4737    /// states
4738    pub fn ok_with_room_ids_and_children_state(
4739        self,
4740        room_ids: Vec<&RoomId>,
4741        children_state: Vec<(&RoomId, Vec<&ServerName>)>,
4742    ) -> MatrixMock<'a> {
4743        let children_state = children_state
4744            .into_iter()
4745            .map(|(id, via)| {
4746                json!({
4747                    "type":
4748                    "m.space.child",
4749                    "state_key": id,
4750                    "content": { "via": via },
4751                    "sender": "@bob:matrix.org",
4752                    "origin_server_ts": MilliSecondsSinceUnixEpoch::now()
4753                })
4754            })
4755            .collect::<Vec<_>>();
4756
4757        let rooms = room_ids
4758            .iter()
4759            .map(|id| {
4760                json!({
4761                  "room_id": id,
4762                  "num_joined_members": 1,
4763                  "world_readable": false,
4764                  "guest_can_join": false,
4765                  "children_state": children_state
4766                })
4767            })
4768            .collect::<Vec<_>>();
4769
4770        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
4771            "rooms": rooms,
4772        })))
4773    }
4774
4775    /// Returns a successful response with an empty list of rooms.
4776    pub fn ok(self) -> MatrixMock<'a> {
4777        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
4778            "rooms": []
4779        })))
4780    }
4781}
4782
4783/// A prebuilt mock for `PUT
4784/// /_matrix/client/v3/rooms/{roomId}/state/m.space.child/{stateKey}`
4785pub struct SetSpaceChildEndpoint;
4786
4787impl<'a> MockEndpoint<'a, SetSpaceChildEndpoint> {
4788    /// Returns a successful response with a given event id.
4789    pub fn ok(self, event_id: OwnedEventId) -> MatrixMock<'a> {
4790        self.ok_with_event_id(event_id)
4791    }
4792
4793    /// Returns an error response with a generic error code indicating the
4794    /// client is not authorized to set space children.
4795    pub fn unauthorized(self) -> MatrixMock<'a> {
4796        self.respond_with(ResponseTemplate::new(400))
4797    }
4798}
4799
4800/// A prebuilt mock for `PUT
4801/// /_matrix/client/v3/rooms/{roomId}/state/m.space.parent/{stateKey}`
4802pub struct SetSpaceParentEndpoint;
4803
4804impl<'a> MockEndpoint<'a, SetSpaceParentEndpoint> {
4805    /// Returns a successful response with a given event id.
4806    pub fn ok(self, event_id: OwnedEventId) -> MatrixMock<'a> {
4807        self.ok_with_event_id(event_id)
4808    }
4809
4810    /// Returns an error response with a generic error code indicating the
4811    /// client is not authorized to set space parents.
4812    pub fn unauthorized(self) -> MatrixMock<'a> {
4813        self.respond_with(ResponseTemplate::new(400))
4814    }
4815}
4816
4817/// A prebuilt mock for running simplified sliding sync.
4818pub struct SlidingSyncEndpoint;
4819
4820impl<'a> MockEndpoint<'a, SlidingSyncEndpoint> {
4821    /// Mocks the sliding sync endpoint with the given response.
4822    pub fn ok(self, response: v5::Response) -> MatrixMock<'a> {
4823        // A bit silly that we need to destructure all the fields ourselves, but
4824        // Response isn't serializable :'(
4825        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
4826            "txn_id": response.txn_id,
4827            "pos": response.pos,
4828            "lists": response.lists,
4829            "rooms": response.rooms,
4830            "extensions": response.extensions,
4831        })))
4832    }
4833
4834    /// Temporarily mocks the sync with the given endpoint and runs a client
4835    /// sync with it.
4836    ///
4837    /// After calling this function, the sync endpoint isn't mocked anymore.
4838    pub async fn ok_and_run<F: FnOnce(SlidingSyncBuilder) -> SlidingSyncBuilder>(
4839        self,
4840        client: &Client,
4841        on_builder: F,
4842        response: v5::Response,
4843    ) {
4844        let _scope = self.ok(response).mount_as_scoped().await;
4845
4846        let sliding_sync =
4847            on_builder(client.sliding_sync("test_id").unwrap()).build().await.unwrap();
4848
4849        let _summary = sliding_sync.sync_once().await.unwrap();
4850    }
4851}
4852
4853/// A prebuilt mock for `GET /_matrix/client/*/profile/{user_id}/{key_name}`.
4854pub struct GetProfileFieldEndpoint {
4855    field: ProfileFieldName,
4856}
4857
4858impl<'a> MockEndpoint<'a, GetProfileFieldEndpoint> {
4859    /// Returns a successful response containing the given value, if any.
4860    pub fn ok_with_value(self, value: Option<Value>) -> MatrixMock<'a> {
4861        if let Some(value) = value {
4862            let field = self.endpoint.field.to_string();
4863            self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
4864                field: value,
4865            })))
4866        } else {
4867            self.ok_empty_json()
4868        }
4869    }
4870}
4871
4872/// A prebuilt mock for `PUT /_matrix/client/*/profile/{user_id}/{key_name}`.
4873pub struct SetProfileFieldEndpoint;
4874
4875impl<'a> MockEndpoint<'a, SetProfileFieldEndpoint> {
4876    /// Returns a successful empty response.
4877    pub fn ok(self) -> MatrixMock<'a> {
4878        self.ok_empty_json()
4879    }
4880}
4881
4882/// A prebuilt mock for `DELETE /_matrix/client/*/profile/{user_id}/{key_name}`.
4883pub struct DeleteProfileFieldEndpoint;
4884
4885impl<'a> MockEndpoint<'a, DeleteProfileFieldEndpoint> {
4886    /// Returns a successful empty response.
4887    pub fn ok(self) -> MatrixMock<'a> {
4888        self.ok_empty_json()
4889    }
4890}
4891
4892/// A prebuilt mock for `GET /_matrix/client/*/profile/{user_id}`.
4893pub struct GetProfileEndpoint;
4894
4895impl<'a> MockEndpoint<'a, GetProfileEndpoint> {
4896    /// Returns a successful empty response.
4897    pub fn ok_with_fields(self, fields: Vec<ProfileFieldValue>) -> MatrixMock<'a> {
4898        let profile = fields
4899            .iter()
4900            .map(|field| (field.field_name(), field.value()))
4901            .collect::<BTreeMap<_, _>>();
4902        self.respond_with(ResponseTemplate::new(200).set_body_json(profile))
4903    }
4904}