From 4f96ac96e2cf2fd11c67b2584451377e04dee5bc Mon Sep 17 00:00:00 2001 From: Devin R Date: Thu, 7 May 2020 15:21:06 -0400 Subject: [PATCH] async_client: add tests for all current endpoints, event emitter typeing/receipt events, set unread notifications --- matrix_sdk/src/async_client.rs | 240 ++++++++++++++++++++--- matrix_sdk_base/src/base_client.rs | 6 + matrix_sdk_base/src/event_emitter/mod.rs | 10 +- matrix_sdk_base/src/models/room.rs | 7 +- test_data/event_id.json | 3 + 5 files changed, 233 insertions(+), 33 deletions(-) create mode 100644 test_data/event_id.json diff --git a/matrix_sdk/src/async_client.rs b/matrix_sdk/src/async_client.rs index fd631bc7..10571acd 100644 --- a/matrix_sdk/src/async_client.rs +++ b/matrix_sdk/src/async_client.rs @@ -324,16 +324,14 @@ impl AsyncClient { /// Returns the invited rooms this client knows about. /// /// A `HashMap` of room id to `matrix::models::Room` - pub async fn invited_rooms( - &self, - ) -> Arc>>>> { + pub fn invited_rooms(&self) -> Arc>>>> { self.base_client.invited_rooms() } /// Returns the left rooms this client knows about. /// /// A `HashMap` of room id to `matrix::models::Room` - pub async fn left_rooms(&self) -> Arc>>>> { + pub fn left_rooms(&self) -> Arc>>>> { self.base_client.left_rooms() } @@ -1196,10 +1194,11 @@ impl AsyncClient { mod test { use super::{ ban_user, create_receipt, create_typing_event, forget_room, invite_user, kick_user, - leave_room, + leave_room, Invite3pid, MessageEventContent, RoomIdOrAliasId, }; use super::{AsyncClient, AsyncClientConfig, Session, SyncSettings, Url}; use crate::events::room::member::MembershipState; + use crate::events::room::message::TextMessageEventContent; use crate::identifiers::{EventId, RoomId, UserId}; use matrix_sdk_base::JsonStore; @@ -1339,7 +1338,7 @@ mod test { } #[tokio::test] - async fn join_room() { + async fn join_room_by_id() { let homeserver = Url::from_str(&mockito::server_url()).unwrap(); let session = Session { @@ -1366,9 +1365,41 @@ mod test { ); } + #[tokio::test] + async fn join_room_by_id_or_alias() { + let homeserver = Url::from_str(&mockito::server_url()).unwrap(); + + let session = Session { + access_token: "1234".to_owned(), + user_id: UserId::try_from("@example:localhost").unwrap(), + device_id: "DEVICEID".to_owned(), + }; + + let _m = mock( + "POST", + Matcher::Regex(r"^/_matrix/client/r0/join/".to_string()), + ) + .with_status(200) + .with_body_from_file("../test_data/room_id.json") + .create(); + + let client = AsyncClient::new(homeserver, Some(session)).unwrap(); + let room_id = RoomIdOrAliasId::try_from("!testroom:example.org").unwrap(); + + assert_eq!( + // this is the `join_by_room_id::Response` but since no PartialEq we check the RoomId field + client + .join_room_by_id_or_alias(&room_id, &["server.com".to_string()]) + .await + .unwrap() + .room_id, + RoomId::try_from("!testroom:example.org").unwrap() + ); + } + #[tokio::test] #[allow(irrefutable_let_patterns)] - async fn invite_room() { + async fn invite_user_by_id() { let homeserver = Url::from_str(&mockito::server_url()).unwrap(); let user = UserId::try_from("@example:localhost").unwrap(); let room_id = RoomId::try_from("!testroom:example.org").unwrap(); @@ -1392,6 +1423,44 @@ mod test { if let invite_user::Response = client.invite_user_by_id(&room_id, &user).await.unwrap() {} } + #[tokio::test] + #[allow(irrefutable_let_patterns)] + async fn invite_user_by_3pid() { + let homeserver = Url::from_str(&mockito::server_url()).unwrap(); + let user = UserId::try_from("@example:localhost").unwrap(); + let room_id = RoomId::try_from("!testroom:example.org").unwrap(); + + let session = Session { + access_token: "1234".to_owned(), + user_id: user.clone(), + device_id: "DEVICEID".to_owned(), + }; + + let _m = mock( + "POST", + Matcher::Regex(r"^/_matrix/client/r0/rooms/.*/invite".to_string()), + ) + .with_status(200) + .with_body_from_file("../test_data/logout_response.json") + .create(); + + let client = AsyncClient::new(homeserver, Some(session)).unwrap(); + + if let invite_user::Response = client + .invite_user_by_3pid( + &room_id, + &Invite3pid { + id_server: "example.org".to_string(), + id_access_token: "IdToken".to_string(), + medium: crate::api::r0::thirdparty::Medium::Email, + address: "address".to_string(), + }, + ) + .await + .unwrap() + {} + } + #[tokio::test] #[allow(irrefutable_let_patterns)] async fn leave_room() { @@ -1604,6 +1673,48 @@ mod test { } } + #[tokio::test] + async fn room_message_send() { + use uuid::Uuid; + + let homeserver = Url::from_str(&mockito::server_url()).unwrap(); + let user = UserId::try_from("@example:localhost").unwrap(); + let room_id = RoomId::try_from("!testroom:example.org").unwrap(); + + let session = Session { + access_token: "1234".to_owned(), + user_id: user.clone(), + device_id: "DEVICEID".to_owned(), + }; + + let _m = mock( + "PUT", + Matcher::Regex(r"^/_matrix/client/r0/rooms/.*/send/".to_string()), + ) + .with_status(200) + .with_body_from_file("../test_data/event_id.json") + .create(); + + let client = AsyncClient::new(homeserver, Some(session)).unwrap(); + + let content = MessageEventContent::Text(TextMessageEventContent { + body: "Hello world".to_owned(), + format: None, + formatted_body: None, + relates_to: None, + }); + let txn_id = Uuid::new_v4(); + let response = client + .room_send(&room_id, content, Some(txn_id)) + .await + .unwrap(); + + assert_eq!( + EventId::try_from("$h29iv0s8:example.com").ok(), + response.event_id + ) + } + #[tokio::test] async fn user_presence() { let homeserver = Url::from_str(&mockito::server_url()).unwrap(); @@ -1644,35 +1755,102 @@ mod test { assert!(room.power_levels.is_some()) } - // #[tokio::test] - // async fn calculate_room_names_from_summary() { - // let homeserver = Url::from_str(&mockito::server_url()).unwrap(); + #[tokio::test] + async fn calculate_room_names_from_summary() { + let homeserver = Url::from_str(&mockito::server_url()).unwrap(); - // let mut bld = EventBuilder::default().build_with_response( - // // this sync has no room.name or room.alias events so only relies on summary - // "../test_data/sync_with_summary.json", - // "GET", - // Matcher::Regex(r"^/_matrix/client/r0/sync\?.*$".to_string()), - // ); + let session = Session { + access_token: "1234".to_owned(), + user_id: UserId::try_from("@example:localhost").unwrap(), + device_id: "DEVICEID".to_owned(), + }; - // let session = Session { - // access_token: "1234".to_owned(), - // user_id: UserId::try_from("@example:localhost").unwrap(), - // device_id: "DEVICEID".to_owned(), - // }; - // let client = AsyncClient::new(homeserver, Some(session)).unwrap(); - // let client = bld.set_client(client).to_client().await.unwrap(); + let _m = mock( + "GET", + Matcher::Regex(r"^/_matrix/client/r0/sync\?.*$".to_string()), + ) + .with_status(200) + .with_body_from_file("../test_data/sync_with_summary.json") + .create(); - // let sync_settings = SyncSettings::new().timeout(Duration::from_millis(3000)); - // let _response = client.sync(sync_settings).await.unwrap(); + let client = AsyncClient::new(homeserver, Some(session)).unwrap(); - // let mut room_names = vec![]; - // for room in client.joined_rooms().read().await.values() { - // room_names.push(room.read().await.display_name()) - // } + let sync_settings = SyncSettings::new().timeout(Duration::from_millis(3000)); + let _response = client.sync(sync_settings).await.unwrap(); - // assert_eq!(vec!["example, example2"], room_names); - // } + let mut room_names = vec![]; + for room in client.joined_rooms().read().await.values() { + room_names.push(room.read().await.display_name()) + } + + assert_eq!(vec!["example, example2"], room_names); + } + + #[tokio::test] + async fn invited_rooms() { + use std::convert::TryFrom; + + let session = crate::Session { + access_token: "12345".to_owned(), + user_id: UserId::try_from("@example:localhost").unwrap(), + device_id: "DEVICEID".to_owned(), + }; + + let homeserver = url::Url::parse(&mockito::server_url()).unwrap(); + let client = AsyncClient::new(homeserver, Some(session)).unwrap(); + + let _m = mock( + "GET", + Matcher::Regex(r"^/_matrix/client/r0/sync\?.*$".to_string()), + ) + .with_status(200) + .with_body_from_file("../test_data/invite_sync.json") + .create(); + + let _response = client.sync(SyncSettings::default()).await.unwrap(); + + assert!(client.joined_rooms().read().await.is_empty()); + assert!(client.left_rooms().read().await.is_empty()); + assert!(!client.invited_rooms().read().await.is_empty()); + + assert!(client + .get_invited_room(&RoomId::try_from("!696r7674:example.com").unwrap()) + .await + .is_some()); + } + + #[tokio::test] + async fn left_rooms() { + use std::convert::TryFrom; + + let session = crate::Session { + access_token: "12345".to_owned(), + user_id: UserId::try_from("@example:localhost").unwrap(), + device_id: "DEVICEID".to_owned(), + }; + + let homeserver = url::Url::parse(&mockito::server_url()).unwrap(); + let client = AsyncClient::new(homeserver, Some(session)).unwrap(); + + let _m = mock( + "GET", + Matcher::Regex(r"^/_matrix/client/r0/sync\?.*$".to_string()), + ) + .with_status(200) + .with_body_from_file("../test_data/leave_sync.json") + .create(); + + let _response = client.sync(SyncSettings::default()).await.unwrap(); + + assert!(client.joined_rooms().read().await.is_empty()); + assert!(!client.left_rooms().read().await.is_empty()); + assert!(client.invited_rooms().read().await.is_empty()); + + assert!(client + .get_left_room(&RoomId::try_from("!SVkFJHzfwvuaIEawgC:localhost").unwrap()) + .await + .is_some()) + } #[tokio::test] async fn test_client_sync_store() { diff --git a/matrix_sdk_base/src/base_client.rs b/matrix_sdk_base/src/base_client.rs index f04d98dd..300ca4ba 100644 --- a/matrix_sdk_base/src/base_client.rs +++ b/matrix_sdk_base/src/base_client.rs @@ -662,6 +662,12 @@ impl Client { .await .set_room_summary(&joined_room.summary); + // set unread notification count + matrix_room + .write() + .await + .set_unread_notice_count(&joined_room.unread_notifications); + // re looping is not ideal here for event in &mut joined_room.state.events { if let Ok(e) = event.deserialize() { diff --git a/matrix_sdk_base/src/event_emitter/mod.rs b/matrix_sdk_base/src/event_emitter/mod.rs index 49f94c73..15d968ce 100644 --- a/matrix_sdk_base/src/event_emitter/mod.rs +++ b/matrix_sdk_base/src/event_emitter/mod.rs @@ -18,6 +18,7 @@ use crate::events::{ ignored_user_list::IgnoredUserListEvent, presence::PresenceEvent, push_rules::PushRulesEvent, + receipt::ReceiptEvent, room::{ aliases::AliasesEvent, avatar::AvatarEvent, @@ -34,6 +35,7 @@ use crate::events::{ StrippedRoomAliases, StrippedRoomAvatar, StrippedRoomCanonicalAlias, StrippedRoomJoinRules, StrippedRoomMember, StrippedRoomName, StrippedRoomPowerLevels, }, + typing::TypingEvent, }; use crate::RoomState; @@ -143,7 +145,7 @@ pub trait EventEmitter: Send + Sync { /// Fires when `AsyncClient` receives a `AnyStrippedStateEvent::StrippedRoomJoinRules` event. async fn on_stripped_state_join_rules(&self, _: RoomState, _: &StrippedRoomJoinRules) {} - // `NonRoomEvent` (this is a type alias from ruma_events) from `IncomingAccountData` + // `NonRoomEvent` (this is a type alias from ruma_events) /// Fires when `AsyncClient` receives a `NonRoomEvent::RoomMember` event. async fn on_account_presence(&self, _: RoomState, _: &PresenceEvent) {} /// Fires when `AsyncClient` receives a `NonRoomEvent::RoomName` event. @@ -152,6 +154,12 @@ pub trait EventEmitter: Send + Sync { async fn on_account_push_rules(&self, _: RoomState, _: &PushRulesEvent) {} /// Fires when `AsyncClient` receives a `NonRoomEvent::RoomAliases` event. async fn on_account_data_fully_read(&self, _: RoomState, _: &FullyReadEvent) {} + /// Fires when `AsyncClient` receives a `NonRoomEvent::Typing` event. + async fn on_account_data_typing(&self, _: RoomState, _: &TypingEvent) {} + /// Fires when `AsyncClient` receives a `NonRoomEvent::Receipt` event. + /// + /// This is always a read receipt. + async fn on_account_data_receipt(&self, _: RoomState, _: &ReceiptEvent) {} // `PresenceEvent` is a struct so there is only the one method /// Fires when `AsyncClient` receives a `NonRoomEvent::RoomAliases` event. diff --git a/matrix_sdk_base/src/models/room.rs b/matrix_sdk_base/src/models/room.rs index b0b31b8b..36832d96 100644 --- a/matrix_sdk_base/src/models/room.rs +++ b/matrix_sdk_base/src/models/room.rs @@ -20,7 +20,7 @@ use std::convert::TryFrom; use super::message::MessageQueue; use super::RoomMember; -use crate::api::r0::sync::sync_events::RoomSummary; +use crate::api::r0::sync::sync_events::{RoomSummary, UnreadNotificationsCount}; use crate::events::collections::all::{RoomEvent, StateEvent}; use crate::events::presence::PresenceEvent; use crate::events::room::{ @@ -320,6 +320,11 @@ impl Room { self.room_name.joined_member_count = *joined_member_count; } + pub(crate) fn set_unread_notice_count(&mut self, notifications: &UnreadNotificationsCount) { + self.unread_highlight = notifications.highlight_count; + self.unread_notifications = notifications.notification_count; + } + /// Handle a room.member updating the room state if necessary. /// /// Returns true if the joined member list changed, false otherwise. diff --git a/test_data/event_id.json b/test_data/event_id.json new file mode 100644 index 00000000..bf423646 --- /dev/null +++ b/test_data/event_id.json @@ -0,0 +1,3 @@ +{ + "event_id": "$h29iv0s8:example.com" +}