From 60d82fde38272e3c988a2e195e2100eef00ca724 Mon Sep 17 00:00:00 2001 From: Benjamin Kampmann Date: Tue, 10 Jan 2023 12:13:44 +0100 Subject: [PATCH 01/14] test: add sliding-sync integration-testing facilities --- Cargo.lock | 12 +++++ .../matrix-sdk-integration-testing/Cargo.toml | 6 ++- .../src/helpers.rs | 7 ++- .../matrix-sdk-integration-testing/src/lib.rs | 4 +- .../sliding-sync-integration-test/Cargo.toml | 13 +++++ .../assets/Dockerfile | 4 ++ .../assets/ci-start.sh | 52 +++++++++++++++++++ .../assets/docker-compose.yml | 43 +++++++++++++++ .../sliding-sync-integration-test/src/lib.rs | 36 +++++++++++++ 9 files changed, 173 insertions(+), 4 deletions(-) create mode 100644 testing/sliding-sync-integration-test/Cargo.toml create mode 100644 testing/sliding-sync-integration-test/assets/Dockerfile create mode 100644 testing/sliding-sync-integration-test/assets/ci-start.sh create mode 100644 testing/sliding-sync-integration-test/assets/docker-compose.yml create mode 100644 testing/sliding-sync-integration-test/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index b8d6f154b..f606f8921 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4441,6 +4441,18 @@ dependencies = [ "syntect", ] +[[package]] +name = "sliding-sync-integration-test" +version = "0.1.0" +dependencies = [ + "anyhow", + "ctor", + "futures", + "matrix-sdk", + "matrix-sdk-integration-testing", + "tokio", +] + [[package]] name = "slog" version = "2.7.0" diff --git a/testing/matrix-sdk-integration-testing/Cargo.toml b/testing/matrix-sdk-integration-testing/Cargo.toml index 585a28003..a6814bfb2 100644 --- a/testing/matrix-sdk-integration-testing/Cargo.toml +++ b/testing/matrix-sdk-integration-testing/Cargo.toml @@ -5,7 +5,11 @@ version = "0.1.0" edition = "2021" publish = false -[dev-dependencies] +[features] +# activate to steal helper functions from this crate for other testing +helpers = [] + +[dependencies] anyhow = { workspace = true } assign = "1" ctor = { workspace = true } diff --git a/testing/matrix-sdk-integration-testing/src/helpers.rs b/testing/matrix-sdk-integration-testing/src/helpers.rs index dd534e339..f18405f26 100644 --- a/testing/matrix-sdk-integration-testing/src/helpers.rs +++ b/testing/matrix-sdk-integration-testing/src/helpers.rs @@ -14,7 +14,12 @@ use tokio::sync::Mutex; static USERS: Lazy>> = Lazy::new(Mutex::default); #[ctor::ctor] -fn init_logging() { +fn startup() { + init_logging(); +} + +/// initialize logging +pub fn init_logging() { use tracing::Level; use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; tracing_subscriber::registry() diff --git a/testing/matrix-sdk-integration-testing/src/lib.rs b/testing/matrix-sdk-integration-testing/src/lib.rs index 5c74eb97b..42a822679 100644 --- a/testing/matrix-sdk-integration-testing/src/lib.rs +++ b/testing/matrix-sdk-integration-testing/src/lib.rs @@ -1,5 +1,5 @@ #[cfg(test)] mod tests; -#[cfg(test)] -mod helpers; +#[cfg(any(test, feature="helpers"))] +pub mod helpers; diff --git a/testing/sliding-sync-integration-test/Cargo.toml b/testing/sliding-sync-integration-test/Cargo.toml new file mode 100644 index 000000000..ca3e5c64b --- /dev/null +++ b/testing/sliding-sync-integration-test/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "sliding-sync-integration-test" +version = "0.1.0" +edition = "2021" +publish = false + +[dependencies] +anyhow = { workspace = true } +ctor = { workspace = true } +matrix-sdk-integration-testing = { path = "../matrix-sdk-integration-testing", features = ["helpers"] } +matrix-sdk = { path = "../../crates/matrix-sdk", features = ["experimental-sliding-sync"] } +tokio = { version = "1", features = ["rt", "rt-multi-thread", "macros"] } +futures = { version = "0.3.25" } diff --git a/testing/sliding-sync-integration-test/assets/Dockerfile b/testing/sliding-sync-integration-test/assets/Dockerfile new file mode 100644 index 000000000..56dd700a7 --- /dev/null +++ b/testing/sliding-sync-integration-test/assets/Dockerfile @@ -0,0 +1,4 @@ +FROM matrixdotorg/synapse:latest +ADD ci-start.sh /ci-start.sh +RUN chmod 770 /ci-start.sh +ENTRYPOINT /ci-start.sh diff --git a/testing/sliding-sync-integration-test/assets/ci-start.sh b/testing/sliding-sync-integration-test/assets/ci-start.sh new file mode 100644 index 000000000..cce1ff4bd --- /dev/null +++ b/testing/sliding-sync-integration-test/assets/ci-start.sh @@ -0,0 +1,52 @@ +#!/bin/bash +set -e +export SYNAPSE_SERVER_NAME=matrix-sdk.rs +export SYNAPSE_REPORT_STATS=no +echo " ====== Generating config ====== " +/start.py generate +echo " ====== Patching for CI ====== " +echo """ +enable_registration: true +enable_registration_without_verification: true + +rc_message: + per_second: 1000 + burst_count: 1000 + +rc_registration: + per_second: 1000 + burst_count: 1000 + +rc_joins: + local: + per_second: 1000 + burst_count: 1000 + +rc_invites: + per_room: + per_second: 1000 + burst_count: 1000 + per_user: + per_second: 1000 + burst_count: 1000 + per_issuer: + per_second: 1000 + burst_count: 1000 + +rc_login: + address: + per_second: 1000 + burst_count: 1000 +# account: +# per_second: 0.17 +# burst_count: 3 +# failed_attempts: +# per_second: 0.17 +# burst_count: 3 + +""" >> /data/homeserver.yaml + +echo " ====== Starting server with: ====== " +cat /data/homeserver.yaml +echo " ====== STARTING ====== " +/start.py run diff --git a/testing/sliding-sync-integration-test/assets/docker-compose.yml b/testing/sliding-sync-integration-test/assets/docker-compose.yml new file mode 100644 index 000000000..a7678ccab --- /dev/null +++ b/testing/sliding-sync-integration-test/assets/docker-compose.yml @@ -0,0 +1,43 @@ + +version: '3' + +services: + + synapse: + build: . + restart: "no" + healthcheck: + disable: true + volumes: + - matrix-rust-sdk-sliding-sync-ci-data:/data + + ports: + - 8228:8008/tcp + + postgres: + image: postgres + environment: + POSTGRES_PASSWORD: postgres + POSTGRES_USER: postgres + POSTGRES_DB: syncv3 + healthcheck: + test: ["pg_isready"] + interval: 10s + timeout: 5s + retries: 5 + + sliding-sync-proxy: + image: ghcr.io/matrix-org/sliding-sync:v0.98.0 + links: + - synapse + - postgres + environment: + SYNCV3_SERVER: http://synapse:8008 + SYNCV3_SECRET: SUPER_SECRET + SYNCV3_BINDADDR: ":8338" + SYNCV3_DB: "user=postgres password=postgres dbname=syncv3 sslmode=disable host=postgres" + ports: + - 8338:8338 + +volumes: + matrix-rust-sdk-sliding-sync-ci-data: diff --git a/testing/sliding-sync-integration-test/src/lib.rs b/testing/sliding-sync-integration-test/src/lib.rs new file mode 100644 index 000000000..870a54e4d --- /dev/null +++ b/testing/sliding-sync-integration-test/src/lib.rs @@ -0,0 +1,36 @@ +use matrix_sdk::{Client, SlidingSyncBuilder}; +use matrix_sdk_integration_testing::helpers::get_client_for_user; + +#[allow(dead_code)] +async fn setup(name: String) -> anyhow::Result<(Client, SlidingSyncBuilder)> { + let sliding_sync_proxy_url = + option_env!("SLIDING_SYNC_PROXY_URL").unwrap_or("http://localhost:8338").to_owned(); + let client = get_client_for_user(name, false).await?; + let sliding_sync_builder = client + .sliding_sync() + .await + .homeserver(sliding_sync_proxy_url.parse()?) + .with_common_extensions(); + Ok((client, sliding_sync_builder)) +} + +#[cfg(test)] +mod tests { + use futures::{pin_mut, stream::StreamExt}; + + use super::*; + + #[tokio::test(flavor = "multi_thread", worker_threads = 4)] + async fn it_works_smoke_test() -> anyhow::Result<()> { + let (_client, sync_proxy_builder) = setup("odo".to_owned()).await?; + let sync_proxy = sync_proxy_builder.add_fullsync_view().build().await?; + let stream = sync_proxy.stream().await?; + pin_mut!(stream); + let Some(room_summary ) = stream.next().await else { + anyhow::bail!("No room summary found, loop ended unsuccessfully"); + }; + let summary = room_summary?; + assert_eq!(summary.rooms.len(), 0); + Ok(()) + } +} From 08bec243ffc35323d883d93db5b80dd6ad11b4e3 Mon Sep 17 00:00:00 2001 From: Benjamin Kampmann Date: Tue, 10 Jan 2023 12:14:06 +0100 Subject: [PATCH 02/14] ci(sliding-sync): add sliding sync integration test --- .github/workflows/ci.yml | 72 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 71 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5840fe3d3..eff72d0d5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -204,7 +204,7 @@ jobs: uses: actions-rs/cargo@v1 with: command: nextest - args: run --workspace --exclude matrix-sdk-integration-testing + args: run --workspace --exclude matrix-sdk-integration-testing --exclude sliding-sync-integration-test - name: Test documentation uses: actions-rs/cargo@v1 @@ -443,3 +443,73 @@ jobs: with: command: nextest args: run -p matrix-sdk-integration-testing + + + sliding-sync-integration-tests: + name: Sliding Sync Integration test + if: github.event_name == 'push' || !github.event.pull_request.draft + + runs-on: ubuntu-latest + # Service containers to run with `runner-job` + services: + # Label used to access the service container + postgres: + # Docker Hub image + image: postgres + # Provide the password for postgres + env: + POSTGRES_PASSWORD: postgres + POSTGRES_USER: postgres + POSTGRES_DB: syncv3 + # Set health checks to wait until postgres has started + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + ports: + # Maps tcp port 5432 on service container to the host + - 5432:5432 + + steps: + - name: Checkout the repo + uses: actions/checkout@v3 + + - name: Install Rust + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + profile: minimal + override: true + + - name: Load cache + uses: Swatinem/rust-cache@v1 + + - name: Install nextest + uses: taiki-e/install-action@nextest + + - uses: actions/setup-python@v4 + with: + python-version: 3.8 + + # local synapse + - uses: michaelkaye/setup-matrix-synapse@main + with: + uploadLogs: true + httpPort: 8228 + disableRateLimiting: true + + # latest sliding sync proxy + + - uses: addnab/docker-run-action@v3 + with: + registry: gcr.io + image: "matrix-org/sliding-sync:v0.98.0" + docker_network: "host" + options: '-e "SYNCV3_SERVER=http://locahost:8228" -e "SYNCV3_SECRET=SUPER_CI_SECRET" -e "SYNCV3_BINDADDR=:8118" -e "SYNCV3_DB=user=postgres password=postgres dbname=syncv3 sslmode=disable host=postgres" -p 8118:8118' + + - name: Test + uses: actions-rs/cargo@v1 + with: + command: nextest + args: run -p sliding-sync-integration-tests From fabf0d40bc13f21f5b518da3e8b1479f26905531 Mon Sep 17 00:00:00 2001 From: Benjamin Kampmann Date: Tue, 10 Jan 2023 15:45:55 +0100 Subject: [PATCH 03/14] test: add test for moving window and rooms --- Cargo.lock | 1 + crates/matrix-sdk/src/sliding_sync.rs | 11 + .../matrix-sdk-integration-testing/src/lib.rs | 2 +- .../sliding-sync-integration-test/Cargo.toml | 1 + .../sliding-sync-integration-test/src/lib.rs | 314 +++++++++++++++++- 5 files changed, 327 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f606f8921..44f49ea13 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4451,6 +4451,7 @@ dependencies = [ "matrix-sdk", "matrix-sdk-integration-testing", "tokio", + "uuid", ] [[package]] diff --git a/crates/matrix-sdk/src/sliding_sync.rs b/crates/matrix-sdk/src/sliding_sync.rs index e9291852c..a1b1a154f 100644 --- a/crates/matrix-sdk/src/sliding_sync.rs +++ b/crates/matrix-sdk/src/sliding_sync.rs @@ -693,6 +693,11 @@ impl SlidingSync { .since = Some(since); } + /// Get access to the SlidingSyncView named `view_name` + pub fn view(&self, view_name: &str) -> Option { + self.views.lock_ref().iter().find(|v| v.name == view_name).cloned().clone() + } + /// Lookup a set of rooms pub fn get_rooms>( &self, @@ -1054,6 +1059,12 @@ impl SlidingSyncViewBuilder { self } + /// Set a single range fetch + pub fn set_range>(mut self, from: U, to: U) -> Self { + let r = self.ranges = Some(RangeState::new(vec![(from.into(), to.into())])); + self + } + /// Set the ranges to fetch pub fn add_range>(mut self, from: U, to: U) -> Self { let r = self.ranges.get_or_insert_with(|| RangeState::new(Vec::new())); diff --git a/testing/matrix-sdk-integration-testing/src/lib.rs b/testing/matrix-sdk-integration-testing/src/lib.rs index 42a822679..fbbbf6dbe 100644 --- a/testing/matrix-sdk-integration-testing/src/lib.rs +++ b/testing/matrix-sdk-integration-testing/src/lib.rs @@ -1,5 +1,5 @@ #[cfg(test)] mod tests; -#[cfg(any(test, feature="helpers"))] +#[cfg(any(test, feature = "helpers"))] pub mod helpers; diff --git a/testing/sliding-sync-integration-test/Cargo.toml b/testing/sliding-sync-integration-test/Cargo.toml index ca3e5c64b..1922c730c 100644 --- a/testing/sliding-sync-integration-test/Cargo.toml +++ b/testing/sliding-sync-integration-test/Cargo.toml @@ -11,3 +11,4 @@ matrix-sdk-integration-testing = { path = "../matrix-sdk-integration-testing", f matrix-sdk = { path = "../../crates/matrix-sdk", features = ["experimental-sliding-sync"] } tokio = { version = "1", features = ["rt", "rt-multi-thread", "macros"] } futures = { version = "0.3.25" } +uuid = { version = "1.2.2" } diff --git a/testing/sliding-sync-integration-test/src/lib.rs b/testing/sliding-sync-integration-test/src/lib.rs index 870a54e4d..399b1fcdf 100644 --- a/testing/sliding-sync-integration-test/src/lib.rs +++ b/testing/sliding-sync-integration-test/src/lib.rs @@ -1,4 +1,7 @@ -use matrix_sdk::{Client, SlidingSyncBuilder}; +use matrix_sdk::{ + ruma::api::client::room::{create_room::v3::Request as CreateRoomRequest, Visibility}, + Client, RoomListEntry, SlidingSyncBuilder, +}; use matrix_sdk_integration_testing::helpers::get_client_for_user; #[allow(dead_code)] @@ -14,9 +17,46 @@ async fn setup(name: String) -> anyhow::Result<(Client, SlidingSyncBuilder)> { Ok((client, sliding_sync_builder)) } +#[allow(dead_code)] +async fn random_setup_with_rooms( + number_of_rooms: usize, +) -> anyhow::Result<(Client, SlidingSyncBuilder)> { + let namespace = uuid::Uuid::new_v4().to_string(); + let (client, sliding_sync_builder) = setup(namespace.clone()).await?; + + for room_num in 0..number_of_rooms { + let mut request = CreateRoomRequest::new(); + request.name = Some(format!("{namespace}-{room_num}")); + let _event_id = client.create_room(request).await?; + } + + Ok((client, sliding_sync_builder)) +} + +#[derive(PartialEq, Eq, Debug)] +enum RoomListEntryEasy { + Empty, + Invalid, + Filled, +} + +impl From<&RoomListEntry> for RoomListEntryEasy { + fn from(value: &RoomListEntry) -> Self { + match value { + RoomListEntry::Empty => RoomListEntryEasy::Empty, + RoomListEntry::Invalidated(_) => RoomListEntryEasy::Invalid, + RoomListEntry::Filled(_) => RoomListEntryEasy::Filled, + } + } +} + #[cfg(test)] mod tests { use futures::{pin_mut, stream::StreamExt}; + use matrix_sdk::{ + ruma::events::room::message::RoomMessageEventContent, SlidingSyncMode, SlidingSyncView, + SlidingSyncViewBuilder, + }; use super::*; @@ -33,4 +73,276 @@ mod tests { assert_eq!(summary.rooms.len(), 0); Ok(()) } + + #[tokio::test(flavor = "multi_thread", worker_threads = 4)] + async fn moving_out_of_sliding_window() -> anyhow::Result<()> { + let (client, sync_proxy_builder) = random_setup_with_rooms(20).await?; + let sliding_window_view = SlidingSyncViewBuilder::default() + .sync_mode(SlidingSyncMode::Selective) + .set_range(1u32, 10u32) + .sort(vec!["by_recency".to_string(), "by_name".to_string()]) + .name("sliding") + .build()?; + let sync_proxy = sync_proxy_builder.add_view(sliding_window_view).build().await?; + let Some(view )= sync_proxy.view("sliding") else { + anyhow::bail!("but we just added that view!"); + }; + let stream = sync_proxy.stream().await?; + pin_mut!(stream); + let Some(room_summary ) = stream.next().await else { + anyhow::bail!("No room summary found, loop ended unsuccessfully"); + }; + let summary = room_summary?; + // we only heard about the ones we had asked for + assert_eq!(summary.rooms.len(), 10); + let collection_simple = view + .rooms_list + .lock_ref() + .iter() + .map(Into::::into) + .collect::>(); + assert_eq!( + collection_simple, + [ + RoomListEntryEasy::Empty, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Empty, + RoomListEntryEasy::Empty, + RoomListEntryEasy::Empty, + RoomListEntryEasy::Empty, + RoomListEntryEasy::Empty, + RoomListEntryEasy::Empty, + RoomListEntryEasy::Empty, + RoomListEntryEasy::Empty, + RoomListEntryEasy::Empty, + ] + ); + + let signal = view.rooms_list.signal_vec_cloned(); + + // let's move the window + + view.set_range(0, 10); + + for _n in 0..2 { + let Some(room_summary ) = stream.next().await else { + anyhow::bail!("sync has closed unexepectedly"); + }; + let summary = room_summary?; + // we only heard about the ones we had asked for + if summary.views.iter().any(|s| s == "sliding") { + break; + } + } + + let collection_simple = view + .rooms_list + .lock_ref() + .iter() + .map(Into::::into) + .collect::>(); + assert_eq!( + collection_simple, + [ + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Empty, + RoomListEntryEasy::Empty, + RoomListEntryEasy::Empty, + RoomListEntryEasy::Empty, + RoomListEntryEasy::Empty, + RoomListEntryEasy::Empty, + RoomListEntryEasy::Empty, + RoomListEntryEasy::Empty, + RoomListEntryEasy::Empty, + ] + ); + + // let's move the window again + + view.set_range(2, 12); + + for _n in 0..2 { + let Some(room_summary ) = stream.next().await else { + anyhow::bail!("sync has closed unexepectedly"); + }; + let summary = room_summary?; + // we only heard about the ones we had asked for + if summary.views.iter().any(|s| s == "sliding") { + break; + } + } + + let collection_simple = view + .rooms_list + .lock_ref() + .iter() + .map(Into::::into) + .collect::>(); + assert_eq!( + collection_simple, + [ + RoomListEntryEasy::Invalid, + RoomListEntryEasy::Invalid, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Empty, + RoomListEntryEasy::Empty, + RoomListEntryEasy::Empty, + RoomListEntryEasy::Empty, + RoomListEntryEasy::Empty, + RoomListEntryEasy::Empty, + RoomListEntryEasy::Empty, + ] + ); + + // now we "move" the room of pos 3 to pos 0; + // this is a bordering case + + let Some(RoomListEntry::Filled(room_id)) = view + .rooms_list + .lock_ref() + .iter().nth(3).map(Clone::clone) else + { + anyhow::bail!("2nd room has moved? how?"); + }; + + let Some(room) = client.get_joined_room(&room_id) else { + anyhow::bail!("No joined room {room_id}"); + }; + + let content = RoomMessageEventContent::text_plain("Hello world"); + + room.send(content, None).await?; // this should put our room up to the most recent + + for _n in 0..2 { + let Some(room_summary ) = stream.next().await else { + anyhow::bail!("sync has closed unexepectedly"); + }; + let summary = room_summary?; + // we only heard about the ones we had asked for + if summary.views.iter().any(|s| s == "sliding") { + break; + } + } + + let collection_simple = view + .rooms_list + .lock_ref() + .iter() + .map(Into::::into) + .collect::>(); + assert_eq!( + collection_simple, + [ + RoomListEntryEasy::Invalid, + RoomListEntryEasy::Invalid, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Empty, + RoomListEntryEasy::Empty, + RoomListEntryEasy::Empty, + RoomListEntryEasy::Empty, + RoomListEntryEasy::Empty, + RoomListEntryEasy::Empty, + RoomListEntryEasy::Empty, + ] + ); + + // items has moved, thus we shouldn't find it where it was + assert!( + view.rooms_list.lock_ref().iter().nth(3).unwrap().as_room_id().unwrap() != &room_id + ); + + // let's move the window again + + view.set_range(0, 10); + + for _n in 0..2 { + let Some(room_summary ) = stream.next().await else { + anyhow::bail!("sync has closed unexepectedly"); + }; + let summary = room_summary?; + // we only heard about the ones we had asked for + if summary.views.iter().any(|s| s == "sliding") { + break; + } + } + + let collection_simple = view + .rooms_list + .lock_ref() + .iter() + .map(Into::::into) + .collect::>(); + assert_eq!( + collection_simple, + [ + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Invalid, + RoomListEntryEasy::Invalid, + RoomListEntryEasy::Empty, + RoomListEntryEasy::Empty, + RoomListEntryEasy::Empty, + RoomListEntryEasy::Empty, + RoomListEntryEasy::Empty, + RoomListEntryEasy::Empty, + RoomListEntryEasy::Empty, + ] + ); + + // and check that our room move has been accepted properly, too. + assert_eq!( + view.rooms_list.lock_ref().iter().next().unwrap().as_room_id().unwrap(), + &room_id + ); + + Ok(()) + } } From 91941a53605738bd2289dfcaf669d3aff211aa07 Mon Sep 17 00:00:00 2001 From: Benjamin Kampmann Date: Wed, 11 Jan 2023 11:58:07 +0100 Subject: [PATCH 04/14] fix(sliding-sync): ensure we are only replacing items in the requested range --- crates/matrix-sdk/src/sliding_sync.rs | 78 ++++++++++++++++++++------- 1 file changed, 58 insertions(+), 20 deletions(-) diff --git a/crates/matrix-sdk/src/sliding_sync.rs b/crates/matrix-sdk/src/sliding_sync.rs index a1b1a154f..4006f01ad 100644 --- a/crates/matrix-sdk/src/sliding_sync.rs +++ b/crates/matrix-sdk/src/sliding_sync.rs @@ -712,6 +712,7 @@ impl SlidingSync { resp: v4::Response, extensions: Option, views: &[SlidingSyncView], + ranges: &[Vec<(usize, usize)>], ) -> Result { let mut processed = self.client.process_sliding_sync(resp.clone()).await?; debug!("main client processed."); @@ -726,11 +727,13 @@ impl SlidingSync { .into()); } - for (view, updates) in std::iter::zip(views, &resp.lists) { + for ((view, ranges), updates) in + std::iter::zip(std::iter::zip(views, ranges), &resp.lists) + { let count: u32 = updates.count.try_into().expect("the list total count convertible into u32"); trace!("view {:?} update: {:?}", view.name, !updates.ops.is_empty()); - if view.handle_response(count, &updates.ops)? { + if view.handle_response(count, &updates.ops, ranges)? { updated_views.push(view.name.clone()); } } @@ -799,12 +802,14 @@ impl SlidingSync { debug!(?self.extensions, "Sync loop running"); let mut requests = Vec::new(); + let mut current_ranges = vec![]; let mut new_remaining_generators = Vec::new(); let mut new_remaining_views = Vec::new(); for (mut generator, view) in std::iter::zip(remaining_generators, remaining_views) { - if let Some(request) = generator.next() { + if let Some((request, range)) = generator.next() { requests.push(request); + current_ranges.push(range); new_remaining_generators.push(generator); new_remaining_views.push(view); } @@ -898,7 +903,7 @@ impl SlidingSync { debug!("received"); - let updates = match self.handle_response(resp, extensions, &remaining_views).await { + let updates = match self.handle_response(resp, extensions, &remaining_views, ¤t_ranges).await { Ok(r) => r, Err(e) => { yield Err(e.into()); @@ -1141,7 +1146,7 @@ impl<'a> SlidingSyncViewRequestGenerator<'a> { start: u32, batch_size: u32, limit: Option, - ) -> (u32, v4::SyncRequestList) { + ) -> (u32, (v4::SyncRequestList, Vec<(usize, usize)>)) { let calc_end = start + batch_size; let end = match limit { Some(l) => std::cmp::min(l, calc_end), @@ -1151,30 +1156,44 @@ impl<'a> SlidingSyncViewRequestGenerator<'a> { (end, self.make_request_for_ranges(ranges)) } - fn make_request_for_ranges(&self, ranges: Vec<(UInt, UInt)>) -> v4::SyncRequestList { + fn make_request_for_ranges( + &self, + ranges: Vec<(UInt, UInt)>, + ) -> (v4::SyncRequestList, Vec<(usize, usize)>) { let sort = self.view.sort.clone(); let required_state = self.view.required_state.clone(); let timeline_limit = self.view.timeline_limit; let filters = self.view.filters.clone(); - assign!(v4::SyncRequestList::default(), { - ranges, - required_state, - sort, - timeline_limit, - filters, - }) + ( + assign!(v4::SyncRequestList::default(), { + ranges: ranges.clone(), + required_state, + sort, + timeline_limit, + filters, + }), + ranges + .into_iter() + .map(|(a, b)| { + ( + usize::try_from(a).expect("range is a valid u32"), + usize::try_from(b).expect("range is a valid u32"), + ) + }) + .collect(), + ) } // generate the next live request - fn live_request(&self) -> v4::SyncRequestList { + fn live_request(&self) -> (v4::SyncRequestList, Vec<(usize, usize)>) { let ranges = self.view.ranges.read_only().get_cloned(); self.make_request_for_ranges(ranges) } } impl<'a> Iterator for SlidingSyncViewRequestGenerator<'a> { - type Item = v4::SyncRequestList; + type Item = (v4::SyncRequestList, Vec<(usize, usize)>); fn next(&mut self) -> Option { if let InnerSlidingSyncViewRequestGenerator::PagingFullSync { position, limit, .. } @@ -1322,9 +1341,22 @@ impl SlidingSyncView { } #[instrument(skip(self, ops))] - fn room_ops(&self, ops: &Vec) -> Result<(), Error> { + fn room_ops( + &self, + ops: &Vec, + room_ranges: &Vec<(usize, usize)>, + ) -> Result<(), Error> { let mut rooms_list = self.rooms_list.lock_mut(); let _rooms_map = self.rooms.lock_mut(); + + let index_in_range = |idx| { + for (start, end) in room_ranges.iter() { + if idx >= *start && idx <= *end { + return true; + } + } + false + }; for op in ops { match &op.op { v4::SlidingOp::Sync => { @@ -1386,9 +1418,10 @@ impl SlidingSyncView { loop { // find the next empty slot and drop it let (prev_p, prev_overflow) = pos.overflowing_sub(dif); - let check_prev = !prev_overflow; + let check_prev = !prev_overflow && index_in_range(prev_p); let (next_p, overflown) = pos.overflowing_add(dif); - let check_after = !overflown && next_p < sliced.len(); + let check_after = + !overflown && next_p < sliced.len() && index_in_range(next_p); if !check_prev && !check_after { return Err(Error::BadResponse("We were asked to insert but could not find any direction to shift to".to_owned())); } @@ -1461,7 +1494,12 @@ impl SlidingSyncView { } #[instrument(skip(self, ops))] - fn handle_response(&self, rooms_count: u32, ops: &Vec) -> Result { + fn handle_response( + &self, + rooms_count: u32, + ops: &Vec, + ranges: &Vec<(usize, usize)>, + ) -> Result { let mut missing = rooms_count.checked_sub(self.rooms_list.lock_ref().len() as u32).unwrap_or_default(); let mut changed = false; @@ -1476,7 +1514,7 @@ impl SlidingSyncView { } if !ops.is_empty() { - self.room_ops(ops)?; + self.room_ops(ops, ranges)?; changed = true; } From b790bf93974338920bbbe2b4a56c808f1c739132 Mon Sep 17 00:00:00 2001 From: Benjamin Kampmann Date: Wed, 11 Jan 2023 12:10:51 +0100 Subject: [PATCH 05/14] test(sliding-sync): add integration test covering #1333 --- crates/matrix-sdk/src/sliding_sync.rs | 2 +- .../sliding-sync-integration-test/src/lib.rs | 205 +++++++++++++++++- 2 files changed, 202 insertions(+), 5 deletions(-) diff --git a/crates/matrix-sdk/src/sliding_sync.rs b/crates/matrix-sdk/src/sliding_sync.rs index 4006f01ad..a82d8cafe 100644 --- a/crates/matrix-sdk/src/sliding_sync.rs +++ b/crates/matrix-sdk/src/sliding_sync.rs @@ -1066,7 +1066,7 @@ impl SlidingSyncViewBuilder { /// Set a single range fetch pub fn set_range>(mut self, from: U, to: U) -> Self { - let r = self.ranges = Some(RangeState::new(vec![(from.into(), to.into())])); + self.ranges = Some(RangeState::new(vec![(from.into(), to.into())])); self } diff --git a/testing/sliding-sync-integration-test/src/lib.rs b/testing/sliding-sync-integration-test/src/lib.rs index 399b1fcdf..d867d9b1a 100644 --- a/testing/sliding-sync-integration-test/src/lib.rs +++ b/testing/sliding-sync-integration-test/src/lib.rs @@ -1,6 +1,6 @@ use matrix_sdk::{ - ruma::api::client::room::{create_room::v3::Request as CreateRoomRequest, Visibility}, - Client, RoomListEntry, SlidingSyncBuilder, + ruma::api::client::room::create_room::v3::Request as CreateRoomRequest, Client, RoomListEntry, + SlidingSyncBuilder, }; use matrix_sdk_integration_testing::helpers::get_client_for_user; @@ -54,7 +54,7 @@ impl From<&RoomListEntry> for RoomListEntryEasy { mod tests { use futures::{pin_mut, stream::StreamExt}; use matrix_sdk::{ - ruma::events::room::message::RoomMessageEventContent, SlidingSyncMode, SlidingSyncView, + ruma::events::room::message::RoomMessageEventContent, SlidingSyncMode, SlidingSyncViewBuilder, }; @@ -74,6 +74,203 @@ mod tests { Ok(()) } + #[tokio::test(flavor = "multi_thread", worker_threads = 4)] + async fn resizing_sliding_window() -> anyhow::Result<()> { + let (_client, sync_proxy_builder) = random_setup_with_rooms(20).await?; + let sliding_window_view = SlidingSyncViewBuilder::default() + .sync_mode(SlidingSyncMode::Selective) + .set_range(0u32, 10u32) + .sort(vec!["by_recency".to_string(), "by_name".to_string()]) + .name("sliding") + .build()?; + let sync_proxy = sync_proxy_builder.add_view(sliding_window_view).build().await?; + let Some(view )= sync_proxy.view("sliding") else { + anyhow::bail!("but we just added that view!"); + }; + let stream = sync_proxy.stream().await?; + pin_mut!(stream); + let Some(room_summary ) = stream.next().await else { + anyhow::bail!("No room summary found, loop ended unsuccessfully"); + }; + let summary = room_summary?; + // we only heard about the ones we had asked for + assert_eq!(summary.rooms.len(), 11); + let collection_simple = view + .rooms_list + .lock_ref() + .iter() + .map(Into::::into) + .collect::>(); + assert_eq!( + collection_simple, + [ + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Empty, + RoomListEntryEasy::Empty, + RoomListEntryEasy::Empty, + RoomListEntryEasy::Empty, + RoomListEntryEasy::Empty, + RoomListEntryEasy::Empty, + RoomListEntryEasy::Empty, + RoomListEntryEasy::Empty, + RoomListEntryEasy::Empty, + ] + ); + + let _signal = view.rooms_list.signal_vec_cloned(); + + // let's move the window + + view.set_range(1, 10); + // Ensure 0-0 invalidation ranges work. + + for _n in 0..2 { + let Some(room_summary ) = stream.next().await else { + anyhow::bail!("sync has closed unexepectedly"); + }; + let summary = room_summary?; + // we only heard about the ones we had asked for + if summary.views.iter().any(|s| s == "sliding") { + break; + } + } + + let collection_simple = view + .rooms_list + .lock_ref() + .iter() + .map(Into::::into) + .collect::>(); + assert_eq!( + collection_simple, + [ + RoomListEntryEasy::Invalid, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Empty, + RoomListEntryEasy::Empty, + RoomListEntryEasy::Empty, + RoomListEntryEasy::Empty, + RoomListEntryEasy::Empty, + RoomListEntryEasy::Empty, + RoomListEntryEasy::Empty, + RoomListEntryEasy::Empty, + RoomListEntryEasy::Empty, + ] + ); + + view.set_range(5, 10); + + for _n in 0..2 { + let Some(room_summary ) = stream.next().await else { + anyhow::bail!("sync has closed unexepectedly"); + }; + let summary = room_summary?; + // we only heard about the ones we had asked for + if summary.views.iter().any(|s| s == "sliding") { + break; + } + } + + let collection_simple = view + .rooms_list + .lock_ref() + .iter() + .map(Into::::into) + .collect::>(); + assert_eq!( + collection_simple, + [ + RoomListEntryEasy::Invalid, + RoomListEntryEasy::Invalid, + RoomListEntryEasy::Invalid, + RoomListEntryEasy::Invalid, + RoomListEntryEasy::Invalid, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Empty, + RoomListEntryEasy::Empty, + RoomListEntryEasy::Empty, + RoomListEntryEasy::Empty, + RoomListEntryEasy::Empty, + RoomListEntryEasy::Empty, + RoomListEntryEasy::Empty, + RoomListEntryEasy::Empty, + RoomListEntryEasy::Empty, + ] + ); + + // let's move the window + + view.set_range(5, 15); + + for _n in 0..2 { + let Some(room_summary ) = stream.next().await else { + anyhow::bail!("sync has closed unexepectedly"); + }; + let summary = room_summary?; + // we only heard about the ones we had asked for + if summary.views.iter().any(|s| s == "sliding") { + break; + } + } + + let collection_simple = view + .rooms_list + .lock_ref() + .iter() + .map(Into::::into) + .collect::>(); + assert_eq!( + collection_simple, + [ + RoomListEntryEasy::Invalid, + RoomListEntryEasy::Invalid, + RoomListEntryEasy::Invalid, + RoomListEntryEasy::Invalid, + RoomListEntryEasy::Invalid, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Filled, + RoomListEntryEasy::Empty, + RoomListEntryEasy::Empty, + RoomListEntryEasy::Empty, + RoomListEntryEasy::Empty, + ] + ); + Ok(()) + } + #[tokio::test(flavor = "multi_thread", worker_threads = 4)] async fn moving_out_of_sliding_window() -> anyhow::Result<()> { let (client, sync_proxy_builder) = random_setup_with_rooms(20).await?; @@ -127,7 +324,7 @@ mod tests { ] ); - let signal = view.rooms_list.signal_vec_cloned(); + let _signal = view.rooms_list.signal_vec_cloned(); // let's move the window From 2949dcc7734a2dc7c22523d00d66200c5f39a169 Mon Sep 17 00:00:00 2001 From: Benjamin Kampmann Date: Wed, 11 Jan 2023 14:29:47 +0100 Subject: [PATCH 06/14] docs: Add a Readme to explain usage --- .../sliding-sync-integration-test/README.md | 41 +++++++++++++++++++ .../sliding-sync-integration-test/src/lib.rs | 14 +++---- 2 files changed, 48 insertions(+), 7 deletions(-) create mode 100644 testing/sliding-sync-integration-test/README.md diff --git a/testing/sliding-sync-integration-test/README.md b/testing/sliding-sync-integration-test/README.md new file mode 100644 index 000000000..8f9a7ebce --- /dev/null +++ b/testing/sliding-sync-integration-test/README.md @@ -0,0 +1,41 @@ +# Matrix SDK sliding sync integration test + +A test harness and tests for integration testing sliding sync against a full synapse server and [sliding sync proxy](https://github.com/matrix-org/sliding-sync/) + + +## Requirements + +This requires a synapse backend with a ci patched configuration and a sliding-sync-proxy. +You can easily get it up and running with `docker-compose` via: + +```sh +docker-compose -f assets/docker-compose.yml up -d +docker-compose -f assets/docker-compose.yml logs --tail 100 -f +``` + +**Patches** +You can see the patches we do to configuration (namely activate registration and +resetting rate limits), check out what `assets/ci-start.sh` changes. + +## Running + +The integration tests can be run with `cargo test` or `cargo nextest run`. + +The integration tests expect the environment variables `HOMESERVER_URL` to be the HTTP URL to +access the synapse server and `HOMESERVER_DOMAIN` to be set to the domain configured in +that server. If you are using the provided `docker-compose`, the default will be fine. + +## Maintenance + +To drop the database of your docker-compose run: + +```bash +docker-compose -f assets/docker-compose.yml stop +docker volume rm -f matrix-rust-sdk-sliding-sync-ci-data +``` + +or simply: + +```bash +docker-compose -f assets/docker-compose.yml down -v +``` diff --git a/testing/sliding-sync-integration-test/src/lib.rs b/testing/sliding-sync-integration-test/src/lib.rs index d867d9b1a..5da56eaad 100644 --- a/testing/sliding-sync-integration-test/src/lib.rs +++ b/testing/sliding-sync-integration-test/src/lib.rs @@ -136,7 +136,7 @@ mod tests { for _n in 0..2 { let Some(room_summary ) = stream.next().await else { - anyhow::bail!("sync has closed unexepectedly"); + anyhow::bail!("sync has closed unexpectedly"); }; let summary = room_summary?; // we only heard about the ones we had asked for @@ -181,7 +181,7 @@ mod tests { for _n in 0..2 { let Some(room_summary ) = stream.next().await else { - anyhow::bail!("sync has closed unexepectedly"); + anyhow::bail!("sync has closed unexpectedly"); }; let summary = room_summary?; // we only heard about the ones we had asked for @@ -228,7 +228,7 @@ mod tests { for _n in 0..2 { let Some(room_summary ) = stream.next().await else { - anyhow::bail!("sync has closed unexepectedly"); + anyhow::bail!("sync has closed unexpectedly"); }; let summary = room_summary?; // we only heard about the ones we had asked for @@ -332,7 +332,7 @@ mod tests { for _n in 0..2 { let Some(room_summary ) = stream.next().await else { - anyhow::bail!("sync has closed unexepectedly"); + anyhow::bail!("sync has closed unexpectedly"); }; let summary = room_summary?; // we only heard about the ones we had asked for @@ -379,7 +379,7 @@ mod tests { for _n in 0..2 { let Some(room_summary ) = stream.next().await else { - anyhow::bail!("sync has closed unexepectedly"); + anyhow::bail!("sync has closed unexpectedly"); }; let summary = room_summary?; // we only heard about the ones we had asked for @@ -441,7 +441,7 @@ mod tests { for _n in 0..2 { let Some(room_summary ) = stream.next().await else { - anyhow::bail!("sync has closed unexepectedly"); + anyhow::bail!("sync has closed unexpectedly"); }; let summary = room_summary?; // we only heard about the ones we had asked for @@ -493,7 +493,7 @@ mod tests { for _n in 0..2 { let Some(room_summary ) = stream.next().await else { - anyhow::bail!("sync has closed unexepectedly"); + anyhow::bail!("sync has closed unexpectedly"); }; let summary = room_summary?; // we only heard about the ones we had asked for From a8d49b86df4e1254d78cd75afbe0620ff4afb612 Mon Sep 17 00:00:00 2001 From: Benjamin Kampmann Date: Wed, 11 Jan 2023 17:24:18 +0100 Subject: [PATCH 07/14] feat(sliding-sync): adding views on live sliding-sync --- bindings/matrix-sdk-ffi/src/sliding_sync.rs | 16 +- crates/matrix-sdk/src/sliding_sync.rs | 37 ++- .../sliding-sync-integration-test/src/lib.rs | 252 ++++++++++++++++++ 3 files changed, 297 insertions(+), 8 deletions(-) diff --git a/bindings/matrix-sdk-ffi/src/sliding_sync.rs b/bindings/matrix-sdk-ffi/src/sliding_sync.rs index b698e5b6b..13dd28f8e 100644 --- a/bindings/matrix-sdk-ffi/src/sliding_sync.rs +++ b/bindings/matrix-sdk-ffi/src/sliding_sync.rs @@ -599,13 +599,15 @@ impl SlidingSync { impl SlidingSync { #[allow(clippy::significant_drop_in_scrutinee)] pub fn get_view(&self, name: String) -> Option> { - let views = self.inner.views.lock_ref(); - for s in views.iter() { - if s.name == name { - return Some(Arc::new(SlidingSyncView { inner: s.clone() })); - } - } - None + self.inner.view(&name).map(|inner| Arc::new(SlidingSyncView { inner })) + } + + pub fn add_view(&self, view: Arc) -> Option { + self.inner.add_view(view.inner.clone()).map(|u| u as u32) + } + + pub fn pop_view(&self, name: String) -> Option> { + self.inner.pop_view(&name).map(|inner| Arc::new(SlidingSyncView { inner })) } pub fn sync(&self) -> Arc { diff --git a/crates/matrix-sdk/src/sliding_sync.rs b/crates/matrix-sdk/src/sliding_sync.rs index a82d8cafe..f3e2b9245 100644 --- a/crates/matrix-sdk/src/sliding_sync.rs +++ b/crates/matrix-sdk/src/sliding_sync.rs @@ -694,8 +694,43 @@ impl SlidingSync { } /// Get access to the SlidingSyncView named `view_name` + /// + /// Note: Remember that this list might have been changed since you started + /// listening to the stream and is therefor not necessarily up to date + /// with the views used for the stream. pub fn view(&self, view_name: &str) -> Option { - self.views.lock_ref().iter().find(|v| v.name == view_name).cloned().clone() + self.views.lock_ref().iter().find(|v| v.name == view_name).cloned() + } + + /// Remove the SlidingSyncView named `view_name` from the views list if + /// found + /// + /// Note: Remember that this change will only be applicable for any new + /// stream created after this. The old stream will still continue to use the + /// previous set of views + pub fn pop_view(&self, _view_name: &str) -> Option { + unimplemented!("Index based sliding sync doesn't have support removing views"); + } + + /// Add the view to the list of views + /// + /// As views need to have a unique `.name`, if a view with the same name + /// is found the new view will replace the old one and the return will give + /// the position it was found at. If none is found, the view will be pushed + /// to the end and `None` is returned. + /// + /// Note: Remember that this change will only be applicable for any new + /// stream created after this. The old stream will still continue to use the + /// previous set of views + pub fn add_view(&self, view: SlidingSyncView) -> Option { + let mut v = self.views.lock_mut(); + if let Some(idx) = v.iter().position(|v| v.name == view.name) { + v.set_cloned(idx, view); + Some(idx) + } else { + v.push_cloned(view); + None + } } /// Lookup a set of rooms diff --git a/testing/sliding-sync-integration-test/src/lib.rs b/testing/sliding-sync-integration-test/src/lib.rs index 5da56eaad..5b976fb63 100644 --- a/testing/sliding-sync-integration-test/src/lib.rs +++ b/testing/sliding-sync-integration-test/src/lib.rs @@ -74,6 +74,258 @@ mod tests { Ok(()) } + #[tokio::test(flavor = "multi_thread", worker_threads = 4)] + async fn adding_view_later() -> anyhow::Result<()> { + let view_name_1 = "sliding1"; + let view_name_2 = "sliding2"; + let view_name_3 = "sliding3"; + + let (client, sync_proxy_builder) = random_setup_with_rooms(20).await?; + let build_view = |name| { + SlidingSyncViewBuilder::default() + .sync_mode(SlidingSyncMode::Selective) + .set_range(0u32, 10u32) + .sort(vec!["by_recency".to_string(), "by_name".to_string()]) + .name(name) + .build() + }; + let sync_proxy = sync_proxy_builder + .add_view(build_view(view_name_1)?) + .add_view(build_view(view_name_2)?) + .build() + .await?; + let Some(view1 )= sync_proxy.view(view_name_1) else { + anyhow::bail!("but we just added that view!"); + }; + let Some(_view2 )= sync_proxy.view(view_name_2) else { + anyhow::bail!("but we just added that view!"); + }; + + assert!(sync_proxy.view(view_name_3).is_none()); + + let stream = sync_proxy.stream().await?; + pin_mut!(stream); + let Some(room_summary ) = stream.next().await else { + anyhow::bail!("No room summary found, loop ended unsuccessfully"); + }; + let summary = room_summary?; + // we only heard about the ones we had asked for + assert_eq!(summary.views, [view_name_1, view_name_2]); + + assert!(sync_proxy.add_view(build_view(view_name_3)?).is_none()); + + // we need to restart the stream after every view listing update + let stream = sync_proxy.stream().await?; + pin_mut!(stream); + + let mut saw_update = false; + for _n in 0..2 { + let Some(room_summary ) = stream.next().await else { + anyhow::bail!("sync has closed unexpectedly"); + }; + let summary = room_summary?; + // we only heard about the ones we had asked for + if !summary.views.is_empty() { + // only if we saw an update come through + assert_eq!(summary.views, [view_name_3]); + // we didn't update the other views, so only no 2 should se an update + saw_update = true; + break; + } + } + + assert!(saw_update, "We didn't see the updae come through the pipe"); + + // and let's update the order of all views again + let Some(RoomListEntry::Filled(room_id)) = view1 + .rooms_list + .lock_ref() + .iter().nth(4).map(Clone::clone) else + { + anyhow::bail!("4th room has moved? how?"); + }; + + let Some(room) = client.get_joined_room(&room_id) else { + anyhow::bail!("No joined room {room_id}"); + }; + + let content = RoomMessageEventContent::text_plain("Hello world"); + + room.send(content, None).await?; // this should put our room up to the most recent + + let mut saw_update = false; + for _n in 0..2 { + let Some(room_summary ) = stream.next().await else { + anyhow::bail!("sync has closed unexpectedly"); + }; + let summary = room_summary?; + // we only heard about the ones we had asked for + if !summary.views.is_empty() { + // only if we saw an update come through + assert_eq!(summary.views, [view_name_1, view_name_2, view_name_3,]); + // notice that our view 2 is now the last view, but all have seen updates + saw_update = true; + break; + } + } + + assert!(saw_update, "We didn't see the updae come through the pipe"); + + Ok(()) + } + + // index-based views don't support removing views. Leaving this test for an API + // update later. + // + // #[tokio::test(flavor = "multi_thread", worker_threads = 4)] + // async fn live_views() -> anyhow::Result<()> { + // let view_name_1 = "sliding1"; + // let view_name_2 = "sliding2"; + // let view_name_3 = "sliding3"; + + // let (client, sync_proxy_builder) = random_setup_with_rooms(20).await?; + // let build_view = |name| { + // SlidingSyncViewBuilder::default() + // .sync_mode(SlidingSyncMode::Selective) + // .set_range(0u32, 10u32) + // .sort(vec!["by_recency".to_string(), "by_name".to_string()]) + // .name(name) + // .build() + // }; + // let sync_proxy = sync_proxy_builder + // .add_view(build_view(view_name_1)?) + // .add_view(build_view(view_name_2)?) + // .add_view(build_view(view_name_3)?) + // .build() + // .await?; + // let Some(view1 )= sync_proxy.view(view_name_1) else { + // anyhow::bail!("but we just added that view!"); + // }; + // let Some(_view2 )= sync_proxy.view(view_name_2) else { + // anyhow::bail!("but we just added that view!"); + // }; + + // let Some(_view3 )= sync_proxy.view(view_name_3) else { + // anyhow::bail!("but we just added that view!"); + // }; + + // let stream = sync_proxy.stream().await?; + // pin_mut!(stream); + // let Some(room_summary ) = stream.next().await else { + // anyhow::bail!("No room summary found, loop ended unsuccessfully"); + // }; + // let summary = room_summary?; + // // we only heard about the ones we had asked for + // assert_eq!(summary.views, [view_name_1, view_name_2, view_name_3]); + + // let Some(view_2) = sync_proxy.pop_view(view_name_2) else { + // anyhow::bail!("Room exists"); + // }; + + // // we need to restart the stream after every view listing update + // let stream = sync_proxy.stream().await?; + // pin_mut!(stream); + + // // Let's trigger an update by sending a message to room pos=3, making it + // move to // pos 0 + + // let Some(RoomListEntry::Filled(room_id)) = view1 + // .rooms_list + // .lock_ref() + // .iter().nth(3).map(Clone::clone) else + // { + // anyhow::bail!("2nd room has moved? how?"); + // }; + + // let Some(room) = client.get_joined_room(&room_id) else { + // anyhow::bail!("No joined room {room_id}"); + // }; + + // let content = RoomMessageEventContent::text_plain("Hello world"); + + // room.send(content, None).await?; // this should put our room up to the + // most recent + + // let mut saw_update = false; + // for _n in 0..2 { + // let Some(room_summary ) = stream.next().await else { + // anyhow::bail!("sync has closed unexpectedly"); + // }; + // let summary = room_summary?; + // // we only heard about the ones we had asked for + // if !summary.views.is_empty() { + // // only if we saw an update come through + // assert_eq!(summary.views, [view_name_1, view_name_3]); + // saw_update = true; + // break; + // } + // } + + // assert!(saw_update, "We didn't see the updae come through the pipe"); + + // assert!(sync_proxy.add_view(view_2).is_none()); + + // // we need to restart the stream after every view listing update + // let stream = sync_proxy.stream().await?; + // pin_mut!(stream); + + // let mut saw_update = false; + // for _n in 0..2 { + // let Some(room_summary ) = stream.next().await else { + // anyhow::bail!("sync has closed unexpectedly"); + // }; + // let summary = room_summary?; + // // we only heard about the ones we had asked for + // if !summary.views.is_empty() { + // // only if we saw an update come through + // assert_eq!(summary.views, [view_name_2]); + // // we didn't update the other views, so only no 2 should se an + // update saw_update = true; + // break; + // } + // } + + // assert!(saw_update, "We didn't see the updae come through the pipe"); + + // // and let's update the order of all views again + // let Some(RoomListEntry::Filled(room_id)) = view1 + // .rooms_list + // .lock_ref() + // .iter().nth(4).map(Clone::clone) else + // { + // anyhow::bail!("4th room has moved? how?"); + // }; + + // let Some(room) = client.get_joined_room(&room_id) else { + // anyhow::bail!("No joined room {room_id}"); + // }; + + // let content = RoomMessageEventContent::text_plain("Hello world"); + + // room.send(content, None).await?; // this should put our room up to the + // most recent + + // let mut saw_update = false; + // for _n in 0..2 { + // let Some(room_summary ) = stream.next().await else { + // anyhow::bail!("sync has closed unexpectedly"); + // }; + // let summary = room_summary?; + // // we only heard about the ones we had asked for + // if !summary.views.is_empty() { + // // only if we saw an update come through + // assert_eq!(summary.views, [view_name_1, view_name_3, + // view_name_2]); // notice that our view 2 is now the last + // view, but all have seen updates saw_update = true; + // break; + // } + // } + + // assert!(saw_update, "We didn't see the updae come through the pipe"); + + // Ok(()) + // } + #[tokio::test(flavor = "multi_thread", worker_threads = 4)] async fn resizing_sliding_window() -> anyhow::Result<()> { let (_client, sync_proxy_builder) = random_setup_with_rooms(20).await?; From 3c6c5f4faead863a3c901cdd08e6cf997ef4fd0c Mon Sep 17 00:00:00 2001 From: Benjamin Kampmann Date: Wed, 11 Jan 2023 17:25:45 +0100 Subject: [PATCH 08/14] ci: disable broken sliding-sync-integration-test-runs --- .github/workflows/ci.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index eff72d0d5..0c48cb3b5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -447,7 +447,9 @@ jobs: sliding-sync-integration-tests: name: Sliding Sync Integration test - if: github.event_name == 'push' || !github.event.pull_request.draft + # disabled until we can figure out the weird docker-not-starting-situation + if: false + # if: github.event_name == 'push' || !github.event.pull_request.draft runs-on: ubuntu-latest # Service containers to run with `runner-job` From 51f2e773a000fa3a2ecf109fa16f009625d41ecd Mon Sep 17 00:00:00 2001 From: Benjamin Kampmann Date: Wed, 11 Jan 2023 17:29:24 +0100 Subject: [PATCH 09/14] fix(ffi): add Pop and Clear to VecDiff for sliding-sync --- bindings/matrix-sdk-ffi/src/api.udl | 5 ++--- bindings/matrix-sdk-ffi/src/sliding_sync.rs | 5 ++++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/bindings/matrix-sdk-ffi/src/api.udl b/bindings/matrix-sdk-ffi/src/api.udl index 1092ae4ed..96302aa37 100644 --- a/bindings/matrix-sdk-ffi/src/api.udl +++ b/bindings/matrix-sdk-ffi/src/api.udl @@ -82,9 +82,8 @@ interface SlidingSyncViewRoomsListDiff { u32 new_index ); Push(RoomListEntry value); - // The following are supported by the generic VecDiff-type but - // in sliding sync effectively do not happen and thus aren't exposed - // to not pollute the API: Pop(); Clear(); + Pop(); + Clear(); }; callback interface SlidingSyncViewRoomListObserver { diff --git a/bindings/matrix-sdk-ffi/src/sliding_sync.rs b/bindings/matrix-sdk-ffi/src/sliding_sync.rs index 13dd28f8e..1fdce3db7 100644 --- a/bindings/matrix-sdk-ffi/src/sliding_sync.rs +++ b/bindings/matrix-sdk-ffi/src/sliding_sync.rs @@ -216,6 +216,8 @@ pub enum SlidingSyncViewRoomsListDiff { RemoveAt { index: u32 }, Move { old_index: u32, new_index: u32 }, Push { value: RoomListEntry }, + Pop, // removes the last item + Clear, // clears the list } impl From> for SlidingSyncViewRoomsListDiff { @@ -242,7 +244,8 @@ impl From> for SlidingSyncViewRoomsListDiff { VecDiff::Push { value } => { SlidingSyncViewRoomsListDiff::Push { value: (&value).into() } } - _ => unimplemented!("Clear and Pop aren't provided within sliding sync"), + VecDiff::Pop {} => SlidingSyncViewRoomsListDiff::Pop, + VecDiff::Clear {} => SlidingSyncViewRoomsListDiff::Clear, } } } From c93a9ef9a351f43adebaacc8e3278c1655483bb3 Mon Sep 17 00:00:00 2001 From: Benjamin Kampmann Date: Thu, 12 Jan 2023 13:18:40 +0100 Subject: [PATCH 10/14] fix(sliding-sync): Simply room_range checking Co-authored-by: Jonas Platte --- crates/matrix-sdk/src/sliding_sync.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/crates/matrix-sdk/src/sliding_sync.rs b/crates/matrix-sdk/src/sliding_sync.rs index f3e2b9245..8a45cdbf5 100644 --- a/crates/matrix-sdk/src/sliding_sync.rs +++ b/crates/matrix-sdk/src/sliding_sync.rs @@ -1385,12 +1385,9 @@ impl SlidingSyncView { let _rooms_map = self.rooms.lock_mut(); let index_in_range = |idx| { - for (start, end) in room_ranges.iter() { - if idx >= *start && idx <= *end { - return true; - } - } - false + room_ranges.iter().any(|(start, end)| { + idx >= *start && idx <= *end + }) }; for op in ops { match &op.op { From 906c09987fc1f99e73c1a2818029a1f307856916 Mon Sep 17 00:00:00 2001 From: Benjamin Kampmann Date: Thu, 12 Jan 2023 13:20:17 +0100 Subject: [PATCH 11/14] style(sliding-sync): minor style refinements --- crates/matrix-sdk/src/sliding_sync.rs | 9 +++------ testing/matrix-sdk-integration-testing/src/helpers.rs | 5 ----- .../assets/docker-compose.yml | 3 +-- 3 files changed, 4 insertions(+), 13 deletions(-) diff --git a/crates/matrix-sdk/src/sliding_sync.rs b/crates/matrix-sdk/src/sliding_sync.rs index 8a45cdbf5..458796d34 100644 --- a/crates/matrix-sdk/src/sliding_sync.rs +++ b/crates/matrix-sdk/src/sliding_sync.rs @@ -709,7 +709,7 @@ impl SlidingSync { /// stream created after this. The old stream will still continue to use the /// previous set of views pub fn pop_view(&self, _view_name: &str) -> Option { - unimplemented!("Index based sliding sync doesn't have support removing views"); + unimplemented!("Index based sliding sync doesn't support removing views"); } /// Add the view to the list of views @@ -1384,11 +1384,8 @@ impl SlidingSyncView { let mut rooms_list = self.rooms_list.lock_mut(); let _rooms_map = self.rooms.lock_mut(); - let index_in_range = |idx| { - room_ranges.iter().any(|(start, end)| { - idx >= *start && idx <= *end - }) - }; + let index_in_range = + |idx| room_ranges.iter().any(|(start, end)| idx >= *start && idx <= *end); for op in ops { match &op.op { v4::SlidingOp::Sync => { diff --git a/testing/matrix-sdk-integration-testing/src/helpers.rs b/testing/matrix-sdk-integration-testing/src/helpers.rs index f18405f26..bd16f2689 100644 --- a/testing/matrix-sdk-integration-testing/src/helpers.rs +++ b/testing/matrix-sdk-integration-testing/src/helpers.rs @@ -15,11 +15,6 @@ static USERS: Lazy>> = Lazy::new(Mutex: #[ctor::ctor] fn startup() { - init_logging(); -} - -/// initialize logging -pub fn init_logging() { use tracing::Level; use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; tracing_subscriber::registry() diff --git a/testing/sliding-sync-integration-test/assets/docker-compose.yml b/testing/sliding-sync-integration-test/assets/docker-compose.yml index a7678ccab..0468562eb 100644 --- a/testing/sliding-sync-integration-test/assets/docker-compose.yml +++ b/testing/sliding-sync-integration-test/assets/docker-compose.yml @@ -1,4 +1,3 @@ - version: '3' services: @@ -34,7 +33,7 @@ services: environment: SYNCV3_SERVER: http://synapse:8008 SYNCV3_SECRET: SUPER_SECRET - SYNCV3_BINDADDR: ":8338" + SYNCV3_BINDADDR: ":8338" SYNCV3_DB: "user=postgres password=postgres dbname=syncv3 sslmode=disable host=postgres" ports: - 8338:8338 From 6ec8ff6363a1f6e2aee2c10ab95c4e9f13fe6254 Mon Sep 17 00:00:00 2001 From: Benjamin Kampmann Date: Thu, 12 Jan 2023 13:51:59 +0100 Subject: [PATCH 12/14] ci(coverage): ignore new sliding-sync-integration-tests for now --- .github/workflows/coverage.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 09488a68d..a4103d8b7 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -53,7 +53,7 @@ jobs: uses: actions-rs/cargo@v1 with: command: tarpaulin - args: --out Xml + args: --out Xml -e sliding-sync-integration-test - name: Upload to codecov.io uses: codecov/codecov-action@v3 From 723e3a3135d7adc8b37da81182992a09436ab37f Mon Sep 17 00:00:00 2001 From: Benjamin Kampmann Date: Thu, 12 Jan 2023 15:35:59 +0100 Subject: [PATCH 13/14] tests(sliding-sync): minor style improvements --- .../sliding-sync-integration-test/src/lib.rs | 124 +++++++----------- 1 file changed, 46 insertions(+), 78 deletions(-) diff --git a/testing/sliding-sync-integration-test/src/lib.rs b/testing/sliding-sync-integration-test/src/lib.rs index 5b976fb63..895c96bb1 100644 --- a/testing/sliding-sync-integration-test/src/lib.rs +++ b/testing/sliding-sync-integration-test/src/lib.rs @@ -52,6 +52,7 @@ impl From<&RoomListEntry> for RoomListEntryEasy { #[cfg(test)] mod tests { + use anyhow::Context; use futures::{pin_mut, stream::StreamExt}; use matrix_sdk::{ ruma::events::room::message::RoomMessageEventContent, SlidingSyncMode, @@ -66,9 +67,8 @@ mod tests { let sync_proxy = sync_proxy_builder.add_fullsync_view().build().await?; let stream = sync_proxy.stream().await?; pin_mut!(stream); - let Some(room_summary ) = stream.next().await else { - anyhow::bail!("No room summary found, loop ended unsuccessfully"); - }; + let room_summary = + stream.next().await.context("No room summary found, loop ended unsuccessfully")?; let summary = room_summary?; assert_eq!(summary.rooms.len(), 0); Ok(()) @@ -94,20 +94,15 @@ mod tests { .add_view(build_view(view_name_2)?) .build() .await?; - let Some(view1 )= sync_proxy.view(view_name_1) else { - anyhow::bail!("but we just added that view!"); - }; - let Some(_view2 )= sync_proxy.view(view_name_2) else { - anyhow::bail!("but we just added that view!"); - }; + let view1 = sync_proxy.view(view_name_1).context("but we just added that view!")?; + let _view2 = sync_proxy.view(view_name_2).context("but we just added that view!")?; assert!(sync_proxy.view(view_name_3).is_none()); let stream = sync_proxy.stream().await?; pin_mut!(stream); - let Some(room_summary ) = stream.next().await else { - anyhow::bail!("No room summary found, loop ended unsuccessfully"); - }; + let room_summary = + stream.next().await.context("No room summary found, loop ended unsuccessfully")?; let summary = room_summary?; // we only heard about the ones we had asked for assert_eq!(summary.views, [view_name_1, view_name_2]); @@ -120,9 +115,7 @@ mod tests { let mut saw_update = false; for _n in 0..2 { - let Some(room_summary ) = stream.next().await else { - anyhow::bail!("sync has closed unexpectedly"); - }; + let room_summary = stream.next().await.context("sync has closed unexpectedly")?; let summary = room_summary?; // we only heard about the ones we had asked for if !summary.views.is_empty() { @@ -140,14 +133,13 @@ mod tests { let Some(RoomListEntry::Filled(room_id)) = view1 .rooms_list .lock_ref() - .iter().nth(4).map(Clone::clone) else - { - anyhow::bail!("4th room has moved? how?"); - }; + .iter() + .nth(4) + .map(Clone::clone) else { + panic!("4th room has moved? how?") + }; - let Some(room) = client.get_joined_room(&room_id) else { - anyhow::bail!("No joined room {room_id}"); - }; + let room = client.get_joined_room(&room_id).context("No joined room {room_id}")?; let content = RoomMessageEventContent::text_plain("Hello world"); @@ -155,9 +147,7 @@ mod tests { let mut saw_update = false; for _n in 0..2 { - let Some(room_summary ) = stream.next().await else { - anyhow::bail!("sync has closed unexpectedly"); - }; + let room_summary = stream.next().await.context("sync has closed unexpectedly")?; let summary = room_summary?; // we only heard about the ones we had asked for if !summary.views.is_empty() { @@ -199,27 +189,27 @@ mod tests { // .build() // .await?; // let Some(view1 )= sync_proxy.view(view_name_1) else { - // anyhow::bail!("but we just added that view!"); + // bail!("but we just added that view!"); // }; // let Some(_view2 )= sync_proxy.view(view_name_2) else { - // anyhow::bail!("but we just added that view!"); + // bail!("but we just added that view!"); // }; // let Some(_view3 )= sync_proxy.view(view_name_3) else { - // anyhow::bail!("but we just added that view!"); + // bail!("but we just added that view!"); // }; // let stream = sync_proxy.stream().await?; // pin_mut!(stream); // let Some(room_summary ) = stream.next().await else { - // anyhow::bail!("No room summary found, loop ended unsuccessfully"); + // bail!("No room summary found, loop ended unsuccessfully"); // }; // let summary = room_summary?; // // we only heard about the ones we had asked for // assert_eq!(summary.views, [view_name_1, view_name_2, view_name_3]); // let Some(view_2) = sync_proxy.pop_view(view_name_2) else { - // anyhow::bail!("Room exists"); + // bail!("Room exists"); // }; // // we need to restart the stream after every view listing update @@ -234,11 +224,11 @@ mod tests { // .lock_ref() // .iter().nth(3).map(Clone::clone) else // { - // anyhow::bail!("2nd room has moved? how?"); + // bail!("2nd room has moved? how?"); // }; // let Some(room) = client.get_joined_room(&room_id) else { - // anyhow::bail!("No joined room {room_id}"); + // bail!("No joined room {room_id}"); // }; // let content = RoomMessageEventContent::text_plain("Hello world"); @@ -249,7 +239,7 @@ mod tests { // let mut saw_update = false; // for _n in 0..2 { // let Some(room_summary ) = stream.next().await else { - // anyhow::bail!("sync has closed unexpectedly"); + // bail!("sync has closed unexpectedly"); // }; // let summary = room_summary?; // // we only heard about the ones we had asked for @@ -272,7 +262,7 @@ mod tests { // let mut saw_update = false; // for _n in 0..2 { // let Some(room_summary ) = stream.next().await else { - // anyhow::bail!("sync has closed unexpectedly"); + // bail!("sync has closed unexpectedly"); // }; // let summary = room_summary?; // // we only heard about the ones we had asked for @@ -293,11 +283,11 @@ mod tests { // .lock_ref() // .iter().nth(4).map(Clone::clone) else // { - // anyhow::bail!("4th room has moved? how?"); + // bail!("4th room has moved? how?"); // }; // let Some(room) = client.get_joined_room(&room_id) else { - // anyhow::bail!("No joined room {room_id}"); + // bail!("No joined room {room_id}"); // }; // let content = RoomMessageEventContent::text_plain("Hello world"); @@ -308,7 +298,7 @@ mod tests { // let mut saw_update = false; // for _n in 0..2 { // let Some(room_summary ) = stream.next().await else { - // anyhow::bail!("sync has closed unexpectedly"); + // bail!("sync has closed unexpectedly"); // }; // let summary = room_summary?; // // we only heard about the ones we had asked for @@ -336,14 +326,11 @@ mod tests { .name("sliding") .build()?; let sync_proxy = sync_proxy_builder.add_view(sliding_window_view).build().await?; - let Some(view )= sync_proxy.view("sliding") else { - anyhow::bail!("but we just added that view!"); - }; + let view = sync_proxy.view("sliding").context("but we just added that view!")?; let stream = sync_proxy.stream().await?; pin_mut!(stream); - let Some(room_summary ) = stream.next().await else { - anyhow::bail!("No room summary found, loop ended unsuccessfully"); - }; + let room_summary = + stream.next().await.context("No room summary found, loop ended unsuccessfully")?; let summary = room_summary?; // we only heard about the ones we had asked for assert_eq!(summary.rooms.len(), 11); @@ -387,9 +374,7 @@ mod tests { // Ensure 0-0 invalidation ranges work. for _n in 0..2 { - let Some(room_summary ) = stream.next().await else { - anyhow::bail!("sync has closed unexpectedly"); - }; + let room_summary = stream.next().await.context("sync has closed unexpectedly")?; let summary = room_summary?; // we only heard about the ones we had asked for if summary.views.iter().any(|s| s == "sliding") { @@ -432,9 +417,7 @@ mod tests { view.set_range(5, 10); for _n in 0..2 { - let Some(room_summary ) = stream.next().await else { - anyhow::bail!("sync has closed unexpectedly"); - }; + let room_summary = stream.next().await.context("sync has closed unexpectedly")?; let summary = room_summary?; // we only heard about the ones we had asked for if summary.views.iter().any(|s| s == "sliding") { @@ -479,9 +462,7 @@ mod tests { view.set_range(5, 15); for _n in 0..2 { - let Some(room_summary ) = stream.next().await else { - anyhow::bail!("sync has closed unexpectedly"); - }; + let room_summary = stream.next().await.context("sync has closed unexpectedly")?; let summary = room_summary?; // we only heard about the ones we had asked for if summary.views.iter().any(|s| s == "sliding") { @@ -533,14 +514,11 @@ mod tests { .name("sliding") .build()?; let sync_proxy = sync_proxy_builder.add_view(sliding_window_view).build().await?; - let Some(view )= sync_proxy.view("sliding") else { - anyhow::bail!("but we just added that view!"); - }; + let view = sync_proxy.view("sliding").context("but we just added that view!")?; let stream = sync_proxy.stream().await?; pin_mut!(stream); - let Some(room_summary ) = stream.next().await else { - anyhow::bail!("No room summary found, loop ended unsuccessfully"); - }; + let room_summary = + stream.next().await.context("No room summary found, loop ended unsuccessfully")?; let summary = room_summary?; // we only heard about the ones we had asked for assert_eq!(summary.rooms.len(), 10); @@ -583,9 +561,7 @@ mod tests { view.set_range(0, 10); for _n in 0..2 { - let Some(room_summary ) = stream.next().await else { - anyhow::bail!("sync has closed unexpectedly"); - }; + let room_summary = stream.next().await.context("sync has closed unexpectedly")?; let summary = room_summary?; // we only heard about the ones we had asked for if summary.views.iter().any(|s| s == "sliding") { @@ -630,9 +606,7 @@ mod tests { view.set_range(2, 12); for _n in 0..2 { - let Some(room_summary ) = stream.next().await else { - anyhow::bail!("sync has closed unexpectedly"); - }; + let room_summary = stream.next().await.context("sync has closed unexpectedly")?; let summary = room_summary?; // we only heard about the ones we had asked for if summary.views.iter().any(|s| s == "sliding") { @@ -678,23 +652,21 @@ mod tests { let Some(RoomListEntry::Filled(room_id)) = view .rooms_list .lock_ref() - .iter().nth(3).map(Clone::clone) else + .iter() + .nth(3) + .map(Clone::clone) else { - anyhow::bail!("2nd room has moved? how?"); + panic!("2nd room has moved? how?"); }; - let Some(room) = client.get_joined_room(&room_id) else { - anyhow::bail!("No joined room {room_id}"); - }; + let room = client.get_joined_room(&room_id).context("No joined room {room_id}")?; let content = RoomMessageEventContent::text_plain("Hello world"); room.send(content, None).await?; // this should put our room up to the most recent for _n in 0..2 { - let Some(room_summary ) = stream.next().await else { - anyhow::bail!("sync has closed unexpectedly"); - }; + let room_summary = stream.next().await.context("sync has closed unexpectedly")?; let summary = room_summary?; // we only heard about the ones we had asked for if summary.views.iter().any(|s| s == "sliding") { @@ -735,18 +707,14 @@ mod tests { ); // items has moved, thus we shouldn't find it where it was - assert!( - view.rooms_list.lock_ref().iter().nth(3).unwrap().as_room_id().unwrap() != &room_id - ); + assert!(view.rooms_list.lock_ref().iter().nth(3).unwrap().as_room_id().unwrap() != room_id); // let's move the window again view.set_range(0, 10); for _n in 0..2 { - let Some(room_summary ) = stream.next().await else { - anyhow::bail!("sync has closed unexpectedly"); - }; + let room_summary = stream.next().await.context("sync has closed unexpectedly")?; let summary = room_summary?; // we only heard about the ones we had asked for if summary.views.iter().any(|s| s == "sliding") { From 0e3ea58aa4873c06a29a3dcf4b56512a5cb1fbbf Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Fri, 13 Jan 2023 10:51:52 +0100 Subject: [PATCH 14/14] Revert unrelated change --- testing/matrix-sdk-integration-testing/src/helpers.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/matrix-sdk-integration-testing/src/helpers.rs b/testing/matrix-sdk-integration-testing/src/helpers.rs index bd16f2689..dd534e339 100644 --- a/testing/matrix-sdk-integration-testing/src/helpers.rs +++ b/testing/matrix-sdk-integration-testing/src/helpers.rs @@ -14,7 +14,7 @@ use tokio::sync::Mutex; static USERS: Lazy>> = Lazy::new(Mutex::default); #[ctor::ctor] -fn startup() { +fn init_logging() { use tracing::Level; use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; tracing_subscriber::registry()