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