feat(ui): Remove visible_rooms from RoomListService.

This patch removes the `visible_rooms` sliding sync list from
`RoomListService`. As we are taking the path of doing client-side
sorting, the ordering of the server-side will most likely always
mismatch the ordering of the client-side, thus using `visible_rooms`
with room indices make no sense (indices from server-side won't map
indices on the client-side, so room ranges from client-side won't map
what the server knows).

We used to use `visible_rooms` to “preload” the timeline of rooms in
the user app viewport, with a `timeline_limit` of 20. This should be
replaced by room subscriptions starting from now. For the moment, the
user of `RoomListService` is responsible to do that manually. Maybe
`RoomListService` will handle that automatically in the future.
This commit is contained in:
Ivan Enderlin
2024-06-20 21:16:24 +02:00
parent 1270cdad1a
commit 7aa7d1ca53
4 changed files with 29 additions and 526 deletions

View File

@@ -65,7 +65,6 @@ impl From<matrix_sdk_ui::room_list_service::Error> for RoomListError {
match value {
SlidingSync(error) => Self::SlidingSync { error: error.to_string() },
UnknownList(list_name) => Self::UnknownList { list_name },
InputCannotBeApplied(_) => Self::InputCannotBeApplied,
RoomNotFound(room_id) => Self::RoomNotFound { room_name: room_id.to_string() },
TimelineAlreadyExists(room_id) => {
Self::TimelineAlreadyExists { room_name: room_id.to_string() }

View File

@@ -23,32 +23,22 @@
//!
//! As such, the `RoomListService` works as an opinionated state machine. The
//! states are defined by [`State`]. Actions are attached to the each state
//! transition. Apart from that, one can apply [`Input`]s on the state machine,
//! like notifying that the client app viewport of the room list has changed (if
//! the user of the client app has scrolled in the room list for example) etc.
//! transition.
//!
//! The API is purposely small. Sliding Sync is versatile. `RoomListService` is
//! _one_ specific usage of Sliding Sync.
//!
//! # Basic principle
//!
//! `RoomListService` works with 2 Sliding Sync List:
//! `RoomListService` works with 1 Sliding Sync List:
//!
//! * `all_rooms` (referred by the constant [`ALL_ROOMS_LIST_NAME`]) is the main
//! * `all_rooms` (referred by the constant [`ALL_ROOMS_LIST_NAME`]) is the only
//! list. Its goal is to load all the user' rooms. It starts with a
//! [`SlidingSyncMode::Selective`] sync-mode with a small range (i.e. a small
//! set of rooms) to load the first rooms quickly, and then updates to a
//! [`SlidingSyncMode::Growing`] sync-mode to load the remaining rooms “in the
//! background”: it will sync the existing rooms and will fetch new rooms, by
//! a certain batch size.
//! * `visible_rooms` (referred by the constant [`VISIBLE_ROOMS_LIST_NAME`]) is
//! the “reactive” list. Its goal is to react to the client app user actions.
//! If the user scrolls in the room list, the `visible_rooms` will be
//! configured to sync for the particular range of rooms the user is actually
//! seeing (the rooms in the current viewport). `visible_rooms` has a
//! different configuration than `all_rooms` as it loads more timeline events:
//! it means that the room will already have a “history”, a timeline, ready to
//! be presented when the user enters the room.
//!
//! This behavior has proven to be empirically satisfying to provide a fast and
//! fluid user experience for a Matrix client.
@@ -67,9 +57,8 @@ mod room_list;
mod state;
use std::{
future::ready,
num::NonZeroUsize,
sync::{Arc, Mutex as StdMutex},
sync::{Arc, Mutex},
time::Duration,
};
@@ -77,8 +66,8 @@ use async_stream::stream;
use eyeball::{SharedObservable, Subscriber};
use futures_util::{pin_mut, Stream, StreamExt};
use matrix_sdk::{
event_cache::EventCacheError, sliding_sync::Ranges, Client, Error as SlidingSyncError,
SlidingSync, SlidingSyncList, SlidingSyncListBuilder, SlidingSyncMode,
event_cache::EventCacheError, Client, Error as SlidingSyncError, SlidingSync, SlidingSyncList,
SlidingSyncMode,
};
use matrix_sdk_base::ring_buffer::RingBuffer;
pub use room::*;
@@ -94,7 +83,7 @@ use ruma::{
};
pub use state::*;
use thiserror::Error;
use tokio::{sync::Mutex, time::timeout};
use tokio::time::timeout;
use crate::timeline;
@@ -113,13 +102,7 @@ pub struct RoomListService {
state: SharedObservable<State>,
/// Room cache, to avoid recreating `Room`s every time users fetch them.
rooms: Arc<StdMutex<RingBuffer<Room>>>,
/// The current viewport ranges.
///
/// This is useful to avoid resetting the ranges to the same value,
/// which would cancel the current in-flight sync request.
viewport_ranges: Mutex<Ranges>,
rooms: Arc<Mutex<RingBuffer<Room>>>,
}
impl RoomListService {
@@ -174,7 +157,7 @@ impl RoomListService {
}
let sliding_sync = builder
.add_cached_list(configure_all_or_visible_rooms_list(
.add_cached_list(
SlidingSyncList::builder(ALL_ROOMS_LIST_NAME)
.sync_mode(
SlidingSyncMode::new_selective()
@@ -187,8 +170,23 @@ impl RoomListService {
(StateEventType::RoomMember, "$ME".to_owned()),
(StateEventType::RoomName, "".to_owned()),
(StateEventType::RoomPowerLevels, "".to_owned()),
])
.sort(vec!["by_recency".to_owned(), "by_name".to_owned()])
.include_heroes(Some(true))
.filters(Some(assign!(SyncRequestListFilters::default(), {
// As defined in the [SlidingSync MSC](https://github.com/matrix-org/matrix-spec-proposals/blob/9450ced7fb9cf5ea9077d029b3adf36aebfa8709/proposals/3575-sync.md?plain=1#L444)
// If unset, both invited and joined rooms are returned. If false, no invited rooms are
// returned. If true, only invited rooms are returned.
is_invite: None,
is_tombstoned: Some(false),
not_room_types: vec!["m.space".to_owned()],
})))
.bump_event_types(&[
TimelineEventType::RoomMessage,
TimelineEventType::RoomEncrypted,
TimelineEventType::Sticker,
]),
))
)
.await
.map_err(Error::SlidingSync)?
.build()
@@ -203,8 +201,7 @@ impl RoomListService {
client,
sliding_sync,
state: SharedObservable::new(State::Init),
rooms: Arc::new(StdMutex::new(RingBuffer::new(Self::ROOM_OBJECT_CACHE_SIZE))),
viewport_ranges: Mutex::new(vec![VISIBLE_ROOMS_DEFAULT_RANGE]),
rooms: Arc::new(Mutex::new(RingBuffer::new(Self::ROOM_OBJECT_CACHE_SIZE))),
})
}
@@ -392,38 +389,6 @@ impl RoomListService {
self.list_for(ALL_ROOMS_LIST_NAME).await
}
/// Pass an [`Input`] onto the state machine.
pub async fn apply_input(&self, input: Input) -> Result<InputResult, Error> {
use Input::*;
match input {
Viewport(ranges) => self.update_viewport(ranges).await,
}
}
async fn update_viewport(&self, ranges: Ranges) -> Result<InputResult, Error> {
let mut viewport_ranges = self.viewport_ranges.lock().await;
// Is it worth updating the viewport?
// The viewport has the same ranges. Don't update it.
if *viewport_ranges == ranges {
return Ok(InputResult::Ignored);
}
self.sliding_sync
.on_list(VISIBLE_ROOMS_LIST_NAME, |list| {
list.set_sync_mode(SlidingSyncMode::new_selective().add_ranges(ranges.clone()));
ready(())
})
.await
.ok_or_else(|| Error::InputCannotBeApplied(Input::Viewport(ranges.clone())))?;
*viewport_ranges = ranges;
Ok(InputResult::Applied)
}
/// Get a [`Room`] if it exists.
pub fn room(&self, room_id: &RoomId) -> Result<Room, Error> {
let mut rooms = self.rooms.lock().unwrap();
@@ -449,32 +414,6 @@ impl RoomListService {
}
}
/// Configure the Sliding Sync list for `ALL_ROOMS_LIST_NAME` and
/// `VISIBLE_ROOMS_LIST_NAME`.
///
/// This function configures the `sort`, the `filters` and the`bump_event_types`
/// properties, so that they are exactly the same.
fn configure_all_or_visible_rooms_list(
list_builder: SlidingSyncListBuilder,
) -> SlidingSyncListBuilder {
list_builder
.sort(vec!["by_recency".to_owned(), "by_name".to_owned()])
.include_heroes(Some(true))
.filters(Some(assign!(SyncRequestListFilters::default(), {
// As defined in the [SlidingSync MSC](https://github.com/matrix-org/matrix-spec-proposals/blob/9450ced7fb9cf5ea9077d029b3adf36aebfa8709/proposals/3575-sync.md?plain=1#L444)
// If unset, both invited and joined rooms are returned. If false, no invited rooms are
// returned. If true, only invited rooms are returned.
is_invite: None,
is_tombstoned: Some(false),
not_room_types: vec!["m.space".to_owned()],
})))
.bump_event_types(&[
TimelineEventType::RoomMessage,
TimelineEventType::RoomEncrypted,
TimelineEventType::Sticker,
])
}
/// [`RoomList`]'s errors.
#[derive(Debug, Error)]
pub enum Error {
@@ -486,10 +425,6 @@ pub enum Error {
#[error("Unknown list `{0}`")]
UnknownList(String),
/// An input was asked to be applied but it wasn't possible to apply it.
#[error("The input cannot be applied: {0:?}")]
InputCannotBeApplied(Input),
/// The requested room doesn't exist.
#[error("Room `{0}` not found")]
RoomNotFound(OwnedRoomId),
@@ -504,32 +439,6 @@ pub enum Error {
EventCache(#[from] EventCacheError),
}
/// An input for the [`RoomList`]' state machine.
///
/// An input is something that has happened or is happening or is requested by
/// the client app using this [`RoomList`].
#[derive(Debug)]
pub enum Input {
/// The client app's viewport of the room list has changed.
///
/// Use this input when the user of the client app is scrolling inside the
/// room list, and the viewport has changed. The viewport is defined as the
/// range of visible rooms in the room list.
Viewport(Ranges),
}
/// An [`Input`] Ok result: whether it's been applied, or ignored.
#[derive(Debug, Eq, PartialEq)]
pub enum InputResult {
/// The input has been applied.
Applied,
/// The input has been ignored.
///
/// Note that this is not an error. The input was valid, but simply ignored.
Ignored,
}
/// An hint whether a _sync spinner/loader/toaster_ should be prompted to the
/// user, indicating that the [`RoomListService`] is syncing.
///

View File

@@ -17,17 +17,12 @@
use std::future::ready;
use async_trait::async_trait;
use matrix_sdk::{
sliding_sync::{Bound, Range},
SlidingSync, SlidingSyncList, SlidingSyncMode,
};
use matrix_sdk::{sliding_sync::Range, SlidingSync, SlidingSyncMode};
use once_cell::sync::Lazy;
use ruma::events::StateEventType;
use super::Error;
pub const ALL_ROOMS_LIST_NAME: &str = "all_rooms";
pub const VISIBLE_ROOMS_LIST_NAME: &str = "visible_rooms";
/// The state of the [`super::RoomList`]' state machine.
#[derive(Clone, Debug, PartialEq)]
@@ -43,7 +38,7 @@ pub enum State {
/// are then slightly different.
Recovering,
/// At this state, all rooms are syncing, and the visible rooms list exist.
/// At this state, all rooms are syncing.
Running,
/// At this state, the sync has been stopped because an error happened.
@@ -96,72 +91,6 @@ trait Action {
async fn run(&self, sliding_sync: &SlidingSync) -> Result<(), Error>;
}
struct AddVisibleRooms;
/// Default timeline for the `VISIBLE_ROOMS_LIST_NAME` list.
pub const VISIBLE_ROOMS_DEFAULT_TIMELINE_LIMIT: Bound = 20;
/// Default range for the `VISIBLE_ROOMS_LIST_NAME` list.
pub const VISIBLE_ROOMS_DEFAULT_RANGE: Range = 0..=19;
#[async_trait]
impl Action for AddVisibleRooms {
async fn run(&self, sliding_sync: &SlidingSync) -> Result<(), Error> {
sliding_sync
.add_list(super::configure_all_or_visible_rooms_list(
SlidingSyncList::builder(VISIBLE_ROOMS_LIST_NAME)
.sync_mode(
SlidingSyncMode::new_selective().add_range(VISIBLE_ROOMS_DEFAULT_RANGE),
)
.timeline_limit(VISIBLE_ROOMS_DEFAULT_TIMELINE_LIMIT)
.required_state(vec![
(StateEventType::RoomEncryption, "".to_owned()),
(StateEventType::RoomMember, "$LAZY".to_owned()),
]),
))
.await
.map_err(Error::SlidingSync)?;
Ok(())
}
}
struct SetVisibleRoomsToZeroTimelineLimit;
#[async_trait]
impl Action for SetVisibleRoomsToZeroTimelineLimit {
async fn run(&self, sliding_sync: &SlidingSync) -> Result<(), Error> {
sliding_sync
.on_list(VISIBLE_ROOMS_LIST_NAME, |list| {
list.set_timeline_limit(Some(0));
ready(())
})
.await
.ok_or_else(|| Error::UnknownList(VISIBLE_ROOMS_LIST_NAME.to_owned()))?;
Ok(())
}
}
struct SetVisibleRoomsToDefaultTimelineLimit;
#[async_trait]
impl Action for SetVisibleRoomsToDefaultTimelineLimit {
async fn run(&self, sliding_sync: &SlidingSync) -> Result<(), Error> {
sliding_sync
.on_list(VISIBLE_ROOMS_LIST_NAME, |list| {
list.set_timeline_limit(Some(VISIBLE_ROOMS_DEFAULT_TIMELINE_LIMIT));
ready(())
})
.await
.ok_or_else(|| Error::UnknownList(VISIBLE_ROOMS_LIST_NAME.to_owned()))?;
Ok(())
}
}
struct SetAllRoomsToSelectiveSyncMode;
/// Default `batch_size` for the selective sync-mode of the
@@ -251,15 +180,12 @@ impl Actions {
none => [],
prepare_for_next_syncs_once_first_rooms_are_loaded => [
SetAllRoomsToGrowingSyncMode,
AddVisibleRooms
],
prepare_for_next_syncs_once_recovered => [
SetAllRoomsToGrowingSyncMode,
SetVisibleRoomsToDefaultTimelineLimit
],
prepare_to_recover => [
SetAllRoomsToSelectiveSyncMode,
SetVisibleRoomsToZeroTimelineLimit
],
}
@@ -372,80 +298,6 @@ mod tests {
Ok(())
}
#[async_test]
async fn test_action_add_visible_rooms_list() -> Result<(), Error> {
let room_list = new_room_list().await?;
let sliding_sync = room_list.sliding_sync();
// List is absent.
assert_eq!(sliding_sync.on_list(VISIBLE_ROOMS_LIST_NAME, |_list| ready(())).await, None);
// Run the action!
AddVisibleRooms.run(sliding_sync).await?;
// List is present.
assert_eq!(
sliding_sync
.on_list(VISIBLE_ROOMS_LIST_NAME, |list| ready(matches!(
list.sync_mode(),
SlidingSyncMode::Selective { ranges } if ranges == vec![VISIBLE_ROOMS_DEFAULT_RANGE]
)))
.await,
Some(true)
);
Ok(())
}
#[async_test]
async fn test_action_set_visible_rooms_list_to_zero_or_default_timeline_limit(
) -> Result<(), Error> {
let room_list = new_room_list().await?;
let sliding_sync = room_list.sliding_sync();
// List is absent.
assert_eq!(sliding_sync.on_list(VISIBLE_ROOMS_LIST_NAME, |_list| ready(())).await, None);
// Run the action!
AddVisibleRooms.run(sliding_sync).await?;
// List is present, and has the default `timeline_limit`.
assert_eq!(
sliding_sync
.on_list(VISIBLE_ROOMS_LIST_NAME, |list| ready(
list.timeline_limit() == Some(VISIBLE_ROOMS_DEFAULT_TIMELINE_LIMIT)
))
.await,
Some(true)
);
// Run the action!
SetVisibleRoomsToZeroTimelineLimit.run(sliding_sync).await?;
// List is present, and has a zero `timeline_limit`.
assert_eq!(
sliding_sync
.on_list(VISIBLE_ROOMS_LIST_NAME, |list| ready(list.timeline_limit() == Some(0)))
.await,
Some(true)
);
// Run the action!
SetVisibleRoomsToDefaultTimelineLimit.run(sliding_sync).await?;
// List is present, and has the default `timeline_limit`.
assert_eq!(
sliding_sync
.on_list(VISIBLE_ROOMS_LIST_NAME, |list| ready(
list.timeline_limit() == Some(VISIBLE_ROOMS_DEFAULT_TIMELINE_LIMIT)
))
.await,
Some(true)
);
Ok(())
}
#[async_test]
async fn test_action_set_all_rooms_list_to_growing_and_selective_sync_mode() -> Result<(), Error>
{

View File

@@ -12,8 +12,7 @@ use matrix_sdk_test::async_test;
use matrix_sdk_ui::{
room_list_service::{
filters::{new_filter_fuzzy_match_room_name, new_filter_non_left, new_filter_none},
Error, Input, InputResult, RoomListLoadingState, State, SyncIndicator,
ALL_ROOMS_LIST_NAME as ALL_ROOMS, VISIBLE_ROOMS_LIST_NAME as VISIBLE_ROOMS,
Error, RoomListLoadingState, State, SyncIndicator, ALL_ROOMS_LIST_NAME as ALL_ROOMS,
},
timeline::{TimelineItemKind, VirtualTimelineItem},
RoomListService,
@@ -344,25 +343,6 @@ async fn test_sync_all_states() -> Result<(), Error> {
ALL_ROOMS: {
"ranges": [[0, 99]],
},
VISIBLE_ROOMS: {
"ranges": [[0, 19]],
"required_state": [
["m.room.encryption", ""],
["m.room.member", "$LAZY"],
],
"include_heroes": true,
"filters": {
"is_tombstoned": false,
"not_room_types": ["m.space"],
},
"bump_event_types": [
"m.room.message",
"m.room.encrypted",
"m.sticker",
],
"sort": ["by_recency", "by_name"],
"timeline_limit": 20,
},
},
},
respond with = {
@@ -371,9 +351,6 @@ async fn test_sync_all_states() -> Result<(), Error> {
ALL_ROOMS: {
"count": 420,
},
VISIBLE_ROOMS: {
"count": 0,
},
},
"rooms": {
// let's ignore them for now
@@ -390,9 +367,6 @@ async fn test_sync_all_states() -> Result<(), Error> {
ALL_ROOMS: {
"ranges": [[0, 199]],
},
VISIBLE_ROOMS: {
"ranges": [[0, 19]],
},
},
},
respond with = {
@@ -401,9 +375,6 @@ async fn test_sync_all_states() -> Result<(), Error> {
ALL_ROOMS: {
"count": 420,
},
VISIBLE_ROOMS: {
"count": 0,
},
},
"rooms": {
// let's ignore them for now
@@ -420,9 +391,6 @@ async fn test_sync_all_states() -> Result<(), Error> {
ALL_ROOMS: {
"ranges": [[0, 299]],
},
VISIBLE_ROOMS: {
"ranges": [[0, 19]],
},
},
},
respond with = {
@@ -431,9 +399,6 @@ async fn test_sync_all_states() -> Result<(), Error> {
ALL_ROOMS: {
"count": 420,
},
VISIBLE_ROOMS: {
"count": 0,
},
},
"rooms": {
// let's ignore them for now
@@ -450,9 +415,6 @@ async fn test_sync_all_states() -> Result<(), Error> {
ALL_ROOMS: {
"ranges": [[0, 399]],
},
VISIBLE_ROOMS: {
"ranges": [[0, 19]],
},
},
},
respond with = {
@@ -461,9 +423,6 @@ async fn test_sync_all_states() -> Result<(), Error> {
ALL_ROOMS: {
"count": 420,
},
VISIBLE_ROOMS: {
"count": 0,
},
},
"rooms": {
// let's ignore them for now
@@ -518,9 +477,6 @@ async fn test_sync_resumes_from_previous_state() -> Result<(), Error> {
ALL_ROOMS: {
"ranges": [[0, 9]],
},
VISIBLE_ROOMS: {
"ranges": [[0, 19]],
},
},
},
respond with = {
@@ -529,9 +485,6 @@ async fn test_sync_resumes_from_previous_state() -> Result<(), Error> {
ALL_ROOMS: {
"count": 10,
},
VISIBLE_ROOMS: {
"count": 0,
},
},
"rooms": {},
},
@@ -551,9 +504,6 @@ async fn test_sync_resumes_from_previous_state() -> Result<(), Error> {
ALL_ROOMS: {
"ranges": [[0, 9]],
},
VISIBLE_ROOMS: {
"ranges": [[0, 19]],
},
},
},
respond with = {
@@ -562,9 +512,6 @@ async fn test_sync_resumes_from_previous_state() -> Result<(), Error> {
ALL_ROOMS: {
"count": 10,
},
VISIBLE_ROOMS: {
"count": 0,
},
},
"rooms": {},
},
@@ -638,11 +585,6 @@ async fn test_sync_resumes_from_error() -> Result<(), Error> {
// The sync-mode has changed to growing, with its initial range.
"ranges": [[0, 99]],
},
VISIBLE_ROOMS: {
// Hello new list.
"ranges": [[0, 19]],
"timeline_limit": 20,
},
},
},
respond with = (code 400) {
@@ -658,9 +600,6 @@ async fn test_sync_resumes_from_error() -> Result<(), Error> {
let sync = room_list.sync();
pin_mut!(sync);
// Update the viewport, just to be sure it's not reset later.
assert_eq!(room_list.apply_input(Input::Viewport(vec![5..=10])).await?, InputResult::Applied);
sync_then_assert_request_and_fake_response! {
[server, room_list, sync]
states = Error { .. } => Recovering,
@@ -670,12 +609,6 @@ async fn test_sync_resumes_from_error() -> Result<(), Error> {
// Due to previous error, the sync-mode is back to selective, with its initial range.
"ranges": [[0, 19]],
},
VISIBLE_ROOMS: {
// We have set a viewport, which reflects here.
"ranges": [[5, 10]],
// The `timeline_limit` has been set to zero.
"timeline_limit": 0,
},
},
},
respond with = {
@@ -698,12 +631,6 @@ async fn test_sync_resumes_from_error() -> Result<(), Error> {
// Sync-mode is now growing.
"ranges": [[0, 99]],
},
VISIBLE_ROOMS: {
// Viewport hasn't changed.
"ranges": [[5, 10]],
// The `timeline_limit` has been restored.
"timeline_limit": 20,
},
},
},
respond with = {
@@ -727,11 +654,6 @@ async fn test_sync_resumes_from_error() -> Result<(), Error> {
// The sync-mode is still growing, and the range has made progress.
"ranges": [[0, 199]],
},
VISIBLE_ROOMS: {
// The range is kept.
"ranges": [[5, 10]],
// `timeline_limit` is a sticky parameter, so it's absent now.
},
},
},
respond with = (code 400) {
@@ -756,12 +678,6 @@ async fn test_sync_resumes_from_error() -> Result<(), Error> {
// Due to previous error, the sync-mode is back to selective, with its initial range.
"ranges": [[0, 19]],
},
VISIBLE_ROOMS: {
// We have set a viewport, which reflects here.
"ranges": [[5, 10]],
// The `timeline_limit` has been set to 0.
"timeline_limit": 0,
},
},
},
respond with = {
@@ -784,12 +700,6 @@ async fn test_sync_resumes_from_error() -> Result<(), Error> {
// The sync-mode is now growing.
"ranges": [[0, 99]],
},
VISIBLE_ROOMS: {
// Viewport hasn't changed.
"ranges": [[5, 10]],
// The `timeline_limit` has been restored.
"timeline_limit": 20,
},
},
},
respond with = {
@@ -812,11 +722,6 @@ async fn test_sync_resumes_from_error() -> Result<(), Error> {
// No error. The range is making progress.
"ranges": [[0, 199]],
},
VISIBLE_ROOMS: {
// No error. The range is still here.
"ranges": [[5, 10]],
// `timeline_limit` is a sticky parameter, so it's absent now.
},
},
},
respond with = {
@@ -841,11 +746,6 @@ async fn test_sync_resumes_from_error() -> Result<(), Error> {
// number of rooms.
"ranges": [[0, 209]],
},
VISIBLE_ROOMS: {
// The range is still here.
"ranges": [[5, 10]],
// `timeline_limit` is a sticky parameter, so it's absent now.
},
},
},
respond with = (code 400) {
@@ -870,12 +770,6 @@ async fn test_sync_resumes_from_error() -> Result<(), Error> {
// Due to previous error, the sync-mode is back to selective, with its initial range.
"ranges": [[0, 19]],
},
VISIBLE_ROOMS: {
// We have set a viewport, which reflects here.
"ranges": [[5, 10]],
// The `timeline_limit` has been set to 0.
"timeline_limit": 0,
},
},
},
respond with = {
@@ -898,12 +792,6 @@ async fn test_sync_resumes_from_error() -> Result<(), Error> {
// Sync-mode is now growing.
"ranges": [[0, 99]],
},
VISIBLE_ROOMS: {
// Viewport hasn't changed.
"ranges": [[5, 10]],
// The `timeline_limit` has been restored.
"timeline_limit": 20,
},
},
},
respond with = {
@@ -972,12 +860,6 @@ async fn test_sync_resumes_from_terminated() -> Result<(), Error> {
// The sync-mode is still selective, with its initial range.
"ranges": [[0, 19]],
},
VISIBLE_ROOMS: {
// Hello new list.
"ranges": [[0, 19]],
// `timeline_limit` has been set to zero.
"timeline_limit": 0,
},
},
},
respond with = {
@@ -1001,11 +883,6 @@ async fn test_sync_resumes_from_terminated() -> Result<(), Error> {
// The sync-mode is now growing, with its initial range.
"ranges": [[0, 99]],
},
VISIBLE_ROOMS: {
"ranges": [[0, 19]],
// `timeline_limit` has been restored.
"timeline_limit": 20,
},
},
},
respond with = {
@@ -1027,9 +904,6 @@ async fn test_sync_resumes_from_terminated() -> Result<(), Error> {
let sync = room_list.sync();
pin_mut!(sync);
// Update the viewport, just to be sure it's not reset later.
assert_eq!(room_list.apply_input(Input::Viewport(vec![5..=10])).await?, InputResult::Applied);
// Do a regular sync from the `Terminated` state.
sync_then_assert_request_and_fake_response! {
[server, room_list, sync]
@@ -1040,12 +914,6 @@ async fn test_sync_resumes_from_terminated() -> Result<(), Error> {
// The sync-mode is back to selective.
"ranges": [[0, 19]],
},
VISIBLE_ROOMS: {
// We have set a viewport, which reflects here.
"ranges": [[5, 10]],
// `timeline_limit` has been set to zero.
"timeline_limit": 0,
},
},
},
respond with = {
@@ -1069,12 +937,6 @@ async fn test_sync_resumes_from_terminated() -> Result<(), Error> {
// Sync-mode is growing, with its initial range.
"ranges": [[0, 99]],
},
VISIBLE_ROOMS: {
// We have set a viewport, which reflects here.
"ranges": [[5, 10]],
// `timeline_limit` has been restored.
"timeline_limit": 20,
},
},
},
respond with = {
@@ -1098,11 +960,6 @@ async fn test_sync_resumes_from_terminated() -> Result<(), Error> {
// Range is making progress, and has reached its maximum.
"ranges": [[0, 149]],
},
VISIBLE_ROOMS: {
// We have set a viewport, which reflects here.
"ranges": [[5, 10]],
// `timeline_limit` is a sticky parameter, so it's absent now.
},
},
},
respond with = {
@@ -1339,9 +1196,6 @@ async fn test_entries_stream() -> Result<(), Error> {
ALL_ROOMS: {
"ranges": [[0, 9]],
},
VISIBLE_ROOMS: {
"ranges": [[0, 19]],
},
},
},
respond with = {
@@ -1350,9 +1204,6 @@ async fn test_entries_stream() -> Result<(), Error> {
ALL_ROOMS: {
"count": 9,
},
VISIBLE_ROOMS: {
"count": 0,
},
},
"rooms": {
"!r3:bar.org": {
@@ -1447,9 +1298,6 @@ async fn test_dynamic_entries_stream() -> Result<(), Error> {
ALL_ROOMS: {
"ranges": [[0, 9]],
},
VISIBLE_ROOMS: {
"ranges": [[0, 19]],
},
},
},
respond with = {
@@ -1458,9 +1306,6 @@ async fn test_dynamic_entries_stream() -> Result<(), Error> {
ALL_ROOMS: {
"count": 10,
},
VISIBLE_ROOMS: {
"count": 0,
},
},
"rooms": {
"!r1:bar.org": {
@@ -1548,9 +1393,6 @@ async fn test_dynamic_entries_stream() -> Result<(), Error> {
ALL_ROOMS: {
"ranges": [[0, 9]],
},
VISIBLE_ROOMS: {
"ranges": [[0, 19]],
},
},
},
respond with = {
@@ -1559,9 +1401,6 @@ async fn test_dynamic_entries_stream() -> Result<(), Error> {
ALL_ROOMS: {
"count": 10,
},
VISIBLE_ROOMS: {
"count": 0,
},
},
"rooms": {
"!r5:bar.org": {
@@ -1800,9 +1639,6 @@ async fn test_dynamic_entries_stream_manual_update() -> Result<(), Error> {
ALL_ROOMS: {
"ranges": [[0, 9]],
},
VISIBLE_ROOMS: {
"ranges": [[0, 19]],
},
},
},
respond with = {
@@ -1811,9 +1647,6 @@ async fn test_dynamic_entries_stream_manual_update() -> Result<(), Error> {
ALL_ROOMS: {
"count": 10,
},
VISIBLE_ROOMS: {
"count": 0,
},
},
"rooms": {
"!r1:bar.org": {
@@ -2346,96 +2179,6 @@ async fn test_room_latest_event() -> Result<(), Error> {
Ok(())
}
/*
#[async_test]
async fn test_input_viewport() -> Result<(), Error> {
let (_, server, room_list) = new_room_list_service().await?;
let sync = room_list.sync();
pin_mut!(sync);
// The input cannot be applied because the `VISIBLE_ROOMS_LIST_NAME` list isn't
// present.
assert_matches!(
room_list.apply_input(Input::Viewport(vec![10..=15])).await,
Err(Error::InputCannotBeApplied(_))
);
sync_then_assert_request_and_fake_response! {
[server, room_list, sync]
states = Init => SettingUp,
assert request >= {
"lists": {
ALL_ROOMS: {
"ranges": [[0, 19]],
},
},
},
respond with = {
"pos": "0",
"lists": {},
"rooms": {},
},
};
sync_then_assert_request_and_fake_response! {
[server, room_list, sync]
states = SettingUp => Running,
assert request >= {
"lists": {
ALL_ROOMS: {
"ranges": [[0, 99]],
},
VISIBLE_ROOMS: {
"ranges": [[0, 19]],
"timeline_limit": 20,
},
},
},
respond with = {
"pos": "1",
"lists": {},
"rooms": {},
},
};
// Now we can change the viewport..
assert_eq!(
room_list.apply_input(Input::Viewport(vec![10..=15, 20..=25])).await?,
InputResult::Applied
);
// Re-changing the viewport has no effect.
assert_eq!(
room_list.apply_input(Input::Viewport(vec![10..=15, 20..=25])).await?,
InputResult::Ignored
);
// The `timeline_limit` is not repeated because it's sticky.
sync_then_assert_request_and_fake_response! {
[server, room_list, sync]
states = Running => Running,
assert request >= {
"lists": {
ALL_ROOMS: {
"ranges": [[0, 99]],
},
VISIBLE_ROOMS: {
"ranges": [[10, 15], [20, 25]],
},
},
},
respond with = {
"pos": "2",
"lists": {},
"rooms": {},
},
};
Ok(())
}
*/
// #[ignore = "Flaky"]
#[async_test]
async fn test_sync_indicator() -> Result<(), Error> {