test: add the start of an integration test for room history sharing

This is only a partial test, since we haven't yet implemented the receiver side
of the history-sharing messages.
This commit is contained in:
Richard van der Hoff committed 2025-04-15 12:55:55 +01:00
1 parent f11158ab6c
commit 9ef1a040dd
2 files changed
+140 -8

No files matched your search

@@ -16,6 +16,7 @@ use matrix_sdk::{
RoomId,
},
sliding_sync::VersionBuilder,
sync::SyncResponse,
Client, ClientBuilder, Room,
};
use once_cell::sync::Lazy;
@@ -185,7 +186,7 @@ impl SyncTokenAwareClient {
Self { client, token: Arc::new(None.into()) }
}
pub async fn sync_once(&self) -> Result<()> {
pub async fn sync_once(&self) -> Result<SyncResponse> {
let mut settings = SyncSettings::default().timeout(Duration::from_secs(1));
let token = { self.token.lock().unwrap().clone() };
@@ -197,9 +198,9 @@ impl SyncTokenAwareClient {
let mut prev_token = self.token.lock().unwrap();
if prev_token.as_ref() != Some(&response.next_batch) {
*prev_token = Some(response.next_batch);
*prev_token = Some(response.next_batch.clone());
}
Ok(())
Ok(response)
}
}
@@ -1,4 +1,5 @@
use std::{
future::IntoFuture,
sync::{Arc, Mutex},
time::Duration,
};
@@ -9,7 +10,7 @@ use assert_matches2::assert_let;
use assign::assign;
use matrix_sdk::{
assert_next_eq_with_timeout,
crypto::{format_emojis, SasState},
crypto::{format_emojis, SasState, UserDevices},
encryption::{
backups::BackupState,
recovery::{Recovery, RecoveryState},
@@ -19,7 +20,10 @@ use matrix_sdk::{
BackupDownloadStrategy, EncryptionSettings, LocalTrust,
},
ruma::{
api::client::room::create_room::v3::Request as CreateRoomRequest,
api::client::{
message::send_message_event,
room::create_room::v3::{Request as CreateRoomRequest, RoomPreset},
},
events::{
key::verification::{request::ToDeviceKeyVerificationRequestEvent, VerificationMethod},
room::message::{
@@ -27,9 +31,10 @@ use matrix_sdk::{
SyncRoomMessageEvent,
},
secret_storage::secret::SecretEventContent,
GlobalAccountDataEventType, OriginalSyncMessageLikeEvent,
GlobalAccountDataEventType, MessageLikeEventType, OriginalSyncMessageLikeEvent,
},
OwnedEventId,
serde::Raw,
OwnedEventId, TransactionId, UserId,
},
timeout::timeout,
Client,
@@ -39,7 +44,7 @@ use matrix_sdk_ui::{
sync_service::SyncService,
};
use similar_asserts::assert_eq;
use tracing::{debug, warn};
use tracing::{debug, info, warn, Instrument};
use crate::helpers::{SyncTokenAwareClient, TestClientBuilder};
@@ -1175,3 +1180,129 @@ async fn test_recovery_disabling_deletes_secret_storage_secrets() -> Result<()>
Ok(())
}
/// When we invite another user to a room with "joined" history visibility, we
/// share the encryption history.
#[tokio::test(flavor = "multi_thread", worker_threads = 4)]
async fn test_history_share_on_invite() -> Result<()> {
let alice_span = tracing::info_span!("alice");
let bob_span = tracing::info_span!("bob");
let encryption_settings =
EncryptionSettings { auto_enable_cross_signing: true, ..Default::default() };
let alice = TestClientBuilder::new("alice")
.use_sqlite()
.encryption_settings(encryption_settings)
.build()
.await?;
let sync_service_span = tracing::info_span!(parent: &alice_span, "sync_service");
let alice_sync_service = Arc::new(
SyncService::builder(alice.clone())
.with_parent_span(sync_service_span)
.build()
.await
.expect("Could not build alice sync service"),
);
alice.encryption().wait_for_e2ee_initialization_tasks().await;
alice_sync_service.start().await;
let bob = SyncTokenAwareClient::new(
TestClientBuilder::new("bob").encryption_settings(encryption_settings).build().await?,
);
{
// Alice and Bob share an encrypted room
// TODO: get rid of all of this: history sharing should work even if Bob and
// Alice do not share a room
let alice_shared_room = alice
.create_room(assign!(CreateRoomRequest::new(), {preset: Some(RoomPreset::PublicChat)}))
.await?;
let shared_room_id = alice_shared_room.room_id();
alice_shared_room.enable_encryption().await?;
bob.join_room_by_id(shared_room_id)
.instrument(bob_span.clone())
.await
.expect("Bob should have joined the room");
// Bob sends a message to trigger another sync from Alice, which causes her to
// send out the outgoing requests
//
// FIXME: this appears to be needed due to a bug in the sliding sync client,
// which means it does not send out outgoing requests caused by a
// /sync response
let request = send_message_event::v3::Request::new_raw(
shared_room_id.to_owned(),
TransactionId::new(),
MessageLikeEventType::Message,
Raw::new(&RoomMessageEventContent::text_plain("")).unwrap().cast(),
);
bob.send(request).into_future().instrument(bob_span.clone()).await?;
// Sanity check: Both users see the others' device
async fn devices_seen(client: &Client, other: &UserId) -> UserDevices {
client
.olm_machine_for_testing()
.await
.as_ref()
.unwrap()
.get_user_devices(other, Some(Duration::from_secs(1)))
.await
.unwrap()
}
timeout(
async {
loop {
let bob_devices = devices_seen(&alice, bob.user_id().unwrap()).await;
if bob_devices.devices().count() >= 1 {
return;
}
}
},
Duration::from_secs(30), // This can take quite a while to happen on the CI runners.
)
.await
.expect("Alice did not see bob's device");
bob.sync_once().instrument(bob_span.clone()).await?;
let alice_devices = devices_seen(&bob, alice.user_id().unwrap()).await;
assert_eq!(alice_devices.devices().count(), 1, "Bob did not see Alice's device");
}
// Alice creates a room ...
let alice_room = alice
.create_room(assign!(CreateRoomRequest::new(), {
preset: Some(RoomPreset::PublicChat),
}))
.await?;
alice_room.enable_encryption().await?;
info!(room_id = ?alice_room.room_id(), "Alice has created and enabled encryption in the room");
// ... and sends a message
alice_room
.send(RoomMessageEventContent::text_plain("Hello Bob"))
.await
.expect("We should be able to send a message to the room");
// Alice invites Bob to the room
// TODO: invite Bob rather than just call `share_history`
alice_room.share_history(bob.user_id().unwrap()).await?;
let bob_response = bob.sync_once().instrument(bob_span.clone()).await?;
// Bob should have received a to-device event with the payload
assert_eq!(bob_response.to_device.len(), 1);
let to_device_event = &bob_response.to_device[0];
assert_eq!(
to_device_event.get_field::<String>("type").unwrap().unwrap(),
"io.element.msc4268.room_key_bundle"
);
// TODO: ensure Bob can decrypt the content
Ok(())
}