Skip to content

Commit

Permalink
refactor: run e2e tests with independent isolated servers too.
Browse files Browse the repository at this point in the history
E2E tests can be executed with a shared app instance with:

```
TORRUST_IDX_BACK_E2E_SHARED=true cargo test
```

or with an isolated instance per test:

```
cargo test
```

In the first case, you have to start the env manbually before running the tests, and manually stop it when tests are finished.
In the second test, the test will launch a new app on a different socket using a different database.

Shared env:

- Requires docker
- It's slower
- It comes with a real traker

Isolated env:

- Doesn't require docker
- It's faster
- You have to mock the TrackerService (not implemented yet)
  • Loading branch information
josecelano committed May 3, 2023
1 parent 1df870b commit 14d0acb
Show file tree
Hide file tree
Showing 26 changed files with 590 additions and 291 deletions.
5 changes: 3 additions & 2 deletions .cargo/config.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
[alias]
cov = "llvm-cov"
cov-lcov = "llvm-cov --lcov --output-path=./.coverage/lcov.info"
cov-html = "llvm-cov --html"
cov-lcov = "llvm-cov --lcov --output-path=./.coverage/lcov.info"
time = "build --timings --all-targets"
e2e = "test --features e2e-tests"



2 changes: 2 additions & 0 deletions .github/workflows/develop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ jobs:
run: cargo check --all-targets
- name: Clippy
run: cargo clippy --all-targets
- name: Install torrent edition tool (needed for testing)
run: cargo install imdl
- name: Unit and integration tests
run: cargo test --all-targets
- uses: taiki-e/install-action@cargo-llvm-cov
Expand Down
3 changes: 0 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@ default-run = "main"
[profile.dev.package.sqlx-macros]
opt-level = 3

[features]
e2e-tests = []

[dependencies]
actix-web = "4.3"
actix-multipart = "0.6"
Expand Down
4 changes: 2 additions & 2 deletions docker/bin/run-e2e-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ sleep 20s
# Just to make sure that everything is up and running
docker ps

# Run E2E tests
cargo test --features e2e-tests
# Run E2E tests with shared app instance
TORRUST_IDX_BACK_E2E_SHARED=true cargo test

