matrix_sdk/test_utils/
mod.rs1#![allow(dead_code)]
4
5use matrix_sdk_base::{deserialized_responses::TimelineEvent, store::RoomLoadSettings};
6use ruma::{
7 api::MatrixVersion,
8 events::{AnySyncMessageLikeEvent, AnySyncTimelineEvent, room::message::MessageType},
9};
10use strass::assert_let;
11use url::Url;
12
13pub mod client;
14#[cfg(not(target_family = "wasm"))]
15pub mod mocks;
16
17#[cfg(not(target_family = "wasm"))]
20pub use wiremock;
21
22use self::client::mock_matrix_session;
23use crate::{Client, ClientBuilder, config::RequestConfig};
24
25#[track_caller]
27pub fn assert_event_matches_msg<E: Clone + Into<TimelineEvent>>(event: &E, expected: &str) {
28 let event: TimelineEvent = event.clone().into();
29 let event = event.raw().deserialize().unwrap();
30 assert_let!(
31 AnySyncTimelineEvent::MessageLike(AnySyncMessageLikeEvent::RoomMessage(message)) = event
32 );
33 let message = message.as_original().unwrap();
34 assert_let!(MessageType::Text(text) = &message.content.msgtype);
35 assert_eq!(text.body, expected);
36}
37
38pub fn test_client_builder(homeserver_url: Option<String>) -> ClientBuilder {
41 let homeserver = homeserver_url
42 .map(|url| Url::try_from(url.as_str()).unwrap())
43 .unwrap_or_else(|| Url::try_from("http://localhost:1234").unwrap());
44 Client::builder().homeserver_url(homeserver).server_versions([MatrixVersion::V1_0])
45}
46
47pub async fn no_retry_test_client(homeserver_url: Option<String>) -> Client {
50 test_client_builder(homeserver_url)
51 .request_config(RequestConfig::new().disable_retry())
52 .build()
53 .await
54 .unwrap()
55}
56
57pub async fn set_client_session(client: &Client) {
59 client
60 .matrix_auth()
61 .restore_session(mock_matrix_session(), RoomLoadSettings::default())
62 .await
63 .unwrap();
64}
65
66pub async fn logged_in_client(homeserver_url: Option<String>) -> Client {
70 let client = no_retry_test_client(homeserver_url).await;
71 set_client_session(&client).await;
72 client
73}
74
75#[cfg(not(target_family = "wasm"))]
77pub async fn test_client_builder_with_server() -> (ClientBuilder, wiremock::MockServer) {
78 let server = wiremock::MockServer::start().await;
79 let builder = test_client_builder(Some(server.uri()));
80 (builder, server)
81}
82
83#[cfg(not(target_family = "wasm"))]
85pub async fn no_retry_test_client_with_server() -> (Client, wiremock::MockServer) {
86 let server = wiremock::MockServer::start().await;
87 let client = no_retry_test_client(Some(server.uri().to_string())).await;
88 (client, server)
89}
90
91#[cfg(not(target_family = "wasm"))]
93pub async fn logged_in_client_with_server() -> (Client, wiremock::MockServer) {
94 let server = wiremock::MockServer::start().await;
95 let client = logged_in_client(Some(server.uri().to_string())).await;
96 (client, server)
97}
98
99#[macro_export]
127macro_rules! assert_next_with_timeout {
128 ($stream:expr) => {
129 $crate::assert_next_with_timeout!($stream, 500)
130 };
131 ($stream:expr, $timeout_ms:expr) => {{
132 #[allow(unused_imports)]
134 use futures_util::StreamExt as _;
135 tokio::time::timeout(std::time::Duration::from_millis($timeout_ms), $stream.next())
136 .await
137 .expect("Next event timed out")
138 .expect("No next event received")
139 }};
140}
141
142#[macro_export]
176macro_rules! assert_recv_with_timeout {
177 ($receiver:expr) => {
178 $crate::assert_recv_with_timeout!($receiver, 500)
179 };
180
181 ($receiver:expr, $timeout_ms:expr) => {{
182 tokio::time::timeout(std::time::Duration::from_millis($timeout_ms), $receiver.recv())
183 .await
184 .expect("Next event timed out")
185 .expect("No next event received")
186 }};
187}
188
189#[macro_export]
194macro_rules! assert_next_matches_with_timeout {
195 ($stream:expr, $pat:pat) => {
196 $crate::assert_next_matches_with_timeout!($stream, $pat => {})
197 };
198 ($stream:expr, $pat:pat => $arm:expr) => {
199 $crate::assert_next_matches_with_timeout!($stream, 100, $pat => $arm)
200 };
201 ($stream:expr, $timeout_ms:expr, $pat:pat) => {
202 $crate::assert_next_matches_with_timeout!($stream, $timeout_ms, $pat => {})
203 };
204 ($stream:expr, $timeout_ms:expr, $pat:pat => $arm:expr) => {
205 match $crate::assert_next_with_timeout!(&mut $stream, $timeout_ms) {
206 $pat => $arm,
207 val => {
208 ::core::panic!(
209 "assertion failed: `{:?}` does not match `{}`",
210 val, ::core::stringify!($pat)
211 );
212 }
213 }
214 };
215}
216
217#[macro_export]
253macro_rules! assert_next_eq_with_timeout {
254 ($stream:expr, $expected:expr) => {
255 $crate::assert_next_eq_with_timeout_impl!($stream, $expected, std::time::Duration::from_millis(100));
256 };
257 ($stream:expr, $expected:expr, $timeout:literal ms) => {
258 $crate::assert_next_eq_with_timeout_impl!($stream, $expected, std::time::Duration::from_millis($timeout));
259 };
260 ($stream:expr, $expected:expr, $timeout:literal ms, $($msg:tt)*) => {
261 $crate::assert_next_eq_with_timeout_impl!($stream, $expected, std::time::Duration::from_millis($timeout), $($msg)*);
262 };
263 ($stream:expr, $expected:expr, $($msg:tt)*) => {
264 $crate::assert_next_eq_with_timeout_impl!($stream, $expected, std::time::Duration::from_millis(100), $($msg)*);
265 };
266}
267
268#[macro_export]
293macro_rules! assert_decrypted_message_eq {
294 ($event:expr, $expected:expr, $($msg:tt)*) => {{
295 strass::assert_let!($crate::deserialized_responses::TimelineEventKind::Decrypted(decrypted_event) = $event.kind);
296
297 let deserialized_event = decrypted_event
298 .event
299 .deserialize()
300 .expect("We should be able to deserialize the decrypted event");
301
302 strass::assert_let!(
303 $crate::ruma::events::AnyTimelineEvent::MessageLike(deserialized_event) = deserialized_event
304 );
305
306 let content =
307 deserialized_event.original_content().expect("The event should not have been redacted");
308 strass::assert_let!($crate::ruma::events::AnyMessageLikeEventContent::RoomMessage(content) = content);
309 assert_eq!(content.body(), $expected, $($msg)*);
310 }};
311 ($event:expr, $expected:expr) => {{
312 assert_decrypted_message_eq!($event, $expected, "The decrypted content did not match to the expected value");
313 }};
314}
315
316#[macro_export]
345macro_rules! assert_let_decrypted_state_event_content {
346 ($pat:pat = $event:expr, $($msg:tt)*) => {
347 strass::assert_let!(
348 $crate::deserialized_responses::TimelineEventKind::Decrypted(decrypted_event) =
349 $event.kind,
350 "Event was not decrypted"
351 );
352
353 let deserialized_event = decrypted_event
354 .event
355 .deserialize_as_unchecked::<$crate::ruma::events::AnyStateEvent>()
356 .expect("We should be able to deserialize the decrypted event");
357
358 let content =
359 deserialized_event.original_content().expect("The event should not have been redacted");
360
361 strass::assert_let!($pat = content, $($msg)*);
362 };
363 ($pat:pat = $event:expr) => {
364 assert_let_decrypted_state_event_content!(
365 $pat = $event,
366 "The decrypted event did not match the expected value"
367 );
368 };
369}
370
371#[doc(hidden)]
372#[macro_export]
373macro_rules! assert_next_eq_with_timeout_impl {
374 ($stream:expr, $expected:expr, $timeout:expr) => {
375 let next_value = tokio::time::timeout(
376 $timeout,
377 $stream.next()
378 )
379 .await
380 .expect("We should be able to get the next value out of the stream by now")
381 .expect("The stream should have given us a new value instead of None");
382
383 assert_eq!(next_value, $expected);
384 };
385 ($stream:expr, $expected:expr, $timeout:expr, $($msg:tt)*) => {{
386 let next_value = tokio::time::timeout(
387 $timeout,
388 futures_util::StreamExt::next(&mut $stream)
389 )
390 .await
391 .expect("We should be able to get the next value out of the stream by now")
392 .expect("The stream should have given us a new value instead of None");
393
394 assert_eq!(next_value, $expected, $($msg)*);
395 }};
396}
397
398#[macro_export]
402macro_rules! assert_let_timeout {
403 ($timeout:expr, $pat:pat = $future:expr) => {
404 strass::assert_let!(Ok($pat) = tokio::time::timeout($timeout, $future).await);
405 };
406
407 ($pat:pat = $future:expr) => {
408 assert_let_timeout!(std::time::Duration::from_millis(100), $pat = $future);
409 };
410}