From 7cdcb0140e2f706937147f202da1555894bc6c4b Mon Sep 17 00:00:00 2001 From: mikoto Date: Fri, 16 Feb 2024 18:21:46 +0000 Subject: [PATCH] chore: first event handler test in client API --- Cargo.toml | 4 +- crates/core/src/room/service.rs | 4 +- crates/matrix/Cargo.toml | 2 +- crates/matrix/src/client/resources/events.rs | 56 ++++++-- crates/matrix/src/client/resources/mxc.rs | 23 +++- crates/matrix/src/client/resources/room.rs | 8 +- crates/matrix/src/event_filter.rs | 33 ----- crates/matrix/src/filter.rs | 97 ++++++++++---- crates/matrix/src/http.rs | 21 ++- crates/matrix/src/lib.rs | 2 +- crates/server/Cargo.toml | 2 + crates/test/Cargo.toml | 4 +- crates/test/src/matrix/events.rs | 129 +++++++++++++++++++ crates/test/src/matrix/room_admin.rs | 42 +++--- crates/test/src/matrix/room_client.rs | 63 ++++----- crates/test/src/matrix/util.rs | 39 +++--- 16 files changed, 361 insertions(+), 168 deletions(-) delete mode 100644 crates/matrix/src/event_filter.rs create mode 100644 crates/test/src/matrix/events.rs diff --git a/Cargo.toml b/Cargo.toml index 59c3dca..5fee52d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,7 @@ axum = { version = "0.7.4", features = ["tokio"] } chrono = { version = "0.4.34", features = ["serde"] } dotenv = "0.15.0" http = "0.2.11" -mime = { version = "0.3.17", features = ["serde1"] } +mime = "0.3.17" openssl = { version = "0.10.63", features = ["vendored"] } openssl-sys = { version = "0.9.99", features = ["vendored"] } reqwest = { version = "0.11.22", default-features = false, features = ["blocking", "json", "rustls", "multipart"] } @@ -22,6 +22,6 @@ serde = "1.0.192" serde_json = "1.0.108" tokio = "1.34.0" tracing = "0.1.40" -tracing-subscriber = "0.3.18" +tracing-subscriber = { version = "0.3.18", features = ["json"] } uuid = { version = "1.6.1", features = ["v4"] } url = "2.4.1" diff --git a/crates/core/src/room/service.rs b/crates/core/src/room/service.rs index 6ba2a82..4fc1f0f 100644 --- a/crates/core/src/room/service.rs +++ b/crates/core/src/room/service.rs @@ -4,7 +4,7 @@ use tracing::instrument; use matrix::{ client::resources::room::{ - CreateRoomBody, Room as MatrixRoom, RoomCreationContent, RoomPreset, + CreateRoomBody, RoomService as MatrixRoomService, RoomCreationContent, RoomPreset, }, Client as MatrixAdminClient, }; @@ -36,7 +36,7 @@ impl RoomService { access_token: &Secret, dto: CreateRoomDto, ) -> Result { - match MatrixRoom::create( + match MatrixRoomService::create( &self.admin, access_token.to_string(), CreateRoomBody { diff --git a/crates/matrix/Cargo.toml b/crates/matrix/Cargo.toml index 4dc5138..27796bc 100644 --- a/crates/matrix/Cargo.toml +++ b/crates/matrix/Cargo.toml @@ -18,7 +18,7 @@ ruma-macros = "0.12.0" # Workspace Dependencies anyhow = { workspace = true } chrono = { workspace = true, features = ["serde"] } -mime = { workspace = true, features = ["serde1"] } +mime = { workspace = true } reqwest = { workspace = true, features = ["json"] } serde = { workspace = true } tokio = { workspace = true } diff --git a/crates/matrix/src/client/resources/events.rs b/crates/matrix/src/client/resources/events.rs index 9416d22..415099a 100644 --- a/crates/matrix/src/client/resources/events.rs +++ b/crates/matrix/src/client/resources/events.rs @@ -2,37 +2,51 @@ use anyhow::Result; use ruma_common::{serde::Raw, EventId, OwnedEventId, RoomId, TransactionId}; use ruma_events::{ - relation::RelationType, AnyMessageLikeEvent, AnyStateEvent, AnyStateEventContent, + relation::RelationType, AnyStateEvent, AnyStateEventContent, AnyTimelineEvent, MessageLikeEventContent, MessageLikeEventType, StateEventContent, StateEventType, }; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use tracing::instrument; -use crate::{admin::resources::room::Direction, filter::RoomEventFilter, Client}; +use crate::{admin::resources::room::Direction, filter::RoomEventFilter, Client, error::MatrixError}; pub struct EventsService; #[derive(Debug, Default, Clone, Serialize)] pub struct GetMessagesQuery { + #[serde(skip_serializing_if = "Option::is_none")] pub from: Option, + + #[serde(skip_serializing_if = "Option::is_none")] pub to: Option, + + #[serde(skip_serializing_if = "Option::is_none")] pub limit: Option, - pub dir: Option, - pub filter: Option, + + pub dir: Direction, + + #[serde(skip_serializing_if = "String::is_empty")] + pub filter: String, } -#[derive(Debug, Default, Serialize)] +#[derive(Debug, Default, Clone, Serialize)] pub struct GetRelationsQuery { + #[serde(skip_serializing_if = "Option::is_none")] pub from: Option, + + #[serde(skip_serializing_if = "Option::is_none")] pub to: Option, + + #[serde(skip_serializing_if = "Option::is_none")] pub limit: Option, - pub dir: Option, + + pub dir: Direction, } #[derive(Debug, Deserialize)] pub struct GetMessagesResponse { - pub chunk: Vec>, + pub chunk: Vec>, pub start: String, pub end: String, pub state: Option>>, @@ -103,10 +117,10 @@ impl EventsService { tmp.set_token(access_token)?; let resp = tmp - .get(format!( + .get_query(format!( "/_matrix/client/v3/rooms/{room_id}/messages", room_id = room_id, - )) + ), &query) .await?; Ok(resp.json().await?) @@ -217,7 +231,13 @@ impl EventsService { ) .await?; - Ok(resp.json().await?) + if resp.status().is_success() { + return Ok(resp.json().await?); + } + + let error = resp.json::().await?; + + Err(anyhow::anyhow!(error.error)) } #[instrument(skip(client, access_token, body))] @@ -243,7 +263,13 @@ impl EventsService { let resp = tmp.put_json(path, &body).await?; - Ok(resp.json().await?) + if resp.status().is_success() { + return Ok(resp.json().await?); + } + + let error = resp.json::().await?; + + Err(anyhow::anyhow!(error.error)) } #[instrument(skip(client, access_token, body))] @@ -270,6 +296,12 @@ impl EventsService { ) .await?; - Ok(resp.json().await?) + if resp.status().is_success() { + return Ok(resp.json().await?); + } + + let error = resp.json::().await?; + + Err(anyhow::anyhow!(error.error)) } } diff --git a/crates/matrix/src/client/resources/mxc.rs b/crates/matrix/src/client/resources/mxc.rs index d50119e..0ea849a 100644 --- a/crates/matrix/src/client/resources/mxc.rs +++ b/crates/matrix/src/client/resources/mxc.rs @@ -1,12 +1,25 @@ +use std::str::FromStr; + use anyhow::Result; +use mime::Mime; use ruma_common::{MxcUri, OwnedMxcUri}; -use serde::{Deserialize, Serialize}; +use serde::{de, Deserialize, Deserializer, Serialize}; use tracing::instrument; use chrono::{serde::ts_microseconds_option, DateTime, Utc}; use crate::error::MatrixError; +fn parse_mime_opt<'de, D>(d: D) -> Result, D::Error> +where + D: Deserializer<'de>, +{ + Option::<&str>::deserialize(d)? + .map(::from_str) + .transpose() + .map_err(de::Error::custom) +} + #[derive(Debug, Serialize)] pub struct GetPreviewUrlQuery { pub url: url::Url, @@ -38,7 +51,7 @@ pub struct GetPreviewUrlResponse { #[serde(rename = "og:image:width")] pub width: Option, - #[serde(rename = "og:image:type")] + #[serde(rename = "og:image:type", deserialize_with = "parse_mime_opt")] pub kind: Option, #[serde(rename = "og:title")] @@ -112,8 +125,8 @@ impl MxcService { Err(anyhow::anyhow!(error.inner.error)) } - /// Retrieve a URL to download content from the content repository, optionally replacing the - /// name of the file. + /// Retrieve a URL to download content from the content repository, + /// optionally replacing the name of the file. /// /// Refer: https://spec.matrix.org/v1.9/client-server-api/#get_matrixmediav3downloadservernamemediaid #[instrument(skip(client, access_token))] @@ -144,7 +157,7 @@ impl MxcService { Ok(base_url) } - /// + /// /// /// Refer: https://spec.matrix.org/v1.9/client-server-api/#get_matrixmediav3preview_url #[instrument(skip(client, access_token))] diff --git a/crates/matrix/src/client/resources/room.rs b/crates/matrix/src/client/resources/room.rs index 078b76d..5d51035 100644 --- a/crates/matrix/src/client/resources/room.rs +++ b/crates/matrix/src/client/resources/room.rs @@ -4,6 +4,8 @@ use ruma_events::{room::power_levels::RoomPowerLevelsEventContent, AnyInitialSta use serde::{Deserialize, Serialize}; use tracing::instrument; +use crate::error::MatrixError; + #[derive(Debug, Serialize)] #[serde(rename_all = "snake_case")] pub enum RoomPreset { @@ -103,12 +105,6 @@ pub struct ForgetRoomResponse {} #[derive(Debug, Deserialize)] pub struct RoomKickOrBanResponse {} -#[derive(Debug, Deserialize)] -pub struct MatrixError { - pub errcode: String, - pub error: String, -} - pub struct RoomService; impl RoomService { diff --git a/crates/matrix/src/event_filter.rs b/crates/matrix/src/event_filter.rs deleted file mode 100644 index 35e30b8..0000000 --- a/crates/matrix/src/event_filter.rs +++ /dev/null @@ -1,33 +0,0 @@ -use ruma_common::{OwnedRoomId, OwnedUserId}; -use serde::Serialize; - -#[derive(Default, Debug, Serialize)] -pub struct RoomEventFilter { - #[serde(skip_serializing_if = "<[_]>::is_empty")] - pub not_types: Vec, - - #[serde(skip_serializing_if = "<[_]>::is_empty")] - pub not_rooms: Vec, - - #[serde(skip_serializing_if = "Option::is_none")] - pub limit: Option, - - #[serde(skip_serializing_if = "<[_]>::is_empty")] - pub rooms: Vec, - - #[serde(skip_serializing_if = "<[_]>::is_empty")] - pub not_senders: Vec, - - #[serde(skip_serializing_if = "<[_]>::is_empty")] - pub senders: Vec, - - #[serde(skip_serializing_if = "<[_]>::is_empty")] - pub types: Vec, - - #[serde(skip_serializing_if = "Option::is_none")] - pub include_urls: Option, - - pub lazy_load_members: bool, - - pub unread_thread_notifications: bool, -} diff --git a/crates/matrix/src/filter.rs b/crates/matrix/src/filter.rs index 5a089ee..3d4e398 100644 --- a/crates/matrix/src/filter.rs +++ b/crates/matrix/src/filter.rs @@ -1,5 +1,5 @@ use anyhow::Result; -use ruma_common::{OwnedRoomId, OwnedUserId}; +use ruma_common::{OwnedRoomId, OwnedUserId, UserId}; use ruma_events::TimelineEventType; use serde::{Deserialize, Serialize}; @@ -14,20 +14,32 @@ pub enum EventFormat { #[derive(Debug, Default, Clone, Serialize, Deserialize)] pub struct Filter { - #[serde(rename = "account_data")] - account: Option, + #[serde(skip_serializing_if = "Option::is_none", rename = "account_data")] + pub account: Option, #[serde(skip_serializing_if = "<[_]>::is_empty")] - event_fields: Vec, + pub event_fields: Vec, #[serde(skip_serializing_if = "Option::is_none")] - event_format: Option, + pub event_format: Option, #[serde(skip_serializing_if = "Option::is_none")] - presence: Option, + pub presence: Option, - #[serde(rename = "room")] - room: Option, + #[serde(skip_serializing_if = "Option::is_none", rename = "room")] + pub room: Option, +} + +impl Filter { + pub fn room_events(filter: RoomEventFilter) -> Self { + Self { + room: Some(RoomFilter { + timeline: Some(filter), + ..Default::default() + }), + ..Default::default() + } + } } #[derive(Debug, Default, Clone, Serialize, Deserialize)] @@ -73,29 +85,26 @@ pub struct RoomFilter { #[derive(Debug, Default, Clone, Serialize, Deserialize)] pub struct RoomEventFilter { - #[serde(flatten)] - pub inner: EventFilter, - - #[serde(skip_serializing_if = "Option::is_none", rename = "contains_url")] - pub include_urls: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub limit: Option, - pub include_redundant_members: bool, + #[serde(skip_serializing_if = "<[_]>::is_empty")] + pub not_rooms: Vec, - pub lazy_load_members: bool, + #[serde(skip_serializing_if = "<[_]>::is_empty")] + pub not_senders: Vec, #[serde(skip_serializing_if = "<[_]>::is_empty")] - pub not_rooms: Vec, + pub not_types: Vec, #[serde(skip_serializing_if = "<[_]>::is_empty")] pub rooms: Vec, - pub unread_thread_notifications: bool, -} + #[serde(skip_serializing_if = "<[_]>::is_empty")] + pub senders: Vec, -#[derive(Debug, Default, Clone, Serialize, Deserialize)] -pub struct StateFilter { - #[serde(flatten)] - pub inner: EventFilter, + #[serde(skip_serializing_if = "<[_]>::is_empty")] + pub types: Vec, #[serde(skip_serializing_if = "Option::is_none", rename = "contains_url")] pub include_urls: Option, @@ -104,29 +113,65 @@ pub struct StateFilter { pub lazy_load_members: bool, + pub unread_thread_notifications: bool, +} + +#[derive(Debug, Default, Clone, Serialize, Deserialize)] +pub struct StateFilter { + #[serde(skip_serializing_if = "Option::is_none")] + pub limit: Option, + #[serde(skip_serializing_if = "<[_]>::is_empty")] pub not_rooms: Vec, + #[serde(skip_serializing_if = "<[_]>::is_empty")] + pub not_senders: Vec, + + #[serde(skip_serializing_if = "<[_]>::is_empty")] + pub not_types: Vec, + #[serde(skip_serializing_if = "<[_]>::is_empty")] pub rooms: Vec, + #[serde(skip_serializing_if = "<[_]>::is_empty")] + pub senders: Vec, + + #[serde(skip_serializing_if = "<[_]>::is_empty")] + pub types: Vec, + + #[serde(skip_serializing_if = "Option::is_none", rename = "contains_url")] + pub include_urls: Option, + + pub include_redundant_members: bool, + + pub lazy_load_members: bool, + pub unread_thread_notifications: bool, } pub struct FilterService; +#[derive(Debug, Deserialize)] +pub struct FilterResponse { + pub filter_id: String, +} + impl FilterService { pub async fn create( client: &Client, access_token: impl Into, + user_id: &UserId, body: Filter, - ) -> Result { + ) -> Result { let mut tmp = (*client).clone(); tmp.set_token(access_token)?; let resp = tmp .post_json( - format!("/_matrix/client/v3/user/@admin:matrix.localhost/filter",), + format!( + "/_matrix/client/v3/user/{user_id}/filter", + user_id = user_id + ), &body, ) .await?; @@ -143,6 +188,7 @@ impl FilterService { pub async fn get( client: &Client, access_token: impl Into, + user_id: &UserId, filter_id: String, ) -> Result { let mut tmp = (*client).clone(); @@ -150,7 +196,8 @@ impl FilterService { let resp = tmp .get(format!( - "/_matrix/client/v3/user/@admin:matrix.localhost/filter/{filter_id}" + "/_matrix/client/v3/user/{user_id}/filter/{filter_id}", + user_id = user_id )) .await?; diff --git a/crates/matrix/src/http.rs b/crates/matrix/src/http.rs index c697d9a..22db5c8 100644 --- a/crates/matrix/src/http.rs +++ b/crates/matrix/src/http.rs @@ -47,6 +47,11 @@ impl Client { Ok(()) } + /// Clear the token for safety purposes. + pub fn clear_token(&mut self) { + self.token = None; + } + pub async fn get(&self, path: impl AsRef) -> Result { let url = self.build_url(path)?; let headers = self.build_headers()?; @@ -67,7 +72,7 @@ impl Client { Ok(response) } - pub async fn post_json(&self, path: impl AsRef, body: &T) -> Result + pub async fn put_json(&self, path: impl AsRef, body: &T) -> Result where T: Serialize, { @@ -75,7 +80,7 @@ impl Client { let headers = self.build_headers()?; let resp = self .client - .post(url) + .put(url) .json(body) .headers(headers) .send() @@ -84,7 +89,15 @@ impl Client { Ok(resp) } - pub async fn put_json(&self, path: impl AsRef, body: &T) -> Result + pub async fn post(&self, path: impl AsRef) -> Result { + let url = self.build_url(path)?; + let headers = self.build_headers()?; + let resp = self.client.post(url).headers(headers).send().await?; + + Ok(resp) + } + + pub async fn post_json(&self, path: impl AsRef, body: &T) -> Result where T: Serialize, { @@ -92,7 +105,7 @@ impl Client { let headers = self.build_headers()?; let resp = self .client - .put(url) + .post(url) .json(body) .headers(headers) .send() diff --git a/crates/matrix/src/lib.rs b/crates/matrix/src/lib.rs index e5458a1..0afb5f3 100644 --- a/crates/matrix/src/lib.rs +++ b/crates/matrix/src/lib.rs @@ -6,7 +6,7 @@ mod http; mod error; -mod event_filter; +pub mod filter; pub use http::Client; diff --git a/crates/server/Cargo.toml b/crates/server/Cargo.toml index cd5f7c1..3dae89d 100644 --- a/crates/server/Cargo.toml +++ b/crates/server/Cargo.toml @@ -31,3 +31,5 @@ uuid = { workspace = true, features= ["serde"] } # Local Dependencies core = { path = "../core" } +chrono = { version = "0.4.34", features = ["serde"] } +mime = { git = "https://github.com/hyperium/mime", version = "0.4.0-a.0" } diff --git a/crates/test/Cargo.toml b/crates/test/Cargo.toml index 71411f1..9edcc22 100644 --- a/crates/test/Cargo.toml +++ b/crates/test/Cargo.toml @@ -10,6 +10,7 @@ path = "src/lib.rs" [dependencies] fake = { version = "2.9.2", features = ["derive"] } +futures = "0.3.30" rand = "0.8.5" scraper = "0.18.1" @@ -20,11 +21,12 @@ dotenv = { workspace = true } reqwest = { workspace = true } openssl = { workspace = true, features = ["vendored"] } serde = { workspace = true } +serde_json = { workspace = true } tokio = { workspace = true, features = ["rt", "rt-multi-thread", "macros"] } url = { workspace = true } uuid = { workspace = true, features = ["serde"] } tracing = { workspace = true } -tracing-subscriber = { workspace = true } +tracing-subscriber = { workspace = true, features = ["json"] } # Local Dependencies core = { path = "../core" } diff --git a/crates/test/src/matrix/events.rs b/crates/test/src/matrix/events.rs new file mode 100644 index 0000000..cf97303 --- /dev/null +++ b/crates/test/src/matrix/events.rs @@ -0,0 +1,129 @@ +#[cfg(test)] +mod tests { + use futures::{future, TryFutureExt}; + use matrix::{ + client::resources::events::{EventsService, GetMessagesQuery, SendMessageResponse}, + filter::{Filter, FilterService, RoomEventFilter}, + ruma_common::TransactionId, + ruma_events::{room::message::RoomMessageEventContent, MessageLikeEventType}, + }; + use tokio::sync::OnceCell; + + use crate::matrix::util::{self, join_helper, Test}; + + static TEST: OnceCell = OnceCell::const_new(); + + #[tokio::test] + async fn send_message() { + let Test { admin, samples, .. } = TEST.get_or_init(util::init).await; + + let mut client = admin.clone(); + client.clear_token(); + + // first join + let joins = join_helper(&client, samples).await; + + assert!(joins + .iter() + .all(|(_, _, resps)| resps.iter().all(Result::is_ok))); + + let mut events = Vec::with_capacity(samples.len()); + + for sample in samples { + let room_id = &sample.room_id; + + let guests: Vec<_> = samples + .iter() + .filter(|g| g.user_id != sample.user_id) + .collect(); + let mut resps = Vec::with_capacity(samples.len()); + + for guest in guests.iter() { + let SendMessageResponse { event_id } = EventsService::send_message( + &client, + guest.access_token.clone(), + room_id, + &TransactionId::new(), + RoomMessageEventContent::text_markdown(format!( + "hello, **my name is {}**", + guest.user_id + )), + ) + .await + .unwrap(); + + tracing::info!( + "{} sent an event with ID {} to {}", + guest.user_id, + event_id, + room_id + ); + + resps.push(event_id); + } + + let SendMessageResponse { event_id } = EventsService::send_message( + &client, + sample.access_token.clone(), + room_id, + &TransactionId::new(), + RoomMessageEventContent::text_plain(format!( + "and I am the admin of the room, {}", + sample.user_id + )), + ) + .await + .unwrap(); + + resps.push(event_id); + events.push((room_id, resps)); + } + + let expected: Vec<_> = (0..samples.len()) + .flat_map(|i| { + (0..samples.len()).map(move |j| match j == i { + true => format!( + "and I am the admin of the room, {}", + samples.get(j).map(|s| s.user_id.clone()).unwrap() + ), + false => format!( + "hello, **my name is {}**", + samples.get(j).map(|s| s.user_id.clone()).unwrap() + ), + }) + }) + .collect(); + + let filter = RoomEventFilter { + types: vec![MessageLikeEventType::RoomMessage.into()], + ..Default::default() + }; + + let filter = serde_json::to_string(&filter).unwrap(); + // dbg!(&s); + + client.clear_token(); + let found = future::try_join_all(samples.iter().map(|s| { + EventsService::get_messages( + &client, + s.access_token.clone(), + &s.room_id, + GetMessagesQuery { + // limit: Some(100), + dir: matrix::admin::resources::room::Direction::Backward, + filter: filter.clone(), + ..Default::default() + }, + ) + })) + .await + .unwrap(); + + dbg!(&found); + + // tracing::info!(?found); + // tracing::info!(?expected); + + // assert_eq!(expected, found); + } +} diff --git a/crates/test/src/matrix/room_admin.rs b/crates/test/src/matrix/room_admin.rs index 067c6bd..acdb407 100644 --- a/crates/test/src/matrix/room_admin.rs +++ b/crates/test/src/matrix/room_admin.rs @@ -19,11 +19,11 @@ mod tests { let Test { samples, server_name, - client, + admin, } = TEST.get_or_init(util::init).await; let ListRoomResponse { rooms: resp, .. } = - AdminRoomService::get_all(client, ListRoomQuery::default()) + AdminRoomService::get_all(admin, ListRoomQuery::default()) .await .unwrap(); @@ -49,7 +49,7 @@ mod tests { ); let ListRoomResponse { rooms: resp, .. } = AdminRoomService::get_all( - client, + admin, ListRoomQuery { order_by: OrderBy::Creator, ..Default::default() @@ -72,10 +72,10 @@ mod tests { #[tokio::test] #[should_panic] async fn get_all_rooms_err() { - let Test { client, .. } = TEST.get_or_init(util::init).await; + let Test { admin, .. } = TEST.get_or_init(util::init).await; let _ = AdminRoomService::get_all( - client, + admin, ListRoomQuery { from: Some(u64::MAX), ..Default::default() @@ -90,13 +90,13 @@ mod tests { let Test { samples, server_name, - client, + admin, } = TEST.get_or_init(util::init).await; let magic_number = Box::into_raw(Box::new(12345)) as usize % samples.len(); let rand = samples.get(magic_number).unwrap(); - let resp = AdminRoomService::get_one(client, &rand.room_id) + let resp = AdminRoomService::get_one(admin, &rand.room_id) .await .unwrap(); @@ -129,12 +129,12 @@ mod tests { async fn get_room_details_err() { let Test { server_name, - client, + admin, .. } = TEST.get_or_init(util::init).await; let _ = AdminRoomService::get_one( - client, + admin, &RoomId::new(&ServerName::parse(server_name).unwrap()), ) .await @@ -144,14 +144,14 @@ mod tests { #[tokio::test] async fn get_room_events() { let Test { - samples, client, .. + samples, admin, .. } = TEST.get_or_init(util::init).await; let magic_number = Box::into_raw(Box::new(12345)) as usize % samples.len(); let rand = samples.get(magic_number).unwrap(); let resp = AdminRoomService::get_room_events( - client, + admin, &rand.room_id, // no idea what the type is MessagesQuery { @@ -174,12 +174,12 @@ mod tests { async fn get_room_events_err() { let Test { server_name, - client, + admin, .. } = TEST.get_or_init(util::init).await; let _ = AdminRoomService::get_room_events( - client, + admin, <&RoomId>::try_from(server_name.as_str()).unwrap(), MessagesQuery { from: "".into(), @@ -196,13 +196,13 @@ mod tests { #[tokio::test] async fn get_state_events() { let Test { - samples, client, .. + samples, admin, .. } = TEST.get_or_init(util::init).await; let magic_number = Box::into_raw(Box::new(12345)) as usize % samples.len(); let rand = samples.get(magic_number).unwrap(); - let resp = AdminRoomService::get_state(client, &rand.room_id) + let resp = AdminRoomService::get_state(admin, &rand.room_id) .await .unwrap(); @@ -217,12 +217,12 @@ mod tests { async fn get_state_events_err() { let Test { server_name, - client, + admin, .. } = TEST.get_or_init(util::init).await; let _ = - AdminRoomService::get_state(client, <&RoomId>::try_from(server_name.as_str()).unwrap()) + AdminRoomService::get_state(admin, <&RoomId>::try_from(server_name.as_str()).unwrap()) .await .unwrap(); } @@ -230,13 +230,13 @@ mod tests { #[tokio::test] async fn get_members() { let Test { - samples, client, .. + samples, admin, .. } = TEST.get_or_init(util::init).await; let magic_number = Box::into_raw(Box::new(12345)) as usize % samples.len(); let rand = samples.get(magic_number).unwrap(); - let resp = AdminRoomService::get_members(client, &rand.room_id) + let resp = AdminRoomService::get_members(admin, &rand.room_id) .await .unwrap(); @@ -248,12 +248,12 @@ mod tests { async fn get_members_err() { let Test { server_name, - client, + admin, .. } = TEST.get_or_init(util::init).await; let _ = AdminRoomService::get_members( - client, + admin, <&RoomId>::try_from(server_name.as_str()).unwrap(), ) .await diff --git a/crates/test/src/matrix/room_client.rs b/crates/test/src/matrix/room_client.rs index e4bc856..6aa1d75 100644 --- a/crates/test/src/matrix/room_client.rs +++ b/crates/test/src/matrix/room_client.rs @@ -3,10 +3,9 @@ mod tests { use matrix::{ admin::resources::room::RoomService as AdminRoomService, client::resources::room::{ - ForgetRoomBody, JoinRoomBody, JoinRoomResponse, LeaveRoomBody, RoomService, - RoomKickOrBanBody, + ForgetRoomBody, LeaveRoomBody, + RoomKickOrBanBody, RoomService, }, - ruma_common::{OwnedRoomId, OwnedRoomOrAliasId, OwnedUserId}, }; use tokio::sync::OnceCell; @@ -16,10 +15,14 @@ mod tests { #[tokio::test] async fn join_all_rooms() { - let Test { client, samples, .. } = TEST.get_or_init(util::init).await; + let Test { admin, samples, .. } = TEST.get_or_init(util::init).await; + + let mut client = admin.clone(); + client.clear_token(); // first join - let result = join_helper(client, samples).await; + let result = join_helper(&client, samples).await; + let rooms: Vec<_> = result.iter().map(|r| &r.0).collect(); tracing::info!(?rooms, "joining all guests"); @@ -44,24 +47,21 @@ mod tests { #[tokio::test] async fn leave_all_rooms() { let Test { - samples, client, .. + samples, admin, .. } = TEST.get_or_init(util::init).await; - let admin = client.clone(); + let mut client = admin.clone(); + client.clear_token(); let mut result = Vec::with_capacity(samples.len()); for sample in samples { - let client = client.clone(); - let guests: Vec<_> = samples .iter() .filter(|g| g.user_id != sample.user_id) .collect(); for guest in guests { - let client = client.clone(); - RoomService::leave( &client, guest.access_token.clone(), @@ -96,20 +96,19 @@ mod tests { #[tokio::test] async fn forget_all_rooms() { let Test { - samples, client, .. + samples, admin, .. } = TEST.get_or_init(util::init).await; - for sample in samples { - let client = client.clone(); + let mut client = admin.clone(); + client.clear_token(); + for sample in samples { let guests: Vec<_> = samples .iter() .filter(|g| g.user_id != sample.user_id) .collect(); for guest in guests { - let client = client.clone(); - RoomService::forget( &client, guest.access_token.clone(), @@ -122,7 +121,6 @@ mod tests { } // check whether all guests are still not present anymore the room - let admin = client.clone(); for sample in samples { let room_id = &sample.room_id; @@ -143,7 +141,6 @@ mod tests { // confirm a room can't be forgotten if we didn't leave first for sample in samples { - let client = client.clone(); let room_id = &sample.room_id; let resp = RoomService::forget( @@ -161,16 +158,18 @@ mod tests { #[tokio::test] async fn kick_all_guests() { let Test { - samples, client, .. + samples, admin, .. } = TEST.get_or_init(util::init).await; + let mut client = admin.clone(); + client.clear_token(); + // second join - let result = join_helper().await; + let result = join_helper(&client, samples).await; let rooms: Vec<_> = result.iter().map(|r| &r.0).collect(); tracing::info!(?rooms, "joining all guests"); // check whether all guests are in the room and joined the expected room - let admin = client.clone(); for (room_id, guests, resps) in result.iter() { let mut resp = AdminRoomService::get_members(&admin, room_id) .await @@ -188,7 +187,6 @@ mod tests { } for sample in samples { - let client = client.clone(); let room_id = &sample.room_id; let guests: Vec<_> = samples @@ -197,8 +195,6 @@ mod tests { .collect(); for guest in guests { - let client = client.clone(); - RoomService::kick( &client, guest.access_token.clone(), @@ -234,16 +230,18 @@ mod tests { #[tokio::test] async fn ban_all_guests() { let Test { - samples, client, .. + samples, admin, .. } = TEST.get_or_init(util::init).await; + let mut client = admin.clone(); + client.clear_token(); + // third join - let result = join_helper().await; + let result = join_helper(&client, samples).await; let rooms: Vec<_> = result.iter().map(|r| &r.0).collect(); tracing::info!(?rooms, "joining all guests"); // check whether all guests are in the room and joined the expected room - let admin = client.clone(); for (room_id, guests, resps) in result.iter() { let mut resp = AdminRoomService::get_members(&admin, room_id) .await @@ -261,8 +259,6 @@ mod tests { } for sample in samples { - let client = client.clone(); - let guests: Vec<_> = samples .iter() .filter(|g| g.user_id != sample.user_id) @@ -287,13 +283,13 @@ mod tests { } // fourth join - let result = join_helper().await; + let result = join_helper(&client, samples).await; let rooms: Vec<_> = result.iter().map(|r| &r.0).collect(); tracing::info!(?rooms, "joining all guests"); // check whether all guests got banned from the room // check whether their join request failed - for (room_id, _, resps) in result { + for (ref room_id, _, resps) in result { let resp = AdminRoomService::get_members(&admin, &room_id) .await .unwrap(); @@ -302,7 +298,7 @@ mod tests { assert_eq!( &[samples .iter() - .find(|s| s.room_id == room_id) + .find(|s| &s.room_id == room_id) .map(|s| s.user_id.clone()) .unwrap()], resp.members.as_slice() @@ -312,15 +308,12 @@ mod tests { } for sample in samples { - let client = client.clone(); - let guests: Vec<_> = samples .iter() .filter(|g| g.user_id != sample.user_id) .collect(); for guest in guests { - let client = client.clone(); let room_id = &sample.room_id; RoomService::unban( diff --git a/crates/test/src/matrix/util.rs b/crates/test/src/matrix/util.rs index f8a4f22..58ab636 100644 --- a/crates/test/src/matrix/util.rs +++ b/crates/test/src/matrix/util.rs @@ -2,14 +2,14 @@ use std::str::FromStr; use matrix::{ admin::resources::{ - room::{DeleteQuery, ListRoomQuery, ListRoomResponse, RoomService as AdminRoomService}, + room::{RoomService as AdminRoomService, ListRoomResponse, ListRoomQuery, DeleteQuery}, user::{ - CreateUserBody, LoginAsUserBody, LoginAsUserResponse, UserService as AdminUserService, + UserService as AdminUserService, CreateUserBody, }, user_id::UserId, }, - client::resources::room::{CreateRoomBody, RoomService, RoomPreset}, - ruma_common::{OwnedRoomId, OwnedUserId}, + client::resources::{room::{CreateRoomBody, RoomService, RoomPreset, JoinRoomResponse, JoinRoomBody, RoomVisibility}, login::{Login, LoginCredentials}}, + ruma_common::{OwnedRoomId, OwnedUserId, OwnedRoomOrAliasId}, Client, }; @@ -20,7 +20,7 @@ use crate::tools::environment::Environment; pub struct Test { pub samples: Vec, pub server_name: String, - pub client: Client, + pub admin: Client, } pub struct Sample { @@ -38,7 +38,8 @@ async fn create_accounts( let mut result = Vec::with_capacity(amount); for i in 0..amount { - let user_id = UserId::new(format!("{seed}-{i}"), server_name.clone()); + let username = format!("{seed}-{i}"); + let user_id = UserId::new(username.clone(), server_name.clone()); let password = "verysecure".to_owned(); let body = CreateUserBody { @@ -57,9 +58,9 @@ async fn create_accounts( .await .unwrap(); - let body = LoginAsUserBody::default(); - let LoginAsUserResponse { access_token } = - AdminUserService::login_as_user(&client, user_id.clone(), body) + let password = "verysecure".to_owned(); + let LoginCredentials { access_token } = + Login::login_credentials(client, username, password) .await .unwrap(); @@ -80,15 +81,17 @@ async fn create_rooms(client: &Client, accounts: &[(OwnedUserId, String)]) -> Ve let name = format!("{id}-room-name"); let topic = format!("{id}-room-topic"); let room_alias_name = format!("{id}-room-alias"); + let visibility = Some(RoomVisibility::Public); let body = CreateRoomBody { name, topic, room_alias_name, preset, + visibility, ..Default::default() }; - let resp = Room::create(client, access_token, body).await.unwrap(); + let resp = RoomService::create(client, access_token, body).await.unwrap(); result.push(resp.room_id); } @@ -132,14 +135,14 @@ pub async fn init() -> Test { let server_name = env.config.synapse_server_name.clone(); let admin_token = env.config.synapse_admin_token.clone(); - let mut client = env.client.clone(); + let mut admin = env.client.clone(); - client.set_token(admin_token).unwrap(); - remove_rooms(&client).await; + admin.set_token(admin_token).unwrap(); + remove_rooms(&admin).await; - let accounts = create_accounts(&client, server_name.clone(), 4, seed).await; + let accounts = create_accounts(&admin, server_name.clone(), 4, seed).await; let rooms = create_rooms( - &client, + &admin, accounts .iter() .map(|(user_id, access_token)| (user_id.clone(), access_token.clone())) @@ -161,7 +164,7 @@ pub async fn init() -> Test { Test { samples, server_name, - client, + admin, } } @@ -173,8 +176,6 @@ pub async fn join_helper(client: &Client, samples: &[Sample]) -> Vec<( let mut result = Vec::with_capacity(samples.len()); for sample in samples { - let client = client.clone(); - let guests: Vec<_> = samples .iter() .filter(|g| g.user_id != sample.user_id) @@ -182,8 +183,6 @@ pub async fn join_helper(client: &Client, samples: &[Sample]) -> Vec<( let mut resps = Vec::with_capacity(guests.len()); for guest in guests.iter() { - let client = client.clone(); - let resp = RoomService::join( &client, guest.access_token.clone(),