mirror of
https://github.com/danbulant/Portfolio
synced 2026-06-19 06:21:15 +00:00
feat: api tests setup
This commit is contained in:
parent
8650efbfe5
commit
6d8319d784
10 changed files with 187 additions and 37 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
|
@ -1981,9 +1981,11 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"async-stream",
|
||||
"async-trait",
|
||||
"chrono",
|
||||
"dotenv",
|
||||
"futures",
|
||||
"futures-util",
|
||||
"once_cell",
|
||||
"portfolio-core",
|
||||
"portfolio-entity",
|
||||
"portfolio-migration",
|
||||
|
|
|
|||
|
|
@ -20,9 +20,15 @@ dotenv = "^0.15"
|
|||
|
||||
serde_json = { version = "^1.0" }
|
||||
|
||||
chrono = "^0.4"
|
||||
|
||||
portfolio-entity = { path = "../entity" }
|
||||
portfolio-migration = { path = "../migration" }
|
||||
portfolio-core = { path = "../core" }
|
||||
|
||||
[dependencies.sea-orm-rocket]
|
||||
version = "^0.5"
|
||||
|
||||
|
||||
[dev-dependencies]
|
||||
once_cell = "1.9.0"
|
||||
|
|
@ -12,6 +12,7 @@ mod guards;
|
|||
mod pool;
|
||||
mod requests;
|
||||
mod routes;
|
||||
pub mod test;
|
||||
|
||||
use pool::Db;
|
||||
|
||||
|
|
@ -29,8 +30,7 @@ async fn run_migrations(rocket: Rocket<Build>) -> fairing::Result {
|
|||
Ok(rocket)
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn start() -> Result<(), rocket::Error> {
|
||||
pub fn rocket() -> Rocket<Build>{
|
||||
rocket::build()
|
||||
.attach(Db::init())
|
||||
.attach(AdHoc::try_on_ignite("Migrations", run_migrations))
|
||||
|
|
@ -80,6 +80,11 @@ async fn start() -> Result<(), rocket::Error> {
|
|||
routes::admin::list_candidates,
|
||||
])
|
||||
.register("/", catchers![])
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn start() -> Result<(), rocket::Error> {
|
||||
rocket()
|
||||
.launch()
|
||||
.await
|
||||
.map(|_| ())
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use portfolio_core::sea_orm;
|
||||
use portfolio_core::{sea_orm::{self}, util::get_memory_sqlite_connection};
|
||||
|
||||
use async_trait::async_trait;
|
||||
use sea_orm::ConnectOptions;
|
||||
|
|
@ -22,20 +22,28 @@ impl sea_orm_rocket::Pool for SeaOrmPool {
|
|||
|
||||
async fn init(_figment: &Figment) -> Result<Self, Self::Error> {
|
||||
dotenv::dotenv().ok();
|
||||
if std::env::var("TEST").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();
|
||||
options
|
||||
.max_connections(1024)
|
||||
.min_connections(0)
|
||||
.connect_timeout(Duration::from_secs(3));
|
||||
|
||||
/* options
|
||||
|
||||
/* options
|
||||
.max_connections(config.max_connections as u32)
|
||||
.min_connections(config.min_connections.unwrap_or_default())
|
||||
.connect_timeout(Duration::from_secs(config.connect_timeout));
|
||||
if let Some(idle_timeout) = config.idle_timeout {
|
||||
options.idle_timeout(Duration::from_secs(idle_timeout));
|
||||
} */
|
||||
if let Some(idle_timeout) = config.idle_timeout {
|
||||
options.idle_timeout(Duration::from_secs(idle_timeout));
|
||||
} */
|
||||
|
||||
let conn = sea_orm::Database::connect(options).await?;
|
||||
|
||||
Ok(SeaOrmPool { conn })
|
||||
|
|
@ -44,4 +52,4 @@ impl sea_orm_rocket::Pool for SeaOrmPool {
|
|||
fn borrow(&self) -> &Self::Connection {
|
||||
&self.conn
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
use std::net::SocketAddr;
|
||||
use std::net::{SocketAddr, IpAddr, Ipv4Addr};
|
||||
|
||||
use portfolio_core::{
|
||||
crypto::random_8_char_string,
|
||||
|
|
@ -17,9 +17,10 @@ use crate::{guards::request::auth::AdminAuth, pool::Db, requests};
|
|||
pub async fn login(
|
||||
conn: Connection<'_, Db>,
|
||||
login_form: Json<AdminLoginRequest>,
|
||||
ip_addr: SocketAddr,
|
||||
// ip_addr: SocketAddr, // TODO uncomment in production
|
||||
cookies: &CookieJar<'_>,
|
||||
) -> Result<String, Custom<String>> {
|
||||
let ip_addr: SocketAddr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 0);
|
||||
let db = conn.into_inner();
|
||||
let session_token_key = AdminService::login(
|
||||
db,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use std::net::SocketAddr;
|
||||
use std::net::{SocketAddr, IpAddr, Ipv4Addr};
|
||||
|
||||
use portfolio_core::candidate_details::ApplicationDetails;
|
||||
use portfolio_core::services::application_service::ApplicationService;
|
||||
|
|
@ -19,9 +19,10 @@ use crate::{guards::request::auth::CandidateAuth, pool::Db, requests};
|
|||
pub async fn login(
|
||||
conn: Connection<'_, Db>,
|
||||
login_form: Json<LoginRequest>,
|
||||
ip_addr: SocketAddr,
|
||||
// ip_addr: SocketAddr, // TODO uncomment in production
|
||||
cookies: &CookieJar<'_>,
|
||||
) -> Result<String, Custom<String>> {
|
||||
let ip_addr: SocketAddr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 0);
|
||||
let db = conn.into_inner();
|
||||
let session_token_key = CandidateService::login(
|
||||
db,
|
||||
|
|
|
|||
40
api/src/test.rs
Normal file
40
api/src/test.rs
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
use entity::admin;
|
||||
use portfolio_core::{sea_orm::{DbConn, Set, ActiveModelTrait}, crypto, services::application_service::ApplicationService};
|
||||
|
||||
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 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()),
|
||||
}
|
||||
.insert(db)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
ApplicationService::create_candidate_with_parent(
|
||||
db,
|
||||
APPLICATION_ID,
|
||||
&CANDIDATE_PASSWORD.to_string(),
|
||||
PERSONAL_ID_NUMBER.to_string()
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
33
api/tests/candidate.rs
Normal file
33
api/tests/candidate.rs
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
mod common;
|
||||
use common::*;
|
||||
use portfolio_api::test::APPLICATION_ID;
|
||||
use rocket::http::Status;
|
||||
|
||||
#[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());
|
||||
}
|
||||
62
api/tests/common.rs
Normal file
62
api/tests/common.rs
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
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<Client> {
|
||||
static INSTANCE: OnceCell<Mutex<Client>> = 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()
|
||||
}
|
||||
|
|
@ -1,30 +1,22 @@
|
|||
#[cfg(test)]
|
||||
use entity::{admin, candidate, parent, session};
|
||||
use sea_orm::{Schema, Database, DbConn};
|
||||
use sea_orm::{sea_query::TableCreateStatement, ConnectionTrait, DbBackend};
|
||||
|
||||
|
||||
pub async fn get_memory_sqlite_connection() -> sea_orm::DbConn {
|
||||
use entity::{admin, candidate, parent, session};
|
||||
use sea_orm::{Schema, Database, DbConn};
|
||||
use sea_orm::{sea_query::TableCreateStatement, ConnectionTrait, DbBackend};
|
||||
|
||||
let base_url = "sqlite::memory:";
|
||||
let db: DbConn = Database::connect(base_url).await.unwrap();
|
||||
let db: DbConn = Database::connect(base_url).await.unwrap();
|
||||
|
||||
let schema = Schema::new(DbBackend::Sqlite);
|
||||
let stmt: TableCreateStatement = schema.create_table_from_entity(candidate::Entity);
|
||||
let stmt2: TableCreateStatement = schema.create_table_from_entity(admin::Entity);
|
||||
let stmt3: TableCreateStatement = schema.create_table_from_entity(session::Entity);
|
||||
let stmt4: TableCreateStatement = schema.create_table_from_entity(parent::Entity);
|
||||
db.execute(db.get_database_backend().build(&stmt))
|
||||
.await
|
||||
.unwrap();
|
||||
db.execute(db.get_database_backend().build(&stmt2))
|
||||
.await
|
||||
.unwrap();
|
||||
db.execute(db.get_database_backend().build(&stmt3))
|
||||
.await
|
||||
.unwrap();
|
||||
db.execute(db.get_database_backend().build(&stmt4))
|
||||
.await
|
||||
.unwrap();
|
||||
db
|
||||
let schema = Schema::new(DbBackend::Sqlite);
|
||||
let stmt: TableCreateStatement = schema.create_table_from_entity(candidate::Entity);
|
||||
let stmt2: TableCreateStatement = schema.create_table_from_entity(admin::Entity);
|
||||
let stmt3: TableCreateStatement = schema.create_table_from_entity(session::Entity);
|
||||
let stmt4: TableCreateStatement = schema.create_table_from_entity(parent::Entity);
|
||||
db.execute(db.get_database_backend().build(&stmt)).await.unwrap();
|
||||
db.execute(db.get_database_backend().build(&stmt2)).await.unwrap();
|
||||
db.execute(db.get_database_backend().build(&stmt3)).await.unwrap();
|
||||
db.execute(db.get_database_backend().build(&stmt4)).await.unwrap();
|
||||
db
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
|||
Loading…
Reference in a new issue