Skip to main content

matrix_sdk/test_utils/mocks/
mod.rs

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