# Stop E2E testing environment
./docker/bin/e2e-env-down.sh
2 changes: 2 additions & 0 deletions src/routes/torrent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ pub async fn upload_torrent(req: HttpRequest, payload: Multipart, app_data: WebA
.await;

// whitelist info hash on tracker
// code-review: why do we always try to whitelist the torrent on the tracker?
// shouldn't we only do this if the torrent is in "Listed" mode?
if let Err(e) = app_data
.tracker
.whitelist_info_hash(torrent_request.torrent.info_hash())
Expand Down
8 changes: 8 additions & 0 deletions tests/common/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@ pub struct Client {
}

impl Client {
pub fn unauthenticated(bind_address: &str) -> Self {
Self::new(ConnectionInfo::anonymous(bind_address))
}

pub fn authenticated(bind_address: &str, token: &str) -> Self {
Self::new(ConnectionInfo::new(bind_address, token))
}

pub fn new(connection_info: ConnectionInfo) -> Self {
Self {
http_client: Http::new(connection_info),
Expand Down
8 changes: 0 additions & 8 deletions tests/common/connection_info.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,3 @@
pub fn anonymous_connection(bind_address: &str) -> ConnectionInfo {
ConnectionInfo::anonymous(bind_address)
}

pub fn authenticated_connection(bind_address: &str, token: &str) -> ConnectionInfo {
ConnectionInfo::new(bind_address, token)
}

#[derive(Clone)]
pub struct ConnectionInfo {
pub bind_address: String,
Expand Down
2 changes: 1 addition & 1 deletion tests/common/contexts/user/responses.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use serde::Deserialize;

#[derive(Deserialize)]
#[derive(Deserialize, Debug)]
pub struct SuccessfulLoginResponse {
pub data: LoggedInUserData,
}
Expand Down
13 changes: 8 additions & 5 deletions tests/e2e/contexts/about/contract.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
//! API contract for `about` context.
use crate::common::asserts::{assert_response_title, assert_text_ok};
use crate::environments::shared::TestEnv;
use crate::common::client::Client;
use crate::e2e::environment::TestEnv;

#[tokio::test]
#[cfg_attr(not(feature = "e2e-tests"), ignore)]
async fn it_should_load_the_about_page_with_information_about_the_api() {
let client = TestEnv::running().await.unauthenticated_client();
let mut env = TestEnv::new();
env.start().await;
let client = Client::unauthenticated(&env.server_socket_addr().unwrap());

let response = client.about().await;

Expand All @@ -14,9 +16,10 @@ async fn it_should_load_the_about_page_with_information_about_the_api() {
}

#[tokio::test]
#[cfg_attr(not(feature = "e2e-tests"), ignore)]
async fn it_should_load_the_license_page_at_the_api_entrypoint() {
let client = TestEnv::running().await.unauthenticated_client();
let mut env = TestEnv::new();
env.start().await;
let client = Client::unauthenticated(&env.server_socket_addr().unwrap());

let response = client.license().await;

Expand Down
78 changes: 47 additions & 31 deletions tests/e2e/contexts/category/contract.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
//! API contract for `category` context.
use crate::common::asserts::assert_json_ok;
use crate::common::client::Client;
use crate::common::contexts::category::fixtures::random_category_name;
use crate::common::contexts::category::forms::{AddCategoryForm, DeleteCategoryForm};
use crate::common::contexts::category::responses::{AddedCategoryResponse, ListResponse};
use crate::e2e::contexts::category::steps::add_category;
use crate::e2e::contexts::user::steps::{logged_in_admin, logged_in_user};
use crate::environments::shared::TestEnv;
use crate::e2e::contexts::user::steps::{new_logged_in_admin, new_logged_in_user};
use crate::e2e::environment::TestEnv;

/* todo:
- it should allow adding a new category to authenticated clients
Expand All @@ -15,25 +16,27 @@ use crate::environments::shared::TestEnv;
*/

#[tokio::test]
#[cfg_attr(not(feature = "e2e-tests"), ignore)]
async fn it_should_return_an_empty_category_list_when_there_are_no_categories() {
let client = TestEnv::running().await.unauthenticated_client();
let mut env = TestEnv::new();
env.start().await;
let client = Client::unauthenticated(&env.server_socket_addr().unwrap());

let response = client.get_categories().await;

assert_json_ok(&response);
}

#[tokio::test]
#[cfg_attr(not(feature = "e2e-tests"), ignore)]
async fn it_should_return_a_category_list() {
let mut env = TestEnv::new();
env.start().await;
let client = Client::unauthenticated(&env.server_socket_addr().unwrap());

// Add a category
let category_name = random_category_name();
let response = add_category(&category_name).await;
let response = add_category(&category_name, &env).await;
assert_eq!(response.status, 200);

let client = TestEnv::running().await.unauthenticated_client();

let response = client.get_categories().await;

let res: ListResponse = serde_json::from_str(&response.body).unwrap();
Expand All @@ -48,9 +51,10 @@ async fn it_should_return_a_category_list() {
}

#[tokio::test]
#[cfg_attr(not(feature = "e2e-tests"), ignore)]
async fn it_should_not_allow_adding_a_new_category_to_unauthenticated_users() {
let client = TestEnv::running().await.unauthenticated_client();
let mut env = TestEnv::new();
env.start().await;
let client = Client::unauthenticated(&env.server_socket_addr().unwrap());

let response = client
.add_category(AddCategoryForm {
Expand All @@ -63,10 +67,13 @@ async fn it_should_not_allow_adding_a_new_category_to_unauthenticated_users() {
}

#[tokio::test]
#[cfg_attr(not(feature = "e2e-tests"), ignore)]
async fn it_should_not_allow_adding_a_new_category_to_non_admins() {
let logged_non_admin = logged_in_user().await;
let client = TestEnv::running().await.authenticated_client(&logged_non_admin.token);
let mut env = TestEnv::new();
env.start().await;

let logged_non_admin = new_logged_in_user(&env).await;

let client = Client::authenticated(&env.server_socket_addr().unwrap(), &logged_non_admin.token);

let response = client
.add_category(AddCategoryForm {
Expand All @@ -79,10 +86,12 @@ async fn it_should_not_allow_adding_a_new_category_to_non_admins() {
}

#[tokio::test]
#[cfg_attr(not(feature = "e2e-tests"), ignore)]
async fn it_should_allow_admins_to_add_new_categories() {
let logged_in_admin = logged_in_admin().await;
let client = TestEnv::running().await.authenticated_client(&logged_in_admin.token);
let mut env = TestEnv::new();
env.start().await;

let logged_in_admin = new_logged_in_admin(&env).await;
let client = Client::authenticated(&env.server_socket_addr().unwrap(), &logged_in_admin.token);

let category_name = random_category_name();

Expand All @@ -103,27 +112,31 @@ async fn it_should_allow_admins_to_add_new_categories() {
}

#[tokio::test]
#[cfg_attr(not(feature = "e2e-tests"), ignore)]
async fn it_should_not_allow_adding_duplicated_categories() {
let mut env = TestEnv::new();
env.start().await;

// Add a category
let random_category_name = random_category_name();
let response = add_category(&random_category_name).await;
let response = add_category(&random_category_name, &env).await;
assert_eq!(response.status, 200);

// Try to add the same category again
let response = add_category(&random_category_name).await;
let response = add_category(&random_category_name, &env).await;
assert_eq!(response.status, 400);
}

#[tokio::test]
#[cfg_attr(not(feature = "e2e-tests"), ignore)]
async fn it_should_allow_admins_to_delete_categories() {
let logged_in_admin = logged_in_admin().await;
let client = TestEnv::running().await.authenticated_client(&logged_in_admin.token);
let mut env = TestEnv::new();
env.start().await;

let logged_in_admin = new_logged_in_admin(&env).await;
let client = Client::authenticated(&env.server_socket_addr().unwrap(), &logged_in_admin.token);

// Add a category
let category_name = random_category_name();
let response = add_category(&category_name).await;
let response = add_category(&category_name, &env).await;
assert_eq!(response.status, 200);

let response = client
Expand All @@ -143,15 +156,17 @@ async fn it_should_allow_admins_to_delete_categories() {
}

#[tokio::test]
#[cfg_attr(not(feature = "e2e-tests"), ignore)]
async fn it_should_not_allow_non_admins_to_delete_categories() {
let mut env = TestEnv::new();
env.start().await;

// Add a category
let category_name = random_category_name();
let response = add_category(&category_name).await;
let response = add_category(&category_name, &env).await;
assert_eq!(response.status, 200);

let logged_in_non_admin = logged_in_user().await;
let client = TestEnv::running().await.authenticated_client(&logged_in_non_admin.token);
let logged_in_non_admin = new_logged_in_user(&env).await;
let client = Client::authenticated(&env.server_socket_addr().unwrap(), &logged_in_non_admin.token);

let response = client
.delete_category(DeleteCategoryForm {
Expand All @@ -164,15 +179,16 @@ async fn it_should_not_allow_non_admins_to_delete_categories() {
}

#[tokio::test]
#[cfg_attr(not(feature = "e2e-tests"), ignore)]
async fn it_should_not_allow_guests_to_delete_categories() {
let mut env = TestEnv::new();
env.start().await;
let client = Client::unauthenticated(&env.server_socket_addr().unwrap());

// Add a category
let category_name = random_category_name();
let response = add_category(&category_name).await;
let response = add_category(&category_name, &env).await;
assert_eq!(response.status, 200);

let client = TestEnv::running().await.unauthenticated_client();

let response = client
.delete_category(DeleteCategoryForm {
name: category_name.to_string(),
Expand Down
11 changes: 6 additions & 5 deletions tests/e2e/contexts/category/steps.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
use crate::common::client::Client;
use crate::common::contexts::category::forms::AddCategoryForm;
use crate::common::responses::TextResponse;
use crate::e2e::contexts::user::steps::logged_in_admin;
use crate::environments::shared::TestEnv;
use crate::e2e::contexts::user::steps::new_logged_in_admin;
use crate::e2e::environment::TestEnv;

pub async fn add_category(category_name: &str) -> TextResponse {
let logged_in_admin = logged_in_admin().await;
let client = TestEnv::running().await.authenticated_client(&logged_in_admin.token);
pub async fn add_category(category_name: &str, env: &TestEnv) -> TextResponse {
let logged_in_admin = new_logged_in_admin(env).await;
let client = Client::authenticated(&env.server_socket_addr().unwrap(), &logged_in_admin.token);

client
.add_category(AddCategoryForm {
Expand Down
8 changes: 5 additions & 3 deletions tests/e2e/contexts/root/contract.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
//! API contract for `root` context.
use crate::common::asserts::{assert_response_title, assert_text_ok};
use crate::environments::shared::TestEnv;
use crate::common::client::Client;
use crate::e2e::environment::TestEnv;

#[tokio::test]
#[cfg_attr(not(feature = "e2e-tests"), ignore)]
async fn it_should_load_the_about_page_at_the_api_entrypoint() {
let client = TestEnv::running().await.unauthenticated_client();
let mut env = TestEnv::new();
env.start().await;
let client = Client::unauthenticated(&env.server_socket_addr().unwrap());

let response = client.root().await;

Expand Down
Loading

0 comments on commit 14d0acb

Please sign in to comment.