Skip to content

Commit

Permalink
Use room.mark_members_missing() instead, add integration test
Browse files Browse the repository at this point in the history
  • Loading branch information
jmartinesp committed Jul 10, 2024
1 parent e7c4add commit 9ba8ba5
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 15 deletions.
22 changes: 8 additions & 14 deletions crates/matrix-sdk/src/room/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1229,13 +1229,10 @@ impl Room {
let request = invite_user::v3::Request::new(self.room_id().to_owned(), recipient);
self.client.send(request, None).await?;

// Force room members reload to prevent UTDs that could happen when a message is
// sent assuming the just invited user is still not invited (/sync
// didn't catch up on time). Ideally we'd just request the single
// member or only invited ones, but there's no current way to do it.
if let Some(room) = self.client.get_room(self.room_id()) {
room.request_members().await?;
}
// Force a future room members reload before sending any event to prevent UTDs
// that can happen when some event is sent after a room member has been invited
// but before the /sync request could fetch the membership change event.
self.mark_members_missing();

Ok(())
}
Expand All @@ -1251,13 +1248,10 @@ impl Room {
let request = invite_user::v3::Request::new(self.room_id().to_owned(), recipient);
self.client.send(request, None).await?;

// Force room members reload to prevent UTDs that could happen when a message is
// sent assuming the just invited user is still not invited (/sync
// didn't catch up on time). Ideally we'd just request the single
// member or only invited ones, but there's no current way to do it.
if let Some(room) = self.client.get_room(self.room_id()) {
room.request_members().await?;
}
// Force a future room members reload before sending any event to prevent UTDs
// that can happen when some event is sent after a room member has been invited
// but before the /sync request could fetch the membership change event.
self.mark_members_missing();

Ok(())
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ use matrix_sdk::{
Client, RoomInfo, RoomListEntry, RoomMemberships, RoomState, SlidingSyncList, SlidingSyncMode,
};
use matrix_sdk_ui::{
room_list_service::filters::new_filter_all, sync_service::SyncService, RoomListService,
room_list_service::filters::new_filter_all, sync_service::SyncService, timeline::RoomExt,
RoomListService,
};
use once_cell::sync::Lazy;
use rand::Rng as _;
Expand Down Expand Up @@ -853,6 +854,97 @@ async fn test_delayed_decryption_latest_event() -> Result<()> {
Ok(())
}

#[tokio::test]
async fn test_delayed_invite_response_and_sent_message_decryption() -> Result<()> {
let alice = TestClientBuilder::new("alice").use_sqlite().build().await?;
let bob = TestClientBuilder::new("bob").use_sqlite().build().await?;

let alice_sync_service = SyncService::builder(alice.clone()).build().await.unwrap();
alice_sync_service.start().await;

let bob_sync_service = SyncService::builder(bob.clone()).build().await.unwrap();
bob_sync_service.start().await;

// alice creates a room and invites bob.
let alice_room = alice
.create_room(assign!(CreateRoomRequest::new(), {
invite: vec![],
is_direct: true,
preset: Some(RoomPreset::PrivateChat),
}))
.await?;
alice_room.enable_encryption().await?;

// Initial message to make sure any lazy /members call is performed before the
// test actually starts
alice_room
.send(RoomMessageEventContent::text_plain("dummy message to make members call"))
.await?;

// Set up sliding sync for bob.
let sliding_bob = bob
.sliding_sync("main")?
.with_all_extensions()
.poll_timeout(Duration::from_secs(2))
.network_timeout(Duration::from_secs(2))
.add_list(
SlidingSyncList::builder("all")
.sync_mode(SlidingSyncMode::new_selective().add_range(0..=20)),
)
.build()
.await?;

let s = sliding_bob.clone();
spawn(async move {
let stream = s.sync();
pin_mut!(stream);
while let Some(up) = stream.next().await {
warn!("bob received update: {up:?}");
}
});

// Send the invite to Bob and a message to reproduce the edge case
alice_room.invite_user_by_id(bob.user_id().unwrap()).await.unwrap();
alice_room.send(RoomMessageEventContent::text_plain("hello world")).await?;

// Join the room from Bob's client
let bob_room = bob.get_room(alice_room.room_id()).unwrap();
bob_room.join().await?;

assert_eq!(alice_room.state(), RoomState::Joined);
assert!(alice_room.is_encrypted().await.unwrap());
assert_eq!(bob_room.state(), RoomState::Joined);
assert!(bob_room.is_encrypted().await.unwrap());

let bob_timeline = bob_room.timeline_builder().build().await?;
let (_, timeline_stream) = bob_timeline.subscribe().await;
pin_mut!(timeline_stream);

// Get previous events, including the sent message
bob_timeline.paginate_backwards(3).await?;

// Look for the sent message, which should not be an UTD event
loop {
let diff = timeout(Duration::from_millis(100), timeline_stream.next())
.await
.expect("Timed out. Neither an UTD or the sent message were found")
.unwrap();
if let VectorDiff::PushFront { value } = diff {
if let Some(event) = value.as_event() {
if let Some(message) = event.content().as_message() {
if message.body() == "hello world" {
return Ok(());
} else {
panic!("Unexpected message event found");
}
} else if event.content().as_unable_to_decrypt().is_some() {
panic!("UTD found!")
}
}
}
}
}

#[tokio::test]
async fn test_room_info_notable_update_deduplication() -> Result<()> {
let alice = TestClientBuilder::new("alice").use_sqlite().build().await?;
Expand Down

0 comments on commit 9ba8ba5

Please sign in to comment.