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 get a preview of a URL
1570    /// without requiring authentication.
1571    pub fn mock_media_preview(&self) -> MockEndpoint<'_, MediaPreviewEndpoint> {
1572        let mock = Mock::given(method("GET")).and(path("/_matrix/media/v3/preview_url"));
1573        self.mock_endpoint(mock, MediaPreviewEndpoint)
1574    }
1575
1576    /// Create a prebuilt mock for the endpoint used to get a preview of a URL
1577    /// that requires authentication.
1578    pub fn mock_authed_media_preview(&self) -> MockEndpoint<'_, AuthedMediaPreviewEndpoint> {
1579        let mock = Mock::given(method("GET")).and(path("/_matrix/client/v1/media/preview_url"));
1580        self.mock_endpoint(mock, AuthedMediaPreviewEndpoint).expect_default_access_token()
1581    }
1582
1583    /// Create a prebuilt mock for the endpoint used to download a thumbnail of
1584    /// a media file that requires authentication.
1585    pub fn mock_authed_media_thumbnail(
1586        &self,
1587        resize_method: Method,
1588        width: u16,
1589        height: u16,
1590        animated: bool,
1591    ) -> MockEndpoint<'_, AuthedMediaThumbnailEndpoint> {
1592        let mock = Mock::given(method("GET"))
1593            .and(path_regex("^/_matrix/client/v1/media/thumbnail/"))
1594            .and(query_param("method", resize_method.as_str()))
1595            .and(query_param("width", width.to_string()))
1596            .and(query_param("height", height.to_string()))
1597            .and(query_param("animated", animated.to_string()));
1598        self.mock_endpoint(mock, AuthedMediaThumbnailEndpoint).expect_default_access_token()
1599    }
1600
1601    /// Create a prebuilt mock for the endpoint used to get a single thread
1602    /// subscription status in a given room.
1603    pub fn mock_room_get_thread_subscription(
1604        &self,
1605    ) -> MockEndpoint<'_, RoomGetThreadSubscriptionEndpoint> {
1606        let mock = Mock::given(method("GET"));
1607        self.mock_endpoint(mock, RoomGetThreadSubscriptionEndpoint::default())
1608            .expect_default_access_token()
1609    }
1610
1611    /// Create a prebuilt mock for the endpoint used to define a thread
1612    /// subscription in a given room.
1613    pub fn mock_room_put_thread_subscription(
1614        &self,
1615    ) -> MockEndpoint<'_, RoomPutThreadSubscriptionEndpoint> {
1616        let mock = Mock::given(method("PUT"));
1617        self.mock_endpoint(mock, RoomPutThreadSubscriptionEndpoint::default())
1618            .expect_default_access_token()
1619    }
1620
1621    /// Create a prebuilt mock for the endpoint used to delete a thread
1622    /// subscription in a given room.
1623    pub fn mock_room_delete_thread_subscription(
1624        &self,
1625    ) -> MockEndpoint<'_, RoomDeleteThreadSubscriptionEndpoint> {
1626        let mock = Mock::given(method("DELETE"));
1627        self.mock_endpoint(mock, RoomDeleteThreadSubscriptionEndpoint::default())
1628            .expect_default_access_token()
1629    }
1630
1631    /// Create a prebuilt mock for the endpoint used to enable a push rule.
1632    pub fn mock_enable_push_rule(
1633        &self,
1634        kind: RuleKind,
1635        rule_id: impl AsRef<str>,
1636    ) -> MockEndpoint<'_, EnablePushRuleEndpoint> {
1637        let rule_id = rule_id.as_ref();
1638        let mock = Mock::given(method("PUT")).and(path_regex(format!(
1639            "^/_matrix/client/v3/pushrules/global/{kind}/{rule_id}/enabled",
1640        )));
1641        self.mock_endpoint(mock, EnablePushRuleEndpoint).expect_default_access_token()
1642    }
1643
1644    /// Create a prebuilt mock for the endpoint used to set push rules actions.
1645    pub fn mock_set_push_rules_actions(
1646        &self,
1647        kind: RuleKind,
1648        rule_id: PushRuleIdSpec<'_>,
1649    ) -> MockEndpoint<'_, SetPushRulesActionsEndpoint> {
1650        let rule_id = rule_id.to_path();
1651        let mock = Mock::given(method("PUT")).and(path_regex(format!(
1652            "^/_matrix/client/v3/pushrules/global/{kind}/{rule_id}/actions",
1653        )));
1654        self.mock_endpoint(mock, SetPushRulesActionsEndpoint).expect_default_access_token()
1655    }
1656
1657    /// Create a prebuilt mock for the endpoint used to set push rules.
1658    pub fn mock_set_push_rules(
1659        &self,
1660        kind: RuleKind,
1661        rule_id: PushRuleIdSpec<'_>,
1662    ) -> MockEndpoint<'_, SetPushRulesEndpoint> {
1663        let rule_id = rule_id.to_path();
1664        let mock = Mock::given(method("PUT"))
1665            .and(path_regex(format!("^/_matrix/client/v3/pushrules/global/{kind}/{rule_id}$",)));
1666        self.mock_endpoint(mock, SetPushRulesEndpoint).expect_default_access_token()
1667    }
1668
1669    /// Create a prebuilt mock for the endpoint used to delete push rules.
1670    pub fn mock_delete_push_rules(
1671        &self,
1672        kind: RuleKind,
1673        rule_id: PushRuleIdSpec<'_>,
1674    ) -> MockEndpoint<'_, DeletePushRulesEndpoint> {
1675        let rule_id = rule_id.to_path();
1676        let mock = Mock::given(method("DELETE"))
1677            .and(path_regex(format!("^/_matrix/client/v3/pushrules/global/{kind}/{rule_id}$",)));
1678        self.mock_endpoint(mock, DeletePushRulesEndpoint).expect_default_access_token()
1679    }
1680
1681    /// Create a prebuilt mock for the federation version endpoint.
1682    pub fn mock_federation_version(&self) -> MockEndpoint<'_, FederationVersionEndpoint> {
1683        let mock = Mock::given(method("GET")).and(path("/_matrix/federation/v1/version"));
1684        self.mock_endpoint(mock, FederationVersionEndpoint)
1685    }
1686
1687    /// Create a prebuilt mock for the endpoint used to get all thread
1688    /// subscriptions across all rooms.
1689    pub fn mock_get_thread_subscriptions(
1690        &self,
1691    ) -> MockEndpoint<'_, GetThreadSubscriptionsEndpoint> {
1692        let mock = Mock::given(method("GET"))
1693            .and(path_regex(r"^/_matrix/client/unstable/io.element.msc4308/thread_subscriptions$"));
1694        self.mock_endpoint(mock, GetThreadSubscriptionsEndpoint::default())
1695            .expect_default_access_token()
1696    }
1697
1698    /// Create a prebuilt mock for the endpoint used to retrieve a space tree
1699    pub fn mock_get_hierarchy(&self) -> MockEndpoint<'_, GetHierarchyEndpoint> {
1700        let mock =
1701            Mock::given(method("GET")).and(path_regex(r"^/_matrix/client/v1/rooms/.*/hierarchy"));
1702        self.mock_endpoint(mock, GetHierarchyEndpoint).expect_default_access_token()
1703    }
1704
1705    /// Create a prebuilt mock for the endpoint used to set a space child.
1706    pub fn mock_set_space_child(&self) -> MockEndpoint<'_, SetSpaceChildEndpoint> {
1707        let mock = Mock::given(method("PUT"))
1708            .and(path_regex(r"^/_matrix/client/v3/rooms/.*/state/m.space.child/.*?"));
1709        self.mock_endpoint(mock, SetSpaceChildEndpoint).expect_default_access_token()
1710    }
1711
1712    /// Create a prebuilt mock for the endpoint used to set a space parent.
1713    pub fn mock_set_space_parent(&self) -> MockEndpoint<'_, SetSpaceParentEndpoint> {
1714        let mock = Mock::given(method("PUT"))
1715            .and(path_regex(r"^/_matrix/client/v3/rooms/.*/state/m.space.parent"));
1716        self.mock_endpoint(mock, SetSpaceParentEndpoint).expect_default_access_token()
1717    }
1718
1719    /// Create a prebuilt mock for the endpoint used to get a profile field.
1720    pub fn mock_get_profile_field(
1721        &self,
1722        user_id: &UserId,
1723        field: ProfileFieldName,
1724    ) -> MockEndpoint<'_, GetProfileFieldEndpoint> {
1725        let mock = Mock::given(method("GET"))
1726            .and(path(format!("/_matrix/client/v3/profile/{user_id}/{field}")));
1727        self.mock_endpoint(mock, GetProfileFieldEndpoint { field })
1728    }
1729
1730    /// Create a prebuilt mock for the endpoint used to set a profile field.
1731    pub fn mock_set_profile_field(
1732        &self,
1733        user_id: &UserId,
1734        field: ProfileFieldName,
1735    ) -> MockEndpoint<'_, SetProfileFieldEndpoint> {
1736        let mock = Mock::given(method("PUT"))
1737            .and(path(format!("/_matrix/client/v3/profile/{user_id}/{field}")));
1738        self.mock_endpoint(mock, SetProfileFieldEndpoint).expect_default_access_token()
1739    }
1740
1741    /// Create a prebuilt mock for the endpoint used to delete a profile field.
1742    pub fn mock_delete_profile_field(
1743        &self,
1744        user_id: &UserId,
1745        field: ProfileFieldName,
1746    ) -> MockEndpoint<'_, DeleteProfileFieldEndpoint> {
1747        let mock = Mock::given(method("DELETE"))
1748            .and(path(format!("/_matrix/client/v3/profile/{user_id}/{field}")));
1749        self.mock_endpoint(mock, DeleteProfileFieldEndpoint).expect_default_access_token()
1750    }
1751
1752    /// Create a prebuilt mock for the endpoint used to get a profile.
1753    pub fn mock_get_profile(&self, user_id: &UserId) -> MockEndpoint<'_, GetProfileEndpoint> {
1754        let mock =
1755            Mock::given(method("GET")).and(path(format!("/_matrix/client/v3/profile/{user_id}")));
1756        self.mock_endpoint(mock, GetProfileEndpoint)
1757    }
1758
1759    /// Create a prebuilt mock for the endpoint used to get the capabilities of
1760    /// the homeserver.
1761    pub fn mock_get_homeserver_capabilities(
1762        &self,
1763    ) -> MockEndpoint<'_, GetHomeserverCapabilitiesEndpoint> {
1764        let mock = Mock::given(method("GET")).and(path("/_matrix/client/v3/capabilities"));
1765        self.mock_endpoint(mock, GetHomeserverCapabilitiesEndpoint)
1766    }
1767}
1768
1769/// A specification for a push rule ID.
1770pub enum PushRuleIdSpec<'a> {
1771    /// A precise rule ID.
1772    Some(&'a str),
1773    /// Any rule ID should match.
1774    Any,
1775}
1776
1777impl<'a> PushRuleIdSpec<'a> {
1778    /// Convert this [`PushRuleIdSpec`] to a path.
1779    pub fn to_path(&self) -> &str {
1780        match self {
1781            PushRuleIdSpec::Some(id) => id,
1782            PushRuleIdSpec::Any => "[^/]*",
1783        }
1784    }
1785}
1786
1787/// Parameter to [`MatrixMockServer::sync_room`].
1788pub enum AnyRoomBuilder {
1789    /// A room we've been invited to.
1790    Invited(InvitedRoomBuilder),
1791    /// A room we've joined.
1792    Joined(JoinedRoomBuilder),
1793    /// A room we've left.
1794    Left(LeftRoomBuilder),
1795    /// A room we've knocked to.
1796    Knocked(KnockedRoomBuilder),
1797}
1798
1799impl AnyRoomBuilder {
1800    /// Get the [`RoomId`] of the room this [`AnyRoomBuilder`] will create.
1801    fn room_id(&self) -> &RoomId {
1802        match self {
1803            AnyRoomBuilder::Invited(r) => r.room_id(),
1804            AnyRoomBuilder::Joined(r) => r.room_id(),
1805            AnyRoomBuilder::Left(r) => r.room_id(),
1806            AnyRoomBuilder::Knocked(r) => r.room_id(),
1807        }
1808    }
1809}
1810
1811impl From<InvitedRoomBuilder> for AnyRoomBuilder {
1812    fn from(val: InvitedRoomBuilder) -> AnyRoomBuilder {
1813        AnyRoomBuilder::Invited(val)
1814    }
1815}
1816
1817impl From<JoinedRoomBuilder> for AnyRoomBuilder {
1818    fn from(val: JoinedRoomBuilder) -> AnyRoomBuilder {
1819        AnyRoomBuilder::Joined(val)
1820    }
1821}
1822
1823impl From<LeftRoomBuilder> for AnyRoomBuilder {
1824    fn from(val: LeftRoomBuilder) -> AnyRoomBuilder {
1825        AnyRoomBuilder::Left(val)
1826    }
1827}
1828
1829impl From<KnockedRoomBuilder> for AnyRoomBuilder {
1830    fn from(val: KnockedRoomBuilder) -> AnyRoomBuilder {
1831        AnyRoomBuilder::Knocked(val)
1832    }
1833}
1834
1835/// The [path percent-encode set] as defined in the WHATWG URL standard + `/`
1836/// since we always encode single segments of the path.
1837///
1838/// [path percent-encode set]: https://url.spec.whatwg.org/#path-percent-encode-set
1839///
1840/// Copied from Ruma:
1841/// https://github.com/ruma/ruma/blob/e4cb409ff3aaa16f31a7fe1e61fee43b2d144f7b/crates/ruma-common/src/percent_encode.rs#L7
1842const PATH_PERCENT_ENCODE_SET: &AsciiSet = &CONTROLS
1843    .add(b' ')
1844    .add(b'"')
1845    .add(b'#')
1846    .add(b'<')
1847    .add(b'>')
1848    .add(b'?')
1849    .add(b'`')
1850    .add(b'{')
1851    .add(b'}')
1852    .add(b'/');
1853
1854fn percent_encoded_path(path: &str) -> String {
1855    percent_encoding::utf8_percent_encode(path, PATH_PERCENT_ENCODE_SET).to_string()
1856}
1857
1858/// A wrapper for a [`Mock`] as well as a [`MockServer`], allowing us to call
1859/// [`Mock::mount`] or [`Mock::mount_as_scoped`] without having to pass the
1860/// [`MockServer`] reference (i.e. call `mount()` instead of `mount(&server)`).
1861pub struct MatrixMock<'a> {
1862    pub(super) mock: Mock,
1863    pub(super) server: &'a MockServer,
1864}
1865
1866impl MatrixMock<'_> {
1867    /// Set an expectation on the number of times this [`MatrixMock`] should
1868    /// match in the current test case.
1869    ///
1870    /// Expectations are verified when the server is shutting down: if
1871    /// the expectation is not satisfied, the [`MatrixMockServer`] will panic
1872    /// and the `error_message` is shown.
1873    ///
1874    /// By default, no expectation is set for [`MatrixMock`]s.
1875    pub fn expect<T: Into<Times>>(self, num_calls: T) -> Self {
1876        Self { mock: self.mock.expect(num_calls), ..self }
1877    }
1878
1879    /// Assign a name to your mock.
1880    ///
1881    /// The mock name will be used in error messages (e.g. if the mock
1882    /// expectation is not satisfied) and debug logs to help you identify
1883    /// what failed.
1884    pub fn named(self, name: impl Into<String>) -> Self {
1885        Self { mock: self.mock.named(name), ..self }
1886    }
1887
1888    /// Respond to a response of this endpoint exactly once.
1889    ///
1890    /// After it's been called, subsequent responses will hit the next handler
1891    /// or a 404.
1892    ///
1893    /// Also verifies that it's been called once.
1894    pub fn mock_once(self) -> Self {
1895        Self { mock: self.mock.up_to_n_times(1).expect(1), ..self }
1896    }
1897
1898    /// Makes sure the endpoint is never reached.
1899    pub fn never(self) -> Self {
1900        Self { mock: self.mock.expect(0), ..self }
1901    }
1902
1903    /// Specify an upper limit to the number of times you would like this
1904    /// [`MatrixMock`] to respond to incoming requests that satisfy the
1905    /// conditions imposed by your matchers.
1906    pub fn up_to_n_times(self, num: u64) -> Self {
1907        Self { mock: self.mock.up_to_n_times(num), ..self }
1908    }
1909
1910    /// Set the priority of this [`MatrixMock`].
1911    ///
1912    /// When several mocks match the same request, the one with the highest
1913    /// priority (i.e. the lowest value, 1 being the highest and 255 the
1914    /// lowest) responds to it. This is useful to mock the same endpoint
1915    /// differently for the first and the subsequent requests, by combining it
1916    /// with [`Self::up_to_n_times`].
1917    pub fn with_priority(self, priority: u8) -> Self {
1918        Self { mock: self.mock.with_priority(priority), ..self }
1919    }
1920
1921    /// Mount a [`MatrixMock`] on the attached server.
1922    ///
1923    /// The [`MatrixMock`] will remain active until the [`MatrixMockServer`] is
1924    /// shut down. If you want to control or limit how long your
1925    /// [`MatrixMock`] stays active, check out [`Self::mount_as_scoped`].
1926    pub async fn mount(self) {
1927        self.mock.mount(self.server).await;
1928    }
1929
1930    /// Mount a [`MatrixMock`] as **scoped** on the attached server.
1931    ///
1932    /// When using [`Self::mount`], your [`MatrixMock`]s will be active until
1933    /// the [`MatrixMockServer`] is shut down.
1934    ///
1935    /// When using `mount_as_scoped`, your [`MatrixMock`]s will be active as
1936    /// long as the returned [`MockGuard`] is not dropped.
1937    ///
1938    /// When the returned [`MockGuard`] is dropped, [`MatrixMockServer`] will
1939    /// verify that the expectations set on the scoped [`MatrixMock`] were
1940    /// verified - if not, it will panic.
1941    pub async fn mount_as_scoped(self) -> MockGuard {
1942        self.mock.mount_as_scoped(self.server).await
1943    }
1944}
1945
1946/// Generic mocked endpoint, with useful common helpers.
1947pub struct MockEndpoint<'a, T> {
1948    server: &'a MockServer,
1949    mock: MockBuilder,
1950    endpoint: T,
1951    expected_access_token: ExpectedAccessToken,
1952}
1953
1954impl<'a, T> MockEndpoint<'a, T> {
1955    fn new(server: &'a MockServer, mock: MockBuilder, endpoint: T) -> Self {
1956        Self { server, mock, endpoint, expected_access_token: ExpectedAccessToken::Ignore }
1957    }
1958
1959    /// Expect authentication with the default access token on this endpoint.
1960    pub fn expect_default_access_token(mut self) -> Self {
1961        self.expected_access_token = ExpectedAccessToken::Default;
1962        self
1963    }
1964
1965    /// Expect authentication with the given access token on this endpoint.
1966    pub fn expect_access_token(mut self, access_token: &'static str) -> Self {
1967        self.expected_access_token = ExpectedAccessToken::Custom(access_token);
1968        self
1969    }
1970
1971    /// Expect authentication with any access token on this endpoint, regardless
1972    /// of its value.
1973    ///
1974    /// This is useful if we don't want to track the value of the access token.
1975    pub fn expect_any_access_token(mut self) -> Self {
1976        self.expected_access_token = ExpectedAccessToken::Any;
1977        self
1978    }
1979
1980    /// Expect no authentication on this endpoint.
1981    ///
1982    /// This means that the endpoint will not match if an `AUTHENTICATION`
1983    /// header is present.
1984    pub fn expect_missing_access_token(mut self) -> Self {
1985        self.expected_access_token = ExpectedAccessToken::Missing;
1986        self
1987    }
1988
1989    /// Ignore the access token on this endpoint.
1990    ///
1991    /// This should be used to override the default behavior of an endpoint that
1992    /// requires access tokens.
1993    pub fn ignore_access_token(mut self) -> Self {
1994        self.expected_access_token = ExpectedAccessToken::Ignore;
1995        self
1996    }
1997
1998    /// Expect the given UIAA auth data in the body of the request.
1999    pub fn expect_uiaa_auth_data(mut self, auth_data: &uiaa::AuthData) -> Self {
2000        self.mock = self.mock.and(body_partial_json(json!({
2001            "auth": auth_data,
2002        })));
2003        self
2004    }
2005
2006    /// Specify how to respond to a query (viz., like
2007    /// [`MockBuilder::respond_with`] does), when other predefined responses
2008    /// aren't sufficient.
2009    ///
2010    /// # Examples
2011    ///
2012    /// ```
2013    /// # tokio_test::block_on(async {
2014    /// use matrix_sdk::{ruma::{room_id, event_id}, test_utils::mocks::MatrixMockServer};
2015    /// use serde_json::json;
2016    /// use wiremock::ResponseTemplate;
2017    ///
2018    /// let mock_server = MatrixMockServer::new().await;
2019    /// let client = mock_server.client_builder().build().await;
2020    ///
2021    /// mock_server.mock_room_state_encryption().plain().mount().await;
2022    ///
2023    /// let room = mock_server
2024    ///     .sync_joined_room(&client, room_id!("!room_id:localhost"))
2025    ///     .await;
2026    ///
2027    /// let event_id = event_id!("$some_id");
2028    /// mock_server
2029    ///     .mock_room_send()
2030    ///     .respond_with(
2031    ///         ResponseTemplate::new(429)
2032    ///             .insert_header("Retry-After", "100")
2033    ///             .set_body_json(json!({
2034    ///                 "errcode": "M_LIMIT_EXCEEDED",
2035    ///                 "custom_field": "with custom data",
2036    ///     })))
2037    ///     .expect(1)
2038    ///     .mount()
2039    ///     .await;
2040    ///
2041    /// room
2042    ///     .send_raw("m.room.message", json!({ "body": "Hello world" }))
2043    ///     .await
2044    ///     .expect_err("The sending of the event should fail");
2045    /// # anyhow::Ok(()) });
2046    /// ```
2047    pub fn respond_with<R: Respond + 'static>(self, func: R) -> MatrixMock<'a> {
2048        let mock = self.mock.and(self.expected_access_token).respond_with(func);
2049        MatrixMock { mock, server: self.server }
2050    }
2051
2052    /// Returns a send endpoint that emulates a transient failure, i.e responds
2053    /// with error 500.
2054    ///
2055    /// # Examples
2056    /// ```
2057    /// # tokio_test::block_on(async {
2058    /// use matrix_sdk::{ruma::{room_id, event_id}, test_utils::mocks::MatrixMockServer};
2059    /// use serde_json::json;
2060    ///
2061    /// let mock_server = MatrixMockServer::new().await;
2062    /// let client = mock_server.client_builder().build().await;
2063    ///
2064    /// mock_server.mock_room_state_encryption().plain().mount().await;
2065    ///
2066    /// let room = mock_server
2067    ///     .sync_joined_room(&client, room_id!("!room_id:localhost"))
2068    ///     .await;
2069    ///
2070    /// mock_server
2071    ///     .mock_room_send()
2072    ///     .error500()
2073    ///     .expect(1)
2074    ///     .mount()
2075    ///     .await;
2076    ///
2077    /// room
2078    ///     .send_raw("m.room.message", json!({ "body": "Hello world" }))
2079    ///     .await.expect_err("The sending of the event should have failed");
2080    /// # anyhow::Ok(()) });
2081    /// ```
2082    pub fn error500(self) -> MatrixMock<'a> {
2083        self.respond_with(ResponseTemplate::new(500))
2084    }
2085
2086    /// Returns a mocked endpoint that emulates an unimplemented endpoint, i.e
2087    /// responds with a 404 HTTP status code and an `M_UNRECOGNIZED` Matrix
2088    /// error code.
2089    ///
2090    /// Note that the default behavior of the mock server is to return a 404
2091    /// status code for endpoints that are not mocked with an empty response.
2092    ///
2093    /// This can be useful to check if an endpoint is called, even if it is not
2094    /// implemented by the server.
2095    pub fn error_unrecognized(self) -> MatrixMock<'a> {
2096        self.respond_with(ResponseTemplate::new(404).set_body_json(json!({
2097            "errcode": "M_UNRECOGNIZED",
2098            "error": "Unrecognized request",
2099        })))
2100    }
2101
2102    /// Returns a mocked endpoint that emulates an unknown token error, i.e
2103    /// responds with a 401 HTTP status code and an `M_UNKNOWN_TOKEN` Matrix
2104    /// error code.
2105    pub fn error_unknown_token(self, soft_logout: bool) -> MatrixMock<'a> {
2106        self.respond_with(ResponseTemplate::new(401).set_body_json(json!({
2107            "errcode": "M_UNKNOWN_TOKEN",
2108            "error": "Unrecognized access token",
2109            "soft_logout": soft_logout,
2110        })))
2111    }
2112
2113    /// Internal helper to return an `{ event_id }` JSON struct along with a 200
2114    /// ok response.
2115    fn ok_with_event_id(self, event_id: OwnedEventId) -> MatrixMock<'a> {
2116        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({ "event_id": event_id })))
2117    }
2118
2119    /// Internal helper to return a 200 OK response with an empty JSON object in
2120    /// the body.
2121    fn ok_empty_json(self) -> MatrixMock<'a> {
2122        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({})))
2123    }
2124
2125    /// Returns an endpoint that emulates a permanent failure error (e.g. event
2126    /// is too large).
2127    ///
2128    /// # Examples
2129    /// ```
2130    /// # tokio_test::block_on(async {
2131    /// use matrix_sdk::{ruma::{room_id, event_id}, test_utils::mocks::MatrixMockServer};
2132    /// use serde_json::json;
2133    ///
2134    /// let mock_server = MatrixMockServer::new().await;
2135    /// let client = mock_server.client_builder().build().await;
2136    ///
2137    /// mock_server.mock_room_state_encryption().plain().mount().await;
2138    ///
2139    /// let room = mock_server
2140    ///     .sync_joined_room(&client, room_id!("!room_id:localhost"))
2141    ///     .await;
2142    ///
2143    /// mock_server
2144    ///     .mock_room_send()
2145    ///     .error_too_large()
2146    ///     .expect(1)
2147    ///     .mount()
2148    ///     .await;
2149    ///
2150    /// room
2151    ///     .send_raw("m.room.message", json!({ "body": "Hello world" }))
2152    ///     .await.expect_err("The sending of the event should have failed");
2153    /// # anyhow::Ok(()) });
2154    /// ```
2155    pub fn error_too_large(self) -> MatrixMock<'a> {
2156        self.respond_with(ResponseTemplate::new(413).set_body_json(json!({
2157            // From https://spec.matrix.org/v1.10/client-server-api/#standard-error-response
2158            "errcode": "M_TOO_LARGE",
2159            "error": "Request body too large",
2160        })))
2161    }
2162}
2163
2164/// The access token to expect on an endpoint.
2165enum ExpectedAccessToken {
2166    /// Ignore any access token or lack thereof.
2167    Ignore,
2168
2169    /// We expect the default access token.
2170    Default,
2171
2172    /// We expect the given access token.
2173    Custom(&'static str),
2174
2175    /// We expect any access token.
2176    Any,
2177
2178    /// We expect that there is no access token.
2179    Missing,
2180}
2181
2182impl ExpectedAccessToken {
2183    /// Get the access token from the given request.
2184    fn access_token(request: &Request) -> Option<&str> {
2185        request
2186            .headers
2187            .get(&http::header::AUTHORIZATION)?
2188            .to_str()
2189            .ok()?
2190            .strip_prefix("Bearer ")
2191            .filter(|token| !token.is_empty())
2192    }
2193}
2194
2195impl wiremock::Match for ExpectedAccessToken {
2196    fn matches(&self, request: &Request) -> bool {
2197        match self {
2198            Self::Ignore => true,
2199            Self::Default => Self::access_token(request) == Some("1234"),
2200            Self::Custom(token) => Self::access_token(request) == Some(token),
2201            Self::Any => Self::access_token(request).is_some(),
2202            Self::Missing => request.headers.get(&http::header::AUTHORIZATION).is_none(),
2203        }
2204    }
2205}
2206
2207/// A prebuilt mock for sending a message like event in a room.
2208pub struct RoomSendEndpoint;
2209
2210impl<'a> MockEndpoint<'a, RoomSendEndpoint> {
2211    /// Ensures that the body of the request is a superset of the provided
2212    /// `body` parameter.
2213    ///
2214    /// # Examples
2215    /// ```
2216    /// # tokio_test::block_on(async {
2217    /// use matrix_sdk::{
2218    ///     ruma::{room_id, event_id, events::room::message::RoomMessageEventContent},
2219    ///     test_utils::mocks::MatrixMockServer
2220    /// };
2221    /// use serde_json::json;
2222    ///
2223    /// let mock_server = MatrixMockServer::new().await;
2224    /// let client = mock_server.client_builder().build().await;
2225    ///
2226    /// mock_server.mock_room_state_encryption().plain().mount().await;
2227    ///
2228    /// let room = mock_server
2229    ///     .sync_joined_room(&client, room_id!("!room_id:localhost"))
2230    ///     .await;
2231    ///
2232    /// let event_id = event_id!("$some_id");
2233    /// mock_server
2234    ///     .mock_room_send()
2235    ///     .body_matches_partial_json(json!({
2236    ///         "body": "Hello world",
2237    ///     }))
2238    ///     .ok(event_id)
2239    ///     .expect(1)
2240    ///     .mount()
2241    ///     .await;
2242    ///
2243    /// let content = RoomMessageEventContent::text_plain("Hello world");
2244    /// let result = room.send(content).await?;
2245    ///
2246    /// assert_eq!(
2247    ///     event_id,
2248    ///     result.response.event_id,
2249    ///     "The event ID we mocked should match the one we received when we sent the event"
2250    /// );
2251    /// # anyhow::Ok(()) });
2252    /// ```
2253    pub fn body_matches_partial_json(self, body: Value) -> Self {
2254        Self { mock: self.mock.and(body_partial_json(body)), ..self }
2255    }
2256
2257    /// Ensures that the send endpoint request uses a specific event type.
2258    ///
2259    /// # Examples
2260    ///
2261    /// see also [`MatrixMockServer::mock_room_send`] for more context.
2262    ///
2263    /// ```
2264    /// # tokio_test::block_on(async {
2265    /// use matrix_sdk::{ruma::{room_id, event_id}, test_utils::mocks::MatrixMockServer};
2266    /// use serde_json::json;
2267    ///
2268    /// let mock_server = MatrixMockServer::new().await;
2269    /// let client = mock_server.client_builder().build().await;
2270    ///
2271    /// mock_server.mock_room_state_encryption().plain().mount().await;
2272    ///
2273    /// let room = mock_server
2274    ///     .sync_joined_room(&client, room_id!("!room_id:localhost"))
2275    ///     .await;
2276    ///
2277    /// let event_id = event_id!("$some_id");
2278    /// mock_server
2279    ///     .mock_room_send()
2280    ///     .for_type("m.room.message".into())
2281    ///     .ok(event_id)
2282    ///     .expect(1)
2283    ///     .mount()
2284    ///     .await;
2285    ///
2286    /// let response_not_mocked = room.send_raw("m.room.reaction", json!({ "body": "Hello world" })).await;
2287    /// // The `m.room.reaction` event type should not be mocked by the server.
2288    /// assert!(response_not_mocked.is_err());
2289    ///
2290    /// let result = room.send_raw("m.room.message", json!({ "body": "Hello world" })).await?;
2291    /// // The `m.room.message` event type should be mocked by the server.
2292    /// assert_eq!(
2293    ///     event_id,
2294    ///     result.response.event_id,
2295    ///     "The event ID we mocked should match the one we received when we sent the event"
2296    /// );
2297    /// # anyhow::Ok(()) });
2298    /// ```
2299    pub fn for_type(self, event_type: MessageLikeEventType) -> Self {
2300        Self {
2301            // Note: we already defined a path when constructing the mock builder, but this one
2302            // ought to be more specialized.
2303            mock: self
2304                .mock
2305                .and(path_regex(format!(r"^/_matrix/client/v3/rooms/.*/send/{event_type}",))),
2306            ..self
2307        }
2308    }
2309
2310    /// Ensures the event was sent as a delayed event.
2311    ///
2312    /// See also [the MSC](https://github.com/matrix-org/matrix-spec-proposals/pull/4140).
2313    ///
2314    /// Note: works with *any* room.
2315    ///
2316    /// # Examples
2317    ///
2318    /// see also [`MatrixMockServer::mock_room_send`] for more context.
2319    ///
2320    /// ```
2321    /// # tokio_test::block_on(async {
2322    /// use matrix_sdk::{
2323    ///     ruma::{
2324    ///         api::client::delayed_events::{delayed_message_event, DelayParameters},
2325    ///         events::{message::MessageEventContent, AnyMessageLikeEventContent},
2326    ///         room_id,
2327    ///         time::Duration,
2328    ///         TransactionId,
2329    ///     },
2330    ///     test_utils::mocks::MatrixMockServer,
2331    /// };
2332    /// use serde_json::json;
2333    /// use wiremock::ResponseTemplate;
2334    ///
2335    /// let mock_server = MatrixMockServer::new().await;
2336    /// let client = mock_server.client_builder().build().await;
2337    ///
2338    /// mock_server.mock_room_state_encryption().plain().mount().await;
2339    ///
2340    /// let room = mock_server.sync_joined_room(&client, room_id!("!room_id:localhost")).await;
2341    ///
2342    /// mock_server
2343    ///     .mock_room_send()
2344    ///     .match_delayed_event(Duration::from_millis(500))
2345    ///     .respond_with(ResponseTemplate::new(200).set_body_json(json!({"delay_id":"$some_id"})))
2346    ///     .mock_once()
2347    ///     .mount()
2348    ///     .await;
2349    ///
2350    /// let response_not_mocked =
2351    ///     room.send_raw("m.room.message", json!({ "body": "Hello world" })).await;
2352    ///
2353    /// // A non delayed event should not be mocked by the server.
2354    /// assert!(response_not_mocked.is_err());
2355    ///
2356    /// let r = delayed_message_event::unstable::Request::new(
2357    ///     room.room_id().to_owned(),
2358    ///     TransactionId::new(),
2359    ///     DelayParameters::Timeout { timeout: Duration::from_millis(500) },
2360    ///     &AnyMessageLikeEventContent::Message(MessageEventContent::plain("hello world")),
2361    /// )
2362    /// .unwrap();
2363    ///
2364    /// let response = room.client().send(r).await.unwrap();
2365    /// // The delayed `m.room.message` event type should be mocked by the server.
2366    /// assert_eq!("$some_id", response.delay_id);
2367    /// # anyhow::Ok(()) });
2368    /// ```
2369    pub fn match_delayed_event(self, delay: Duration) -> Self {
2370        Self {
2371            mock: self
2372                .mock
2373                .and(query_param("org.matrix.msc4140.delay", delay.as_millis().to_string())),
2374            ..self
2375        }
2376    }
2377
2378    /// Returns a send endpoint that emulates success, i.e. the event has been
2379    /// sent with the given event id.
2380    ///
2381    /// # Examples
2382    /// ```
2383    /// # tokio_test::block_on(async {
2384    /// use matrix_sdk::{ruma::{room_id, event_id}, test_utils::mocks::MatrixMockServer};
2385    /// use serde_json::json;
2386    ///
2387    /// let mock_server = MatrixMockServer::new().await;
2388    /// let client = mock_server.client_builder().build().await;
2389    ///
2390    /// mock_server.mock_room_state_encryption().plain().mount().await;
2391    ///
2392    /// let room = mock_server
2393    ///     .sync_joined_room(&client, room_id!("!room_id:localhost"))
2394    ///     .await;
2395    ///
2396    /// let event_id = event_id!("$some_id");
2397    /// let send_guard = mock_server
2398    ///     .mock_room_send()
2399    ///     .ok(event_id)
2400    ///     .expect(1)
2401    ///     .mount_as_scoped()
2402    ///     .await;
2403    ///
2404    /// let result = room.send_raw("m.room.message", json!({ "body": "Hello world" })).await?;
2405    ///
2406    /// assert_eq!(
2407    ///     event_id,
2408    ///     result.response.event_id,
2409    ///     "The event ID we mocked should match the one we received when we sent the event"
2410    /// );
2411    /// # anyhow::Ok(()) });
2412    /// ```
2413    pub fn ok(self, returned_event_id: impl Into<OwnedEventId>) -> MatrixMock<'a> {
2414        self.ok_with_event_id(returned_event_id.into())
2415    }
2416
2417    /// Returns a send endpoint that emulates success after a delay, i.e. the
2418    /// event has been sent with the given event id, but the response is delayed
2419    /// by the given duration.
2420    ///
2421    /// This is useful for testing ordering guarantees when multiple events are
2422    /// in-flight simultaneously.
2423    ///
2424    /// # Examples
2425    /// ```
2426    /// # tokio_test::block_on(async {
2427    /// use std::time::Duration;
2428    ///
2429    /// use matrix_sdk::{
2430    ///     ruma::{event_id, room_id},
2431    ///     test_utils::mocks::MatrixMockServer,
2432    /// };
2433    /// use serde_json::json;
2434    ///
2435    /// let mock_server = MatrixMockServer::new().await;
2436    /// let client = mock_server.client_builder().build().await;
2437    ///
2438    /// mock_server.mock_room_state_encryption().plain().mount().await;
2439    ///
2440    /// let room = mock_server
2441    ///     .sync_joined_room(&client, room_id!("!room_id:localhost"))
2442    ///     .await;
2443    ///
2444    /// mock_server
2445    ///     .mock_room_send()
2446    ///     .ok_with_delay(event_id!("$some_id"), Duration::from_millis(100))
2447    ///     .mock_once()
2448    ///     .mount()
2449    ///     .await;
2450    ///
2451    /// let result = room.send_raw("m.room.message", json!({ "body": "Hello world" })).await?;
2452    ///
2453    /// assert_eq!(
2454    ///     event_id!("$some_id"),
2455    ///     result.response.event_id,
2456    ///     "The event ID we mocked should match the one we received when we sent the event"
2457    /// );
2458    /// # anyhow::Ok(()) });
2459    /// ```
2460    pub fn ok_with_delay(
2461        self,
2462        returned_event_id: impl Into<OwnedEventId>,
2463        delay: Duration,
2464    ) -> MatrixMock<'a> {
2465        let event_id = returned_event_id.into();
2466        self.respond_with(
2467            ResponseTemplate::new(200)
2468                .set_body_json(json!({ "event_id": event_id }))
2469                .set_delay(delay),
2470        )
2471    }
2472
2473    /// Returns a send endpoint that emulates success, i.e. the event has been
2474    /// sent with the given event id.
2475    ///
2476    /// The sent event is captured and can be accessed using the returned
2477    /// [`Receiver`]. The [`Receiver`] is valid only for a send call. The given
2478    /// `event_sender` are added to the event JSON.
2479    ///
2480    /// # Examples
2481    ///
2482    /// ```no_run
2483    /// # tokio_test::block_on(async {
2484    /// use matrix_sdk::{
2485    ///     ruma::{
2486    ///         event_id, events::room::message::RoomMessageEventContent, room_id,
2487    ///     },
2488    ///     test_utils::mocks::MatrixMockServer,
2489    /// };
2490    /// use matrix_sdk_test::JoinedRoomBuilder;
2491    ///
2492    /// let room_id = room_id!("!room_id:localhost");
2493    /// let event_id = event_id!("$some_id");
2494    ///
2495    /// let server = MatrixMockServer::new().await;
2496    /// let client = server.client_builder().build().await;
2497    ///
2498    /// let user_id = client.user_id().expect("We should have a user ID by now");
2499    ///
2500    /// let (receiver, mock) =
2501    ///     server.mock_room_send().ok_with_capture(event_id, user_id);
2502    ///
2503    /// server
2504    ///     .mock_sync()
2505    ///     .ok_and_run(&client, |builder| {
2506    ///         builder.add_joined_room(JoinedRoomBuilder::new(room_id));
2507    ///     })
2508    ///     .await;
2509    ///
2510    /// // Mock any additional endpoints that might be needed to send the message.
2511    ///
2512    /// let room = client
2513    ///     .get_room(room_id)
2514    ///     .expect("We should have access to our room now");
2515    ///
2516    /// let event_id = room
2517    ///     .send(RoomMessageEventContent::text_plain("It's a secret to everybody"))
2518    ///     .await
2519    ///     .expect("We should be able to send an initial message")
2520    ///     .response
2521    ///     .event_id;
2522    ///
2523    /// let event = receiver.await?;
2524    /// # anyhow::Ok(()) });
2525    /// ```
2526    pub fn ok_with_capture(
2527        self,
2528        returned_event_id: impl Into<OwnedEventId>,
2529        event_sender: impl Into<OwnedUserId>,
2530    ) -> (Receiver<Raw<AnySyncTimelineEvent>>, MatrixMock<'a>) {
2531        let event_id = returned_event_id.into();
2532        let event_sender = event_sender.into();
2533
2534        let (sender, receiver) = oneshot::channel();
2535        let sender = Arc::new(Mutex::new(Some(sender)));
2536
2537        let ret = self.respond_with(move |request: &Request| {
2538            if let Some(sender) = sender.lock().unwrap().take() {
2539                let uri = &request.url;
2540                let path_segments = uri.path_segments();
2541                let maybe_event_type = path_segments.and_then(|mut s| s.nth_back(1));
2542                let event_type = maybe_event_type
2543                    .as_ref()
2544                    .map(|&e| e.to_owned())
2545                    .unwrap_or("m.room.message".to_owned());
2546
2547                let body: Value =
2548                    request.body_json().expect("The received body should be valid JSON");
2549
2550                let event = json!({
2551                    "event_id": event_id.clone(),
2552                    "sender": event_sender,
2553                    "type": event_type,
2554                    "origin_server_ts": MilliSecondsSinceUnixEpoch::now(),
2555                    "content": body,
2556                });
2557
2558                let event: Raw<AnySyncTimelineEvent> = from_value(event)
2559                    .expect("We should be able to create a raw event from the content");
2560
2561                sender.send(event).expect("We should be able to send the event to the receiver");
2562            }
2563
2564            ResponseTemplate::new(200).set_body_json(json!({ "event_id": event_id.clone() }))
2565        });
2566
2567        (receiver, ret)
2568    }
2569}
2570
2571/// A prebuilt mock for sending a state event in a room.
2572#[derive(Default)]
2573pub struct RoomSendStateEndpoint {
2574    state_key: Option<String>,
2575    event_type: Option<StateEventType>,
2576}
2577
2578impl<'a> MockEndpoint<'a, RoomSendStateEndpoint> {
2579    fn generate_path_regexp(endpoint: &RoomSendStateEndpoint) -> String {
2580        format!(
2581            r"^/_matrix/client/v3/rooms/.*/state/{}/{}",
2582            endpoint.event_type.as_ref().map_or_else(|| ".*".to_owned(), |t| t.to_string()),
2583            endpoint.state_key.as_ref().map_or_else(|| ".*".to_owned(), |k| k.to_string())
2584        )
2585    }
2586
2587    /// Ensures that the body of the request is a superset of the provided
2588    /// `body` parameter.
2589    ///
2590    /// # Examples
2591    /// ```
2592    /// # tokio_test::block_on(async {
2593    /// use matrix_sdk::{
2594    ///     ruma::{
2595    ///         room_id, event_id,
2596    ///         events::room::power_levels::RoomPowerLevelsEventContent,
2597    ///         room_version_rules::AuthorizationRules
2598    ///     },
2599    ///     test_utils::mocks::MatrixMockServer
2600    /// };
2601    /// use serde_json::json;
2602    ///
2603    /// let mock_server = MatrixMockServer::new().await;
2604    /// let client = mock_server.client_builder().build().await;
2605    ///
2606    /// mock_server.mock_room_state_encryption().plain().mount().await;
2607    ///
2608    /// let room = mock_server
2609    ///     .sync_joined_room(&client, room_id!("!room_id:localhost"))
2610    ///     .await;
2611    ///
2612    /// let event_id = event_id!("$some_id");
2613    /// mock_server
2614    ///     .mock_room_send_state()
2615    ///     .body_matches_partial_json(json!({
2616    ///         "redact": 51,
2617    ///     }))
2618    ///     .ok(event_id)
2619    ///     .expect(1)
2620    ///     .mount()
2621    ///     .await;
2622    ///
2623    /// let mut content = RoomPowerLevelsEventContent::new(&AuthorizationRules::V1);
2624    /// // Update the power level to a non default value.
2625    /// // Otherwise it will be skipped from serialization.
2626    /// content.redact = 51.into();
2627    ///
2628    /// let response = room.send_state_event(content).await?;
2629    ///
2630    /// assert_eq!(
2631    ///     event_id,
2632    ///     response.event_id,
2633    ///     "The event ID we mocked should match the one we received when we sent the event"
2634    /// );
2635    /// # anyhow::Ok(()) });
2636    /// ```
2637    pub fn body_matches_partial_json(self, body: Value) -> Self {
2638        Self { mock: self.mock.and(body_partial_json(body)), ..self }
2639    }
2640
2641    /// Ensures that the send endpoint request uses a specific event type.
2642    ///
2643    /// Note: works with *any* room.
2644    ///
2645    /// # Examples
2646    ///
2647    /// see also [`MatrixMockServer::mock_room_send`] for more context.
2648    ///
2649    /// ```
2650    /// # tokio_test::block_on(async {
2651    /// use matrix_sdk::{
2652    ///     ruma::{
2653    ///         event_id,
2654    ///         events::room::{
2655    ///             create::RoomCreateEventContent, power_levels::RoomPowerLevelsEventContent,
2656    ///         },
2657    ///         events::StateEventType,
2658    ///         room_id,
2659    ///         room_version_rules::AuthorizationRules,
2660    ///     },
2661    ///     test_utils::mocks::MatrixMockServer,
2662    /// };
2663    ///
2664    /// let mock_server = MatrixMockServer::new().await;
2665    /// let client = mock_server.client_builder().build().await;
2666    ///
2667    /// mock_server.mock_room_state_encryption().plain().mount().await;
2668    ///
2669    /// let room = mock_server.sync_joined_room(&client, room_id!("!room_id:localhost")).await;
2670    ///
2671    /// let event_id = event_id!("$some_id");
2672    ///
2673    /// mock_server
2674    ///     .mock_room_send_state()
2675    ///     .for_type(StateEventType::RoomPowerLevels)
2676    ///     .ok(event_id)
2677    ///     .expect(1)
2678    ///     .mount()
2679    ///     .await;
2680    ///
2681    /// let response_not_mocked = room.send_state_event(RoomCreateEventContent::new_v11()).await;
2682    /// // The `m.room.reaction` event type should not be mocked by the server.
2683    /// assert!(response_not_mocked.is_err());
2684    ///
2685    /// let response = room.send_state_event(RoomPowerLevelsEventContent::new(&AuthorizationRules::V1)).await?;
2686    /// // The `m.room.message` event type should be mocked by the server.
2687    /// assert_eq!(
2688    ///     event_id, response.event_id,
2689    ///     "The event ID we mocked should match the one we received when we sent the event"
2690    /// );
2691    ///
2692    /// # anyhow::Ok(()) });
2693    /// ```
2694    pub fn for_type(mut self, event_type: StateEventType) -> Self {
2695        self.endpoint.event_type = Some(event_type);
2696        // Note: we may have already defined a path, but this one ought to be more
2697        // specialized (unless for_key/for_type were called multiple times).
2698        Self { mock: self.mock.and(path_regex(Self::generate_path_regexp(&self.endpoint))), ..self }
2699    }
2700
2701    /// Ensures the event was sent as a delayed event.
2702    ///
2703    /// See also [the MSC](https://github.com/matrix-org/matrix-spec-proposals/pull/4140).
2704    ///
2705    /// Note: works with *any* room.
2706    ///
2707    /// # Examples
2708    ///
2709    /// see also [`MatrixMockServer::mock_room_send`] for more context.
2710    ///
2711    /// ```
2712    /// # tokio_test::block_on(async {
2713    /// use matrix_sdk::{
2714    ///     ruma::{
2715    ///         api::client::delayed_events::{delayed_state_event, DelayParameters},
2716    ///         events::{room::create::RoomCreateEventContent, AnyStateEventContent},
2717    ///         room_id,
2718    ///         time::Duration,
2719    ///     },
2720    ///     test_utils::mocks::MatrixMockServer,
2721    /// };
2722    /// use wiremock::ResponseTemplate;
2723    /// use serde_json::json;
2724    ///
2725    /// let mock_server = MatrixMockServer::new().await;
2726    /// let client = mock_server.client_builder().build().await;
2727    ///
2728    /// mock_server.mock_room_state_encryption().plain().mount().await;
2729    ///
2730    /// let room = mock_server.sync_joined_room(&client, room_id!("!room_id:localhost")).await;
2731    ///
2732    /// mock_server
2733    ///     .mock_room_send_state()
2734    ///     .match_delayed_event(Duration::from_millis(500))
2735    ///     .respond_with(ResponseTemplate::new(200).set_body_json(json!({"delay_id":"$some_id"})))
2736    ///     .mock_once()
2737    ///     .mount()
2738    ///     .await;
2739    ///
2740    /// let response_not_mocked = room.send_state_event(RoomCreateEventContent::new_v11()).await;
2741    /// // A non delayed event should not be mocked by the server.
2742    /// assert!(response_not_mocked.is_err());
2743    ///
2744    /// let r = delayed_state_event::unstable::Request::new(
2745    ///     room.room_id().to_owned(),
2746    ///     "".to_owned(),
2747    ///     DelayParameters::Timeout { timeout: Duration::from_millis(500) },
2748    ///     &AnyStateEventContent::RoomCreate(RoomCreateEventContent::new_v11()),
2749    /// )
2750    /// .unwrap();
2751    /// let response = room.client().send(r).await.unwrap();
2752    /// // The delayed `m.room.message` event type should be mocked by the server.
2753    /// assert_eq!("$some_id", response.delay_id);
2754    ///
2755    /// # anyhow::Ok(()) });
2756    /// ```
2757    pub fn match_delayed_event(self, delay: Duration) -> Self {
2758        Self {
2759            mock: self
2760                .mock
2761                .and(query_param("org.matrix.msc4140.delay", delay.as_millis().to_string())),
2762            ..self
2763        }
2764    }
2765
2766    ///
2767    /// ```
2768    /// # tokio_test::block_on(async {
2769    /// use matrix_sdk::{
2770    ///     ruma::{
2771    ///         event_id,
2772    ///         events::{call::member::CallMemberEventContent, AnyStateEventContent},
2773    ///         room_id,
2774    ///     },
2775    ///     test_utils::mocks::MatrixMockServer,
2776    /// };
2777    ///
2778    /// let mock_server = MatrixMockServer::new().await;
2779    /// let client = mock_server.client_builder().build().await;
2780    ///
2781    /// mock_server.mock_room_state_encryption().plain().mount().await;
2782    ///
2783    /// let room = mock_server.sync_joined_room(&client, room_id!("!room_id:localhost")).await;
2784    ///
2785    /// let event_id = event_id!("$some_id");
2786    ///
2787    /// mock_server
2788    ///     .mock_room_send_state()
2789    ///     .for_key("my_key".to_owned())
2790    ///     .ok(event_id)
2791    ///     .expect(1)
2792    ///     .mount()
2793    ///     .await;
2794    ///
2795    /// let response_not_mocked = room
2796    ///     .send_state_event_for_key(
2797    ///         "",
2798    ///         AnyStateEventContent::CallMember(CallMemberEventContent::new_empty(None)),
2799    ///     )
2800    ///     .await;
2801    /// // The `m.room.reaction` event type should not be mocked by the server.
2802    /// assert!(response_not_mocked.is_err());
2803    ///
2804    /// let response = room
2805    ///     .send_state_event_for_key(
2806    ///         "my_key",
2807    ///         AnyStateEventContent::CallMember(CallMemberEventContent::new_empty(None)),
2808    ///     )
2809    ///     .await
2810    ///     .unwrap();
2811    ///
2812    /// // The `m.room.message` event type should be mocked by the server.
2813    /// assert_eq!(
2814    ///     event_id, response.event_id,
2815    ///     "The event ID we mocked should match the one we received when we sent the event"
2816    /// );
2817    /// # anyhow::Ok(()) });
2818    /// ```
2819    pub fn for_key(mut self, state_key: String) -> Self {
2820        self.endpoint.state_key = Some(state_key);
2821        // Note: we may have already defined a path, but this one ought to be more
2822        // specialized (unless for_key/for_type were called multiple times).
2823        Self { mock: self.mock.and(path_regex(Self::generate_path_regexp(&self.endpoint))), ..self }
2824    }
2825
2826    /// Returns a send endpoint that emulates success, i.e. the event has been
2827    /// sent with the given event id.
2828    ///
2829    /// # Examples
2830    /// ```
2831    /// # tokio_test::block_on(async {
2832    /// use matrix_sdk::{ruma::{room_id, event_id}, test_utils::mocks::MatrixMockServer};
2833    /// use serde_json::json;
2834    ///
2835    /// let mock_server = MatrixMockServer::new().await;
2836    /// let client = mock_server.client_builder().build().await;
2837    ///
2838    /// mock_server.mock_room_state_encryption().plain().mount().await;
2839    ///
2840    /// let room = mock_server
2841    ///     .sync_joined_room(&client, room_id!("!room_id:localhost"))
2842    ///     .await;
2843    ///
2844    /// let event_id = event_id!("$some_id");
2845    /// let send_guard = mock_server
2846    ///     .mock_room_send_state()
2847    ///     .ok(event_id)
2848    ///     .expect(1)
2849    ///     .mount_as_scoped()
2850    ///     .await;
2851    ///
2852    /// let response = room.send_state_event_raw("m.room.message", "my_key", json!({ "body": "Hello world" })).await?;
2853    ///
2854    /// assert_eq!(
2855    ///     event_id,
2856    ///     response.event_id,
2857    ///     "The event ID we mocked should match the one we received when we sent the event"
2858    /// );
2859    /// # anyhow::Ok(()) });
2860    /// ```
2861    pub fn ok(self, returned_event_id: impl Into<OwnedEventId>) -> MatrixMock<'a> {
2862        self.ok_with_event_id(returned_event_id.into())
2863    }
2864}
2865
2866/// A prebuilt mock for running sync v2.
2867pub struct SyncEndpoint {
2868    sync_response_builder: Arc<Mutex<SyncResponseBuilder>>,
2869}
2870
2871impl<'a> MockEndpoint<'a, SyncEndpoint> {
2872    /// Expect the given timeout, or lack thereof, in the request.
2873    pub fn timeout(mut self, timeout: Option<Duration>) -> Self {
2874        if let Some(timeout) = timeout {
2875            self.mock = self.mock.and(query_param("timeout", timeout.as_millis().to_string()));
2876        } else {
2877            self.mock = self.mock.and(query_param_is_missing("timeout"));
2878        }
2879
2880        self
2881    }
2882
2883    /// Expect the given `set_presence` value in the request.
2884    pub fn set_presence(mut self, presence: impl Into<String>) -> Self {
2885        self.mock = self.mock.and(query_param("set_presence", presence.into()));
2886        self
2887    }
2888
2889    /// Expect no explicit `set_presence` value in the request.
2890    pub fn set_presence_missing(mut self) -> Self {
2891        self.mock = self.mock.and(query_param_is_missing("set_presence"));
2892        self
2893    }
2894
2895    /// Mocks the sync endpoint, using the given function to generate the
2896    /// response.
2897    pub fn ok<F: FnOnce(&mut SyncResponseBuilder)>(self, func: F) -> MatrixMock<'a> {
2898        let json_response = {
2899            let mut builder = self.endpoint.sync_response_builder.lock().unwrap();
2900            func(&mut builder);
2901            builder.build_json_sync_response()
2902        };
2903
2904        self.respond_with(ResponseTemplate::new(200).set_body_json(json_response))
2905    }
2906
2907    /// Temporarily mocks the sync with the given endpoint and runs a client
2908    /// sync with it.
2909    ///
2910    /// After calling this function, the sync endpoint isn't mocked anymore.
2911    ///
2912    /// # Examples
2913    ///
2914    /// ```
2915    /// # tokio_test::block_on(async {
2916    /// use matrix_sdk::{ruma::room_id, test_utils::mocks::MatrixMockServer};
2917    /// use matrix_sdk_test::JoinedRoomBuilder;
2918    ///
2919    /// // First create the mock server and client pair.
2920    /// let mock_server = MatrixMockServer::new().await;
2921    /// let client = mock_server.client_builder().build().await;
2922    /// let room_id = room_id!("!room_id:localhost");
2923    ///
2924    /// // Let's emulate what `MatrixMockServer::sync_joined_room()` does.
2925    /// mock_server
2926    ///     .mock_sync()
2927    ///     .ok_and_run(&client, |builder| {
2928    ///         builder.add_joined_room(JoinedRoomBuilder::new(room_id));
2929    ///     })
2930    ///     .await;
2931    ///
2932    /// let room = client
2933    ///     .get_room(room_id)
2934    ///     .expect("The room should be available after we mocked the sync");
2935    /// # anyhow::Ok(()) });
2936    /// ```
2937    pub async fn ok_and_run<F: FnOnce(&mut SyncResponseBuilder)>(self, client: &Client, func: F) {
2938        let _scope = self.ok(func).mount_as_scoped().await;
2939
2940        let _response = client.sync_once(Default::default()).await.unwrap();
2941    }
2942}
2943
2944/// A prebuilt mock for reading the encryption state of a room.
2945pub struct EncryptionStateEndpoint;
2946
2947impl<'a> MockEndpoint<'a, EncryptionStateEndpoint> {
2948    /// Marks the room as encrypted.
2949    ///
2950    /// # Examples
2951    ///
2952    /// ```
2953    /// # tokio_test::block_on(async {
2954    /// use matrix_sdk::{ruma::room_id, test_utils::mocks::MatrixMockServer};
2955    ///
2956    /// let mock_server = MatrixMockServer::new().await;
2957    /// let client = mock_server.client_builder().build().await;
2958    ///
2959    /// mock_server.mock_room_state_encryption().encrypted().mount().await;
2960    ///
2961    /// let room = mock_server
2962    ///     .sync_joined_room(&client, room_id!("!room_id:localhost"))
2963    ///     .await;
2964    ///
2965    /// assert!(
2966    ///     room.latest_encryption_state().await?.is_encrypted(),
2967    ///     "The room should be marked as encrypted."
2968    /// );
2969    /// # anyhow::Ok(()) });
2970    /// ```
2971    pub fn encrypted(self) -> MatrixMock<'a> {
2972        self.respond_with(
2973            ResponseTemplate::new(200)
2974                .set_body_json(EventFactory::new().room_encryption().into_content()),
2975        )
2976    }
2977
2978    /// Marks the room as encrypted, opting into experimental state event
2979    /// encryption.
2980    ///
2981    /// # Examples
2982    ///
2983    /// ```
2984    /// # tokio_test::block_on(async {
2985    /// use matrix_sdk::{ruma::room_id, test_utils::mocks::MatrixMockServer};
2986    ///
2987    /// let mock_server = MatrixMockServer::new().await;
2988    /// let client = mock_server.client_builder().build().await;
2989    ///
2990    /// mock_server.mock_room_state_encryption().state_encrypted().mount().await;
2991    ///
2992    /// let room = mock_server
2993    ///     .sync_joined_room(&client, room_id!("!room_id:localhost"))
2994    ///     .await;
2995    ///
2996    /// assert!(
2997    ///     room.latest_encryption_state().await?.is_state_encrypted(),
2998    ///     "The room should be marked as state encrypted."
2999    /// );
3000    /// # anyhow::Ok(()) });
3001    #[cfg(feature = "experimental-encrypted-state-events")]
3002    pub fn state_encrypted(self) -> MatrixMock<'a> {
3003        self.respond_with(ResponseTemplate::new(200).set_body_json(
3004            EventFactory::new().room_encryption_with_state_encryption().into_content(),
3005        ))
3006    }
3007
3008    /// Marks the room as not encrypted.
3009    ///
3010    /// # Examples
3011    ///
3012    /// ```
3013    /// # tokio_test::block_on(async {
3014    /// use matrix_sdk::{ruma::room_id, test_utils::mocks::MatrixMockServer};
3015    ///
3016    /// let mock_server = MatrixMockServer::new().await;
3017    /// let client = mock_server.client_builder().build().await;
3018    ///
3019    /// mock_server.mock_room_state_encryption().plain().mount().await;
3020    ///
3021    /// let room = mock_server
3022    ///     .sync_joined_room(&client, room_id!("!room_id:localhost"))
3023    ///     .await;
3024    ///
3025    /// assert!(
3026    ///     !room.latest_encryption_state().await?.is_encrypted(),
3027    ///     "The room should not be marked as encrypted."
3028    /// );
3029    /// # anyhow::Ok(()) });
3030    /// ```
3031    pub fn plain(self) -> MatrixMock<'a> {
3032        self.respond_with(ResponseTemplate::new(404).set_body_json(&*test_json::NOT_FOUND))
3033    }
3034}
3035
3036/// A prebuilt mock for setting the encryption state of a room.
3037pub struct SetEncryptionStateEndpoint;
3038
3039impl<'a> MockEndpoint<'a, SetEncryptionStateEndpoint> {
3040    /// Returns a mock for a successful setting of the encryption state event.
3041    pub fn ok(self, returned_event_id: impl Into<OwnedEventId>) -> MatrixMock<'a> {
3042        self.ok_with_event_id(returned_event_id.into())
3043    }
3044}
3045
3046/// A prebuilt mock for redacting an event in a room.
3047pub struct RoomRedactEndpoint;
3048
3049impl<'a> MockEndpoint<'a, RoomRedactEndpoint> {
3050    /// Returns a redact endpoint that emulates success, i.e. the redaction
3051    /// event has been sent with the given event id.
3052    pub fn ok(self, returned_event_id: impl Into<OwnedEventId>) -> MatrixMock<'a> {
3053        self.ok_with_event_id(returned_event_id.into())
3054    }
3055}
3056
3057/// A prebuilt mock for getting a single event in a room.
3058pub struct RoomEventEndpoint {
3059    room: Option<OwnedRoomId>,
3060    match_event_id: bool,
3061}
3062
3063impl<'a> MockEndpoint<'a, RoomEventEndpoint> {
3064    /// Limits the scope of this mock to a specific room.
3065    pub fn room(mut self, room: impl Into<OwnedRoomId>) -> Self {
3066        self.endpoint.room = Some(room.into());
3067        self
3068    }
3069
3070    /// Whether the mock checks for the event id from the event.
3071    pub fn match_event_id(mut self) -> Self {
3072        self.endpoint.match_event_id = true;
3073        self
3074    }
3075
3076    /// Returns a redact endpoint that emulates success, i.e. the redaction
3077    /// event has been sent with the given event id.
3078    pub fn ok(self, event: TimelineEvent) -> MatrixMock<'a> {
3079        let event_path = if self.endpoint.match_event_id {
3080            let event_id = event.event_id().expect("an event id is required");
3081            // The event id should begin with `$`, which would be taken as the end of the
3082            // regex so we need to escape it
3083            event_id.as_str().replace("$", "\\$")
3084        } else {
3085            // Event is at the end, so no need to add anything.
3086            "".to_owned()
3087        };
3088
3089        let room_path = self.endpoint.room.map_or_else(|| ".*".to_owned(), |room| room.to_string());
3090
3091        let mock = self
3092            .mock
3093            .and(path_regex(format!(r"^/_matrix/client/v3/rooms/{room_path}/event/{event_path}")))
3094            .respond_with(ResponseTemplate::new(200).set_body_json(event.into_raw().json()));
3095        MatrixMock { server: self.server, mock }
3096    }
3097
3098    /// Returns a room event endpoint mock with a custom [`ResponseTemplate`].
3099    ///
3100    /// The path restriction is applied automatically. This is useful when you
3101    /// need to configure specific response properties like delays.
3102    pub fn ok_with_template(self, template: ResponseTemplate) -> MatrixMock<'a> {
3103        let room_path = self.endpoint.room.map_or_else(|| ".*".to_owned(), |room| room.to_string());
3104        let mock = self
3105            .mock
3106            .and(path_regex(format!(r"^/_matrix/client/v3/rooms/{room_path}/event/")))
3107            .respond_with(template);
3108        MatrixMock { server: self.server, mock }
3109    }
3110}
3111
3112/// A builder pattern for the response to a [`RoomEventContextEndpoint`]
3113/// request.
3114pub struct RoomContextResponseTemplate {
3115    event: TimelineEvent,
3116    events_before: Vec<TimelineEvent>,
3117    events_after: Vec<TimelineEvent>,
3118    start: Option<String>,
3119    end: Option<String>,
3120    state_events: Vec<Raw<AnyStateEvent>>,
3121}
3122
3123impl RoomContextResponseTemplate {
3124    /// Creates a new context response with the given focused event.
3125    pub fn new(event: TimelineEvent) -> Self {
3126        Self {
3127            event,
3128            events_before: Vec::new(),
3129            events_after: Vec::new(),
3130            start: None,
3131            end: None,
3132            state_events: Vec::new(),
3133        }
3134    }
3135
3136    /// Add some events before the target event.
3137    pub fn events_before(mut self, events: Vec<TimelineEvent>) -> Self {
3138        self.events_before = events;
3139        self
3140    }
3141
3142    /// Add some events after the target event.
3143    pub fn events_after(mut self, events: Vec<TimelineEvent>) -> Self {
3144        self.events_after = events;
3145        self
3146    }
3147
3148    /// Set the start token that could be used for paginating backwards.
3149    pub fn start(mut self, start: impl Into<String>) -> Self {
3150        self.start = Some(start.into());
3151        self
3152    }
3153
3154    /// Set the end token that could be used for paginating forwards.
3155    pub fn end(mut self, end: impl Into<String>) -> Self {
3156        self.end = Some(end.into());
3157        self
3158    }
3159
3160    /// Pass some extra state events to this response.
3161    pub fn state_events(mut self, state_events: Vec<Raw<AnyStateEvent>>) -> Self {
3162        self.state_events = state_events;
3163        self
3164    }
3165}
3166
3167/// A prebuilt mock for getting a single event with its context in a room.
3168pub struct RoomEventContextEndpoint {
3169    room: Option<OwnedRoomId>,
3170    match_event_id: bool,
3171}
3172
3173impl<'a> MockEndpoint<'a, RoomEventContextEndpoint> {
3174    /// Limits the scope of this mock to a specific room.
3175    pub fn room(mut self, room: impl Into<OwnedRoomId>) -> Self {
3176        self.endpoint.room = Some(room.into());
3177        self
3178    }
3179
3180    /// Whether the mock checks for the event id from the event.
3181    pub fn match_event_id(mut self) -> Self {
3182        self.endpoint.match_event_id = true;
3183        self
3184    }
3185
3186    /// Returns an endpoint that emulates a successful response.
3187    pub fn ok(self, response: RoomContextResponseTemplate) -> MatrixMock<'a> {
3188        let event_path = if self.endpoint.match_event_id {
3189            let event_id = response.event.event_id().expect("an event id is required");
3190            // The event id should begin with `$`, which would be taken as the end of the
3191            // regex so we need to escape it
3192            event_id.as_str().replace("$", "\\$")
3193        } else {
3194            // Event is at the end, so no need to add anything.
3195            "".to_owned()
3196        };
3197
3198        let room_path = self.endpoint.room.map_or_else(|| ".*".to_owned(), |room| room.to_string());
3199
3200        let mock = self
3201            .mock
3202            .and(path_regex(format!(r"^/_matrix/client/v3/rooms/{room_path}/context/{event_path}")))
3203            .respond_with(ResponseTemplate::new(200).set_body_json(json!({
3204                "event": response.event.into_raw().json(),
3205                "events_before": response.events_before.into_iter().map(|event| event.into_raw().json().to_owned()).collect::<Vec<_>>(),
3206                "events_after": response.events_after.into_iter().map(|event| event.into_raw().json().to_owned()).collect::<Vec<_>>(),
3207                "end": response.end,
3208                "start": response.start,
3209                "state": response.state_events,
3210            })));
3211        MatrixMock { server: self.server, mock }
3212    }
3213}
3214
3215/// A prebuilt mock for the `/messages` endpoint.
3216pub struct RoomMessagesEndpoint;
3217
3218/// A prebuilt mock for getting a room messages in a room.
3219impl<'a> MockEndpoint<'a, RoomMessagesEndpoint> {
3220    /// Expects an optional limit to be set on the request.
3221    pub fn match_limit(self, limit: u32) -> Self {
3222        Self { mock: self.mock.and(query_param("limit", limit.to_string())), ..self }
3223    }
3224
3225    /// Expects an optional `from` to be set on the request.
3226    pub fn match_from(self, from: &str) -> Self {
3227        Self { mock: self.mock.and(query_param("from", from)), ..self }
3228    }
3229
3230    /// Returns a messages endpoint that emulates success, i.e. the messages
3231    /// provided as `response` could be retrieved.
3232    ///
3233    /// Note: pass `chunk` in the correct order: topological for forward
3234    /// pagination, reverse topological for backwards pagination.
3235    pub fn ok(self, response: RoomMessagesResponseTemplate) -> MatrixMock<'a> {
3236        let mut template = ResponseTemplate::new(200).set_body_json(json!({
3237            "start": response.start,
3238            "end": response.end,
3239            "chunk": response.chunk,
3240            "state": response.state,
3241        }));
3242
3243        if let Some(delay) = response.delay {
3244            template = template.set_delay(delay);
3245        }
3246
3247        self.respond_with(template)
3248    }
3249}
3250
3251/// A response to a [`RoomMessagesEndpoint`] query.
3252pub struct RoomMessagesResponseTemplate {
3253    /// The start token for this /messages query.
3254    pub start: String,
3255    /// The end token for this /messages query (previous batch for back
3256    /// paginations, next batch for forward paginations).
3257    pub end: Option<String>,
3258    /// The set of timeline events returned by this query.
3259    pub chunk: Vec<Raw<AnyTimelineEvent>>,
3260    /// The set of state events returned by this query.
3261    pub state: Vec<Raw<AnyStateEvent>>,
3262    /// Optional delay to respond to the query.
3263    pub delay: Option<Duration>,
3264}
3265
3266impl RoomMessagesResponseTemplate {
3267    /// Fill the events returned as part of this response.
3268    pub fn events(mut self, chunk: Vec<impl Into<Raw<AnyTimelineEvent>>>) -> Self {
3269        self.chunk = chunk.into_iter().map(Into::into).collect();
3270        self
3271    }
3272
3273    /// Fill the end token.
3274    pub fn end_token(mut self, token: impl Into<String>) -> Self {
3275        self.end = Some(token.into());
3276        self
3277    }
3278
3279    /// Respond with a given delay to the query.
3280    pub fn with_delay(mut self, delay: Duration) -> Self {
3281        self.delay = Some(delay);
3282        self
3283    }
3284}
3285
3286impl Default for RoomMessagesResponseTemplate {
3287    fn default() -> Self {
3288        Self {
3289            start: "start-token-unused".to_owned(),
3290            end: Default::default(),
3291            chunk: Default::default(),
3292            state: Default::default(),
3293            delay: None,
3294        }
3295    }
3296}
3297
3298/// A prebuilt mock for uploading media.
3299pub struct UploadEndpoint;
3300
3301impl<'a> MockEndpoint<'a, UploadEndpoint> {
3302    /// Expect that the content type matches what's given here.
3303    pub fn expect_mime_type(self, content_type: &str) -> Self {
3304        Self { mock: self.mock.and(header("content-type", content_type)), ..self }
3305    }
3306
3307    /// Returns a upload endpoint that emulates success, i.e. the media has been
3308    /// uploaded to the media server and can be accessed using the given
3309    /// event has been sent with the given [`MxcUri`].
3310    ///
3311    /// The uploaded content is captured and can be accessed using the returned
3312    /// [`Receiver`]. The [`Receiver`] is valid only for a single media
3313    /// upload.
3314    ///
3315    /// # Examples
3316    ///
3317    /// ```no_run
3318    /// # tokio_test::block_on(async {
3319    /// use matrix_sdk::{
3320    ///     ruma::{event_id, mxc_uri, room_id},
3321    ///     test_utils::mocks::MatrixMockServer,
3322    /// };
3323    ///
3324    /// let mxid = mxc_uri!("mxc://localhost/12345");
3325    ///
3326    /// let server = MatrixMockServer::new().await;
3327    /// let (receiver, upload_mock) = server.mock_upload().ok_with_capture(mxid);
3328    /// let client = server.client_builder().build().await;
3329    ///
3330    /// client.media().upload(&mime::TEXT_PLAIN, vec![1, 2, 3, 4, 5], None).await?;
3331    ///
3332    /// let uploaded = receiver.await?;
3333    ///
3334    /// assert_eq!(uploaded, vec![1, 2, 3, 4, 5]);
3335    /// # anyhow::Ok(()) });
3336    /// ```
3337    pub fn ok_with_capture(self, mxc_id: &MxcUri) -> (Receiver<Vec<u8>>, MatrixMock<'a>) {
3338        let (sender, receiver) = oneshot::channel();
3339        let sender = Arc::new(Mutex::new(Some(sender)));
3340        let response_body = json!({"content_uri": mxc_id});
3341
3342        let ret = self.respond_with(move |request: &Request| {
3343            let maybe_sender = sender.lock().unwrap().take();
3344
3345            if let Some(sender) = maybe_sender {
3346                let body = request.body.clone();
3347                let _ = sender.send(body);
3348            }
3349
3350            ResponseTemplate::new(200).set_body_json(response_body.clone())
3351        });
3352
3353        (receiver, ret)
3354    }
3355
3356    /// Returns a upload endpoint that emulates success, i.e. the media has been
3357    /// uploaded to the media server and can be accessed using the given
3358    /// event has been sent with the given [`MxcUri`].
3359    pub fn ok(self, mxc_id: &MxcUri) -> MatrixMock<'a> {
3360        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
3361            "content_uri": mxc_id
3362        })))
3363    }
3364}
3365
3366/// A prebuilt mock for resolving a room alias.
3367pub struct ResolveRoomAliasEndpoint;
3368
3369impl<'a> MockEndpoint<'a, ResolveRoomAliasEndpoint> {
3370    /// Sets up the endpoint to only intercept requests for the given room
3371    /// alias.
3372    pub fn for_alias(self, alias: impl Into<String>) -> Self {
3373        let alias = alias.into();
3374        Self {
3375            mock: self.mock.and(path_regex(format!(
3376                r"^/_matrix/client/v3/directory/room/{}",
3377                percent_encoded_path(&alias)
3378            ))),
3379            ..self
3380        }
3381    }
3382
3383    /// Returns a data endpoint with a resolved room alias.
3384    pub fn ok(self, room_id: &str, servers: Vec<String>) -> MatrixMock<'a> {
3385        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
3386            "room_id": room_id,
3387            "servers": servers,
3388        })))
3389    }
3390
3391    /// Returns a data endpoint for a room alias that does not exit.
3392    pub fn not_found(self) -> MatrixMock<'a> {
3393        self.respond_with(ResponseTemplate::new(404).set_body_json(json!({
3394          "errcode": "M_NOT_FOUND",
3395          "error": "Room alias not found."
3396        })))
3397    }
3398}
3399
3400/// A prebuilt mock for creating a room alias.
3401pub struct CreateRoomAliasEndpoint;
3402
3403impl<'a> MockEndpoint<'a, CreateRoomAliasEndpoint> {
3404    /// Returns a data endpoint for creating a room alias.
3405    pub fn ok(self) -> MatrixMock<'a> {
3406        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({})))
3407    }
3408}
3409
3410/// A prebuilt mock for removing a room alias.
3411pub struct RemoveRoomAliasEndpoint;
3412
3413impl<'a> MockEndpoint<'a, RemoveRoomAliasEndpoint> {
3414    /// Returns a data endpoint for removing a room alias.
3415    pub fn ok(self) -> MatrixMock<'a> {
3416        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({})))
3417    }
3418}
3419
3420/// A prebuilt mock for paginating the public room list.
3421pub struct PublicRoomsEndpoint;
3422
3423impl<'a> MockEndpoint<'a, PublicRoomsEndpoint> {
3424    /// Returns a data endpoint for paginating the public room list.
3425    pub fn ok(
3426        self,
3427        chunk: Vec<PublicRoomsChunk>,
3428        next_batch: Option<String>,
3429        prev_batch: Option<String>,
3430        total_room_count_estimate: Option<u64>,
3431    ) -> MatrixMock<'a> {
3432        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
3433            "chunk": chunk,
3434            "next_batch": next_batch,
3435            "prev_batch": prev_batch,
3436            "total_room_count_estimate": total_room_count_estimate,
3437        })))
3438    }
3439
3440    /// Returns a data endpoint for paginating the public room list with several
3441    /// `via` params.
3442    ///
3443    /// Each `via` param must be in the `server_map` parameter, otherwise it'll
3444    /// fail.
3445    pub fn ok_with_via_params(
3446        self,
3447        server_map: BTreeMap<OwnedServerName, Vec<PublicRoomsChunk>>,
3448    ) -> MatrixMock<'a> {
3449        self.respond_with(move |req: &Request| {
3450            #[derive(Deserialize)]
3451            struct PartialRequest {
3452                server: Option<OwnedServerName>,
3453            }
3454
3455            let (_, server) = req
3456                .url
3457                .query_pairs()
3458                .into_iter()
3459                .find(|(key, _)| key == "server")
3460                .expect("Server param not found in request URL");
3461            let server = ServerName::parse(server).expect("Couldn't parse server name");
3462            let chunk = server_map.get(&server).expect("Chunk for the server param not found");
3463            ResponseTemplate::new(200).set_body_json(json!({
3464                "chunk": chunk,
3465                "total_room_count_estimate": chunk.len(),
3466            }))
3467        })
3468    }
3469}
3470
3471/// A prebuilt mock for getting the room's visibility in the room directory.
3472pub struct GetRoomVisibilityEndpoint;
3473
3474impl<'a> MockEndpoint<'a, GetRoomVisibilityEndpoint> {
3475    /// Returns an endpoint that get the room's public visibility.
3476    pub fn ok(self, visibility: Visibility) -> MatrixMock<'a> {
3477        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
3478            "visibility": visibility,
3479        })))
3480    }
3481}
3482
3483/// A prebuilt mock for setting the room's visibility in the room directory.
3484pub struct SetRoomVisibilityEndpoint;
3485
3486impl<'a> MockEndpoint<'a, SetRoomVisibilityEndpoint> {
3487    /// Returns an endpoint that updates the room's visibility.
3488    pub fn ok(self) -> MatrixMock<'a> {
3489        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({})))
3490    }
3491}
3492
3493/// A prebuilt mock for `GET room_keys/version`: storage ("backup") of room
3494/// keys.
3495pub struct RoomKeysVersionEndpoint;
3496
3497impl<'a> MockEndpoint<'a, RoomKeysVersionEndpoint> {
3498    /// Returns an endpoint that says there is a single room keys backup
3499    pub fn exists(self) -> 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": "abcdefg",
3504                "signatures": {},
3505            },
3506            "count": 42,
3507            "etag": "anopaquestring",
3508            "version": "1",
3509        })))
3510    }
3511
3512    /// Returns an endpoint that says there is a single room keys backup
3513    pub fn exists_with_key(self, public_key: &str) -> MatrixMock<'a> {
3514        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
3515            "algorithm": "m.megolm_backup.v1.curve25519-aes-sha2",
3516            "auth_data": {
3517                "public_key": public_key,
3518                "signatures": {},
3519            },
3520            "count": 42,
3521            "etag": "anopaquestring",
3522            "version": "1",
3523        })))
3524    }
3525
3526    /// Returns an endpoint that says there is no room keys backup
3527    pub fn none(self) -> MatrixMock<'a> {
3528        self.respond_with(ResponseTemplate::new(404).set_body_json(json!({
3529            "errcode": "M_NOT_FOUND",
3530            "error": "No current backup version"
3531        })))
3532    }
3533
3534    /// Returns an endpoint that 429 errors when we get it
3535    pub fn error429(self) -> MatrixMock<'a> {
3536        self.respond_with(ResponseTemplate::new(429).set_body_json(json!({
3537            "errcode": "M_LIMIT_EXCEEDED",
3538            "error": "Too many requests",
3539            "retry_after_ms": 2000
3540        })))
3541    }
3542
3543    /// Returns an endpoint that 404 errors when we get it
3544    pub fn error404(self) -> MatrixMock<'a> {
3545        self.respond_with(ResponseTemplate::new(404))
3546    }
3547}
3548
3549/// A prebuilt mock for `POST room_keys/version`: adding room key backups.
3550pub struct AddRoomKeysVersionEndpoint;
3551
3552impl<'a> MockEndpoint<'a, AddRoomKeysVersionEndpoint> {
3553    /// Returns an endpoint that may be used to add room key backups
3554    pub fn ok(self) -> MatrixMock<'a> {
3555        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
3556          "version": "1"
3557        })))
3558        .named("POST for the backup creation")
3559    }
3560}
3561
3562/// A prebuilt mock for `DELETE room_keys/version/xxx`: deleting room key
3563/// backups.
3564pub struct DeleteRoomKeysVersionEndpoint;
3565
3566impl<'a> MockEndpoint<'a, DeleteRoomKeysVersionEndpoint> {
3567    /// Returns an endpoint that allows deleting room key backups
3568    pub fn ok(self) -> MatrixMock<'a> {
3569        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({})))
3570            .named("DELETE for the backup deletion")
3571    }
3572}
3573
3574/// A prebuilt mock for the `/sendToDevice` endpoint.
3575///
3576/// This mock can be used to simulate sending to-device messages in tests.
3577pub struct SendToDeviceEndpoint;
3578impl<'a> MockEndpoint<'a, SendToDeviceEndpoint> {
3579    /// Returns a successful response with default data.
3580    pub fn ok(self) -> MatrixMock<'a> {
3581        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({})))
3582    }
3583}
3584
3585/// A prebuilt mock for `GET /members` request.
3586pub struct GetRoomMembersEndpoint;
3587
3588impl<'a> MockEndpoint<'a, GetRoomMembersEndpoint> {
3589    /// Returns a successful get members request with a list of members.
3590    pub fn ok(self, members: Vec<Raw<RoomMemberEvent>>) -> MatrixMock<'a> {
3591        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
3592            "chunk": members,
3593        })))
3594    }
3595}
3596
3597/// A prebuilt mock for `POST /invite` request.
3598pub struct InviteUserByIdEndpoint;
3599
3600impl<'a> MockEndpoint<'a, InviteUserByIdEndpoint> {
3601    /// Returns a successful invite user by id request.
3602    pub fn ok(self) -> MatrixMock<'a> {
3603        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({})))
3604    }
3605}
3606
3607/// A prebuilt mock for `POST /kick` request.
3608pub struct KickUserEndpoint;
3609
3610impl<'a> MockEndpoint<'a, KickUserEndpoint> {
3611    /// Returns a successful kick user request.
3612    pub fn ok(self) -> MatrixMock<'a> {
3613        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({})))
3614    }
3615}
3616
3617/// A prebuilt mock for `POST /ban` request.
3618pub struct BanUserEndpoint;
3619
3620impl<'a> MockEndpoint<'a, BanUserEndpoint> {
3621    /// Returns a successful ban user request.
3622    pub fn ok(self) -> MatrixMock<'a> {
3623        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({})))
3624    }
3625}
3626
3627/// A prebuilt mock for `GET /versions` request.
3628pub struct VersionsEndpoint {
3629    versions: Vec<&'static str>,
3630    features: BTreeMap<&'static str, bool>,
3631}
3632
3633impl VersionsEndpoint {
3634    // Get a JSON array of commonly supported versions.
3635    fn commonly_supported_versions() -> Vec<&'static str> {
3636        vec![
3637            "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",
3638            "v1.3", "v1.4", "v1.5", "v1.6", "v1.7", "v1.8", "v1.9", "v1.10", "v1.11",
3639        ]
3640    }
3641}
3642
3643impl Default for VersionsEndpoint {
3644    fn default() -> Self {
3645        Self { versions: Self::commonly_supported_versions(), features: BTreeMap::new() }
3646    }
3647}
3648
3649impl<'a> MockEndpoint<'a, VersionsEndpoint> {
3650    /// Returns a successful `/_matrix/client/versions` request.
3651    ///
3652    /// The response will return some commonly supported versions.
3653    pub fn ok(mut self) -> MatrixMock<'a> {
3654        let features = std::mem::take(&mut self.endpoint.features);
3655        let versions = std::mem::take(&mut self.endpoint.versions);
3656        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
3657            "unstable_features": features,
3658            "versions": versions
3659        })))
3660    }
3661
3662    /// Set the supported flag for the given unstable feature in the response of
3663    /// this endpoint.
3664    pub fn with_feature(mut self, feature: &'static str, supported: bool) -> Self {
3665        self.endpoint.features.insert(feature, supported);
3666        self
3667    }
3668
3669    /// Indicate that push for encrypted events is supported by this homeserver.
3670    pub fn with_push_encrypted_events(self) -> Self {
3671        self.with_feature("org.matrix.msc4028", true)
3672    }
3673
3674    /// Indicate that thread subscriptions are supported by this homeserver.
3675    pub fn with_thread_subscriptions(self) -> Self {
3676        self.with_feature("org.matrix.msc4306", true)
3677    }
3678
3679    /// Indicate that simplified sliding sync is supported by this homeserver.
3680    pub fn with_simplified_sliding_sync(self) -> Self {
3681        self.with_feature("org.matrix.simplified_msc3575", true)
3682    }
3683
3684    /// Indicate that global profile sync is supported by this homeserver.
3685    pub fn with_profiles_sliding_sync_extension(self) -> Self {
3686        self.with_feature("org.matrix.msc4262", true)
3687    }
3688
3689    /// Set the supported versions in the response of this endpoint.
3690    pub fn with_versions(mut self, versions: Vec<&'static str>) -> Self {
3691        self.endpoint.versions = versions;
3692        self
3693    }
3694}
3695
3696/// A prebuilt mock for the room summary endpoint.
3697pub struct RoomSummaryEndpoint;
3698
3699impl<'a> MockEndpoint<'a, RoomSummaryEndpoint> {
3700    /// Returns a successful response with some default data for the given room
3701    /// id.
3702    pub fn ok(self, room_id: &RoomId) -> MatrixMock<'a> {
3703        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
3704            "room_id": room_id,
3705            "guest_can_join": true,
3706            "num_joined_members": 1,
3707            "world_readable": true,
3708            "join_rule": "public",
3709        })))
3710    }
3711}
3712
3713/// A prebuilt mock to set a room's pinned events.
3714pub struct SetRoomPinnedEventsEndpoint;
3715
3716impl<'a> MockEndpoint<'a, SetRoomPinnedEventsEndpoint> {
3717    /// Returns a successful response with a given event id.
3718    /// id.
3719    pub fn ok(self, event_id: OwnedEventId) -> MatrixMock<'a> {
3720        self.ok_with_event_id(event_id)
3721    }
3722
3723    /// Returns an error response with a generic error code indicating the
3724    /// client is not authorized to set pinned events.
3725    pub fn unauthorized(self) -> MatrixMock<'a> {
3726        self.respond_with(ResponseTemplate::new(400))
3727    }
3728}
3729
3730/// A prebuilt mock for `GET /account/whoami` request.
3731pub struct WhoAmIEndpoint;
3732
3733impl<'a> MockEndpoint<'a, WhoAmIEndpoint> {
3734    /// Returns a successful response with the default device ID.
3735    pub fn ok(self) -> MatrixMock<'a> {
3736        self.ok_with_device_id(device_id!("D3V1C31D"))
3737    }
3738
3739    /// Returns a successful response with the given device ID.
3740    pub fn ok_with_device_id(self, device_id: &DeviceId) -> MatrixMock<'a> {
3741        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
3742            "user_id": "@joe:example.org",
3743            "device_id": device_id,
3744        })))
3745    }
3746}
3747
3748/// A prebuilt mock for `POST /keys/upload` request.
3749pub struct UploadKeysEndpoint;
3750
3751impl<'a> MockEndpoint<'a, UploadKeysEndpoint> {
3752    /// Returns a successful response with counts of 10 curve25519 keys and 20
3753    /// signed curve25519 keys.
3754    pub fn ok(self) -> MatrixMock<'a> {
3755        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
3756            "one_time_key_counts": {
3757                "curve25519": 10,
3758                "signed_curve25519": 20,
3759            },
3760        })))
3761    }
3762
3763    /// Returns a successful response with the given number of signed curve25519
3764    /// one-time keys.
3765    pub fn ok_with_signed_curve_key_count(self, n: u32) -> MatrixMock<'a> {
3766        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
3767            "one_time_key_counts": {
3768                "signed_curve25519": n,
3769            },
3770        })))
3771    }
3772}
3773
3774/// A prebuilt mock for `POST /keys/query` request.
3775pub struct QueryKeysEndpoint;
3776
3777impl<'a> MockEndpoint<'a, QueryKeysEndpoint> {
3778    /// Returns a successful empty response.
3779    pub fn ok(self) -> MatrixMock<'a> {
3780        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({})))
3781    }
3782}
3783
3784/// A prebuilt mock for `GET /.well-known/matrix/client` request.
3785pub struct WellKnownEndpoint;
3786
3787impl<'a> MockEndpoint<'a, WellKnownEndpoint> {
3788    /// Returns a successful response with the URL for this homeserver.
3789    pub fn ok(self) -> MatrixMock<'a> {
3790        let server_uri = self.server.uri();
3791        self.ok_with_homeserver_url(&server_uri)
3792    }
3793
3794    /// Returns a successful response with the given homeserver URL.
3795    pub fn ok_with_homeserver_url(self, homeserver_url: &str) -> MatrixMock<'a> {
3796        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
3797            "m.homeserver": {
3798                "base_url": homeserver_url,
3799            },
3800            "m.rtc_foci": [
3801                {
3802                    "type": "livekit",
3803                    "livekit_service_url": "https://livekit.example.com",
3804                },
3805            ],
3806        })))
3807    }
3808
3809    /// Returns a 404 error response.
3810    pub fn error404(self) -> MatrixMock<'a> {
3811        self.respond_with(ResponseTemplate::new(404))
3812    }
3813}
3814
3815/// A prebuilt mock for `POST /keys/device_signing/upload` request.
3816pub struct UploadCrossSigningKeysEndpoint;
3817
3818impl<'a> MockEndpoint<'a, UploadCrossSigningKeysEndpoint> {
3819    /// Returns a successful empty response.
3820    pub fn ok(self) -> MatrixMock<'a> {
3821        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({})))
3822    }
3823
3824    /// Returns an error response with a UIAA stage that failed to authenticate
3825    /// because of an invalid password.
3826    pub fn uiaa_invalid_password(self) -> MatrixMock<'a> {
3827        self.respond_with(ResponseTemplate::new(401).set_body_json(json!({
3828            "errcode": "M_FORBIDDEN",
3829            "error": "Invalid password",
3830            "flows": [
3831                {
3832                    "stages": [
3833                        "m.login.password"
3834                    ]
3835                }
3836            ],
3837            "params": {},
3838            "session": "oFIJVvtEOCKmRUTYKTYIIPHL"
3839        })))
3840    }
3841
3842    /// Returns an error response with a UIAA stage.
3843    pub fn uiaa(self) -> MatrixMock<'a> {
3844        self.respond_with(ResponseTemplate::new(401).set_body_json(json!({
3845            "flows": [
3846                {
3847                    "stages": [
3848                        "m.login.password"
3849                    ]
3850                }
3851            ],
3852            "params": {},
3853            "session": "oFIJVvtEOCKmRUTYKTYIIPHL"
3854        })))
3855    }
3856
3857    /// Returns an error response with an unstable OAuth 2.0 UIAA stage.
3858    pub fn uiaa_unstable_oauth(self) -> MatrixMock<'a> {
3859        let server_uri = self.server.uri();
3860        self.respond_with(ResponseTemplate::new(401).set_body_json(json!({
3861            "session": "dummy",
3862            "flows": [{
3863                "stages": [ "org.matrix.cross_signing_reset" ]
3864            }],
3865            "params": {
3866                "org.matrix.cross_signing_reset": {
3867                    "url": format!("{server_uri}/account/?action=org.matrix.cross_signing_reset"),
3868                }
3869            },
3870            "msg": "To reset your end-to-end encryption cross-signing identity, you first need to approve it and then try again."
3871        })))
3872    }
3873
3874    /// Returns an error response with a stable OAuth 2.0 UIAA stage with the
3875    /// given session key and optional extra error message.
3876    pub fn uiaa_stable_oauth(
3877        self,
3878        session: &str,
3879        extra_error: Option<&StandardErrorBody>,
3880    ) -> MatrixMock<'a> {
3881        let mut json = json!({
3882            "session": session,
3883            "flows": [{
3884                "stages": [ "m.oauth" ]
3885            }],
3886            "params": {
3887                "m.oauth": {
3888                    "url": format!("{}/account/?action=org.matrix.cross_signing_reset", self.server.uri()),
3889                }
3890            },
3891            "msg": "To reset your end-to-end encryption cross-signing identity, you first need to approve it and then try again."
3892        });
3893
3894        if let Some(extra_error) = extra_error {
3895            let extra_json = as_variant!(
3896                serde_json::to_value(extra_error)
3897                    .expect("extra error should serialize successfully"),
3898                Value::Object
3899            )
3900            .expect("extra error should be a JSON object");
3901
3902            let json_object = json.as_object_mut().expect("UIAA response should be a JSON object");
3903            json_object.extend(extra_json);
3904        }
3905
3906        self.respond_with(ResponseTemplate::new(401).set_body_json(json))
3907    }
3908}
3909
3910/// A prebuilt mock for `POST /keys/signatures/upload` request.
3911pub struct UploadCrossSigningSignaturesEndpoint;
3912
3913impl<'a> MockEndpoint<'a, UploadCrossSigningSignaturesEndpoint> {
3914    /// Returns a successful empty response.
3915    pub fn ok(self) -> MatrixMock<'a> {
3916        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({})))
3917    }
3918}
3919
3920/// A prebuilt mock for the MSC3814 `GET /dehydrated_device` request.
3921#[cfg(feature = "e2e-encryption")]
3922pub struct GetDehydratedDeviceEndpoint;
3923
3924#[cfg(feature = "e2e-encryption")]
3925impl<'a> MockEndpoint<'a, GetDehydratedDeviceEndpoint> {
3926    /// Returns a successful response carrying the given dehydrated device.
3927    pub fn ok(self, device_id: &DeviceId, device_data: Value) -> MatrixMock<'a> {
3928        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
3929            "device_id": device_id,
3930            "device_data": device_data,
3931        })))
3932    }
3933
3934    /// Returns a 404 response with `M_NOT_FOUND`, signalling that no device
3935    /// is currently dehydrated for the user.
3936    pub fn not_found(self) -> MatrixMock<'a> {
3937        self.respond_with(ResponseTemplate::new(404).set_body_json(json!({
3938            "errcode": "M_NOT_FOUND",
3939            "error": "No dehydrated device found",
3940        })))
3941    }
3942}
3943
3944/// A prebuilt mock for the MSC3814 `PUT /dehydrated_device` request.
3945#[cfg(feature = "e2e-encryption")]
3946pub struct PutDehydratedDeviceEndpoint;
3947
3948#[cfg(feature = "e2e-encryption")]
3949impl<'a> MockEndpoint<'a, PutDehydratedDeviceEndpoint> {
3950    /// Returns a successful response echoing the supplied device ID.
3951    pub fn ok(self, device_id: &DeviceId) -> MatrixMock<'a> {
3952        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
3953            "device_id": device_id,
3954        })))
3955    }
3956
3957    /// Returns a successful response, computing the response body from the
3958    /// `device_id` field in the request payload. Useful when the caller does
3959    /// not know the device ID ahead of time.
3960    pub fn ok_echo(self) -> MatrixMock<'a> {
3961        self.respond_with(|req: &Request| {
3962            #[derive(serde::Deserialize)]
3963            struct Body {
3964                device_id: OwnedDeviceId,
3965            }
3966            let body: Body = req.body_json().expect("dehydrated device PUT body");
3967            ResponseTemplate::new(200).set_body_json(json!({ "device_id": body.device_id }))
3968        })
3969    }
3970}
3971
3972/// A prebuilt mock for the MSC3814 `DELETE /dehydrated_device` request.
3973#[cfg(feature = "e2e-encryption")]
3974pub struct DeleteDehydratedDeviceEndpoint;
3975
3976#[cfg(feature = "e2e-encryption")]
3977impl<'a> MockEndpoint<'a, DeleteDehydratedDeviceEndpoint> {
3978    /// Returns a successful response echoing the deleted device ID.
3979    pub fn ok(self, device_id: &DeviceId) -> MatrixMock<'a> {
3980        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
3981            "device_id": device_id,
3982        })))
3983    }
3984
3985    /// Returns a 404 with `M_NOT_FOUND`.
3986    pub fn not_found(self) -> MatrixMock<'a> {
3987        self.respond_with(ResponseTemplate::new(404).set_body_json(json!({
3988            "errcode": "M_NOT_FOUND",
3989            "error": "No dehydrated device to delete",
3990        })))
3991    }
3992}
3993
3994/// A prebuilt mock for the MSC3814
3995/// `POST /dehydrated_device/{device_id}/events` request.
3996#[cfg(feature = "e2e-encryption")]
3997pub struct DehydratedDeviceEventsEndpoint;
3998
3999#[cfg(feature = "e2e-encryption")]
4000impl<'a> MockEndpoint<'a, DehydratedDeviceEventsEndpoint> {
4001    /// Returns a successful response with the supplied events array and an
4002    /// optional pagination cursor.
4003    pub fn ok(self, events: Vec<Value>, next_batch: Option<&str>) -> MatrixMock<'a> {
4004        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
4005            "events": events,
4006            "next_batch": next_batch,
4007        })))
4008    }
4009
4010    /// Constrain the mock to only match requests whose `next_batch` body field
4011    /// equals the given token. Pair with [`Self::match_missing_next_batch`]
4012    /// for the initial request in a paginated flow.
4013    pub fn match_next_batch(mut self, token: &str) -> Self {
4014        self.mock = self.mock.and(body_partial_json(json!({ "next_batch": token })));
4015        self
4016    }
4017
4018    /// Constrain the mock to only match requests whose body has no
4019    /// `next_batch` field (i.e. the first call in a paginated flow).
4020    pub fn match_missing_next_batch(mut self) -> Self {
4021        self.mock = self.mock.and(body_json(json!({})));
4022        self
4023    }
4024}
4025
4026/// A prebuilt mock for the room leave endpoint.
4027pub struct RoomLeaveEndpoint;
4028
4029impl<'a> MockEndpoint<'a, RoomLeaveEndpoint> {
4030    /// Returns a successful response with some default data for the given room
4031    /// id.
4032    pub fn ok(self, room_id: &RoomId) -> MatrixMock<'a> {
4033        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
4034            "room_id": room_id,
4035        })))
4036    }
4037
4038    /// Returns a `M_FORBIDDEN` response.
4039    pub fn forbidden(self) -> MatrixMock<'a> {
4040        self.respond_with(ResponseTemplate::new(403).set_body_json(json!({
4041            "errcode": "M_FORBIDDEN",
4042            "error": "sowwy",
4043        })))
4044    }
4045}
4046
4047/// A prebuilt mock for the room forget endpoint.
4048pub struct RoomForgetEndpoint;
4049
4050impl<'a> MockEndpoint<'a, RoomForgetEndpoint> {
4051    /// Returns a successful response with some default data for the given room
4052    /// id.
4053    pub fn ok(self) -> MatrixMock<'a> {
4054        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({})))
4055    }
4056}
4057
4058/// A prebuilt mock for `POST /logout` request.
4059pub struct LogoutEndpoint;
4060
4061impl<'a> MockEndpoint<'a, LogoutEndpoint> {
4062    /// Returns a successful empty response.
4063    pub fn ok(self) -> MatrixMock<'a> {
4064        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({})))
4065    }
4066}
4067
4068/// A prebuilt mock for a `GET /rooms/{roomId}/threads` request.
4069pub struct RoomThreadsEndpoint;
4070
4071impl<'a> MockEndpoint<'a, RoomThreadsEndpoint> {
4072    /// Expects an optional `from` to be set on the request.
4073    pub fn match_from(self, from: &str) -> Self {
4074        Self { mock: self.mock.and(query_param("from", from)), ..self }
4075    }
4076
4077    /// Returns a successful response with some optional events and previous
4078    /// batch token.
4079    pub fn ok(
4080        self,
4081        chunk: Vec<Raw<AnyTimelineEvent>>,
4082        next_batch: Option<String>,
4083    ) -> MatrixMock<'a> {
4084        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
4085            "chunk": chunk,
4086            "next_batch": next_batch
4087        })))
4088    }
4089}
4090
4091/// A prebuilt mock for a `GET /rooms/{roomId}/relations/{eventId}` family of
4092/// requests.
4093#[derive(Default)]
4094pub struct RoomRelationsEndpoint {
4095    event_id: Option<OwnedEventId>,
4096    spec: Option<IncludeRelations>,
4097}
4098
4099impl<'a> MockEndpoint<'a, RoomRelationsEndpoint> {
4100    /// Expects an optional `from` to be set on the request.
4101    pub fn match_from(self, from: &str) -> Self {
4102        Self { mock: self.mock.and(query_param("from", from)), ..self }
4103    }
4104
4105    /// Expects an optional `limit` to be set on the request.
4106    pub fn match_limit(self, limit: u32) -> Self {
4107        Self { mock: self.mock.and(query_param("limit", limit.to_string())), ..self }
4108    }
4109
4110    /// Match the given subrequest, according to the given specification.
4111    pub fn match_subrequest(mut self, spec: IncludeRelations) -> Self {
4112        self.endpoint.spec = Some(spec);
4113        self
4114    }
4115
4116    /// Expects the request to match a specific event id.
4117    pub fn match_target_event(mut self, event_id: OwnedEventId) -> Self {
4118        self.endpoint.event_id = Some(event_id);
4119        self
4120    }
4121
4122    /// Returns a successful response with some optional events and pagination
4123    /// tokens.
4124    pub fn ok(mut self, response: RoomRelationsResponseTemplate) -> MatrixMock<'a> {
4125        // Escape the leading $ to not confuse the regular expression engine.
4126        let event_spec = self
4127            .endpoint
4128            .event_id
4129            .take()
4130            .map(|event_id| event_id.as_str().replace("$", "\\$"))
4131            .unwrap_or_else(|| ".*".to_owned());
4132
4133        match self.endpoint.spec.take() {
4134            Some(IncludeRelations::RelationsOfType(rel_type)) => {
4135                self.mock = self.mock.and(path_regex(format!(
4136                    r"^/_matrix/client/v1/rooms/.*/relations/{event_spec}/{rel_type}$"
4137                )));
4138            }
4139            Some(IncludeRelations::RelationsOfTypeAndEventType(rel_type, event_type)) => {
4140                self.mock = self.mock.and(path_regex(format!(
4141                    r"^/_matrix/client/v1/rooms/.*/relations/{event_spec}/{rel_type}/{event_type}$"
4142                )));
4143            }
4144            _ => {
4145                self.mock = self.mock.and(path_regex(format!(
4146                    r"^/_matrix/client/v1/rooms/.*/relations/{event_spec}",
4147                )));
4148            }
4149        }
4150
4151        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
4152            "chunk": response.chunk,
4153            "next_batch": response.next_batch,
4154            "prev_batch": response.prev_batch,
4155            "recursion_depth": response.recursion_depth,
4156        })))
4157    }
4158}
4159
4160/// Helper function to set up a [`MockBuilder`] so it intercepts the account
4161/// data URLs.
4162fn global_account_data_mock_builder(
4163    builder: MockBuilder,
4164    user_id: &UserId,
4165    event_type: GlobalAccountDataEventType,
4166) -> MockBuilder {
4167    builder
4168        .and(path_regex(format!(r"^/_matrix/client/v3/user/{user_id}/account_data/{event_type}",)))
4169}
4170
4171/// A prebuilt mock for a `GET
4172/// /_matrix/client/v3/user/{userId}/account_data/io.element.recent_emoji`
4173/// request, which fetches the recently used emojis in the account data.
4174#[cfg(feature = "experimental-element-recent-emojis")]
4175pub struct GetRecentEmojisEndpoint;
4176
4177#[cfg(feature = "experimental-element-recent-emojis")]
4178impl<'a> MockEndpoint<'a, GetRecentEmojisEndpoint> {
4179    /// Returns a mock for a successful fetch of the recently used emojis in the
4180    /// account data.
4181    pub fn ok(self, user_id: &UserId, emojis: Vec<(String, UInt)>) -> MatrixMock<'a> {
4182        let mock =
4183            global_account_data_mock_builder(self.mock, user_id, "io.element.recent_emoji".into())
4184                .respond_with(
4185                    ResponseTemplate::new(200).set_body_json(json!({ "recent_emoji": emojis })),
4186                );
4187        MatrixMock { server: self.server, mock }
4188    }
4189}
4190
4191/// A prebuilt mock for a `PUT
4192/// /_matrix/client/v3/user/{userId}/account_data/io.element.recent_emoji`
4193/// request, which updates the recently used emojis in the account data.
4194#[cfg(feature = "experimental-element-recent-emojis")]
4195pub struct UpdateRecentEmojisEndpoint {
4196    pub(crate) request_body: Option<Vec<(String, UInt)>>,
4197}
4198
4199#[cfg(feature = "experimental-element-recent-emojis")]
4200impl UpdateRecentEmojisEndpoint {
4201    /// Creates a new instance of the recent update recent emojis mock endpoint.
4202    fn new() -> Self {
4203        Self { request_body: None }
4204    }
4205}
4206
4207#[cfg(feature = "experimental-element-recent-emojis")]
4208impl<'a> MockEndpoint<'a, UpdateRecentEmojisEndpoint> {
4209    /// Returns a mock that will check the body of the request, making sure its
4210    /// contents match the provided list of emojis.
4211    pub fn match_emojis_in_request_body(self, emojis: Vec<(String, UInt)>) -> Self {
4212        Self::new(
4213            self.server,
4214            self.mock.and(body_json(json!(RecentEmojisContent::new(emojis)))),
4215            self.endpoint,
4216        )
4217    }
4218
4219    /// Returns a mock for a successful update of the recent emojis account data
4220    /// event. The request body contents should match the provided emoji
4221    /// list.
4222    #[cfg(feature = "experimental-element-recent-emojis")]
4223    pub fn ok(self, user_id: &UserId) -> MatrixMock<'a> {
4224        let mock =
4225            global_account_data_mock_builder(self.mock, user_id, "io.element.recent_emoji".into())
4226                .respond_with(ResponseTemplate::new(200).set_body_json(()));
4227        MatrixMock { server: self.server, mock }
4228    }
4229}
4230
4231/// A prebuilt mock for a `GET
4232/// /_matrix/client/v3/user/{userId}/account_data/m.secret_storage.default_key`
4233/// request, which fetches the ID of the default secret storage key.
4234#[cfg(feature = "e2e-encryption")]
4235pub struct GetDefaultSecretStorageKeyEndpoint;
4236
4237#[cfg(feature = "e2e-encryption")]
4238impl<'a> MockEndpoint<'a, GetDefaultSecretStorageKeyEndpoint> {
4239    /// Returns a mock for a successful fetch of the default secret storage key.
4240    pub fn ok(self, user_id: &UserId, key_id: &str) -> MatrixMock<'a> {
4241        let mock = global_account_data_mock_builder(
4242            self.mock,
4243            user_id,
4244            GlobalAccountDataEventType::SecretStorageDefaultKey,
4245        )
4246        .respond_with(ResponseTemplate::new(200).set_body_json(json!({
4247            "key": key_id
4248        })));
4249        MatrixMock { server: self.server, mock }
4250    }
4251}
4252
4253/// A prebuilt mock for a `GET
4254/// /_matrix/client/v3/user/{userId}/account_data/m.secret_storage.key.{keyId}`
4255/// request, which fetches information about a secret storage key.
4256#[cfg(feature = "e2e-encryption")]
4257pub struct GetSecretStorageKeyEndpoint;
4258
4259#[cfg(feature = "e2e-encryption")]
4260impl<'a> MockEndpoint<'a, GetSecretStorageKeyEndpoint> {
4261    /// Returns a mock for a successful fetch of the secret storage key
4262    pub fn ok(
4263        self,
4264        user_id: &UserId,
4265        secret_storage_key_event_content: &ruma::events::secret_storage::key::SecretStorageKeyEventContent,
4266    ) -> MatrixMock<'a> {
4267        let mock = global_account_data_mock_builder(
4268            self.mock,
4269            user_id,
4270            GlobalAccountDataEventType::SecretStorageKey(
4271                secret_storage_key_event_content.key_id.clone(),
4272            ),
4273        )
4274        .respond_with(ResponseTemplate::new(200).set_body_json(secret_storage_key_event_content));
4275        MatrixMock { server: self.server, mock }
4276    }
4277}
4278
4279/// A prebuilt mock for a `GET
4280/// /_matrix/client/v3/user/{userId}/account_data/m.cross_signing.master`
4281/// request, which fetches information about the master signing key.
4282#[cfg(feature = "e2e-encryption")]
4283pub struct GetMasterSigningKeyEndpoint;
4284
4285#[cfg(feature = "e2e-encryption")]
4286impl<'a> MockEndpoint<'a, GetMasterSigningKeyEndpoint> {
4287    /// Returns a mock for a successful fetch of the master signing key
4288    pub fn ok<B: Serialize>(self, user_id: &UserId, key_json: B) -> MatrixMock<'a> {
4289        let mock = global_account_data_mock_builder(
4290            self.mock,
4291            user_id,
4292            GlobalAccountDataEventType::from("m.cross_signing.master".to_owned()),
4293        )
4294        .respond_with(ResponseTemplate::new(200).set_body_json(key_json));
4295        MatrixMock { server: self.server, mock }
4296    }
4297}
4298
4299/// A response to a [`RoomRelationsEndpoint`] query.
4300#[derive(Default)]
4301pub struct RoomRelationsResponseTemplate {
4302    /// The set of timeline events returned by this query.
4303    pub chunk: Vec<Raw<AnyTimelineEvent>>,
4304
4305    /// An opaque string representing a pagination token, which semantics depend
4306    /// on the direction used in the request.
4307    pub next_batch: Option<String>,
4308
4309    /// An opaque string representing a pagination token, which semantics depend
4310    /// on the direction used in the request.
4311    pub prev_batch: Option<String>,
4312
4313    /// If `recurse` was set on the request, the depth to which the server
4314    /// recursed.
4315    ///
4316    /// If `recurse` was not set, this field must be absent.
4317    pub recursion_depth: Option<u32>,
4318}
4319
4320impl RoomRelationsResponseTemplate {
4321    /// Fill the events returned as part of this response.
4322    pub fn events(mut self, chunk: Vec<impl Into<Raw<AnyTimelineEvent>>>) -> Self {
4323        self.chunk = chunk.into_iter().map(Into::into).collect();
4324        self
4325    }
4326
4327    /// Fill the `next_batch` token returned as part of this response.
4328    pub fn next_batch(mut self, token: impl Into<String>) -> Self {
4329        self.next_batch = Some(token.into());
4330        self
4331    }
4332
4333    /// Fill the `prev_batch` token returned as part of this response.
4334    pub fn prev_batch(mut self, token: impl Into<String>) -> Self {
4335        self.prev_batch = Some(token.into());
4336        self
4337    }
4338
4339    /// Fill the recursion depth returned in this response.
4340    pub fn recursion_depth(mut self, depth: u32) -> Self {
4341        self.recursion_depth = Some(depth);
4342        self
4343    }
4344}
4345
4346/// A prebuilt mock for `POST /rooms/{roomId}/receipt/{receiptType}/{eventId}`
4347/// request.
4348pub struct ReceiptEndpoint;
4349
4350impl<'a> MockEndpoint<'a, ReceiptEndpoint> {
4351    /// Returns a successful empty response.
4352    pub fn ok(self) -> MatrixMock<'a> {
4353        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({})))
4354    }
4355
4356    /// Ensures that the body of the request is a superset of the provided
4357    /// `body` parameter.
4358    pub fn body_matches_partial_json(self, body: Value) -> Self {
4359        Self { mock: self.mock.and(body_partial_json(body)), ..self }
4360    }
4361
4362    /// Ensures that the body of the request is the exact provided `body`
4363    /// parameter.
4364    pub fn body_json(self, body: Value) -> Self {
4365        Self { mock: self.mock.and(body_json(body)), ..self }
4366    }
4367
4368    /// Ensures that the request matches a specific receipt thread.
4369    pub fn match_thread(self, thread: ReceiptThread) -> Self {
4370        if let Some(thread_str) = thread.as_str() {
4371            self.body_matches_partial_json(json!({
4372                "thread_id": thread_str
4373            }))
4374        } else {
4375            self
4376        }
4377    }
4378
4379    /// Ensures that the request matches a specific event id.
4380    pub fn match_event_id(self, event_id: &EventId) -> Self {
4381        Self {
4382            mock: self.mock.and(path_regex(format!(
4383                r"^/_matrix/client/v3/rooms/.*/receipt/.*/{}$",
4384                event_id.as_str().replace("$", "\\$")
4385            ))),
4386            ..self
4387        }
4388    }
4389}
4390
4391/// A prebuilt mock for `POST /rooms/{roomId}/read_markers` request.
4392pub struct ReadMarkersEndpoint;
4393
4394impl<'a> MockEndpoint<'a, ReadMarkersEndpoint> {
4395    /// Returns a successful empty response.
4396    pub fn ok(self) -> MatrixMock<'a> {
4397        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({})))
4398    }
4399}
4400
4401/// A prebuilt mock for `PUT /user/{userId}/rooms/{roomId}/account_data/{type}`
4402/// request.
4403pub struct RoomAccountDataEndpoint;
4404
4405impl<'a> MockEndpoint<'a, RoomAccountDataEndpoint> {
4406    /// Returns a successful empty response.
4407    pub fn ok(self) -> MatrixMock<'a> {
4408        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({})))
4409    }
4410}
4411
4412/// A prebuilt mock for `GET /_matrix/client/v1/media/config` request.
4413pub struct AuthenticatedMediaConfigEndpoint;
4414
4415impl<'a> MockEndpoint<'a, AuthenticatedMediaConfigEndpoint> {
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    /// Returns a successful response with a maxed out max upload size.
4424    pub fn ok_default(self) -> MatrixMock<'a> {
4425        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
4426            "m.upload.size": UInt::MAX,
4427        })))
4428    }
4429}
4430
4431/// A prebuilt mock for `GET /_matrix/media/v3/config` request.
4432pub struct MediaConfigEndpoint;
4433
4434impl<'a> MockEndpoint<'a, MediaConfigEndpoint> {
4435    /// Returns a successful response with the provided max upload size.
4436    pub fn ok(self, max_upload_size: UInt) -> MatrixMock<'a> {
4437        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
4438            "m.upload.size": max_upload_size,
4439        })))
4440    }
4441}
4442
4443/// A prebuilt mock for `POST /login` requests.
4444pub struct LoginEndpoint;
4445
4446impl<'a> MockEndpoint<'a, LoginEndpoint> {
4447    /// Returns a successful response.
4448    pub fn ok(self) -> MatrixMock<'a> {
4449        self.respond_with(ResponseTemplate::new(200).set_body_json(&*test_json::LOGIN))
4450    }
4451
4452    /// Returns a given response on POST /login requests
4453    ///
4454    /// # Arguments
4455    ///
4456    /// * `response` - The response that the mock server sends on POST /login
4457    ///   requests.
4458    ///
4459    /// # Returns
4460    ///
4461    /// Returns a [`MatrixMock`] which can be mounted.
4462    ///
4463    /// # Examples
4464    ///
4465    /// ```
4466    /// use matrix_sdk::test_utils::mocks::{
4467    ///     LoginResponseTemplate200, MatrixMockServer,
4468    /// };
4469    /// use matrix_sdk_test::async_test;
4470    /// use ruma::{device_id, time::Duration, user_id};
4471    ///
4472    /// #[async_test]
4473    /// async fn test_ok_with() {
4474    ///     let server = MatrixMockServer::new().await;
4475    ///     server
4476    ///         .mock_login()
4477    ///         .ok_with(LoginResponseTemplate200::new(
4478    ///             "qwerty",
4479    ///             device_id!("DEADBEEF"),
4480    ///             user_id!("@cheeky_monkey:matrix.org"),
4481    ///         ))
4482    ///         .mount()
4483    ///         .await;
4484    ///
4485    ///     let client = server.client_builder().unlogged().build().await;
4486    ///
4487    ///     let result = client
4488    ///         .matrix_auth()
4489    ///         .login_username("example", "wordpass")
4490    ///         .send()
4491    ///         .await
4492    ///         .unwrap();
4493    ///
4494    ///     assert!(
4495    ///         result.access_tokesn.unwrap() == "qwerty",
4496    ///         "wrong access token in response"
4497    ///     );
4498    ///     assert!(
4499    ///         result.device_id.unwrap() == "DEADBEEF",
4500    ///         "wrong device id in response"
4501    ///     );
4502    ///     assert!(
4503    ///         result.user_id.unwrap() == "@cheeky_monkey:matrix.org",
4504    ///         "wrong user id in response"
4505    ///     );
4506    /// }
4507    /// ```
4508    pub fn ok_with(self, response: LoginResponseTemplate200) -> MatrixMock<'a> {
4509        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
4510            "access_token": response.access_token,
4511            "device_id": response.device_id,
4512            "user_id": response.user_id,
4513            "expires_in": response.expires_in.map(|duration| { duration.as_millis() }),
4514            "refresh_token": response.refresh_token,
4515            "well_known": response.well_known.map(|vals| {
4516                json!({
4517                    "m.homeserver": {
4518                        "base_url": vals.homeserver_url
4519                    },
4520                    "m.identity_server": vals.identity_url.map(|url| {
4521                        json!({
4522                            "base_url": url
4523                        })
4524                    })
4525                })
4526            }),
4527        })))
4528    }
4529
4530    /// Ensures that the body of the request is a superset of the provided
4531    /// `body` parameter.
4532    pub fn body_matches_partial_json(self, body: Value) -> Self {
4533        Self { mock: self.mock.and(body_partial_json(body)), ..self }
4534    }
4535}
4536
4537#[derive(Default)]
4538struct LoginResponseWellKnown {
4539    /// Required if well_known is used: The base URL for the homeserver for
4540    /// client-server connections.
4541    homeserver_url: String,
4542
4543    /// Required if well_known and m.identity_server are used: The base URL for
4544    /// the identity server for client-server connections.
4545    identity_url: Option<String>,
4546}
4547
4548/// A response to a [`LoginEndpoint`] query with status code 200.
4549#[derive(Default)]
4550pub struct LoginResponseTemplate200 {
4551    /// Required: An access token for the account. This access token can then be
4552    /// used to authorize other requests.
4553    access_token: Option<String>,
4554
4555    /// Required: ID of the logged-in device. Will be the same as the
4556    /// corresponding parameter in the request, if one was specified.
4557    device_id: Option<OwnedDeviceId>,
4558
4559    /// The lifetime of the access token, in milliseconds. Once the access token
4560    /// has expired a new access token can be obtained by using the provided
4561    /// refresh token. If no refresh token is provided, the client will need
4562    /// to re-log in to obtain a new access token. If not given, the client
4563    /// can assume that the access token will not expire.
4564    expires_in: Option<Duration>,
4565
4566    /// A refresh token for the account. This token can be used to obtain a new
4567    /// access token when it expires by calling the /refresh endpoint.
4568    refresh_token: Option<String>,
4569
4570    /// Required: The fully-qualified Matrix ID for the account.
4571    user_id: Option<OwnedUserId>,
4572
4573    /// Optional client configuration provided by the server.
4574    well_known: Option<LoginResponseWellKnown>,
4575}
4576
4577impl LoginResponseTemplate200 {
4578    /// Constructor for empty response
4579    pub fn new<T1: Into<OwnedDeviceId>, T2: Into<OwnedUserId>>(
4580        access_token: &str,
4581        device_id: T1,
4582        user_id: T2,
4583    ) -> Self {
4584        Self {
4585            access_token: Some(access_token.to_owned()),
4586            device_id: Some(device_id.into()),
4587            user_id: Some(user_id.into()),
4588            ..Default::default()
4589        }
4590    }
4591
4592    /// sets expires_in
4593    pub fn expires_in(mut self, value: Duration) -> Self {
4594        self.expires_in = Some(value);
4595        self
4596    }
4597
4598    /// sets refresh_token
4599    pub fn refresh_token(mut self, value: &str) -> Self {
4600        self.refresh_token = Some(value.to_owned());
4601        self
4602    }
4603
4604    /// sets well_known which takes a homeserver_url and an optional
4605    /// identity_url
4606    pub fn well_known(mut self, homeserver_url: String, identity_url: Option<String>) -> Self {
4607        self.well_known = Some(LoginResponseWellKnown { homeserver_url, identity_url });
4608        self
4609    }
4610}
4611
4612/// A prebuilt mock for `GET /devices` requests.
4613pub struct DevicesEndpoint;
4614
4615impl<'a> MockEndpoint<'a, DevicesEndpoint> {
4616    /// Returns a successful response.
4617    pub fn ok(self) -> MatrixMock<'a> {
4618        self.respond_with(ResponseTemplate::new(200).set_body_json(&*test_json::DEVICES))
4619    }
4620}
4621
4622/// A prebuilt mock for `GET /devices/{deviceId}` requests.
4623pub struct GetDeviceEndpoint;
4624
4625impl<'a> MockEndpoint<'a, GetDeviceEndpoint> {
4626    /// Returns a successful response.
4627    pub fn ok(self) -> MatrixMock<'a> {
4628        self.respond_with(ResponseTemplate::new(200).set_body_json(&*test_json::DEVICE))
4629    }
4630}
4631
4632/// A prebuilt mock for `POST /user_directory/search` requests.
4633pub struct UserDirectoryEndpoint;
4634
4635impl<'a> MockEndpoint<'a, UserDirectoryEndpoint> {
4636    /// Returns a successful response.
4637    pub fn ok(self) -> MatrixMock<'a> {
4638        self.respond_with(
4639            ResponseTemplate::new(200)
4640                .set_body_json(&*test_json::search_users::SEARCH_USERS_RESPONSE),
4641        )
4642    }
4643}
4644
4645/// A prebuilt mock for `POST /createRoom` requests.
4646pub struct CreateRoomEndpoint;
4647
4648impl<'a> MockEndpoint<'a, CreateRoomEndpoint> {
4649    /// Returns a successful response.
4650    pub fn ok(self) -> MatrixMock<'a> {
4651        self.respond_with(
4652            ResponseTemplate::new(200).set_body_json(json!({ "room_id": "!room:example.org"})),
4653        )
4654    }
4655}
4656
4657/// A prebuilt mock for `POST /rooms/{roomId}/upgrade` requests.
4658pub struct UpgradeRoomEndpoint;
4659
4660impl<'a> MockEndpoint<'a, UpgradeRoomEndpoint> {
4661    /// Returns a successful response with desired replacement_room ID.
4662    pub fn ok_with(self, new_room_id: &RoomId) -> MatrixMock<'a> {
4663        self.respond_with(
4664            ResponseTemplate::new(200)
4665                .set_body_json(json!({ "replacement_room": new_room_id.as_str()})),
4666        )
4667    }
4668}
4669
4670/// A prebuilt mock for `POST /media/v1/create` requests.
4671pub struct MediaAllocateEndpoint;
4672
4673impl<'a> MockEndpoint<'a, MediaAllocateEndpoint> {
4674    /// Returns a successful response.
4675    pub fn ok(self) -> MatrixMock<'a> {
4676        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
4677          "content_uri": "mxc://example.com/AQwafuaFswefuhsfAFAgsw"
4678        })))
4679    }
4680}
4681
4682/// A prebuilt mock for `PUT /media/v3/upload/{server_name}/{media_id}`
4683/// requests.
4684pub struct MediaAllocatedUploadEndpoint;
4685
4686impl<'a> MockEndpoint<'a, MediaAllocatedUploadEndpoint> {
4687    /// Returns a successful response.
4688    pub fn ok(self) -> MatrixMock<'a> {
4689        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({})))
4690    }
4691}
4692
4693/// A prebuilt mock for `GET /media/v3/download` requests.
4694pub struct MediaDownloadEndpoint;
4695
4696impl<'a> MockEndpoint<'a, MediaDownloadEndpoint> {
4697    /// Returns a successful response with a plain text content.
4698    pub fn ok_plain_text(self) -> MatrixMock<'a> {
4699        self.respond_with(ResponseTemplate::new(200).set_body_string("Hello, World!"))
4700    }
4701
4702    /// Returns a successful response with a fake image content.
4703    pub fn ok_image(self) -> MatrixMock<'a> {
4704        self.respond_with(
4705            ResponseTemplate::new(200).set_body_raw(b"binaryjpegfullimagedata", "image/jpeg"),
4706        )
4707    }
4708}
4709
4710/// A prebuilt mock for `GET /media/v3/thumbnail` requests.
4711pub struct MediaThumbnailEndpoint;
4712
4713impl<'a> MockEndpoint<'a, MediaThumbnailEndpoint> {
4714    /// Returns a successful response with a fake image content.
4715    pub fn ok(self) -> MatrixMock<'a> {
4716        self.respond_with(
4717            ResponseTemplate::new(200).set_body_raw(b"binaryjpegthumbnaildata", "image/jpeg"),
4718        )
4719    }
4720}
4721
4722/// A prebuilt mock for `GET /media/v3/preview_url` requests.
4723pub struct MediaPreviewEndpoint;
4724
4725impl<'a> MockEndpoint<'a, MediaPreviewEndpoint> {
4726    /// Returns a successful response with OpenGraph-like data for the URL.
4727    pub fn ok(self) -> MatrixMock<'a> {
4728        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
4729            "og:title": "Matrix Blog Post",
4730            "og:description": "This is a really cool blog post from matrix.org",
4731            "og:image": "mxc://example.com/ascERGshawAWawugaAcauga",
4732            "og:image:type": "image/png",
4733            "og:image:height": 48,
4734            "og:image:width": 48,
4735            "matrix:image:size": 102_400,
4736        })))
4737    }
4738
4739    /// Returns a successful but empty response.
4740    ///
4741    /// Homeservers legitimately return an empty object when they could not
4742    /// extract any metadata from the URL.
4743    pub fn ok_empty(self) -> MatrixMock<'a> {
4744        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({})))
4745    }
4746}
4747
4748/// A prebuilt mock for `GET /client/v1/media/preview_url` requests.
4749pub struct AuthedMediaPreviewEndpoint;
4750
4751impl<'a> MockEndpoint<'a, AuthedMediaPreviewEndpoint> {
4752    /// Returns a successful response with OpenGraph-like data for the URL.
4753    pub fn ok(self) -> MatrixMock<'a> {
4754        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
4755            "og:title": "Matrix Blog Post",
4756            "og:description": "This is a really cool blog post from matrix.org",
4757            "og:image": "mxc://example.com/ascERGshawAWawugaAcauga",
4758            "og:image:type": "image/png",
4759            "og:image:height": 48,
4760            "og:image:width": 48,
4761            "matrix:image:size": 102_400,
4762        })))
4763    }
4764
4765    /// Returns a successful but empty response.
4766    ///
4767    /// Homeservers legitimately return an empty object when they could not
4768    /// extract any metadata from the URL.
4769    pub fn ok_empty(self) -> MatrixMock<'a> {
4770        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({})))
4771    }
4772}
4773
4774/// A prebuilt mock for `GET /client/v1/media/download` requests.
4775pub struct AuthedMediaDownloadEndpoint;
4776
4777impl<'a> MockEndpoint<'a, AuthedMediaDownloadEndpoint> {
4778    /// Returns a successful response with a plain text content.
4779    pub fn ok_plain_text(self) -> MatrixMock<'a> {
4780        self.respond_with(ResponseTemplate::new(200).set_body_string("Hello, World!"))
4781    }
4782
4783    /// Returns a successful response with the given bytes.
4784    pub fn ok_bytes(self, bytes: Vec<u8>) -> MatrixMock<'a> {
4785        self.respond_with(
4786            ResponseTemplate::new(200).set_body_raw(bytes, "application/octet-stream"),
4787        )
4788    }
4789
4790    /// Returns a successful response with a fake image content.
4791    pub fn ok_image(self) -> MatrixMock<'a> {
4792        self.respond_with(
4793            ResponseTemplate::new(200).set_body_raw(b"binaryjpegfullimagedata", "image/jpeg"),
4794        )
4795    }
4796}
4797
4798/// A prebuilt mock for `GET /client/v1/media/thumbnail` requests.
4799pub struct AuthedMediaThumbnailEndpoint;
4800
4801impl<'a> MockEndpoint<'a, AuthedMediaThumbnailEndpoint> {
4802    /// Returns a successful response with a fake image content.
4803    pub fn ok(self) -> MatrixMock<'a> {
4804        self.respond_with(
4805            ResponseTemplate::new(200).set_body_raw(b"binaryjpegthumbnaildata", "image/jpeg"),
4806        )
4807    }
4808}
4809
4810/// A prebuilt mock for `GET /client/v3/rooms/{room_id}/join` requests.
4811pub struct JoinRoomEndpoint {
4812    room_id: OwnedRoomId,
4813}
4814
4815impl<'a> MockEndpoint<'a, JoinRoomEndpoint> {
4816    /// Returns a successful response using the provided [`RoomId`].
4817    pub fn ok(self) -> MatrixMock<'a> {
4818        let room_id = self.endpoint.room_id.to_owned();
4819
4820        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
4821            "room_id": room_id,
4822        })))
4823    }
4824}
4825
4826#[derive(Default)]
4827struct ThreadSubscriptionMatchers {
4828    /// Optional room id to match in the query.
4829    room_id: Option<OwnedRoomId>,
4830    /// Optional thread root event id to match in the query.
4831    thread_root: Option<OwnedEventId>,
4832}
4833
4834impl ThreadSubscriptionMatchers {
4835    /// Match the request parameter against a specific room id.
4836    fn match_room_id(mut self, room_id: OwnedRoomId) -> Self {
4837        self.room_id = Some(room_id);
4838        self
4839    }
4840
4841    /// Match the request parameter against a specific thread root event id.
4842    fn match_thread_id(mut self, thread_root: OwnedEventId) -> Self {
4843        self.thread_root = Some(thread_root);
4844        self
4845    }
4846
4847    /// Compute the final URI for the thread subscription endpoint.
4848    fn endpoint_regexp_uri(&self) -> String {
4849        if self.room_id.is_some() || self.thread_root.is_some() {
4850            format!(
4851                "^/_matrix/client/unstable/io.element.msc4306/rooms/{}/thread/{}/subscription$",
4852                self.room_id.as_deref().map(|s| s.as_str()).unwrap_or(".*"),
4853                self.thread_root.as_deref().map(|s| s.as_str()).unwrap_or(".*").replace("$", "\\$")
4854            )
4855        } else {
4856            "^/_matrix/client/unstable/io.element.msc4306/rooms/.*/thread/.*/subscription$"
4857                .to_owned()
4858        }
4859    }
4860}
4861
4862/// A prebuilt mock for `GET
4863/// /client/*/rooms/{room_id}/threads/{thread_root}/subscription`
4864#[derive(Default)]
4865pub struct RoomGetThreadSubscriptionEndpoint {
4866    matchers: ThreadSubscriptionMatchers,
4867}
4868
4869impl<'a> MockEndpoint<'a, RoomGetThreadSubscriptionEndpoint> {
4870    /// Returns a successful response for the given thread subscription.
4871    pub fn ok(mut self, automatic: bool) -> MatrixMock<'a> {
4872        self.mock = self.mock.and(path_regex(self.endpoint.matchers.endpoint_regexp_uri()));
4873        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
4874            "automatic": automatic
4875        })))
4876    }
4877
4878    /// Match the request parameter against a specific room id.
4879    pub fn match_room_id(mut self, room_id: OwnedRoomId) -> Self {
4880        self.endpoint.matchers = self.endpoint.matchers.match_room_id(room_id);
4881        self
4882    }
4883    /// Match the request parameter against a specific thread root event id.
4884    pub fn match_thread_id(mut self, thread_root: OwnedEventId) -> Self {
4885        self.endpoint.matchers = self.endpoint.matchers.match_thread_id(thread_root);
4886        self
4887    }
4888}
4889
4890/// A prebuilt mock for `PUT
4891/// /client/*/rooms/{room_id}/threads/{thread_root}/subscription`
4892#[derive(Default)]
4893pub struct RoomPutThreadSubscriptionEndpoint {
4894    matchers: ThreadSubscriptionMatchers,
4895}
4896
4897impl<'a> MockEndpoint<'a, RoomPutThreadSubscriptionEndpoint> {
4898    /// Returns a successful response for the given setting of thread
4899    /// subscription.
4900    pub fn ok(mut self) -> MatrixMock<'a> {
4901        self.mock = self.mock.and(path_regex(self.endpoint.matchers.endpoint_regexp_uri()));
4902        self.respond_with(ResponseTemplate::new(200))
4903    }
4904
4905    /// Returns that the server skipped an automated thread subscription,
4906    /// because the user unsubscribed to the thread after the event id passed in
4907    /// the automatic subscription.
4908    pub fn conflicting_unsubscription(mut self) -> MatrixMock<'a> {
4909        self.mock = self.mock.and(path_regex(self.endpoint.matchers.endpoint_regexp_uri()));
4910        self.respond_with(ResponseTemplate::new(409).set_body_json(json!({
4911            "errcode": "IO.ELEMENT.MSC4306.M_CONFLICTING_UNSUBSCRIPTION",
4912            "error": "the user unsubscribed after the subscription event id"
4913        })))
4914    }
4915
4916    /// Match the request parameter against a specific room id.
4917    pub fn match_room_id(mut self, room_id: OwnedRoomId) -> Self {
4918        self.endpoint.matchers = self.endpoint.matchers.match_room_id(room_id);
4919        self
4920    }
4921    /// Match the request parameter against a specific thread root event id.
4922    pub fn match_thread_id(mut self, thread_root: OwnedEventId) -> Self {
4923        self.endpoint.matchers = self.endpoint.matchers.match_thread_id(thread_root);
4924        self
4925    }
4926    /// Match the request body's `automatic` field against a specific event id.
4927    pub fn match_automatic_event_id(mut self, up_to_event_id: &EventId) -> Self {
4928        self.mock = self.mock.and(body_json(json!({
4929            "automatic": up_to_event_id
4930        })));
4931        self
4932    }
4933}
4934
4935/// A prebuilt mock for `DELETE
4936/// /client/*/rooms/{room_id}/threads/{thread_root}/subscription`
4937#[derive(Default)]
4938pub struct RoomDeleteThreadSubscriptionEndpoint {
4939    matchers: ThreadSubscriptionMatchers,
4940}
4941
4942impl<'a> MockEndpoint<'a, RoomDeleteThreadSubscriptionEndpoint> {
4943    /// Returns a successful response for the deletion of a given thread
4944    /// subscription.
4945    pub fn ok(mut self) -> MatrixMock<'a> {
4946        self.mock = self.mock.and(path_regex(self.endpoint.matchers.endpoint_regexp_uri()));
4947        self.respond_with(ResponseTemplate::new(200))
4948    }
4949
4950    /// Match the request parameter against a specific room id.
4951    pub fn match_room_id(mut self, room_id: OwnedRoomId) -> Self {
4952        self.endpoint.matchers = self.endpoint.matchers.match_room_id(room_id);
4953        self
4954    }
4955    /// Match the request parameter against a specific thread root event id.
4956    pub fn match_thread_id(mut self, thread_root: OwnedEventId) -> Self {
4957        self.endpoint.matchers = self.endpoint.matchers.match_thread_id(thread_root);
4958        self
4959    }
4960}
4961
4962/// A prebuilt mock for `PUT
4963/// /_matrix/client/v3/pushrules/global/{kind}/{ruleId}/enabled`.
4964pub struct EnablePushRuleEndpoint;
4965
4966impl<'a> MockEndpoint<'a, EnablePushRuleEndpoint> {
4967    /// Returns a successful empty JSON response.
4968    pub fn ok(self) -> MatrixMock<'a> {
4969        self.ok_empty_json()
4970    }
4971}
4972
4973/// A prebuilt mock for `PUT
4974/// /_matrix/client/v3/pushrules/global/{kind}/{ruleId}/actions`.
4975pub struct SetPushRulesActionsEndpoint;
4976
4977impl<'a> MockEndpoint<'a, SetPushRulesActionsEndpoint> {
4978    /// Returns a successful empty JSON response.
4979    pub fn ok(self) -> MatrixMock<'a> {
4980        self.ok_empty_json()
4981    }
4982}
4983
4984/// A prebuilt mock for `PUT
4985/// /_matrix/client/v3/pushrules/global/{kind}/{ruleId}`.
4986pub struct SetPushRulesEndpoint;
4987
4988impl<'a> MockEndpoint<'a, SetPushRulesEndpoint> {
4989    /// Returns a successful empty JSON response.
4990    pub fn ok(self) -> MatrixMock<'a> {
4991        self.ok_empty_json()
4992    }
4993}
4994
4995/// A prebuilt mock for `DELETE
4996/// /_matrix/client/v3/pushrules/global/{kind}/{ruleId}`.
4997pub struct DeletePushRulesEndpoint;
4998
4999impl<'a> MockEndpoint<'a, DeletePushRulesEndpoint> {
5000    /// Returns a successful empty JSON response.
5001    pub fn ok(self) -> MatrixMock<'a> {
5002        self.ok_empty_json()
5003    }
5004}
5005
5006/// A prebuilt mock for the federation version endpoint.
5007pub struct FederationVersionEndpoint;
5008
5009impl<'a> MockEndpoint<'a, FederationVersionEndpoint> {
5010    /// Returns a successful response with the given server name and version.
5011    pub fn ok(self, server_name: &str, version: &str) -> MatrixMock<'a> {
5012        let response_body = json!({
5013            "server": {
5014                "name": server_name,
5015                "version": version
5016            }
5017        });
5018        self.respond_with(ResponseTemplate::new(200).set_body_json(response_body))
5019    }
5020
5021    /// Returns a successful response with empty/missing server information.
5022    pub fn ok_empty(self) -> MatrixMock<'a> {
5023        let response_body = json!({});
5024        self.respond_with(ResponseTemplate::new(200).set_body_json(response_body))
5025    }
5026}
5027
5028/// A prebuilt mock for `GET ^/_matrix/client/v3/thread_subscriptions`.
5029#[derive(Default)]
5030pub struct GetThreadSubscriptionsEndpoint {
5031    /// New thread subscriptions per (room id, thread root event id).
5032    subscribed: BTreeMap<OwnedRoomId, BTreeMap<OwnedEventId, ThreadSubscription>>,
5033    /// New thread unsubscriptions per (room id, thread root event id).
5034    unsubscribed: BTreeMap<OwnedRoomId, BTreeMap<OwnedEventId, ThreadUnsubscription>>,
5035    /// Optional delay to respond to the query.
5036    delay: Option<Duration>,
5037}
5038
5039impl<'a> MockEndpoint<'a, GetThreadSubscriptionsEndpoint> {
5040    /// Add a single thread subscription to the response.
5041    pub fn add_subscription(
5042        mut self,
5043        room_id: OwnedRoomId,
5044        thread_root: OwnedEventId,
5045        subscription: ThreadSubscription,
5046    ) -> Self {
5047        self.endpoint.subscribed.entry(room_id).or_default().insert(thread_root, subscription);
5048        self
5049    }
5050
5051    /// Add a single thread unsubscription to the response.
5052    pub fn add_unsubscription(
5053        mut self,
5054        room_id: OwnedRoomId,
5055        thread_root: OwnedEventId,
5056        unsubscription: ThreadUnsubscription,
5057    ) -> Self {
5058        self.endpoint.unsubscribed.entry(room_id).or_default().insert(thread_root, unsubscription);
5059        self
5060    }
5061
5062    /// Respond with a given delay to the query.
5063    pub fn with_delay(mut self, delay: Duration) -> Self {
5064        self.endpoint.delay = Some(delay);
5065        self
5066    }
5067
5068    /// Match the `from` query parameter to a given value.
5069    pub fn match_from(self, from: &str) -> Self {
5070        Self { mock: self.mock.and(query_param("from", from)), ..self }
5071    }
5072    /// Match the `to` query parameter to a given value.
5073    pub fn match_to(self, to: &str) -> Self {
5074        Self { mock: self.mock.and(query_param("to", to)), ..self }
5075    }
5076
5077    /// Returns a successful response with the given thread subscriptions, and
5078    /// "end" parameter to be used in the next query.
5079    pub fn ok(self, end: Option<String>) -> MatrixMock<'a> {
5080        let response_body = json!({
5081            "subscribed": self.endpoint.subscribed,
5082            "unsubscribed": self.endpoint.unsubscribed,
5083            "end": end,
5084        });
5085
5086        let mut template = ResponseTemplate::new(200).set_body_json(response_body);
5087
5088        if let Some(delay) = self.endpoint.delay {
5089            template = template.set_delay(delay);
5090        }
5091
5092        self.respond_with(template)
5093    }
5094}
5095
5096/// A prebuilt mock for `GET /client/*/rooms/{roomId}/hierarchy`
5097#[derive(Default)]
5098pub struct GetHierarchyEndpoint;
5099
5100impl<'a> MockEndpoint<'a, GetHierarchyEndpoint> {
5101    /// Returns a successful response containing the given room IDs.
5102    pub fn ok_with_room_ids(self, room_ids: Vec<&RoomId>) -> MatrixMock<'a> {
5103        let rooms = room_ids
5104            .iter()
5105            .map(|id| {
5106                json!({
5107                  "room_id": id,
5108                  "num_joined_members": 1,
5109                  "world_readable": false,
5110                  "guest_can_join": false,
5111                  "children_state": []
5112                })
5113            })
5114            .collect::<Vec<_>>();
5115
5116        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
5117            "rooms": rooms,
5118        })))
5119    }
5120
5121    /// Returns a successful response containing the given room IDs and children
5122    /// states
5123    pub fn ok_with_room_ids_and_children_state(
5124        self,
5125        room_ids: Vec<&RoomId>,
5126        children_state: Vec<(&RoomId, Vec<&ServerName>)>,
5127    ) -> MatrixMock<'a> {
5128        let children_state = children_state
5129            .into_iter()
5130            .map(|(id, via)| {
5131                json!({
5132                    "type":
5133                    "m.space.child",
5134                    "state_key": id,
5135                    "content": { "via": via },
5136                    "sender": "@bob:matrix.org",
5137                    "origin_server_ts": MilliSecondsSinceUnixEpoch::now()
5138                })
5139            })
5140            .collect::<Vec<_>>();
5141
5142        let rooms = room_ids
5143            .iter()
5144            .map(|id| {
5145                json!({
5146                  "room_id": id,
5147                  "num_joined_members": 1,
5148                  "world_readable": false,
5149                  "guest_can_join": false,
5150                  "children_state": children_state
5151                })
5152            })
5153            .collect::<Vec<_>>();
5154
5155        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
5156            "rooms": rooms,
5157        })))
5158    }
5159
5160    /// Returns a successful response with an empty list of rooms.
5161    pub fn ok(self) -> MatrixMock<'a> {
5162        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
5163            "rooms": []
5164        })))
5165    }
5166}
5167
5168/// A prebuilt mock for `PUT
5169/// /_matrix/client/v3/rooms/{roomId}/state/m.space.child/{stateKey}`
5170pub struct SetSpaceChildEndpoint;
5171
5172impl<'a> MockEndpoint<'a, SetSpaceChildEndpoint> {
5173    /// Returns a successful response with a given event id.
5174    pub fn ok(self, event_id: OwnedEventId) -> MatrixMock<'a> {
5175        self.ok_with_event_id(event_id)
5176    }
5177
5178    /// Returns an error response with a generic error code indicating the
5179    /// client is not authorized to set space children.
5180    pub fn unauthorized(self) -> MatrixMock<'a> {
5181        self.respond_with(ResponseTemplate::new(400))
5182    }
5183}
5184
5185/// A prebuilt mock for `PUT
5186/// /_matrix/client/v3/rooms/{roomId}/state/m.space.parent/{stateKey}`
5187pub struct SetSpaceParentEndpoint;
5188
5189impl<'a> MockEndpoint<'a, SetSpaceParentEndpoint> {
5190    /// Returns a successful response with a given event id.
5191    pub fn ok(self, event_id: OwnedEventId) -> MatrixMock<'a> {
5192        self.ok_with_event_id(event_id)
5193    }
5194
5195    /// Returns an error response with a generic error code indicating the
5196    /// client is not authorized to set space parents.
5197    pub fn unauthorized(self) -> MatrixMock<'a> {
5198        self.respond_with(ResponseTemplate::new(400))
5199    }
5200}
5201
5202/// A prebuilt mock for running simplified sliding sync.
5203pub struct SlidingSyncEndpoint;
5204
5205impl<'a> MockEndpoint<'a, SlidingSyncEndpoint> {
5206    /// Mocks the sliding sync endpoint with the given response.
5207    pub fn ok(self, response: v5::Response) -> MatrixMock<'a> {
5208        // A bit silly that we need to destructure all the fields ourselves, but
5209        // Response isn't serializable :'(
5210        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
5211            "txn_id": response.txn_id,
5212            "pos": response.pos,
5213            "lists": response.lists,
5214            "rooms": response.rooms,
5215            "extensions": response.extensions,
5216        })))
5217    }
5218
5219    /// Temporarily mocks the sync with the given endpoint and runs a client
5220    /// sync with it.
5221    ///
5222    /// After calling this function, the sync endpoint isn't mocked anymore.
5223    pub async fn ok_and_run<F: FnOnce(SlidingSyncBuilder) -> SlidingSyncBuilder>(
5224        self,
5225        client: &Client,
5226        on_builder: F,
5227        response: v5::Response,
5228    ) {
5229        let _scope = self.ok(response).mount_as_scoped().await;
5230
5231        let sliding_sync =
5232            on_builder(client.sliding_sync("test_id").unwrap()).build().await.unwrap();
5233
5234        let _summary = sliding_sync.sync_once().await.unwrap();
5235    }
5236}
5237
5238/// A prebuilt mock for `GET /_matrix/client/*/profile/{user_id}/{key_name}`.
5239pub struct GetProfileFieldEndpoint {
5240    field: ProfileFieldName,
5241}
5242
5243impl<'a> MockEndpoint<'a, GetProfileFieldEndpoint> {
5244    /// Returns a successful response containing the given value, if any.
5245    pub fn ok_with_value(self, value: Option<Value>) -> MatrixMock<'a> {
5246        if let Some(value) = value {
5247            let field = self.endpoint.field.to_string();
5248            self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
5249                field: value,
5250            })))
5251        } else {
5252            self.ok_empty_json()
5253        }
5254    }
5255}
5256
5257/// A prebuilt mock for `PUT /_matrix/client/*/profile/{user_id}/{key_name}`.
5258pub struct SetProfileFieldEndpoint;
5259
5260impl<'a> MockEndpoint<'a, SetProfileFieldEndpoint> {
5261    /// Returns a successful empty response.
5262    pub fn ok(self) -> MatrixMock<'a> {
5263        self.ok_empty_json()
5264    }
5265
5266    /// Expect the request body to set the given [`ProfileFieldValue`].
5267    pub fn expect_field_value(mut self, value: ProfileFieldValue) -> Self {
5268        let body = BTreeMap::from([(value.field_name(), value.value())]);
5269        self.mock = self.mock.and(body_json(body));
5270        self
5271    }
5272}
5273
5274/// A prebuilt mock for `DELETE /_matrix/client/*/profile/{user_id}/{key_name}`.
5275pub struct DeleteProfileFieldEndpoint;
5276
5277impl<'a> MockEndpoint<'a, DeleteProfileFieldEndpoint> {
5278    /// Returns a successful empty response.
5279    pub fn ok(self) -> MatrixMock<'a> {
5280        self.ok_empty_json()
5281    }
5282}
5283
5284/// A prebuilt mock for `GET /_matrix/client/*/profile/{user_id}`.
5285pub struct GetProfileEndpoint;
5286
5287impl<'a> MockEndpoint<'a, GetProfileEndpoint> {
5288    /// Returns a successful empty response.
5289    pub fn ok_with_fields(self, fields: Vec<ProfileFieldValue>) -> MatrixMock<'a> {
5290        let profile = fields
5291            .iter()
5292            .map(|field| (field.field_name(), field.value()))
5293            .collect::<BTreeMap<_, _>>();
5294        self.respond_with(ResponseTemplate::new(200).set_body_json(profile))
5295    }
5296}
5297
5298/// A prebuilt mock for `GET /_matrix/client/*/capabilities`.
5299pub struct GetHomeserverCapabilitiesEndpoint;
5300
5301impl<'a> MockEndpoint<'a, GetHomeserverCapabilitiesEndpoint> {
5302    /// Returns a successful empty response.
5303    pub fn ok_with_capabilities(self, capabilities: Capabilities) -> MatrixMock<'a> {
5304        self.respond_with(ResponseTemplate::new(200).set_body_json(json!({
5305            "capabilities": capabilities,
5306        })))
5307    }
5308}