From 970c8315d1ed493e266a4cc91f205954d7953926 Mon Sep 17 00:00:00 2001 From: EETagent Date: Mon, 21 Nov 2022 17:36:37 +0100 Subject: [PATCH] refactor: rework api tests --- .github/workflows/rust.yml | 1 - api/src/pool.rs | 14 ++-- api/src/routes/candidate.rs | 141 +++++++++++++++++++++++++++++++++++ api/src/test.rs | 144 ++++++++++++++++++++++++++++-------- api/tests/candidate.rs | 139 ---------------------------------- api/tests/common.rs | 62 ---------------- 6 files changed, 263 insertions(+), 238 deletions(-) delete mode 100644 api/tests/candidate.rs delete mode 100644 api/tests/common.rs diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index b9e9704..a9edd92 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -7,7 +7,6 @@ on: env: CARGO_TERM_COLOR: always - TEST_API: true jobs: build: diff --git a/api/src/pool.rs b/api/src/pool.rs index 2951fa2..280b0c6 100644 --- a/api/src/pool.rs +++ b/api/src/pool.rs @@ -20,14 +20,16 @@ impl sea_orm_rocket::Pool for SeaOrmPool { type Connection = sea_orm::DatabaseConnection; + #[cfg(test)] + async fn init(_figment: &Figment) -> Result { + let conn = get_memory_sqlite_connection().await; + crate::test::tests::run_test_migrations(&conn).await; + return Ok(Self { conn }); + } + + #[cfg(not(test))] async fn init(_figment: &Figment) -> Result { dotenv::dotenv().ok(); - if std::env::var("TEST_API").is_ok() { - let conn = get_memory_sqlite_connection().await; - crate::test::run_test_migrations(&conn).await; - return Ok(Self { conn }); - } - let database_url = std::env::var("DATABASE_URL").unwrap(); let mut options: ConnectOptions = database_url.into(); diff --git a/api/src/routes/candidate.rs b/api/src/routes/candidate.rs index 2175b5d..0076602 100644 --- a/api/src/routes/candidate.rs +++ b/api/src/routes/candidate.rs @@ -283,4 +283,145 @@ pub async fn download_portfolio(session: CandidateAuth) -> Result, Custo } Ok(file.unwrap()) +} + +#[cfg(test)] +mod tests { + use portfolio_core::{candidate_details::ApplicationDetails, sea_orm::prelude::Uuid, crypto}; + use rocket::http::{Status, Cookie}; + + use crate::test::tests::{create_candidate, admin_login, test_client, candidate_login, APPLICATION_ID}; + + const CANDIDATE_DETAILS: &'static str = "{ + \"name\": \"idk\", + \"surname\": \"idk\", + \"birthplace\": \"Praha 1\", + \"birthdate\": \"2015-09-18\", + \"address\": \"Stefanikova jidelna\", + \"telephone\": \"000111222333\", + \"citizenship\": \"Czech Republic\", + \"email\": \"magor@magor.cz\", + \"sex\": \"MALE\", + \"study\": \"KB\", + \"parent_name\": \"maminka\", + \"parent_surname\": \"chad\", + \"parent_telephone\": \"420111222333\", + \"parent_email\": \"maminka@centrum.cz\" + }"; + + #[test] + fn test_login_valid_credentials() { + let client = test_client().lock().unwrap(); + let _response = candidate_login(&client); + } + + #[test] + fn test_create_candidate() { + let client = test_client().lock().unwrap(); + let cookies = admin_login(&client); + let password = create_candidate(&client, cookies, 1031511, "0".to_string()); + + assert_eq!(password.len(), 8); + } + + #[test] + fn test_auth_candidate() { + let client = test_client().lock().unwrap(); + let cookies = candidate_login(&client); + let response = client + .get("/candidate/whoami") + .cookie(cookies.0) + .cookie(cookies.1) + .dispatch(); + + assert_eq!(response.status(), Status::Ok); + assert_eq!(response.into_string().unwrap(), APPLICATION_ID.to_string()); + } + + #[test] + fn test_add_get_candidate_details() { + let client = test_client().lock().unwrap(); + let cookies = candidate_login(&client); + + let details_orig: ApplicationDetails = serde_json::from_str(CANDIDATE_DETAILS).unwrap(); + + let response = client + .post("/candidate/add/details") + .cookie(cookies.0.clone()) + .cookie(cookies.1.clone()) + .body(CANDIDATE_DETAILS.to_string()) + .dispatch(); + + assert_eq!(response.status(), Status::Ok); + + let response = client + .post("/candidate/get_details") + .cookie(cookies.0) + .cookie(cookies.1) + .dispatch(); + + assert_eq!(response.status(), Status::Ok); + + let details_resp: ApplicationDetails = serde_json::from_str(&response.into_string().unwrap()).unwrap(); + assert_eq!(details_orig, details_resp); + } + + #[test] + fn test_invalid_token_every_secured_endpoint() { + let client = test_client().lock().unwrap(); + + let id = Cookie::new("id", Uuid::new_v4().to_string()); + let (private_key, _) = crypto::create_identity(); + let key = Cookie::new("key", private_key); + + let response = client + .post("/candidate/add/details") + .cookie(id.clone()) + .cookie(key.clone()) + .body(CANDIDATE_DETAILS.to_string()) + .dispatch(); + assert_eq!(response.status(), Status::Unauthorized); + + let response = client + .post("/candidate/get_details") + .cookie(id.clone()) + .cookie(key.clone()) + .dispatch(); + assert_eq!(response.status(), Status::Unauthorized); + + let response = client + .get("/candidate/whoami") + .cookie(id.clone()) + .cookie(key.clone()) + .dispatch(); + assert_eq!(response.status(), Status::Unauthorized); + } + + #[test] + fn test_admin_token_on_secured_candidate_endpoints() { + let client = test_client().lock().unwrap(); + let cookies = admin_login(&client); + + let response = client + .post("/candidate/add/details") + .cookie(cookies.0.clone()) + .cookie(cookies.1.clone()) + .body(CANDIDATE_DETAILS.to_string()) + .dispatch(); + assert_eq!(response.status(), Status::Unauthorized); + + let response = client + .post("/candidate/get_details") + .cookie(cookies.0.clone()) + .cookie(cookies.1.clone()) + .dispatch(); + assert_eq!(response.status(), Status::Unauthorized); + + let response = client + .get("/candidate/whoami") + .cookie(cookies.0.clone()) + .cookie(cookies.1.clone()) + .dispatch(); + assert_eq!(response.status(), Status::Unauthorized); + } } \ No newline at end of file diff --git a/api/src/test.rs b/api/src/test.rs index 2ce5bde..b1db8f9 100644 --- a/api/src/test.rs +++ b/api/src/test.rs @@ -1,40 +1,124 @@ -use entity::admin; -use portfolio_core::{sea_orm::{DbConn, Set, ActiveModelTrait}, crypto, services::application_service::ApplicationService}; +#[cfg(test)] +pub mod tests { + use crate::rocket; + use entity::admin; + use once_cell::sync::OnceCell; + use portfolio_core::{ + crypto, + sea_orm::{ActiveModelTrait, DbConn, Set}, + services::application_service::ApplicationService, + }; + use rocket::{ + http::{Cookie, Status}, + local::blocking::Client, + }; + use std::sync::Mutex; -pub const ADMIN_ID: i32 = 1; -pub const ADMIN_PASSWORD: &'static str = "test"; + pub const ADMIN_ID: i32 = 1; + pub const ADMIN_PASSWORD: &'static str = "test"; -pub const APPLICATION_ID: i32 = 103151; -pub const CANDIDATE_PASSWORD: &'static str = "test"; -pub const PERSONAL_ID_NUMBER: &'static str = "0101010000"; + pub const APPLICATION_ID: i32 = 103151; + pub const CANDIDATE_PASSWORD: &'static str = "test"; + pub const PERSONAL_ID_NUMBER: &'static str = "0101010000"; -pub async fn run_test_migrations(db: &DbConn) { - let (pubkey, priv_key) = crypto::create_identity(); - let priv_key = crypto::encrypt_password( - priv_key, - ADMIN_PASSWORD.to_string() - ).await.unwrap(); - let password_hash = crypto::hash_password(ADMIN_PASSWORD.to_string()).await.unwrap(); + pub async fn run_test_migrations(db: &DbConn) { + let (pubkey, priv_key) = crypto::create_identity(); + let priv_key = crypto::encrypt_password(priv_key, ADMIN_PASSWORD.to_string()) + .await + .unwrap(); + let password_hash = crypto::hash_password(ADMIN_PASSWORD.to_string()) + .await + .unwrap(); - admin::ActiveModel { - id: Set(ADMIN_ID), - name: Set("admin pepa".to_string()), - public_key: Set(pubkey), - private_key: Set(priv_key), - password: Set(password_hash), - created_at: Set(chrono::Utc::now().naive_utc()), - updated_at: Set(chrono::Utc::now().naive_utc()), - } + admin::ActiveModel { + id: Set(ADMIN_ID), + name: Set("admin pepa".to_string()), + public_key: Set(pubkey), + private_key: Set(priv_key), + password: Set(password_hash), + created_at: Set(chrono::Utc::now().naive_utc()), + updated_at: Set(chrono::Utc::now().naive_utc()), + } .insert(db) .await .unwrap(); - ApplicationService::create_candidate_with_parent( - db, - APPLICATION_ID, - &CANDIDATE_PASSWORD.to_string(), - PERSONAL_ID_NUMBER.to_string() - ) + ApplicationService::create_candidate_with_parent( + db, + APPLICATION_ID, + &CANDIDATE_PASSWORD.to_string(), + PERSONAL_ID_NUMBER.to_string(), + ) .await .unwrap(); -} \ No newline at end of file + } + + pub fn test_client() -> &'static Mutex { + static INSTANCE: OnceCell> = OnceCell::new(); + INSTANCE.get_or_init(|| { + let rocket = rocket(); + Mutex::from(Client::tracked(rocket).expect("valid rocket instance")) + }) + } + + pub fn candidate_login(client: &Client) -> (Cookie, Cookie) { + let response = client + .post("/candidate/login") + .body(format!( + "{{ + \"application_id\": {}, + \"password\": \"{}\" + }}", + APPLICATION_ID, CANDIDATE_PASSWORD + )) + .dispatch(); + + ( + response.cookies().get("id").unwrap().to_owned(), + response.cookies().get("key").unwrap().to_owned(), + ) + } + + pub fn admin_login(client: &Client) -> (Cookie, Cookie) { + let response = client + .post("/admin/login") + .body(format!( + "{{ + \"admin_id\": {}, + \"password\": \"{}\" + }}", + ADMIN_ID, ADMIN_PASSWORD + )) + .dispatch(); + + println!("{:?}", response); + ( + response.cookies().get("id").unwrap().to_owned(), + response.cookies().get("key").unwrap().to_owned(), + ) + } + + pub fn create_candidate( + client: &Client, + cookies: (Cookie, Cookie), + id: i32, + pid: String, + ) -> String { + let response = client + .post("/admin/create") + .body(format!( + "{{ + \"application_id\": {}, + \"personal_id_number\": \"{}\" + }}", + id, pid + )) + .cookie(cookies.0) + .cookie(cookies.1) + .dispatch(); + + assert_eq!(response.status(), Status::Ok); + + response.into_string().unwrap() + } +} diff --git a/api/tests/candidate.rs b/api/tests/candidate.rs deleted file mode 100644 index 68d5981..0000000 --- a/api/tests/candidate.rs +++ /dev/null @@ -1,139 +0,0 @@ -mod common; -use common::*; -use portfolio_api::test::APPLICATION_ID; -use portfolio_core::{candidate_details::ApplicationDetails, sea_orm::prelude::Uuid, crypto}; -use rocket::{http::{Status, Cookie}}; - - -const CANDIDATE_DETAILS: &'static str = "{ - \"name\": \"idk\", - \"surname\": \"idk\", - \"birthplace\": \"Praha 1\", - \"birthdate\": \"2015-09-18\", - \"address\": \"Stefanikova jidelna\", - \"telephone\": \"000111222333\", - \"citizenship\": \"Czech Republic\", - \"email\": \"magor@magor.cz\", - \"sex\": \"MALE\", - \"study\": \"KB\", - \"parent_name\": \"maminka\", - \"parent_surname\": \"chad\", - \"parent_telephone\": \"420111222333\", - \"parent_email\": \"maminka@centrum.cz\" -}"; - -#[test] -fn test_login_valid_credentials() { - let client = test_client().lock().unwrap(); - let _response = candidate_login(&client); -} - -#[test] -fn test_create_candidate() { - let client = test_client().lock().unwrap(); - let cookies = admin_login(&client); - let password = create_candidate(&client, cookies, 1031511, "0".to_string()); - - assert_eq!(password.len(), 8); -} - -#[test] -fn test_auth_candidate() { - let client = test_client().lock().unwrap(); - let cookies = candidate_login(&client); - let response = client - .get("/candidate/whoami") - .cookie(cookies.0) - .cookie(cookies.1) - .dispatch(); - - assert_eq!(response.status(), Status::Ok); - assert_eq!(response.into_string().unwrap(), APPLICATION_ID.to_string()); -} - -#[test] -fn test_add_get_candidate_details() { - let client = test_client().lock().unwrap(); - let cookies = candidate_login(&client); - - let details_orig: ApplicationDetails = serde_json::from_str(CANDIDATE_DETAILS).unwrap(); - - let response = client - .post("/candidate/add/details") - .cookie(cookies.0.clone()) - .cookie(cookies.1.clone()) - .body(CANDIDATE_DETAILS.to_string()) - .dispatch(); - - assert_eq!(response.status(), Status::Ok); - - let response = client - .post("/candidate/get_details") - .cookie(cookies.0) - .cookie(cookies.1) - .dispatch(); - - assert_eq!(response.status(), Status::Ok); - - let details_resp: ApplicationDetails = serde_json::from_str(&response.into_string().unwrap()).unwrap(); - assert_eq!(details_orig, details_resp); -} - -#[test] -fn test_invalid_token_every_secured_endpoint() { - let client = test_client().lock().unwrap(); - - let id = Cookie::new("id", Uuid::new_v4().to_string()); - let (private_key, _) = crypto::create_identity(); - let key = Cookie::new("key", private_key); - - let response = client - .post("/candidate/add/details") - .cookie(id.clone()) - .cookie(key.clone()) - .body(CANDIDATE_DETAILS.to_string()) - .dispatch(); - assert_eq!(response.status(), Status::Unauthorized); - - let response = client - .post("/candidate/get_details") - .cookie(id.clone()) - .cookie(key.clone()) - .dispatch(); - assert_eq!(response.status(), Status::Unauthorized); - - let response = client - .get("/candidate/whoami") - .cookie(id.clone()) - .cookie(key.clone()) - .dispatch(); - assert_eq!(response.status(), Status::Unauthorized); -} - -#[test] -fn test_admin_token_on_secured_candidate_endpoints() { - let client = test_client().lock().unwrap(); - let cookies = admin_login(&client); - - let response = client - .post("/candidate/add/details") - .cookie(cookies.0.clone()) - .cookie(cookies.1.clone()) - .body(CANDIDATE_DETAILS.to_string()) - .dispatch(); - assert_eq!(response.status(), Status::Unauthorized); - - let response = client - .post("/candidate/get_details") - .cookie(cookies.0.clone()) - .cookie(cookies.1.clone()) - .dispatch(); - assert_eq!(response.status(), Status::Unauthorized); - - let response = client - .get("/candidate/whoami") - .cookie(cookies.0.clone()) - .cookie(cookies.1.clone()) - .dispatch(); - assert_eq!(response.status(), Status::Unauthorized); -} \ No newline at end of file diff --git a/api/tests/common.rs b/api/tests/common.rs deleted file mode 100644 index 1214b48..0000000 --- a/api/tests/common.rs +++ /dev/null @@ -1,62 +0,0 @@ -use once_cell::sync::OnceCell; -use std::sync::Mutex; -use rocket::http::{Cookie, Status}; -use rocket::local::blocking::{Client}; -use portfolio_api::rocket; - -use portfolio_api::test::{ADMIN_ID, ADMIN_PASSWORD, APPLICATION_ID, CANDIDATE_PASSWORD}; - -pub fn test_client() -> &'static Mutex { - static INSTANCE: OnceCell> = OnceCell::new(); - INSTANCE.get_or_init(|| { - let rocket = rocket(); - Mutex::from(Client::tracked(rocket).expect("valid rocket instance")) - }) -} - -pub fn candidate_login(client: &Client) -> (Cookie, Cookie) { - let response = client - .post("/candidate/login") - .body(format!("{{ - \"application_id\": {}, - \"password\": \"{}\" - }}", APPLICATION_ID, CANDIDATE_PASSWORD)) - .dispatch(); - - ( - response.cookies().get("id").unwrap().to_owned(), - response.cookies().get("key").unwrap().to_owned() - ) -} - -pub fn admin_login(client: &Client) -> (Cookie, Cookie) { - let response = client - .post("/admin/login") - .body(format!("{{ - \"admin_id\": {}, - \"password\": \"{}\" - }}", ADMIN_ID, ADMIN_PASSWORD)) - .dispatch(); - - println!("{:?}", response); - ( - response.cookies().get("id").unwrap().to_owned(), - response.cookies().get("key").unwrap().to_owned(), - ) -} - -pub fn create_candidate(client: &Client, cookies: (Cookie, Cookie), id: i32, pid: String) -> String { - let response = client - .post("/admin/create") - .body(format!("{{ - \"application_id\": {}, - \"personal_id_number\": \"{}\" - }}", id, pid)) - .cookie(cookies.0) - .cookie(cookies.1) - .dispatch(); - - assert_eq!(response.status(), Status::Ok); - - response.into_string().unwrap() -} \ No newline at end of file