Additional tests, macros for tests

This commit is contained in:
eraden 2022-06-05 21:03:22 +02:00
parent cf464beb27
commit a34f32dc15
10 changed files with 171 additions and 176 deletions

5
Cargo.lock generated
View File

@ -1162,6 +1162,7 @@ dependencies = [
"serde", "serde",
"sqlx", "sqlx",
"sqlx-core", "sqlx-core",
"testx",
"thiserror", "thiserror",
"uuid 0.8.2", "uuid 0.8.2",
] ]
@ -3830,6 +3831,10 @@ dependencies = [
"winapi-util", "winapi-util",
] ]
[[package]]
name = "testx"
version = "0.1.0"
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "1.0.31" version = "1.0.31"

View File

@ -4,6 +4,7 @@ members = [
"shared/model", "shared/model",
"shared/bus", "shared/bus",
"shared/config", "shared/config",
"shared/testx",
# actors # actors
"actors/account_manager", "actors/account_manager",
"actors/cart_manager", "actors/cart_manager",

View File

@ -30,3 +30,6 @@ rand = { version = "0.8.5", optional = true }
itertools = { version = "0.10.3" } itertools = { version = "0.10.3" }
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
[dev-dependencies]
testx = { path = "../../shared/testx" }

View File

@ -248,15 +248,7 @@ mod test {
#[actix::test] #[actix::test]
async fn full_check() { async fn full_check() {
let config = config::default_load(&mut NoOpts); testx::db_t!(t);
config
.lock()
.database_mut()
.set_url("postgres://postgres@localhost/bazzar_test");
let db = Database::build(config).await;
let pool = db.pool();
let mut t = pool.begin().await.unwrap();
// account // account
let account = test_create_account(&mut t).await; let account = test_create_account(&mut t).await;
@ -351,7 +343,7 @@ mod test {
.await .await
.unwrap(); .unwrap();
t.rollback().await.unwrap(); testx::db_rollback!(t);
assert_eq!(default_address, address); assert_eq!(default_address, address);
} }
} }

View File

@ -268,15 +268,7 @@ mod tests {
#[actix::test] #[actix::test]
async fn create_account() { async fn create_account() {
let config = config::default_load(&mut NoOpts); testx::db_t!(t);
config
.lock()
.database_mut()
.set_url("postgres://postgres@localhost/bazzar_test");
let db = Database::build(config).await;
let pool = db.pool();
let mut t = pool.begin().await.unwrap();
let login: String = fake::faker::internet::en::Username().fake(); let login: String = fake::faker::internet::en::Username().fake();
let email: String = fake::faker::internet::en::FreeEmail().fake(); let email: String = fake::faker::internet::en::FreeEmail().fake();
@ -310,36 +302,21 @@ mod tests {
#[actix::test] #[actix::test]
async fn all_accounts() { async fn all_accounts() {
let config = config::default_load(&mut NoOpts); testx::db_t!(t);
config
.lock()
.database_mut()
.set_url("postgres://postgres@localhost/bazzar_test");
let db = Database::build(config).await;
let pool = db.pool();
let mut t = pool.begin().await.unwrap();
test_create_account(&mut t, None, None, None).await; test_create_account(&mut t, None, None, None).await;
test_create_account(&mut t, None, None, None).await; test_create_account(&mut t, None, None, None).await;
test_create_account(&mut t, None, None, None).await; test_create_account(&mut t, None, None, None).await;
let v: Vec<FullAccount> = super::all_accounts(AllAccounts, &mut t).await.unwrap(); let v: Vec<FullAccount> = super::all_accounts(AllAccounts, &mut t).await.unwrap();
testx::db_rollback!(t);
assert!(v.len() >= 3); assert!(v.len() >= 3);
t.rollback().await.unwrap();
} }
#[actix::test] #[actix::test]
async fn update_account_without_pass() { async fn update_account_without_pass() {
let config = config::default_load(&mut NoOpts); testx::db_t!(t);
config
.lock()
.database_mut()
.set_url("postgres://postgres@localhost/bazzar_test");
let db = Database::build(config).await;
let pool = db.pool();
let mut t = pool.begin().await.unwrap();
let original_login: String = fake::faker::internet::en::Username().fake(); let original_login: String = fake::faker::internet::en::Username().fake();
let original_email: String = fake::faker::internet::en::FreeEmail().fake(); let original_email: String = fake::faker::internet::en::FreeEmail().fake();
@ -380,22 +357,14 @@ mod tests {
state: AccountState::Active, state: AccountState::Active,
}; };
t.rollback().await.unwrap(); testx::db_rollback!(t);
assert_ne!(original_account, expected); assert_ne!(original_account, expected);
assert_eq!(updated_account, expected); assert_eq!(updated_account, expected);
} }
#[actix::test] #[actix::test]
async fn update_account_with_pass() { async fn update_account_with_pass() {
let config = config::default_load(&mut NoOpts); testx::db_t!(t);
config
.lock()
.database_mut()
.set_url("postgres://postgres@localhost/bazzar_test");
let db = Database::build(config).await;
let pool = db.pool();
let mut t = pool.begin().await.unwrap();
let original_login: String = fake::faker::internet::en::Username().fake(); let original_login: String = fake::faker::internet::en::Username().fake();
let original_email: String = fake::faker::internet::en::FreeEmail().fake(); let original_email: String = fake::faker::internet::en::FreeEmail().fake();
@ -437,22 +406,14 @@ mod tests {
state: AccountState::Active, state: AccountState::Active,
}; };
t.rollback().await.unwrap(); testx::db_rollback!(t);
assert_ne!(original_account, expected); assert_ne!(original_account, expected);
assert_eq!(updated_account, expected); assert_eq!(updated_account, expected);
} }
#[actix::test] #[actix::test]
async fn find() { async fn find() {
let config = config::default_load(&mut NoOpts); testx::db_t!(t);
config
.lock()
.database_mut()
.set_url("postgres://postgres@localhost/bazzar_test");
let db = Database::build(config).await;
let pool = db.pool();
let mut t = pool.begin().await.unwrap();
let account = test_create_account(&mut t, None, None, None).await; let account = test_create_account(&mut t, None, None, None).await;
@ -465,21 +426,13 @@ mod tests {
.await .await
.unwrap(); .unwrap();
t.rollback().await.unwrap(); testx::db_rollback!(t);
assert_eq!(account, res); assert_eq!(account, res);
} }
#[actix::test] #[actix::test]
async fn find_identity_email() { async fn find_identity_email() {
let config = config::default_load(&mut NoOpts); testx::db_t!(t);
config
.lock()
.database_mut()
.set_url("postgres://postgres@localhost/bazzar_test");
let db = Database::build(config).await;
let pool = db.pool();
let mut t = pool.begin().await.unwrap();
let account = test_create_account(&mut t, None, None, None).await; let account = test_create_account(&mut t, None, None, None).await;
@ -493,21 +446,13 @@ mod tests {
.await .await
.unwrap(); .unwrap();
t.rollback().await.unwrap(); testx::db_rollback!(t);
assert_eq!(account, res); assert_eq!(account, res);
} }
#[actix::test] #[actix::test]
async fn find_identity_login() { async fn find_identity_login() {
let config = config::default_load(&mut NoOpts); testx::db_t!(t);
config
.lock()
.database_mut()
.set_url("postgres://postgres@localhost/bazzar_test");
let db = Database::build(config).await;
let pool = db.pool();
let mut t = pool.begin().await.unwrap();
let account = test_create_account(&mut t, None, None, None).await; let account = test_create_account(&mut t, None, None, None).await;
@ -521,7 +466,7 @@ mod tests {
.await .await
.unwrap(); .unwrap();
t.rollback().await.unwrap(); testx::db_rollback!(t);
assert_eq!(account, res); assert_eq!(account, res);
} }
} }

View File

@ -31,6 +31,7 @@ async fn all_stocks(
r#" r#"
SELECT id, product_id, quantity, quantity_unit SELECT id, product_id, quantity, quantity_unit
FROM stocks FROM stocks
ORDER BY id ASC
"#, "#,
) )
.fetch_all(pool) .fetch_all(pool)
@ -235,30 +236,16 @@ mod tests {
#[actix::test] #[actix::test]
async fn create_stock() { async fn create_stock() {
let config = config::default_load(&mut NoOpts); testx::db_t!(t);
config
.lock()
.database_mut()
.set_url("postgres://postgres@localhost/bazzar_test");
let db = Database::build(config).await;
let pool = db.pool();
let mut t = pool.begin().await.unwrap();
test_stock(&mut t, None, None, None).await; test_stock(&mut t, None, None, None).await;
t.rollback().await.unwrap();
testx::db_rollback!(t);
} }
#[actix::test] #[actix::test]
async fn products_stock() { async fn products_stock() {
let config = config::default_load(&mut NoOpts); testx::db_t!(t);
config
.lock()
.database_mut()
.set_url("postgres://postgres@localhost/bazzar_test");
let db = Database::build(config).await;
let pool = db.pool();
let mut t = pool.begin().await.unwrap();
let first = test_stock(&mut t, None, None, None).await; let first = test_stock(&mut t, None, None, None).await;
let second = test_stock(&mut t, None, None, None).await; let second = test_stock(&mut t, None, None, None).await;
@ -272,7 +259,42 @@ mod tests {
.await .await
.unwrap(); .unwrap();
t.rollback().await.unwrap(); testx::db_rollback!(t);
assert_eq!(stocks, vec![first, second]); assert_eq!(stocks, vec![first, second]);
} }
#[actix::test]
async fn all_stocks() {
testx::db_t!(t);
let first = test_stock(&mut t, None, None, None).await;
let second = test_stock(&mut t, None, None, None).await;
let stocks: Vec<Stock> = super::all_stocks(AllStocks, &mut t).await.unwrap();
testx::db_rollback!(t);
assert_eq!(stocks, vec![first, second]);
}
#[actix::test]
async fn delete_stock() {
testx::db_t!(t);
let first = test_stock(&mut t, None, None, None).await;
let second = test_stock(&mut t, None, None, None).await;
let deleted: Option<Stock> = super::delete_stock(
DeleteStock {
stock_id: second.id,
},
&mut t,
)
.await
.unwrap();
// let reloaded = super::Stock
testx::db_rollback!(t);
assert_eq!(deleted, Some(second));
assert_ne!(deleted, Some(first));
}
} }

View File

@ -1,6 +1,5 @@
use actix::Message; use actix::Message;
use model::{AccountId, Audience, Token}; use model::{AccountId, Audience, Token};
use sqlx::PgPool;
use crate::{db_async_handler, Result}; use crate::{db_async_handler, Result};
@ -36,16 +35,19 @@ pub struct TokenByJti {
pub jti: uuid::Uuid, pub jti: uuid::Uuid,
} }
db_async_handler!(TokenByJti, token_by_jti, Token); db_async_handler!(TokenByJti, token_by_jti, Token, inner_token_by_jti);
pub(crate) async fn token_by_jti(msg: TokenByJti, pool: PgPool) -> Result<Token> { pub(crate) async fn token_by_jti(
msg: TokenByJti,
t: &mut sqlx::Transaction<'_, sqlx::Postgres>,
) -> Result<Token> {
sqlx::query_as(r#" sqlx::query_as(r#"
SELECT id, customer_id, role, issuer, subject, audience, expiration_time, not_before_time, issued_at_time, jwt_id SELECT id, customer_id, role, issuer, subject, audience, expiration_time, not_before_time, issued_at_time, jwt_id
FROM tokens FROM tokens
WHERE jwt_id = $1 AND expiration_time > now() WHERE jwt_id = $1 AND expiration_time > now()
"#) "#)
.bind(msg.jti) .bind(msg.jti)
.fetch_one(&pool) .fetch_one(t)
.await .await
.map_err(|e| { .map_err(|e| {
log::error!("{e:?}"); log::error!("{e:?}");
@ -62,9 +64,12 @@ pub struct CreateToken {
pub audience: Audience, pub audience: Audience,
} }
db_async_handler!(CreateToken, create_token, Token); db_async_handler!(CreateToken, create_token, Token, inner_create_token);
pub(crate) async fn create_token(msg: CreateToken, pool: PgPool) -> Result<Token> { pub(crate) async fn create_token(
msg: CreateToken,
t: &mut sqlx::Transaction<'_, sqlx::Postgres>,
) -> Result<Token> {
let CreateToken { let CreateToken {
customer_id, customer_id,
role, role,
@ -80,7 +85,7 @@ RETURNING id, customer_id, role, issuer, subject, audience, expiration_time, not
.bind(role) .bind(role)
.bind(subject) .bind(subject)
.bind(audience) .bind(audience)
.fetch_one(&pool) .fetch_one(t)
.await .await
.map_err(|e| { .map_err(|e| {
log::error!("{e:?}"); log::error!("{e:?}");
@ -98,9 +103,17 @@ pub struct CreateExtendedToken {
pub expiration_time: chrono::NaiveDateTime, pub expiration_time: chrono::NaiveDateTime,
} }
db_async_handler!(CreateExtendedToken, create_extended_token, Token); db_async_handler!(
CreateExtendedToken,
create_extended_token,
Token,
inner_create_extended_token
);
pub(crate) async fn create_extended_token(msg: CreateExtendedToken, pool: PgPool) -> Result<Token> { pub(crate) async fn create_extended_token(
msg: CreateExtendedToken,
t: &mut sqlx::Transaction<'_, sqlx::Postgres>,
) -> Result<Token> {
let CreateExtendedToken { let CreateExtendedToken {
customer_id, customer_id,
role, role,
@ -118,7 +131,7 @@ RETURNING id, customer_id, role, issuer, subject, audience, expiration_time, not
.bind(subject) .bind(subject)
.bind(audience) .bind(audience)
.bind(expiration_time) .bind(expiration_time)
.fetch_one(&pool) .fetch_one(t)
.await .await
.map_err(|e| { .map_err(|e| {
log::error!("{e:?}"); log::error!("{e:?}");
@ -128,7 +141,6 @@ RETURNING id, customer_id, role, issuer, subject, audience, expiration_time, not
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use actix::Addr;
use config::UpdateConfig; use config::UpdateConfig;
use fake::Fake; use fake::Fake;
use model::*; use model::*;
@ -140,25 +152,27 @@ mod tests {
impl UpdateConfig for NoOpts {} impl UpdateConfig for NoOpts {}
async fn test_create_account(db: Addr<Database>) -> FullAccount { async fn test_create_account(t: &mut sqlx::Transaction<'_, sqlx::Postgres>) -> FullAccount {
use fake::faker::internet::en; use fake::faker::internet::en;
let login: String = en::Username().fake(); let login: String = en::Username().fake();
let email: String = en::FreeEmail().fake(); let email: String = en::FreeEmail().fake();
let hash: String = en::Password(10..20).fake(); let hash: String = en::Password(10..20).fake();
db.send(CreateAccount { crate::create_account(
CreateAccount {
email: Email::new(email), email: Email::new(email),
login: Login::new(login), login: Login::new(login),
pass_hash: PassHash::new(hash), pass_hash: PassHash::new(hash),
role: Role::Admin, role: Role::Admin,
}) },
t,
)
.await .await
.unwrap() .unwrap()
.unwrap()
} }
async fn test_create_token_extended( async fn test_create_token_extended(
db: Addr<Database>, t: &mut sqlx::Transaction<'_, sqlx::Postgres>,
customer_id: Option<Uuid>, customer_id: Option<Uuid>,
role: Option<Role>, role: Option<Role>,
subject: Option<AccountId>, subject: Option<AccountId>,
@ -169,93 +183,77 @@ mod tests {
let role = role.unwrap_or_else(|| Role::Admin); let role = role.unwrap_or_else(|| Role::Admin);
let subject = match subject { let subject = match subject {
Some(id) => id, Some(id) => id,
_ => test_create_account(db.clone()).await.id, _ => test_create_account(t).await.id,
}; };
let audience = audience.unwrap_or_else(|| Audience::Web); let audience = audience.unwrap_or_else(|| Audience::Web);
let expiration_time = expiration_time let expiration_time = expiration_time
.unwrap_or_else(|| (chrono::Utc::now() + chrono::Duration::days(60)).naive_utc()); .unwrap_or_else(|| (chrono::Utc::now() + chrono::Duration::days(60)).naive_utc());
db.send(CreateExtendedToken { super::create_extended_token(
CreateExtendedToken {
customer_id, customer_id,
role, role,
subject, subject,
audience, audience,
expiration_time, expiration_time,
}) },
t,
)
.await .await
.unwrap() .unwrap()
.unwrap()
} }
#[actix::test] #[actix::test]
async fn create_token() { async fn create_token() {
let config = config::default_load(&mut NoOpts); testx::db_t!(t);
config
.lock()
.database_mut()
.set_url("postgres://postgres@localhost/bazzar_test");
let db = Database::build(config).await.start(); super::create_token(
CreateToken {
db.send(CreateToken {
customer_id: Uuid::new_v4(), customer_id: Uuid::new_v4(),
role: Role::Admin, role: Role::Admin,
subject: test_create_account(db.clone()).await.id, subject: test_create_account(&mut t).await.id,
audience: Audience::Web, audience: Audience::Web,
}) },
&mut t,
)
.await .await
.unwrap()
.unwrap(); .unwrap();
} }
#[actix::test] #[actix::test]
async fn create_extended_token() { async fn create_extended_token() {
let config = config::default_load(&mut NoOpts); testx::db_t!(t);
config
.lock()
.database_mut()
.set_url("postgres://postgres@localhost/bazzar_test");
let db = Database::build(config).await.start(); test_create_account(&mut t).await;
test_create_account(db).await; testx::db_rollback!(t);
} }
#[actix::test] #[actix::test]
async fn find_by_jti() { async fn find_by_jti() {
let config = config::default_load(&mut NoOpts); testx::db_t!(t);
config
.lock()
.database_mut()
.set_url("postgres://postgres@localhost/bazzar_test");
let db = Database::build(config).await.start(); let original = test_create_token_extended(&mut t, None, None, None, None, None).await;
let original = test_create_token_extended(db.clone(), None, None, None, None, None).await; let found = super::token_by_jti(
TokenByJti {
let found = db
.send(TokenByJti {
jti: original.jwt_id, jti: original.jwt_id,
}) },
&mut t,
)
.await .await
.unwrap()
.unwrap(); .unwrap();
testx::db_rollback!(t);
assert_eq!(found, original); assert_eq!(found, original);
} }
#[actix::test] #[actix::test]
async fn find_by_jti_expired() { async fn find_by_jti_expired() {
let config = config::default_load(&mut NoOpts); testx::db_t!(t);
config
.lock()
.database_mut()
.set_url("postgres://postgres@localhost/bazzar_test");
let db = Database::build(config).await.start();
let original = test_create_token_extended( let original = test_create_token_extended(
db.clone(), &mut t,
None, None,
None, None,
None, None,
@ -264,13 +262,15 @@ mod tests {
) )
.await; .await;
let found = db let found = super::token_by_jti(
.send(TokenByJti { TokenByJti {
jti: original.jwt_id, jti: original.jwt_id,
}) },
.await &mut t,
.unwrap(); )
.await;
testx::db_rollback!(t);
assert_eq!(found, Err(crate::Error::Token(super::Error::Jti))); assert_eq!(found, Err(crate::Error::Token(super::Error::Jti)));
} }
} }

View File

@ -862,7 +862,7 @@ pub struct Product {
#[cfg_attr(feature = "dummy", derive(fake::Dummy))] #[cfg_attr(feature = "dummy", derive(fake::Dummy))]
#[cfg_attr(feature = "db", derive(sqlx::Type))] #[cfg_attr(feature = "db", derive(sqlx::Type))]
#[cfg_attr(feature = "db", sqlx(transparent))] #[cfg_attr(feature = "db", sqlx(transparent))]
#[derive(Debug, PartialEq, Serialize, Deserialize)] #[derive(Debug, PartialEq, Copy, Clone, Serialize, Deserialize)]
#[serde(transparent)] #[serde(transparent)]
pub struct StockId(pub RecordId); pub struct StockId(pub RecordId);

6
shared/testx/Cargo.toml Normal file
View File

@ -0,0 +1,6 @@
[package]
name = "testx"
version = "0.1.0"
edition = "2021"
[dependencies]

21
shared/testx/src/lib.rs Normal file
View File

@ -0,0 +1,21 @@
#[macro_export]
macro_rules! db_t {
($t: ident) => {
let config = config::default_load(&mut NoOpts);
config
.lock()
.database_mut()
.set_url("postgres://postgres@localhost/bazzar_test");
let db = Database::build(config).await;
let pool = db.pool();
let mut $t = pool.begin().await.unwrap();
};
}
#[macro_export]
macro_rules! db_rollback {
($t: expr) => {
$t.rollback().await.unwrap();
};
}