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