Skip to main content

matrix_sdk/test_utils/mocks/
mod.rs

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