diff --git a/tests/test.rs b/tests/test.rs new file mode 100644 index 0000000..d947449 --- /dev/null +++ b/tests/test.rs @@ -0,0 +1,196 @@ +use std::io::Write; + +use common_multipart_rfc7578::client::multipart::{Body as MultipartBody, Form as MultipartForm}; +use tower::ServiceExt; + +use textsender_api::db; + +mod db_mgr { + use std::str::FromStr; + + pub const LIMIT: usize = 6; + + pub async fn get_pool() -> Result { + let tm_db_url = textsender_models::envy::environment::get_db_url() + .await + .value; + let tm_options = sqlx::postgres::PgConnectOptions::from_str(&tm_db_url).unwrap(); + sqlx::PgPool::connect_with(tm_options).await + } + + pub async fn generate_db_name() -> String { + let db_name = + get_database_name().await.unwrap() + &"_" + &uuid::Uuid::new_v4().to_string()[..LIMIT]; + db_name + } + + pub async fn connect_to_db(db_name: &str) -> Result { + let db_url = textsender_models::envy::environment::get_db_url() + .await + .value; + let options = sqlx::postgres::PgConnectOptions::from_str(&db_url)?.database(db_name); + sqlx::PgPool::connect_with(options).await + } + + pub async fn create_database( + template_pool: &sqlx::PgPool, + db_name: &str, + ) -> Result<(), sqlx::Error> { + let create_query = format!("CREATE DATABASE {}", db_name); + match sqlx::query(&create_query).execute(template_pool).await { + Ok(_) => Ok(()), + Err(e) => Err(e), + } + } + + // Function to drop a database + pub async fn drop_database( + template_pool: &sqlx::PgPool, + db_name: &str, + ) -> Result<(), sqlx::Error> { + let drop_query = format!("DROP DATABASE IF EXISTS {} WITH (FORCE)", db_name); + sqlx::query(&drop_query).execute(template_pool).await?; + Ok(()) + } + + pub async fn get_database_name() -> Result> { + let database_url = textsender_models::envy::environment::get_db_url() + .await + .value; + let parsed_url = url::Url::parse(&database_url)?; + + if parsed_url.scheme() == "postgres" || parsed_url.scheme() == "postgresql" { + match parsed_url + .path_segments() + .and_then(|segments| segments.last().map(|s| s.to_string())) + { + Some(sss) => Ok(sss), + None => Err("Error parsing".into()), + } + } else { + // Handle other database types if needed + Err("Error parsing".into()) + } + } + + pub async fn migrations(pool: &sqlx::PgPool) { + // Run migrations using the sqlx::migrate! macro + // Assumes your test migrations are in a ./test_migrations folder relative to Cargo.toml + sqlx::migrate!("./migrations") + .run(pool) + .await + .expect("Failed to run migrations"); + } +} + +mod init { + pub async fn app(pool: sqlx::PgPool) -> axum::Router { + textsender_api::config::init::routes() + .await + .layer(axum::Extension(pool)) + .layer(axum::extract::DefaultBodyLimit::max(1024 * 1024 * 1024)) + .layer(tower_http::timeout::TimeoutLayer::new( + std::time::Duration::from_secs(300), + )) + } +} + +mod util { + pub async fn resp_to_bytes( + response: axum::response::Response, + ) -> Result { + axum::body::to_bytes(response.into_body(), std::usize::MAX).await + } + + pub async fn get_resp_data(response: axum::response::Response) -> Data + where + Data: for<'a> serde::Deserialize<'a>, + { + let body = resp_to_bytes(response).await.unwrap(); + serde_json::from_slice(&body).unwrap() + } + + pub async fn format_url_with_value(endpoint: &str, value: &uuid::Uuid) -> String { + let last = endpoint.len() - 5; + format!("{}/{value}", &endpoint[0..last]) + } +} + +pub fn token_fields() -> (String, String, String) { + ( + String::from("What a twist!"), + String::from("icarus_test"), + String::from("icarus"), + ) +} + +pub const TEST_USER_ID: uuid::Uuid = uuid::uuid!("cc938368-615a-4694-b2ca-6e122fa31c52"); + +pub async fn test_token() -> Result { + let key: String = textsender_models::envy::environment::get_secret_main_key() + .await + .value; + let (message, issuer, audience) = token_fields(); + + let token_resource = textsender_models::token::TokenResource { + message: message, + issuer: issuer, + audiences: vec![audience], + user_id: TEST_USER_ID, + }; + + match textsender_models::token::create_token(&key, &token_resource, time::Duration::hours(1)) { + Ok((access_token, _some_time)) => Ok(access_token), + Err(err) => Err(err), + } +} + +pub async fn bearer_auth() -> String { + let token = match test_token().await { + Ok(access_token) => access_token, + Err(err) => { + assert!(false, "Error: {err:?}"); + String::new() + } + }; + + format!("Bearer {token}") +} + +mod request {} + +#[tokio::test] +async fn test_create_contact() { + let tm_pool = db_mgr::get_pool().await.unwrap(); + let db_name = db_mgr::generate_db_name().await; + + match db_mgr::create_database(&tm_pool, &db_name).await { + Ok(_) => { + println!("Success"); + } + Err(err) => { + assert!(false, "Error: {:?}", err); + } + } + + let pool = db_mgr::connect_to_db(&db_name).await.unwrap(); + db::migrations(&pool).await; + + let app = init::app(pool).await; + + // Send request + match request::create_contact(&app).await { + Ok(response) => { + let resp = util::get_resp_data::< + textsender_api::caller::contact::response::AddContactResponse, + >(response) + .await; + assert_eq!(false, resp.data.is_empty(), "Should not be empty"); + } + Err(err) => { + assert!(false, "Error: {:?}", err); + } + }; + + let _ = db_mgr::drop_database(&tm_pool, &db_name).await; +}