diff --git a/testing/matrix-sdk-integration-testing/Cargo.toml b/testing/matrix-sdk-integration-testing/Cargo.toml new file mode 100644 index 000000000..5f2e37145 --- /dev/null +++ b/testing/matrix-sdk-integration-testing/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "matrix-sdk-integration-testing" +description = "internal integration testing for matrix rust sdk" +version = "0.1.0" +edition = "2021" +publish = false + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dev-dependencies] +matrix-sdk = { path = "../../crates/matrix-sdk" } +tokio = { version = "1", features = ["rt", "macros"] } +tempfile = "3.3.0" +anyhow = "1" +lazy_static = "1.4" +assign = "1" \ No newline at end of file diff --git a/testing/matrix-sdk-integration-testing/README.md b/testing/matrix-sdk-integration-testing/README.md new file mode 100644 index 000000000..9ad4fc5b3 --- /dev/null +++ b/testing/matrix-sdk-integration-testing/README.md @@ -0,0 +1,26 @@ +# Matrix SDK integration test + +## Requirements + +This requires a synapse backend with a ci patched configuration. You can easily get it up and running with `docker-compose` via: + +```sh +docker-compose -f assets/docker-compose.yml up -d +docker-compose -f assets/docker-compose.yml logs --tail 100 -f +``` + +**Patches** +You can see the patches we do to configuration (namely activate registration and resetting rate limits), check out what `assets/ci-start.sh` changes. + +## Running + +The integration tests expect environment variables `HOMESERVER_URL` be the http-url to access the synapse server and `HOMESERVER_DOMAIN` to be set to the domain configured in that server. If you are using the provided `docker-compose`, the default will be fine. + +## Maintainance + +To drop the database of your docker-compose run: + +```bash +docker-compose -f assets/docker-compose.yml stop +docker volume rm -f assets_marix-rust-sdk-ci-data +``` \ No newline at end of file diff --git a/testing/matrix-sdk-integration-testing/assets/Dockerfile b/testing/matrix-sdk-integration-testing/assets/Dockerfile new file mode 100644 index 000000000..548d1551e --- /dev/null +++ b/testing/matrix-sdk-integration-testing/assets/Dockerfile @@ -0,0 +1,4 @@ +FROM matrixdotorg/synapse:latest +ADD ci-start.sh /ci-start.sh +RUN chmod 770 /ci-start.sh +ENTRYPOINT /ci-start.sh \ No newline at end of file diff --git a/testing/matrix-sdk-integration-testing/assets/ci-start.sh b/testing/matrix-sdk-integration-testing/assets/ci-start.sh new file mode 100644 index 000000000..c44cfc209 --- /dev/null +++ b/testing/matrix-sdk-integration-testing/assets/ci-start.sh @@ -0,0 +1,36 @@ +#!/bin/bash +set -e +export SYNAPSE_SERVER_NAME=matrix-sdk.rs +export SYNAPSE_REPORT_STATS=no +echo " ====== Generating config ====== " +/start.py generate +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 """ + +rc_message: + per_second: 1000 + burst_count: 1000 + +rc_registration: + per_second: 1000 + burst_count: 1000 + +rc_login: + address: + per_second: 1000 + burst_count: 1000 +# account: +# per_second: 0.17 +# burst_count: 3 +# failed_attempts: +# per_second: 0.17 +# burst_count: 3 + +""" >> /data/homeserver.yaml + +echo " ====== Starting server with: ====== " +cat /data/homeserver.yaml +echo " ====== STARTING ====== " +/start.py run \ No newline at end of file diff --git a/testing/matrix-sdk-integration-testing/assets/docker-compose.yml b/testing/matrix-sdk-integration-testing/assets/docker-compose.yml new file mode 100644 index 000000000..cac05a9f6 --- /dev/null +++ b/testing/matrix-sdk-integration-testing/assets/docker-compose.yml @@ -0,0 +1,18 @@ + +version: '3' + +services: + + synapse: + build: . + restart: "no" + healthcheck: + disable: true + volumes: + - matrix-rust-sdk-ci-data:/data + + ports: + - 8228:8008/tcp + +volumes: + matrix-rust-sdk-ci-data: \ No newline at end of file diff --git a/testing/matrix-sdk-integration-testing/src/lib.rs b/testing/matrix-sdk-integration-testing/src/lib.rs new file mode 100644 index 000000000..bf9d74945 --- /dev/null +++ b/testing/matrix-sdk-integration-testing/src/lib.rs @@ -0,0 +1,2 @@ +#[cfg(test)] +mod tests; \ No newline at end of file diff --git a/testing/matrix-sdk-integration-testing/src/tests.rs b/testing/matrix-sdk-integration-testing/src/tests.rs new file mode 100644 index 000000000..2c837981a --- /dev/null +++ b/testing/matrix-sdk-integration-testing/src/tests.rs @@ -0,0 +1,72 @@ + +use std::option_env; +use matrix_sdk::{ + store::make_store_config, Client, ClientBuilder, + ruma::{ + api::client::{ + account::register::v3::Request as RegistrationRequest, room::Visibility, uiaa, + }, + } +}; +use anyhow::Result; +use tempfile::{tempdir, TempDir}; +use assign::assign; +use lazy_static::lazy_static; + +use std::collections::HashMap; +use std::sync::Mutex; + +lazy_static! { + static ref USERS: Mutex> = { + Mutex::new(HashMap::new()) + }; +} + +/// read the test configuration from the environment +pub fn test_server_conf() -> (String, String) { + ( + option_env!("HOMSERVER_URL").unwrap_or("http://localhost:8228").to_owned(), + option_env!("HOMSERVER_DOMAIN").unwrap_or("matrix-sdk.rs").to_owned(), + ) +} + + +pub async fn get_client_for_user(username: String) -> Result { + let mut users = USERS.lock().expect("Static doesn't fail"); + if let Some((client, _)) = users.get(&username) { + return Ok(client.clone()) + } + + let (homeserver_url, _domain_name) = test_server_conf(); + + let tmp_dir = tempdir()?; + + let client = Client::builder() + .user_agent("matrix-sdk-integation-tests".to_owned()) + .store_config(make_store_config(tmp_dir.path(), None)?) + .homeserver_url(homeserver_url) + .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 { + // FIXME: do actually check the registration types... + if let Some(_response) = resp.uiaa_response() { + let request = assign!(RegistrationRequest::new(), { + username: Some(username.as_ref()), + password: Some(username.as_ref()), + + auth: Some(uiaa::AuthData::Dummy(uiaa::Dummy::new())), + }); + // we don't care if this failed, then we just try to login anyways + let _ = client.register(request).await; + } + } + client.login_username(&username, &username).send().await?; + users.insert(username, (client.clone(), tmp_dir)); // keeping temp dir around so it doesn't get destroyed yet + + Ok(client) + +} + +mod invitations; \ No newline at end of file diff --git a/testing/matrix-sdk-integration-testing/src/tests/invitations.rs b/testing/matrix-sdk-integration-testing/src/tests/invitations.rs new file mode 100644 index 000000000..af6e07669 --- /dev/null +++ b/testing/matrix-sdk-integration-testing/src/tests/invitations.rs @@ -0,0 +1,40 @@ + +use super::get_client_for_user; +use anyhow::{bail, Result}; +use assign::assign; +use matrix_sdk::{ + room::Room, + ruma::api::client::room::{ + create_room::v3::Request as CreateRoomRequest, + } +}; + +#[tokio::test] +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 invites = [sebastian.user_id().expect("sebastian has a userid!").to_owned()]; + // create a room and invite sebastian; + let request = assign!(CreateRoomRequest::new(), { + invite: &invites, + is_direct: true, + }); + + let response = tamatoa.create_room(request).await?; + let room_id = response.room_id; + + // the actual test + sebastian.sync_once(Default::default()).await?; + let room = sebastian.get_room(&room_id).expect("Sebstian doesn't know about the room"); + + if let Room::Invited(iv) = room { + let details = iv.invite_details().await?; + let sender = details.inviter.expect("invite details doesn't have inviter"); + assert_eq!(sender.user_id(), tamatoa.user_id().expect("tamatoa has a user_id")); + } else { + bail!("The room tamatoa invited sebastian in isn't an invite: {:?}", room); + } + Ok(()) +} \ No newline at end of file