test: Add test for repeated joining and leaving

This commit is contained in:
Flix
2022-08-27 23:31:30 +02:00
parent 321e56cff8
commit df4ee7db4c
6 changed files with 191 additions and 9 deletions

2
Cargo.lock generated
View File

@@ -2464,10 +2464,12 @@ version = "0.1.0"
dependencies = [
"anyhow",
"assign",
"ctor",
"matrix-sdk",
"once_cell",
"tempfile",
"tokio",
"tracing-subscriber",
]
[[package]]

View File

@@ -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"

View File

@@ -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:

View File

@@ -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;

View File

@@ -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;

View File

@@ -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");
}