mirror of
https://github.com/matrix-org/matrix-rust-sdk.git
synced 2026-02-14 17:44:12 -05:00
test: Add test for repeated joining and leaving
This commit is contained in:
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -2464,10 +2464,12 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"assign",
|
||||
"ctor",
|
||||
"matrix-sdk",
|
||||
"once_cell",
|
||||
"tempfile",
|
||||
"tokio",
|
||||
"tracing-subscriber",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@@ -8,7 +8,9 @@ publish = false
|
||||
[dev-dependencies]
|
||||
anyhow = "1"
|
||||
assign = "1"
|
||||
ctor = "0.1.23"
|
||||
matrix-sdk = { path = "../../crates/matrix-sdk" }
|
||||
once_cell = "1.13.0"
|
||||
tempfile = "3.3.0"
|
||||
tokio = { version = "1", features = ["rt", "rt-multi-thread", "macros"] }
|
||||
tracing-subscriber = "0.3.15"
|
||||
|
||||
@@ -8,6 +8,8 @@ echo " ====== Patching for CI ====== "
|
||||
sed -i 's/^#enable_registration_without_verification:.*$/enable_registration_without_verification: true/g' /data/homeserver.yaml
|
||||
sed -i 's/^#enable_registration:.*$/enable_registration: true/g' /data/homeserver.yaml
|
||||
echo """
|
||||
enable_registration: true
|
||||
enable_registration_without_verification: true
|
||||
|
||||
rc_message:
|
||||
per_second: 1000
|
||||
@@ -16,6 +18,22 @@ rc_message:
|
||||
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:
|
||||
|
||||
@@ -3,8 +3,8 @@ use std::{collections::HashMap, option_env};
|
||||
use anyhow::Result;
|
||||
use assign::assign;
|
||||
use matrix_sdk::{
|
||||
config::RequestConfig,
|
||||
ruma::api::client::{account::register::v3::Request as RegistrationRequest, uiaa},
|
||||
store::make_store_config,
|
||||
Client,
|
||||
};
|
||||
use once_cell::sync::Lazy;
|
||||
@@ -13,6 +13,11 @@ use tokio::sync::Mutex;
|
||||
|
||||
static USERS: Lazy<Mutex<HashMap<String, (Client, TempDir)>>> = Lazy::new(Mutex::default);
|
||||
|
||||
#[ctor::ctor]
|
||||
fn init_logging() {
|
||||
tracing_subscriber::FmtSubscriber::builder().with_test_writer().init();
|
||||
}
|
||||
|
||||
/// read the test configuration from the environment
|
||||
pub fn test_server_conf() -> (String, String) {
|
||||
(
|
||||
@@ -21,7 +26,14 @@ pub fn test_server_conf() -> (String, String) {
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn get_client_for_user(username: String) -> Result<Client> {
|
||||
/// The StateStore to use.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Store {
|
||||
Memory,
|
||||
Sled,
|
||||
}
|
||||
|
||||
pub async fn get_client_for_user(store: Store, username: String) -> Result<Client> {
|
||||
let mut users = USERS.lock().await;
|
||||
if let Some((client, _)) = users.get(&username) {
|
||||
return Ok(client.clone());
|
||||
@@ -31,12 +43,15 @@ pub async fn get_client_for_user(username: String) -> Result<Client> {
|
||||
|
||||
let tmp_dir = tempdir()?;
|
||||
|
||||
let client = Client::builder()
|
||||
let mut builder = Client::builder()
|
||||
.user_agent("matrix-sdk-integation-tests")
|
||||
.store_config(make_store_config(tmp_dir.path(), None)?)
|
||||
.homeserver_url(homeserver_url)
|
||||
.build()
|
||||
.await?;
|
||||
.request_config(RequestConfig::new().disable_retry());
|
||||
builder = match store {
|
||||
Store::Memory => builder,
|
||||
Store::Sled => builder.sled_store(tmp_dir.path(), None)?,
|
||||
};
|
||||
let client = builder.build().await?;
|
||||
// safe to assume we have not registered this user yet, but ignore if we did
|
||||
|
||||
if let Err(resp) = client.register(RegistrationRequest::new()).await {
|
||||
@@ -59,3 +74,4 @@ pub async fn get_client_for_user(username: String) -> Result<Client> {
|
||||
}
|
||||
|
||||
mod invitations;
|
||||
mod repeated_join;
|
||||
|
||||
@@ -6,12 +6,12 @@ use matrix_sdk::{
|
||||
room::Room, ruma::api::client::room::create_room::v3::Request as CreateRoomRequest,
|
||||
};
|
||||
|
||||
use super::get_client_for_user;
|
||||
use super::{get_client_for_user, Store};
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 4)]
|
||||
async fn test_invitation_details() -> Result<()> {
|
||||
let tamatoa = get_client_for_user("tamatoa".to_owned()).await?;
|
||||
let sebastian = get_client_for_user("sebastian".to_owned()).await?;
|
||||
let tamatoa = get_client_for_user(Store::Sled, "tamatoa".to_owned()).await?;
|
||||
let sebastian = get_client_for_user(Store::Sled, "sebastian".to_owned()).await?;
|
||||
|
||||
let invites = [sebastian.user_id().expect("sebastian has a userid!").to_owned()];
|
||||
// create a room and invite sebastian;
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
use std::time::Duration;
|
||||
|
||||
use anyhow::Result;
|
||||
use assign::assign;
|
||||
use matrix_sdk::{
|
||||
event_handler::Ctx,
|
||||
room::Room,
|
||||
ruma::{
|
||||
api::client::room::create_room::v3::Request as CreateRoomRequest,
|
||||
events::room::member::{MembershipState, StrippedRoomMemberEvent},
|
||||
},
|
||||
Client, RoomType,
|
||||
};
|
||||
use tokio::sync::mpsc;
|
||||
|
||||
use super::{get_client_for_user, Store};
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 4)]
|
||||
async fn test_repeated_join_leave() -> Result<()> {
|
||||
let peter = get_client_for_user(Store::Memory, "peter".to_owned()).await?;
|
||||
// FIXME: Run once with memory, once with sled
|
||||
let karl = get_client_for_user(Store::Sled, "karl".to_owned()).await?;
|
||||
let karl_id = karl.user_id().expect("karl has a userid!").to_owned();
|
||||
|
||||
// Create a room and invite karl.
|
||||
let invites = [karl_id.clone()];
|
||||
let request = assign!(CreateRoomRequest::new(), {
|
||||
invite: &invites,
|
||||
is_direct: true,
|
||||
});
|
||||
|
||||
// Sync after 1 second to so that create_room receives the event it is waiting
|
||||
// for.
|
||||
let peter_clone = peter.clone();
|
||||
tokio::spawn(async move {
|
||||
tokio::time::sleep(Duration::from_secs(1)).await;
|
||||
peter_clone.sync_once(Default::default()).await
|
||||
});
|
||||
|
||||
let created_room = peter.create_room(request).await?;
|
||||
let room_id = created_room.room_id();
|
||||
|
||||
// Sync karl once to ensure he got the invite.
|
||||
karl.sync_once(Default::default()).await?;
|
||||
|
||||
// Continuously sync karl from now on.
|
||||
let karl_clone = karl.clone();
|
||||
let join_handle = tokio::spawn(async move {
|
||||
karl_clone.sync(Default::default()).await;
|
||||
});
|
||||
let (invite_signal_sender, mut invite_signal) = mpsc::channel::<()>(1);
|
||||
karl.add_event_handler_context(invite_signal_sender);
|
||||
karl.add_event_handler(signal_on_invite);
|
||||
|
||||
for i in 0..3 {
|
||||
println!("Iteration {i}");
|
||||
|
||||
// Test that karl has the expected state in its client.
|
||||
assert!(karl.get_invited_room(room_id).is_some());
|
||||
assert!(karl.get_joined_room(room_id).is_none());
|
||||
assert!(karl.get_left_room(room_id).is_none());
|
||||
|
||||
let room = karl.get_room(room_id).expect("karl has the room");
|
||||
let membership = room.get_member_no_sync(&karl_id).await?.expect("karl was invited");
|
||||
assert_eq!(*membership.membership(), MembershipState::Invite);
|
||||
|
||||
// Join the room
|
||||
println!("Joining..");
|
||||
let room =
|
||||
karl.get_invited_room(room_id).expect("karl has the room").accept_invitation().await?;
|
||||
println!("Done");
|
||||
let membership = room.get_member_no_sync(&karl_id).await?.expect("karl joined");
|
||||
assert_eq!(*membership.membership(), MembershipState::Join);
|
||||
|
||||
assert!(karl.get_invited_room(room_id).is_none());
|
||||
assert!(karl.get_joined_room(room_id).is_some());
|
||||
assert!(karl.get_left_room(room_id).is_none());
|
||||
|
||||
// Leave the room
|
||||
println!("Leaving..");
|
||||
let room = room.leave().await?;
|
||||
println!("Done");
|
||||
let membership = room.get_member_no_sync(&karl_id).await?.expect("karl left");
|
||||
assert_eq!(*membership.membership(), MembershipState::Leave);
|
||||
|
||||
assert!(karl.get_invited_room(room_id).is_none());
|
||||
assert!(karl.get_joined_room(room_id).is_none());
|
||||
assert!(karl.get_left_room(room_id).is_some());
|
||||
|
||||
// Invite karl again and wait for karl to receive the invite.
|
||||
println!("Inviting..");
|
||||
let room = peter.get_joined_room(room_id).expect("peter created the room!");
|
||||
room.invite_user_by_id(&karl_id).await?;
|
||||
println!("Waiting to receive invite..");
|
||||
invite_signal.recv().await.expect("sender must be open");
|
||||
}
|
||||
|
||||
// Stop the sync.
|
||||
join_handle.abort();
|
||||
|
||||
// Now check the underlying state store that it also has the correct information
|
||||
// (for when the client restarts).
|
||||
let invited = karl.store().get_invited_user_ids(room_id).await?;
|
||||
assert_eq!(invited.len(), 1);
|
||||
assert_eq!(invited[0], karl_id);
|
||||
|
||||
let joined = karl.store().get_joined_user_ids(room_id).await?;
|
||||
assert!(!joined.contains(&karl_id));
|
||||
|
||||
let event =
|
||||
karl.store().get_member_event(room_id, &karl_id).await?.expect("member event should exist");
|
||||
assert_eq!(*event.membership(), MembershipState::Invite);
|
||||
|
||||
// Yay, test succeeded
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn signal_on_invite(
|
||||
event: StrippedRoomMemberEvent,
|
||||
room: Room,
|
||||
client: Client,
|
||||
sender: Ctx<mpsc::Sender<()>>,
|
||||
) {
|
||||
let own_id = client.user_id().expect("client is logged in");
|
||||
if event.sender == own_id {
|
||||
return;
|
||||
}
|
||||
|
||||
if room.room_type() != RoomType::Invited {
|
||||
return;
|
||||
}
|
||||
|
||||
if event.content.membership != MembershipState::Invite {
|
||||
return;
|
||||
}
|
||||
|
||||
let invited = &event.state_key;
|
||||
if invited != own_id {
|
||||
return;
|
||||
}
|
||||
|
||||
// Send signal that we received an invite.
|
||||
sender.send(()).await.expect("receiver must be open");
|
||||
}
|
||||
Reference in New Issue
Block a user