From 9f672ca7d2136e198b2852af3a813faa17e06264 Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Tue, 16 Apr 2024 19:58:16 +0200 Subject: [PATCH 1/4] dependencies: use a fork of Ruma for the time being --- Cargo.lock | 59 +++++++++++++++++++++++++++--------------------------- Cargo.toml | 5 +++-- 2 files changed, 33 insertions(+), 31 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a802d556fa2..19b4c34daab 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1260,6 +1260,12 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" +[[package]] +name = "date_header" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c03c416ed1a30fbb027ef484ba6ab6f80e1eada675e1a2b92fd673c045a1f1d" + [[package]] name = "deadpool" version = "0.9.5" @@ -2292,16 +2298,16 @@ dependencies = [ [[package]] name = "html5ever" -version = "0.26.0" +version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bea68cab48b8459f17cf1c944c67ddc572d272d9f2b274140f223ecb1da4a3b7" +checksum = "c13771afe0e6e846f1e67d038d4cb29998a6779f93c809212e4e9c32efd244d4" dependencies = [ "log", "mac", "markup5ever", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.48", ] [[package]] @@ -2970,12 +2976,12 @@ checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" [[package]] name = "markup5ever" -version = "0.11.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2629bb1404f3d34c2e921f21fd34ba00b206124c81f65c50b43b6aaefeb016" +checksum = "c7940b09815a02810a42b9e1bc41c069880a87de68e9b1dcbe754a3ba3b47c20" dependencies = [ "log", - "phf 0.10.1", + "phf", "phf_codegen", "string_cache", "string_cache_codegen", @@ -4190,15 +4196,6 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" -[[package]] -name = "phf" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" -dependencies = [ - "phf_shared 0.10.0", -] - [[package]] name = "phf" version = "0.11.2" @@ -4211,12 +4208,12 @@ dependencies = [ [[package]] name = "phf_codegen" -version = "0.10.0" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb1c3a8bc4dd4e5cfce29b44ffc14bedd2ee294559a294e2a4d4c9e9a6a13cd" +checksum = "e8d39688d359e6b34654d328e262234662d16cc0f60ec8dcbe5e718709342a5a" dependencies = [ - "phf_generator 0.10.0", - "phf_shared 0.10.0", + "phf_generator 0.11.2", + "phf_shared 0.11.2", ] [[package]] @@ -5017,7 +5014,7 @@ dependencies = [ [[package]] name = "ruma" version = "0.9.4" -source = "git+https://github.com/ruma/ruma?rev=4c00bd010dbdca6005bd599b52e90a0b7015d056#4c00bd010dbdca6005bd599b52e90a0b7015d056" +source = "git+https://github.com/ruma/ruma?rev=21b644ac6ae1c7d4a4f7e98a6481a3318f2deeaa#21b644ac6ae1c7d4a4f7e98a6481a3318f2deeaa" dependencies = [ "assign", "js_int", @@ -5028,16 +5025,18 @@ dependencies = [ "ruma-federation-api", "ruma-html", "ruma-push-gateway-api", + "web-time", ] [[package]] name = "ruma-client-api" version = "0.17.4" -source = "git+https://github.com/ruma/ruma?rev=4c00bd010dbdca6005bd599b52e90a0b7015d056#4c00bd010dbdca6005bd599b52e90a0b7015d056" +source = "git+https://github.com/ruma/ruma?rev=21b644ac6ae1c7d4a4f7e98a6481a3318f2deeaa#21b644ac6ae1c7d4a4f7e98a6481a3318f2deeaa" dependencies = [ "as_variant", "assign", "bytes", + "date_header", "http", "js_int", "js_option", @@ -5047,12 +5046,14 @@ dependencies = [ "serde", "serde_html_form", "serde_json", + "thiserror", + "web-time", ] [[package]] name = "ruma-common" version = "0.12.1" -source = "git+https://github.com/ruma/ruma?rev=4c00bd010dbdca6005bd599b52e90a0b7015d056#4c00bd010dbdca6005bd599b52e90a0b7015d056" +source = "git+https://github.com/ruma/ruma?rev=21b644ac6ae1c7d4a4f7e98a6481a3318f2deeaa#21b644ac6ae1c7d4a4f7e98a6481a3318f2deeaa" dependencies = [ "as_variant", "base64 0.21.7", @@ -5084,7 +5085,7 @@ dependencies = [ [[package]] name = "ruma-events" version = "0.27.11" -source = "git+https://github.com/ruma/ruma?rev=4c00bd010dbdca6005bd599b52e90a0b7015d056#4c00bd010dbdca6005bd599b52e90a0b7015d056" +source = "git+https://github.com/ruma/ruma?rev=21b644ac6ae1c7d4a4f7e98a6481a3318f2deeaa#21b644ac6ae1c7d4a4f7e98a6481a3318f2deeaa" dependencies = [ "as_variant", "indexmap 2.2.2", @@ -5108,7 +5109,7 @@ dependencies = [ [[package]] name = "ruma-federation-api" version = "0.8.0" -source = "git+https://github.com/ruma/ruma?rev=4c00bd010dbdca6005bd599b52e90a0b7015d056#4c00bd010dbdca6005bd599b52e90a0b7015d056" +source = "git+https://github.com/ruma/ruma?rev=21b644ac6ae1c7d4a4f7e98a6481a3318f2deeaa#21b644ac6ae1c7d4a4f7e98a6481a3318f2deeaa" dependencies = [ "js_int", "ruma-common", @@ -5120,11 +5121,11 @@ dependencies = [ [[package]] name = "ruma-html" version = "0.1.0" -source = "git+https://github.com/ruma/ruma?rev=4c00bd010dbdca6005bd599b52e90a0b7015d056#4c00bd010dbdca6005bd599b52e90a0b7015d056" +source = "git+https://github.com/ruma/ruma?rev=21b644ac6ae1c7d4a4f7e98a6481a3318f2deeaa#21b644ac6ae1c7d4a4f7e98a6481a3318f2deeaa" dependencies = [ "as_variant", "html5ever", - "phf 0.11.2", + "phf", "tracing", "wildmatch", ] @@ -5132,7 +5133,7 @@ dependencies = [ [[package]] name = "ruma-identifiers-validation" version = "0.9.3" -source = "git+https://github.com/ruma/ruma?rev=4c00bd010dbdca6005bd599b52e90a0b7015d056#4c00bd010dbdca6005bd599b52e90a0b7015d056" +source = "git+https://github.com/ruma/ruma?rev=21b644ac6ae1c7d4a4f7e98a6481a3318f2deeaa#21b644ac6ae1c7d4a4f7e98a6481a3318f2deeaa" dependencies = [ "js_int", "thiserror", @@ -5141,7 +5142,7 @@ dependencies = [ [[package]] name = "ruma-macros" version = "0.12.0" -source = "git+https://github.com/ruma/ruma?rev=4c00bd010dbdca6005bd599b52e90a0b7015d056#4c00bd010dbdca6005bd599b52e90a0b7015d056" +source = "git+https://github.com/ruma/ruma?rev=21b644ac6ae1c7d4a4f7e98a6481a3318f2deeaa#21b644ac6ae1c7d4a4f7e98a6481a3318f2deeaa" dependencies = [ "once_cell", "proc-macro-crate 2.0.2", @@ -5156,7 +5157,7 @@ dependencies = [ [[package]] name = "ruma-push-gateway-api" version = "0.8.0" -source = "git+https://github.com/ruma/ruma?rev=4c00bd010dbdca6005bd599b52e90a0b7015d056#4c00bd010dbdca6005bd599b52e90a0b7015d056" +source = "git+https://github.com/ruma/ruma?rev=21b644ac6ae1c7d4a4f7e98a6481a3318f2deeaa#21b644ac6ae1c7d4a4f7e98a6481a3318f2deeaa" dependencies = [ "js_int", "ruma-common", diff --git a/Cargo.toml b/Cargo.toml index 29b2a43a62f..a811822845c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,15 +39,16 @@ futures-util = { version = "0.3.26", default-features = false, features = [ http = "0.2.6" imbl = "2.0.0" itertools = "0.12.0" -ruma = { git = "https://github.com/ruma/ruma", rev = "4c00bd010dbdca6005bd599b52e90a0b7015d056", features = [ +ruma = { git = "https://github.com/ruma/ruma", rev = "21b644ac6ae1c7d4a4f7e98a6481a3318f2deeaa", features = [ "client-api-c", "compat-upload-signatures", "compat-user-id", "compat-arbitrary-length-ids", "compat-tag-info", "unstable-msc3401", + "unstable-msc3266", ] } -ruma-common = { git = "https://github.com/ruma/ruma", rev = "4c00bd010dbdca6005bd599b52e90a0b7015d056" } +ruma-common = { git = "https://github.com/ruma/ruma", rev = "21b644ac6ae1c7d4a4f7e98a6481a3318f2deeaa" } once_cell = "1.16.0" rand = "0.8.5" serde = "1.0.151" From e24d5a2f4304c8f0748eb249da01f25e28f05df5 Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Tue, 16 Apr 2024 19:57:58 +0200 Subject: [PATCH 2/4] dependencies: bump ruma MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Honestly, I'm not sure how the retry-after that's a fixed point in time in the future should be handled, open to suggestions hereā€¦ --- crates/matrix-sdk/src/http_client/native.rs | 14 ++++++++------ crates/matrix-sdk/tests/integration/matrix_auth.rs | 4 ++-- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/crates/matrix-sdk/src/http_client/native.rs b/crates/matrix-sdk/src/http_client/native.rs index d28cd52a170..ebf320462b2 100644 --- a/crates/matrix-sdk/src/http_client/native.rs +++ b/crates/matrix-sdk/src/http_client/native.rs @@ -26,7 +26,7 @@ use eyeball::SharedObservable; use http::header::CONTENT_LENGTH; use reqwest::Certificate; use ruma::api::{ - client::error::{ErrorBody as ClientApiErrorBody, ErrorKind as ClientApiErrorKind}, + client::error::{ErrorBody as ClientApiErrorBody, ErrorKind as ClientApiErrorKind, RetryAfter}, error::FromHttpResponseError, IncomingResponse, OutgoingRequest, }; @@ -68,13 +68,15 @@ impl HttpClient { let status_code = match api_error { RumaApiError::ClientApi(e) => match e.body { ClientApiErrorBody::Standard { - kind: ClientApiErrorKind::LimitExceeded { retry_after_ms }, + kind: ClientApiErrorKind::LimitExceeded { retry_after }, .. } => { - return RetryError::Transient { - err, - retry_after: retry_after_ms, - }; + let retry_after = + retry_after.and_then(|retry_after| match retry_after { + RetryAfter::Delay(d) => Some(d), + RetryAfter::DateTime(_) => None, + }); + return RetryError::Transient { err, retry_after }; } _ => Some(e.status_code), }, diff --git a/crates/matrix-sdk/tests/integration/matrix_auth.rs b/crates/matrix-sdk/tests/integration/matrix_auth.rs index acee16bf2ca..873f62bc94c 100644 --- a/crates/matrix-sdk/tests/integration/matrix_auth.rs +++ b/crates/matrix-sdk/tests/integration/matrix_auth.rs @@ -206,7 +206,7 @@ async fn test_login_error() { assert_eq!(api_err.status_code, http::StatusCode::from_u16(403).unwrap()); if let client_api::error::ErrorBody::Standard { kind, message } = &api_err.body { - if *kind != client_api::error::ErrorKind::Forbidden { + if !matches!(*kind, client_api::error::ErrorKind::Forbidden { .. }) { panic!("found the wrong `ErrorKind` {kind:?}, expected `Forbidden"); } @@ -247,7 +247,7 @@ async fn test_register_error() { if let Some(api_err) = err.as_client_api_error() { assert_eq!(api_err.status_code, http::StatusCode::from_u16(403).unwrap()); if let client_api::error::ErrorBody::Standard { kind, message } = &api_err.body { - if *kind != client_api::error::ErrorKind::Forbidden { + if !matches!(*kind, client_api::error::ErrorKind::Forbidden { .. }) { panic!("found the wrong `ErrorKind` {kind:?}, expected `Forbidden"); } From 4ce137794f87f0009cca77e169e6d9710ec61afb Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Tue, 16 Apr 2024 19:59:52 +0200 Subject: [PATCH 3/4] room preview: add support for MSC3266, room summary --- bindings/matrix-sdk-ffi/src/room_preview.rs | 15 ++- crates/matrix-sdk/src/room_preview.rs | 90 ++++++++++++-- .../assets/ci-start.sh | 3 + .../src/tests/sliding_sync/room.rs | 116 ++++++++++++------ 4 files changed, 170 insertions(+), 54 deletions(-) diff --git a/bindings/matrix-sdk-ffi/src/room_preview.rs b/bindings/matrix-sdk-ffi/src/room_preview.rs index f5f390ef7aa..112a6732fc5 100644 --- a/bindings/matrix-sdk-ffi/src/room_preview.rs +++ b/bindings/matrix-sdk-ffi/src/room_preview.rs @@ -1,8 +1,5 @@ use matrix_sdk::{room_preview::RoomPreview as SdkRoomPreview, RoomState}; -use ruma::{ - events::room::{history_visibility::HistoryVisibility, join_rules::JoinRule}, - OwnedRoomId, -}; +use ruma::{space::SpaceRoomJoinRule, OwnedRoomId}; /// The preview of a room, be it invited/joined/left, or not. #[derive(uniffi::Record)] @@ -43,12 +40,14 @@ impl RoomPreview { avatar_url: preview.avatar_url.map(|url| url.to_string()), num_joined_members: preview.num_joined_members, room_type: preview.room_type.map(|room_type| room_type.to_string()), - is_history_world_readable: preview.history_visibility - == HistoryVisibility::WorldReadable, + is_history_world_readable: preview.is_world_readable, is_joined: preview.state.map_or(false, |state| state == RoomState::Joined), is_invited: preview.state.map_or(false, |state| state == RoomState::Invited), - is_public: preview.join_rule == JoinRule::Public, - can_knock: matches!(preview.join_rule, JoinRule::KnockRestricted(_) | JoinRule::Knock), + is_public: preview.join_rule == SpaceRoomJoinRule::Public, + can_knock: matches!( + preview.join_rule, + SpaceRoomJoinRule::KnockRestricted | SpaceRoomJoinRule::Knock + ), } } } diff --git a/crates/matrix-sdk/src/room_preview.rs b/crates/matrix-sdk/src/room_preview.rs index 9d9227f8c64..a113f80e152 100644 --- a/crates/matrix-sdk/src/room_preview.rs +++ b/crates/matrix-sdk/src/room_preview.rs @@ -23,6 +23,7 @@ use ruma::{ api::client::{membership::joined_members, state::get_state_events}, events::room::{history_visibility::HistoryVisibility, join_rules::JoinRule}, room::RoomType, + space::SpaceRoomJoinRule, OwnedMxcUri, OwnedRoomAliasId, RoomId, }; use tokio::try_join; @@ -52,10 +53,11 @@ pub struct RoomPreview { pub room_type: Option, /// What's the join rule for this room? - pub join_rule: JoinRule, + pub join_rule: SpaceRoomJoinRule, - /// What's the history visibility for this room? - pub history_visibility: HistoryVisibility, + /// Is the room world-readable (i.e. is its history_visibility set to + /// world_readable)? + pub is_world_readable: bool, /// Has the current user been invited/joined/left this room? /// @@ -79,8 +81,20 @@ impl RoomPreview { topic: room_info.topic().map(ToOwned::to_owned), avatar_url: room_info.avatar_url().map(ToOwned::to_owned), room_type: room_info.room_type().cloned(), - join_rule: room_info.join_rule().clone(), - history_visibility: room_info.history_visibility().clone(), + join_rule: match room_info.join_rule() { + JoinRule::Invite => SpaceRoomJoinRule::Invite, + JoinRule::Knock => SpaceRoomJoinRule::Knock, + JoinRule::Private => SpaceRoomJoinRule::Private, + JoinRule::Restricted(_) => SpaceRoomJoinRule::Restricted, + JoinRule::KnockRestricted(_) => SpaceRoomJoinRule::KnockRestricted, + JoinRule::Public => SpaceRoomJoinRule::Public, + _ => { + // The JoinRule enum is non-exhaustive. Let's do a white lie and pretend it's + // private (a cautious choice). + SpaceRoomJoinRule::Private + } + }, + is_world_readable: *room_info.history_visibility() == HistoryVisibility::WorldReadable, num_joined_members, state, @@ -95,14 +109,72 @@ impl RoomPreview { #[instrument(skip(client))] pub(crate) async fn from_unknown(client: &Client, room_id: &RoomId) -> crate::Result { - // TODO: (optimization) Use the room summary endpoint, if available, as - // described in https://github.com/deepbluev7/matrix-doc/blob/room-summaries/proposals/3266-room-summary.md + // Use the room summary endpoint, if available, as described in + // https://github.com/deepbluev7/matrix-doc/blob/room-summaries/proposals/3266-room-summary.md + match Self::from_room_summary(client, room_id).await { + Ok(res) => return Ok(res), + Err(err) => { + warn!("error when previewing room from the room summary endpoint: {err}"); + } + } // TODO: (optimization) Use the room search directory, if available: // - if the room directory visibility is public, // - then use a public room filter set to this room id // Resort to using the room state endpoint, as well as the joined members one. + Self::from_state_events(client, room_id).await + } + + /// Get a [`RoomPreview`] using MSC3266, if available on the remote server. + /// + /// Will fail with a 404 if the API is not available. + /// + /// This method is exposed for testing purposes; clients should prefer + /// `Client::get_room_preview` in general over this. + pub async fn from_room_summary(client: &Client, room_id: &RoomId) -> crate::Result { + let request = ruma::api::client::room::get_summary::msc3266::Request::new( + room_id.to_owned().into(), + Vec::new(), + ); + + let response = client.send(request, None).await?; + + // The server returns a `Left` room state for rooms the user has not joined. Be + // more precise than that, and set it to `None` if we haven't joined + // that room. + let state = if client.get_room(room_id).is_none() { + None + } else { + response.membership.map(|membership| RoomState::from(&membership)) + }; + + Ok(RoomPreview { + canonical_alias: response.canonical_alias, + name: response.name, + topic: response.topic, + avatar_url: response.avatar_url, + num_joined_members: response.num_joined_members.into(), + room_type: response.room_type, + join_rule: response.join_rule, + is_world_readable: response.world_readable, + state, + }) + } + + /// Get a [`RoomPreview`] using the room state endpoint. + /// + /// This is always available on a remote server, but will only work if one + /// of these two conditions is true: + /// + /// - the user has joined the room at some point (i.e. they're still joined + /// or they've joined + /// it and left it later). + /// - the room has an history visibility set to world-readable. + /// + /// This method is exposed for testing purposes; clients should prefer + /// `Client::get_room_preview` in general over this. + pub async fn from_state_events(client: &Client, room_id: &RoomId) -> crate::Result { let state_request = get_state_events::v3::Request::new(room_id.to_owned()); let joined_members_request = joined_members::v3::Request::new(room_id.to_owned()); @@ -128,6 +200,8 @@ impl RoomPreview { room_info.handle_state_event(&ev.into()); } - Ok(Self::from_room_info(room_info, num_joined_members, None)) + let state = client.get_room(room_id).map(|room| room.state()); + + Ok(Self::from_room_info(room_info, num_joined_members, state)) } } diff --git a/testing/matrix-sdk-integration-testing/assets/ci-start.sh b/testing/matrix-sdk-integration-testing/assets/ci-start.sh index 911878063b2..2c7e9b3efdd 100644 --- a/testing/matrix-sdk-integration-testing/assets/ci-start.sh +++ b/testing/matrix-sdk-integration-testing/assets/ci-start.sh @@ -56,6 +56,9 @@ rc_invites: per_issuer: per_second: 1000 burst_count: 1000 + +experimental_features: + msc3266_enabled: true """ >> /data/homeserver.yaml echo " ====== Starting server with: ====== " diff --git a/testing/matrix-sdk-integration-testing/src/tests/sliding_sync/room.rs b/testing/matrix-sdk-integration-testing/src/tests/sliding_sync/room.rs index b179cc46e9e..90134197e77 100644 --- a/testing/matrix-sdk-integration-testing/src/tests/sliding_sync/room.rs +++ b/testing/matrix-sdk-integration-testing/src/tests/sliding_sync/room.rs @@ -10,6 +10,7 @@ use futures_util::{pin_mut, FutureExt, StreamExt as _}; use matrix_sdk::{ bytes::Bytes, config::SyncSettings, + room_preview::RoomPreview, ruma::{ api::client::{ receipt::create_receipt::v3::ReceiptType, @@ -29,6 +30,8 @@ use matrix_sdk::{ AnySyncMessageLikeEvent, InitialStateEvent, Mentions, StateEventType, }, mxc_uri, + space::SpaceRoomJoinRule, + RoomId, }, Client, RoomInfo, RoomListEntry, RoomMemberships, RoomState, SlidingSyncList, SlidingSyncMode, }; @@ -1082,14 +1085,24 @@ async fn test_room_preview() -> Result<()> { InitialStateEvent::new(RoomHistoryVisibilityEventContent::new(HistoryVisibility::WorldReadable)).to_raw_any(), InitialStateEvent::new(RoomJoinRulesEventContent::new(JoinRule::Invite)).to_raw_any(), ], - //TODO: this doesn't allow preview => could be tested! - //preset: Some(RoomPreset::PrivateChat), })) .await?; room.set_avatar_url(mxc_uri!("mxc://localhost/alice"), None).await?; + // Alice creates another room, and still doesn't invite Bob. + let private_room = alice + .create_room(assign!(CreateRoomRequest::new(), { + name: Some("Alice's Room 2".to_owned()), + initial_state: vec![ + InitialStateEvent::new(RoomHistoryVisibilityEventContent::new(HistoryVisibility::Shared)).to_raw_any(), + InitialStateEvent::new(RoomJoinRulesEventContent::new(JoinRule::Public)).to_raw_any(), + ], + })) + .await?; + let room_id = room.room_id(); + let private_room_id = private_room.room_id(); // Wait for Alice's stream to stabilize (stop updating when we haven't received // successful updates for more than 2 seconds). @@ -1104,49 +1117,76 @@ async fn test_room_preview() -> Result<()> { } } - let preview = alice.get_room_preview(room_id).await?; - assert_eq!(preview.canonical_alias.unwrap().alias(), room_alias); - assert_eq!(preview.name.unwrap(), "Alice's Room"); - assert_eq!(preview.topic.unwrap(), "Discussing Alice's Topic"); - assert_eq!(preview.avatar_url.unwrap(), mxc_uri!("mxc://localhost/alice")); - assert_eq!(preview.num_joined_members, 1); - assert!(preview.room_type.is_none()); - // Because of the preset: - assert_eq!(preview.join_rule, JoinRule::Invite); - assert_eq!(preview.history_visibility, HistoryVisibility::WorldReadable); - assert_eq!(preview.state, Some(RoomState::Joined)); + get_room_preview_with_room_state(&alice, &bob, &room_alias, room_id, private_room_id).await; + get_room_preview_with_room_summary(&alice, &bob, &room_alias, room_id, private_room_id).await; - // Bob definitely doesn't know about the room, but they can get a preview of the - // room too. - let preview = bob.get_room_preview(room_id).await?; + { + // Dummy test for `Client::get_room_preview` which may call one or the other + // methods. + let preview = alice.get_room_preview(room_id).await.unwrap(); + assert_room_preview(&preview, &room_alias); + assert_eq!(preview.state, Some(RoomState::Joined)); + } - assert_eq!(preview.canonical_alias.unwrap().alias(), room_alias); - assert_eq!(preview.name.unwrap(), "Alice's Room"); - assert_eq!(preview.topic.unwrap(), "Discussing Alice's Topic"); - assert_eq!(preview.avatar_url.unwrap(), mxc_uri!("mxc://localhost/alice")); + Ok(()) +} + +fn assert_room_preview(preview: &RoomPreview, room_alias: &str) { + assert_eq!(preview.canonical_alias.as_ref().unwrap().alias(), room_alias); + assert_eq!(preview.name.as_ref().unwrap(), "Alice's Room"); + assert_eq!(preview.topic.as_ref().unwrap(), "Discussing Alice's Topic"); + assert_eq!(preview.avatar_url.as_ref().unwrap(), mxc_uri!("mxc://localhost/alice")); assert_eq!(preview.num_joined_members, 1); assert!(preview.room_type.is_none()); - assert_eq!(preview.join_rule, JoinRule::Invite); - assert_eq!(preview.history_visibility, HistoryVisibility::WorldReadable); + assert_eq!(preview.join_rule, SpaceRoomJoinRule::Invite); + assert!(preview.is_world_readable); +} - // Only difference with Alice's room is here: since Bob hasn't joined the room, - // they don't have any associated room state. - assert_eq!(preview.state, None); +async fn get_room_preview_with_room_state( + alice: &Client, + bob: &Client, + room_alias: &str, + room_id: &RoomId, + public_no_history_room_id: &RoomId, +) { + // Alice has joined the room, so they get the full details. + let preview = RoomPreview::from_state_events(alice, room_id).await.unwrap(); + assert_room_preview(&preview, room_alias); + assert_eq!(preview.state, Some(RoomState::Joined)); - // Now Alice creates another room, with a private preset, and still doesn't - // invite Bob. - let room = alice - .create_room(assign!(CreateRoomRequest::new(), { - initial_state: vec![ - InitialStateEvent::new(RoomHistoryVisibilityEventContent::new(HistoryVisibility::Shared)).to_raw_any(), - InitialStateEvent::new(RoomJoinRulesEventContent::new(JoinRule::Invite)).to_raw_any(), - ], - })) - .await?; + // Bob definitely doesn't know about the room, but they can get a preview of the + // room too. + let preview = RoomPreview::from_state_events(bob, room_id).await.unwrap(); + assert_room_preview(&preview, room_alias); + assert!(preview.state.is_none()); - // So Bob can't preview it. - let preview_result = bob.get_room_preview(room.room_id()).await; + // Bob can't preview the second room, because its history visibility is neither + // world-readable, nor have they joined the room before. + let preview_result = RoomPreview::from_state_events(bob, public_no_history_room_id).await; assert_eq!(preview_result.unwrap_err().as_client_api_error().unwrap().status_code, 403); +} - Ok(()) +async fn get_room_preview_with_room_summary( + alice: &Client, + bob: &Client, + room_alias: &str, + room_id: &RoomId, + public_no_history_room_id: &RoomId, +) { + // Alice has joined the room, so they get the full details. + let preview = RoomPreview::from_room_summary(alice, room_id).await.unwrap(); + assert_room_preview(&preview, room_alias); + assert_eq!(preview.state, Some(RoomState::Joined)); + + // Bob definitely doesn't know about the room, but they can get a preview of the + // room too. + let preview = RoomPreview::from_room_summary(bob, room_id).await.unwrap(); + assert_room_preview(&preview, room_alias); + assert!(preview.state.is_none()); + + // Bob can preview the second room with the room summary (because its join rule + // is set to public, or because Alice is a member of that room). + let preview = RoomPreview::from_room_summary(bob, public_no_history_room_id).await.unwrap(); + assert_eq!(preview.name.unwrap(), "Alice's Room 2"); + assert!(preview.state.is_none()); } From a57b00366c31adfdde0b1c55b5408b3507b9d7a8 Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Thu, 18 Apr 2024 15:38:42 +0200 Subject: [PATCH 4/4] test: silently skip the room summary test on CI, if the server doesn't support it --- .../src/tests/sliding_sync/room.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/testing/matrix-sdk-integration-testing/src/tests/sliding_sync/room.rs b/testing/matrix-sdk-integration-testing/src/tests/sliding_sync/room.rs index 90134197e77..02742e5c9f8 100644 --- a/testing/matrix-sdk-integration-testing/src/tests/sliding_sync/room.rs +++ b/testing/matrix-sdk-integration-testing/src/tests/sliding_sync/room.rs @@ -1174,7 +1174,19 @@ async fn get_room_preview_with_room_summary( public_no_history_room_id: &RoomId, ) { // Alice has joined the room, so they get the full details. - let preview = RoomPreview::from_room_summary(alice, room_id).await.unwrap(); + let preview = match RoomPreview::from_room_summary(alice, room_id).await { + Ok(r) => r, + Err(err) => { + if let Some(client_api_error) = err.as_client_api_error() { + if client_api_error.status_code == 404 { + warn!("Skipping the room summary test, because the server may not support it."); + return; + } + } + panic!("{err}"); + } + }; + assert_room_preview(&preview, room_alias); assert_eq!(preview.state, Some(RoomState::Joined));