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