matrix_sdk_test/
lib.rs

1use http::Response;
2pub use matrix_sdk_test_macros::async_test;
3use once_cell::sync::Lazy;
4use ruma::{
5    api::{
6        client::sync::sync_events::v3::Response as SyncResponse, IncomingResponse, OutgoingResponse,
7    },
8    room_id, user_id, RoomId, UserId,
9};
10use serde_json::Value as JsonValue;
11
12/// Create a `Raw<AnyMessageLikeEventContent>` from arbitrary JSON.
13///
14/// Forwards all arguments to [`serde_json::json`].
15#[macro_export]
16macro_rules! message_like_event_content {
17    ($( $tt:tt )*) => {
18        ::ruma::serde::Raw::new(&::serde_json::json!( $($tt)* ))
19            .unwrap()
20            .cast::<::ruma::events::AnyMessageLikeEventContent>()
21    }
22}
23
24/// Create a `Raw<AnyTimelineEvent>` from arbitrary JSON.
25///
26/// Forwards all arguments to [`serde_json::json`].
27#[macro_export]
28macro_rules! timeline_event {
29    ($( $tt:tt )*) => {
30        ::ruma::serde::Raw::new(&::serde_json::json!( $($tt)* ))
31            .unwrap()
32            .cast::<::ruma::events::AnyTimelineEvent>()
33    }
34}
35
36/// Create a `Raw<AnySyncTimelineEvent>` from arbitrary JSON.
37///
38/// Forwards all arguments to [`serde_json::json`].
39#[macro_export]
40macro_rules! sync_timeline_event {
41    ($( $tt:tt )*) => {
42        ::ruma::serde::Raw::new(&::serde_json::json!( $($tt)* ))
43            .unwrap()
44            .cast::<::ruma::events::AnySyncTimelineEvent>()
45    }
46}
47
48/// Create a `Raw<AnySyncStateEvent>` from arbitrary JSON.
49///
50/// Forwards all arguments to [`serde_json::json`].
51#[macro_export]
52macro_rules! sync_state_event {
53    ($( $tt:tt )*) => {
54        ::ruma::serde::Raw::new(&::serde_json::json!( $($tt)* ))
55            .unwrap()
56            .cast::<::ruma::events::AnySyncStateEvent>()
57    }
58}
59
60/// Create a `Raw<AnyStrippedStateEvent>` from arbitrary JSON.
61///
62/// Forwards all arguments to [`serde_json::json`].
63#[macro_export]
64macro_rules! stripped_state_event {
65    ($( $tt:tt )*) => {
66        ::ruma::serde::Raw::new(&::serde_json::json!( $($tt)* ))
67            .unwrap()
68            .cast::<::ruma::events::AnyStrippedStateEvent>()
69    }
70}
71
72/// Initialize a tracing subscriber if the target architecture is not WASM.
73///
74/// Uses a sensible default filter that can be overridden through the `RUST_LOG`
75/// environment variable and runs once before all tests by using the [`ctor`]
76/// crate.
77///
78/// Invoke this macro once per compilation unit (`lib.rs`, `tests/*.rs`,
79/// `tests/*/main.rs`).
80#[macro_export]
81macro_rules! init_tracing_for_tests {
82    () => {
83        #[cfg(not(target_arch = "wasm32"))]
84        #[$crate::__macro_support::ctor]
85        fn init_logging() {
86            use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
87            use $crate::__macro_support::tracing_subscriber;
88
89            tracing_subscriber::registry()
90                .with(tracing_subscriber::EnvFilter::try_from_default_env().unwrap_or_else(|_| {
91                    // Output is only printed for failing tests, but still we shouldn't overload
92                    // the output with unnecessary info. When debugging a specific test, it's easy
93                    // to override this default by setting the `RUST_LOG` environment variable.
94                    //
95                    // Since tracing_subscriber does prefix matching, the `matrix_sdk=` directive
96                    // takes effect for all the main crates (`matrix_sdk_base`, `matrix_sdk_crypto`
97                    // and so on).
98                    "info,matrix_sdk=debug".into()
99                }))
100                .with(tracing_subscriber::fmt::layer().with_test_writer())
101                .init();
102        }
103    };
104}
105
106#[doc(hidden)]
107pub mod __macro_support {
108    #[cfg(not(target_arch = "wasm32"))]
109    pub use ctor::ctor;
110    #[cfg(not(target_arch = "wasm32"))]
111    pub use tracing_subscriber;
112}
113
114#[cfg(not(target_arch = "wasm32"))]
115pub mod mocks;
116
117pub mod event_factory;
118pub mod notification_settings;
119mod sync_builder;
120pub mod test_json;
121
122pub use self::sync_builder::{
123    bulk_room_members, EphemeralTestEvent, GlobalAccountDataTestEvent, InvitedRoomBuilder,
124    JoinedRoomBuilder, KnockedRoomBuilder, LeftRoomBuilder, PresenceTestEvent,
125    RoomAccountDataTestEvent, StateTestEvent, StrippedStateTestEvent, SyncResponseBuilder,
126};
127
128pub static ALICE: Lazy<&UserId> = Lazy::new(|| user_id!("@alice:server.name"));
129pub static BOB: Lazy<&UserId> = Lazy::new(|| user_id!("@bob:other.server"));
130pub static CAROL: Lazy<&UserId> = Lazy::new(|| user_id!("@carol:other.server"));
131
132/// The default room ID for tests.
133pub static DEFAULT_TEST_ROOM_ID: Lazy<&RoomId> =
134    Lazy::new(|| room_id!("!SVkFJHzfwvuaIEawgC:localhost"));
135
136/// Embedded sync response files
137pub enum SyncResponseFile {
138    All,
139    Default,
140    DefaultWithSummary,
141    Invite,
142    Leave,
143    Voip,
144}
145
146/// Get specific API responses for testing
147pub fn sync_response(kind: SyncResponseFile) -> SyncResponse {
148    let data: &JsonValue = match kind {
149        SyncResponseFile::All => &test_json::MORE_SYNC,
150        SyncResponseFile::Default => &test_json::SYNC,
151        SyncResponseFile::DefaultWithSummary => &test_json::DEFAULT_SYNC_SUMMARY,
152        SyncResponseFile::Invite => &test_json::INVITE_SYNC,
153        SyncResponseFile::Leave => &test_json::LEAVE_SYNC,
154        SyncResponseFile::Voip => &test_json::VOIP_SYNC,
155    };
156
157    ruma_response_from_json(data)
158}
159
160/// Build a typed Ruma [`IncomingResponse`] object from a json body.
161pub fn ruma_response_from_json<ResponseType: IncomingResponse>(
162    json: &serde_json::Value,
163) -> ResponseType {
164    let json_bytes = serde_json::to_vec(json).expect("JSON-serialization of response value failed");
165    let http_response =
166        Response::builder().status(200).body(json_bytes).expect("Failed to build HTTP response");
167    ResponseType::try_from_http_response(http_response).expect("Can't parse the response json")
168}
169
170/// Serialise a typed Ruma [`OutgoingResponse`] object to JSON.
171pub fn ruma_response_to_json<ResponseType: OutgoingResponse>(
172    response: ResponseType,
173) -> serde_json::Value {
174    let http_response: Response<Vec<u8>> =
175        response.try_into_http_response().expect("Failed to build HTTP response");
176    let json_bytes = http_response.into_body();
177    serde_json::from_slice(&json_bytes).expect("Can't parse the response JSON")
178}