diff --git a/.env.test b/.env.test new file mode 100644 index 0000000..de4f2e9 --- /dev/null +++ b/.env.test @@ -0,0 +1,3 @@ +SFRS_ENV=development +SFRS_JWT_SECRET=whatever_a_secret_is +DATABASE_URL=./db/database.test.db \ No newline at end of file diff --git a/.gitignore b/.gitignore index 2778035..4bacf12 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /target .env -database.db \ No newline at end of file +database.db +database.test.db \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 33d6499..49c9a02 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1005,6 +1005,7 @@ dependencies = [ "diesel_migrations", "dotenv", "jwt", + "lazy_static", "rocket", "rocket_contrib", "rust-crypto", diff --git a/Cargo.toml b/Cargo.toml index d074b54..b286e40 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,7 @@ jwt = "0.4.0" diesel = { version = "1.4.3", features = ["sqlite"] } diesel_migrations = "1.4.0" dotenv = "0.9.0" +lazy_static = "1.4.0" serde = { version = "1.0.104", features = ["derive"] } scrypt = "0.2.0" rust-crypto = "0.2.36" \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 51e9cf2..9c1f105 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,17 +13,22 @@ extern crate dotenv; extern crate serde; extern crate crypto; extern crate scrypt; +#[macro_use] +#[cfg(test)] +extern crate lazy_static; mod schema; mod api; mod user; +#[cfg(test)] +mod tests; + use diesel::prelude::*; use diesel::sqlite::SqliteConnection; use dotenv::dotenv; use rocket::Rocket; use rocket::config::{Config, Environment, Value}; -use rocket::fairing::AdHoc; use std::collections::HashMap; use std::env; @@ -69,10 +74,10 @@ fn build_config() -> Config { .unwrap() } -fn run_db_migrations(rocket: Rocket) -> Result { +fn run_db_migrations(rocket: Rocket) -> Rocket { let db = DbConn::get_one(&rocket).expect("Could not connect to Database"); match embedded_migrations::run(&*db) { - Ok(()) => Ok(rocket), + Ok(()) => rocket, Err(e) => { // We should not do anything if database failed to migrate panic!("Failed to run database migrations: {:?}", e); @@ -80,11 +85,14 @@ fn run_db_migrations(rocket: Rocket) -> Result { } } +pub fn build_rocket() -> Rocket { + let r = rocket::custom(build_config()) + .attach(DbConn::fairing()) + .mount("/", api::routes()); + run_db_migrations(r) +} + fn main() { dotenv().ok(); - rocket::custom(build_config()) - .attach(DbConn::fairing()) - .attach(AdHoc::on_attach("Database Migrations", run_db_migrations)) - .mount("/", api::routes()) - .launch(); + build_rocket().launch(); } diff --git a/src/tests.rs b/src/tests.rs new file mode 100644 index 0000000..0cdff69 --- /dev/null +++ b/src/tests.rs @@ -0,0 +1,112 @@ +use crate::build_rocket; +use rocket::local::Client; +use rocket::http::{ContentType, Status}; +use lazy_static::*; + +fn get_test_client() -> Client { + dotenv::from_filename(".env.test").unwrap(); + Client::new(build_rocket()) + .expect("valid rocket instance") +} + +lazy_static! { + static ref CLIENT: Client = get_test_client(); +} + +#[test] +fn should_add_user() { + let mut resp = CLIENT + .post("/auth") + .header(ContentType::JSON) + .body(r#"{ + "email": "test@example.com", + "password": "testpw", + "pw_cost": "100", + "pw_nonce": "whatever", + "version": "001" + }"#) + .dispatch(); + assert_eq!(resp.status(), Status::Ok); + assert!(resp.body_string().unwrap().contains(r#"{"token":"#)); +} + +#[test] +fn should_not_add_user_twice() { + CLIENT.post("/auth") + .header(ContentType::JSON) + .body(r#"{ + "email": "test1@example.com", + "password": "testpw", + "pw_cost": "100", + "pw_nonce": "whatever", + "version": "001" + }"#) + .dispatch() + .body_string() + .unwrap(); + let resp = CLIENT + .post("/auth") + .header(ContentType::JSON) + .body(r#"{ + "email": "test1@example.com", + "password": "does not matter", + "pw_cost": "100", + "pw_nonce": "whatever", + "version": "001" + }"#) + .dispatch(); + assert_eq!(resp.status(), Status::InternalServerError); +} + +#[test] +fn should_log_in_successfully() { + CLIENT.post("/auth") + .header(ContentType::JSON) + .body(r#"{ + "email": "test2@example.com", + "password": "testpw", + "pw_cost": "100", + "pw_nonce": "whatever", + "version": "001" + }"#) + .dispatch() + .body_string() + .unwrap(); + let mut resp = CLIENT + .post("/auth/sign_in") + .header(ContentType::JSON) + .body(r#"{ + "email": "test2@example.com", + "password": "testpw" + }"#) + .dispatch(); + assert_eq!(resp.status(), Status::Ok); + let body = resp.body_string().unwrap(); + //println!("{}", body); + assert!(body.contains(r#"{"token":"#)); +} + +#[test] +fn should_log_in_fail() { + CLIENT.post("/auth") + .header(ContentType::JSON) + .body(r#"{ + "email": "test3@example.com", + "password": "testpw", + "pw_cost": "100", + "pw_nonce": "whatever", + "version": "001" + }"#) + .dispatch() + .body_string() + .unwrap(); + let resp = CLIENT + .post("/auth/sign_in") + .header(ContentType::JSON) + .body(r#"{ + "email": "test3@example.com", + "password": "testpw1" + }"#) + .dispatch(); + assert_eq!(resp.status(), Status::InternalServerError); +} \ No newline at end of file diff --git a/test.sh b/test.sh new file mode 100755 index 0000000..74b51f5 --- /dev/null +++ b/test.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +rm -rf db/database.test.db +cargo test +rm -rf db/database.test.db \ No newline at end of file