feat: wip test helper
This commit is contained in:
parent
b27bdb6daa
commit
00b1b87da4
27
Cargo.lock
generated
27
Cargo.lock
generated
@ -757,10 +757,12 @@ dependencies = [
|
||||
"chrono",
|
||||
"dotenv",
|
||||
"futures-util",
|
||||
"idna 1.0.2",
|
||||
"lettre",
|
||||
"pico-args",
|
||||
"quick-xml",
|
||||
"rand",
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sqlx",
|
||||
@ -1714,23 +1716,24 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "1.0.3"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e"
|
||||
checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
|
||||
dependencies = [
|
||||
"idna_adapter",
|
||||
"smallvec",
|
||||
"utf8_iter",
|
||||
"unicode-bidi",
|
||||
"unicode-normalization",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna_adapter"
|
||||
version = "1.2.0"
|
||||
name = "idna"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71"
|
||||
checksum = "bd69211b9b519e98303c015e21a007e293db403b6c85b9b124e133d25e242cdd"
|
||||
dependencies = [
|
||||
"icu_normalizer",
|
||||
"icu_properties",
|
||||
"smallvec",
|
||||
"utf8_iter",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1846,7 +1849,7 @@ dependencies = [
|
||||
"futures-util",
|
||||
"hostname",
|
||||
"httpdate",
|
||||
"idna",
|
||||
"idna 1.0.2",
|
||||
"mime",
|
||||
"native-tls",
|
||||
"nom",
|
||||
@ -3058,12 +3061,12 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "2.5.4"
|
||||
version = "2.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60"
|
||||
checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c"
|
||||
dependencies = [
|
||||
"form_urlencoded",
|
||||
"idna",
|
||||
"idna 0.5.0",
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
|
@ -30,6 +30,8 @@ actix-web-static-files = "4.0"
|
||||
static-files = "0.2.1"
|
||||
zxcvbn = "3.1.0"
|
||||
thiserror = "1.0.63"
|
||||
idna = "=1.0.2"
|
||||
regex = "1.11.1"
|
||||
|
||||
[build-dependencies]
|
||||
built = "0.7.4"
|
||||
|
@ -4,6 +4,7 @@ pub mod password_help;
|
||||
pub mod token_generation;
|
||||
pub mod event_planning_template;
|
||||
mod application_error;
|
||||
pub mod test_helper;
|
||||
|
||||
pub use application_error::ApplicationError;
|
||||
use chrono::{NaiveDate, Utc};
|
||||
|
128
src/utils/test_helper/mod.rs
Normal file
128
src/utils/test_helper/mod.rs
Normal file
@ -0,0 +1,128 @@
|
||||
use std::{cell::OnceCell, env, str::FromStr, sync::Arc};
|
||||
|
||||
use rand::{distributions::Alphanumeric, thread_rng, Rng};
|
||||
use regex::{Captures, Regex};
|
||||
use sqlx::{postgres::{PgConnectOptions, PgPoolOptions}, Connection, Executor, PgConnection, PgPool};
|
||||
|
||||
|
||||
pub struct DbTestContext {
|
||||
//pub app: Router,
|
||||
pub db_pool: PgPool,
|
||||
}
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn db_test(_: TokenStream, item: TokenStream) -> TokenStream {
|
||||
let input = parse_macro_input!(item as ItemFn);
|
||||
let test_name = input.sig.ident.clone();
|
||||
let test_arguments = input.sig.inputs;
|
||||
let test_block = input.block;
|
||||
let inner_test_name = syn::Ident::new(
|
||||
format!("inner_{}", test_name).as_str(),
|
||||
input.sig.ident.span(),
|
||||
);
|
||||
|
||||
let setup = quote! {
|
||||
let context = abc_web::test_helpers::setup().await;
|
||||
};
|
||||
|
||||
let teardown = quote! {
|
||||
abc_web::test_helpers::teardown(context).await;
|
||||
};
|
||||
|
||||
let output = quote!(
|
||||
#[::tokio::test]
|
||||
async fn #test_name() {
|
||||
#setup
|
||||
async fn #inner_test_name(#test_arguments) #test_block
|
||||
#inner_test_name(&context).await;
|
||||
#teardown
|
||||
}
|
||||
);
|
||||
|
||||
TokenStream::from(output)
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub async fn setup() -> DbTestContext {
|
||||
//let init_config: OnceCell<Config> = OnceCell::new();
|
||||
//let config = init_config.get_or_init(|| load_config(&Environment::Test).unwrap());
|
||||
|
||||
let test_db_pool = setup_db(&env::var("DATABASE_URL").unwrap()).await;
|
||||
|
||||
//let app = init_routes(AppState {
|
||||
// db_pool: test_db_pool.clone(),
|
||||
//});
|
||||
|
||||
DbTestContext {
|
||||
//app,
|
||||
db_pool: test_db_pool,
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub async fn teardown(context: DbTestContext) {
|
||||
//drop(context.app);
|
||||
|
||||
teardown_db(context.db_pool);
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub async fn setup_db(url: &str) -> PgPool {
|
||||
let test_db_config = prepare_db(url).await;
|
||||
|
||||
let pool = PgPoolOptions::new()
|
||||
.connect(url)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
pool
|
||||
}
|
||||
|
||||
/// Drops a dedicated database for a test case.
|
||||
///
|
||||
/// This function is automatically called by the [`abc-macros::db_test`] macro. It ensures test-specific database are cleaned up after each test run so we don't end up with large numbers of unused databases.
|
||||
pub async fn teardown_db(pool: PgPool) {
|
||||
let cloned_pool = pool.clone();
|
||||
//let mut connect_options = pool.connect_options();
|
||||
//let db_config = Arc::make_mut(&mut connect_options);
|
||||
let db_config = cloned_pool.connect_options();
|
||||
|
||||
drop(pool);
|
||||
|
||||
let root_db_config = db_config.clone().database("postgres");
|
||||
let mut connection: PgConnection = Connection::connect_with(&root_db_config).await.unwrap();
|
||||
|
||||
let test_db_name = db_config.get_database().unwrap();
|
||||
|
||||
let query = format!("DROP DATABASE IF EXISTS {}", test_db_name);
|
||||
connection.execute(query.as_str()).await.unwrap();
|
||||
}
|
||||
|
||||
async fn prepare_db(url: &str) -> String {
|
||||
let db_config = PgConnectOptions::from_str(url).expect("Invalid DATABASE_URL!");
|
||||
let db_name = db_config.get_database().unwrap();
|
||||
|
||||
let root_db_config = db_config.clone().database("postgres");
|
||||
let mut connection: PgConnection = Connection::connect_with(&root_db_config).await.unwrap();
|
||||
|
||||
let test_db_name = build_test_db_name(db_name);
|
||||
|
||||
let query = format!("CREATE DATABASE {} TEMPLATE {}", test_db_name, db_name);
|
||||
connection.execute(query.as_str()).await.unwrap();
|
||||
|
||||
let regex = Regex::new(r"(.+)\/(.+$)").unwrap();
|
||||
let test_db_url = regex.replace(url, |caps: &Captures| {
|
||||
format!("{}/{}", &caps[1], test_db_name)
|
||||
});
|
||||
|
||||
test_db_url.to_string()
|
||||
}
|
||||
|
||||
fn build_test_db_name(base_name: &str) -> String {
|
||||
let test_db_suffix: String = thread_rng()
|
||||
.sample_iter(&Alphanumeric)
|
||||
.take(30)
|
||||
.map(char::from)
|
||||
.collect();
|
||||
format!("{}_{}", base_name, test_db_suffix).to_lowercase()
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user