From 4fb9505f65a48fa62348ada3660c790e4d13cba9 Mon Sep 17 00:00:00 2001 From: phoenix Date: Thu, 3 Apr 2025 14:41:16 -0400 Subject: [PATCH 01/31] Updated .env.sample --- .env.sample | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.env.sample b/.env.sample index 1625b7a..5cad34d 100644 --- a/.env.sample +++ b/.env.sample @@ -1,2 +1,2 @@ DATABASE_URL=postgres://username:password@localhost/database_name -TEST_DATABASE_URL=postgres://username:password@localhost/database_name_test +TEST_DATABASE_URL=postgres://icarus_op_test:password@localhost/icarus_auth_test -- 2.43.0 From 943d258cc03f9278fc662b7ada4ba808d6d08bfc Mon Sep 17 00:00:00 2001 From: phoenix Date: Thu, 3 Apr 2025 15:13:45 -0400 Subject: [PATCH 02/31] Updated migration --- migrations/20250402221858_init_migrate.sql | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/migrations/20250402221858_init_migrate.sql b/migrations/20250402221858_init_migrate.sql index 8ddc1d3..9bf6818 100644 --- a/migrations/20250402221858_init_migrate.sql +++ b/migrations/20250402221858_init_migrate.sql @@ -1 +1,13 @@ -- Add migration script here +-- CREATE DATABASE icarus_auth_test; + +-- ALTER DATABASE icarus_auth_test OWNER TO icarus_op_test; + +CREATE EXTENSION IF NOT EXISTS pgcrypto; + +CREATE TABLE IF NOT EXISTS "user" ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + username TEXT NOT NULL, + password TEXT NOT NULL, + date_created TIMESTAMPTZ NOT NULL DEFAULT NOW() +); \ No newline at end of file -- 2.43.0 From 9cfec4fa27529cf67072295923813da5061bf17f Mon Sep 17 00:00:00 2001 From: phoenix Date: Thu, 3 Apr 2025 15:21:13 -0400 Subject: [PATCH 03/31] Integrated migrations --- src/main.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main.rs b/src/main.rs index 3e254b3..a079bca 100644 --- a/src/main.rs +++ b/src/main.rs @@ -37,6 +37,13 @@ async fn app() -> Router { .await .expect("Failed to create pool"); + // Run migrations using the sqlx::migrate! macro + // Assumes your migrations are in a ./migrations folder relative to Cargo.toml + sqlx::migrate!("./migrations") + .run(&pool) + .await + .expect("Failed to run migrations on testcontainer DB"); + routes().await.layer(axum::Extension(pool)) } -- 2.43.0 From 5943a3342cbc31cbe1a4fe3e7b5a7b9f74d51345 Mon Sep 17 00:00:00 2001 From: phoenix Date: Thu, 3 Apr 2025 15:52:24 -0400 Subject: [PATCH 04/31] Added uuid support --- Cargo.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index fac1e92..061d402 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,8 +11,9 @@ tokio = { version = "1.44.1", features = ["rt-multi-thread"] } tracing-subscriber = { version = "0.3.19" } tower = { version = "0.5.2" } hyper = { version = "1.6.0" } -sqlx = { version = "0.8.3", features = ["postgres", "runtime-tokio-native-tls"] } +sqlx = { version = "0.8.3", features = ["postgres", "runtime-tokio-native-tls", "uuid"] } dotenvy = { version = "0.15.7" } +uuid = { version = "1.16.0" } icarus_models = { git = "ssh://git@git.kundeng.us/phoenix/icarus_models.git", tag = "v0.2.0" } [dev-dependencies] -- 2.43.0 From 35c35660d8b5ea10eae03bbf4140328e3fc2aecd Mon Sep 17 00:00:00 2001 From: phoenix Date: Thu, 3 Apr 2025 16:09:01 -0400 Subject: [PATCH 05/31] Added support to serialize uuid --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 061d402..80fcf2e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ tower = { version = "0.5.2" } hyper = { version = "1.6.0" } sqlx = { version = "0.8.3", features = ["postgres", "runtime-tokio-native-tls", "uuid"] } dotenvy = { version = "0.15.7" } -uuid = { version = "1.16.0" } +uuid = { version = "1.16.0", features = ["v4", "serde"] } icarus_models = { git = "ssh://git@git.kundeng.us/phoenix/icarus_models.git", tag = "v0.2.0" } [dev-dependencies] -- 2.43.0 From 07cd30f8976c561d0a5c56142626a66654d331e9 Mon Sep 17 00:00:00 2001 From: phoenix Date: Thu, 3 Apr 2025 16:09:57 -0400 Subject: [PATCH 06/31] Saving changes --- src/callers/register.rs | 44 +++++++++++++++++++++++++++++++++++++++-- src/models/common.rs | 3 +++ 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/src/callers/register.rs b/src/callers/register.rs index 7a1299a..1330ef4 100644 --- a/src/callers/register.rs +++ b/src/callers/register.rs @@ -1,12 +1,52 @@ use axum::{Json, http::StatusCode}; +// use sqlx::{Executor, PgPool, Row, postgres::PgPoolOptions}; // Added Row for potential use use crate::models; pub async fn register_user( + axum::Extension(pool): axum::Extension, Json(payload): Json, ) -> (StatusCode, Json) { - let user = models::common::User { + let mut user = models::common::User { + id: uuid::Uuid::nil(), username: payload.username.clone(), + password: payload.password.clone(), }; - (StatusCode::CREATED, Json(user)) + + let insert_sql = "INSERT INTO \"user\" (username, password) VALUES ($1, $2) RETURNING id"; + println!("SQL: {:?}", insert_sql); + /* + sqlx::query(insert_sql) + .bind(&user.username) + .bind(&user.password) + .execute(&pool) + .await; + */ + + /* + let returned_id: uuid::Uuid = sqlx::query_scalar(insert_sql) + .bind(&user.username) + .bind(&user.password) + .fetch_one(&pool).await? // fetch_one expects exactly one row + */ + let id = match sqlx::query_scalar(insert_sql) + .bind(&user.username) // Bind the input message securely + .bind(&user.password) + .fetch_one(&pool) // Execute and expect exactly ONE row with ONE column back + .await + { + Ok(o) => o, + _ => { + uuid::Uuid::nil() + // (StatusCode::BAD_REQUEST, Json(user)) + } + }; + + if id != uuid::Uuid::nil() { + println!("User inserted."); + user.id = id; + (StatusCode::CREATED, Json(user)) + } else { + (StatusCode::BAD_REQUEST, Json(user)) + } } diff --git a/src/models/common.rs b/src/models/common.rs index cda15f2..6838cfb 100644 --- a/src/models/common.rs +++ b/src/models/common.rs @@ -3,9 +3,12 @@ use serde::{Deserialize, Serialize}; #[derive(Deserialize)] pub struct CreateUser { pub username: String, + pub password: String, } #[derive(Serialize)] pub struct User { + pub id: uuid::Uuid, pub username: String, + pub password: String, } -- 2.43.0 From 104b1827a6be6918a15cf6a7704ad577ef0d630e Mon Sep 17 00:00:00 2001 From: phoenix Date: Thu, 3 Apr 2025 16:13:18 -0400 Subject: [PATCH 07/31] Updating migration commands --- run_migrations.txt | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/run_migrations.txt b/run_migrations.txt index ae8892a..f29a9f8 100644 --- a/run_migrations.txt +++ b/run_migrations.txt @@ -1,3 +1,15 @@ cargo install sqlx-cli sqlx migrate add init_migration sqlx migrate run + +# Create +sqlx database create + +# Drop +sqlx database drop + +# setup +sqlx database setup + +# Reset +sqlx database reset \ No newline at end of file -- 2.43.0 From aec7fff676a163f812806198ea93694c99b021d1 Mon Sep 17 00:00:00 2001 From: KD Date: Thu, 3 Apr 2025 16:40:02 -0400 Subject: [PATCH 08/31] Updated instructions --- run_migrations.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/run_migrations.txt b/run_migrations.txt index f29a9f8..66d3518 100644 --- a/run_migrations.txt +++ b/run_migrations.txt @@ -1,3 +1,7 @@ +# Make sure role has CREATEDB +ALTER ROLE username_that_needs_permission CREATEDB; + +# Install migrations cargo install sqlx-cli sqlx migrate add init_migration sqlx migrate run @@ -12,4 +16,4 @@ sqlx database drop sqlx database setup # Reset -sqlx database reset \ No newline at end of file +sqlx database reset -- 2.43.0 From 6c2d7264dc1dd7b084b65dee5ba7b0ad2b692be1 Mon Sep 17 00:00:00 2001 From: KD Date: Thu, 3 Apr 2025 16:51:35 -0400 Subject: [PATCH 09/31] Removing code --- src/main.rs | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/src/main.rs b/src/main.rs index a079bca..64534e0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,11 +2,9 @@ use axum::{ Router, routing::{get, post}, }; -// use std::net::SocketAddr; use icarus_auth::callers; use icarus_auth::config; -// use sqlx::Postgres; #[tokio::main] async fn main() { @@ -52,14 +50,9 @@ mod tests { use super::*; use axum::{ body::Body, - // extract::connect_info::MockConnectInfo, http::{Request, StatusCode}, }; use http_body_util::BodyExt; - // use http_body_util::BodyExt; // for `collect` - // use serde_json::{Value, json}; - // use tokio::net::TcpListener; - // use tower::{Service, ServiceExt}; // for `call`, `oneshot`, and `ready` use tower::ServiceExt; // for `call`, `oneshot`, and `ready` #[tokio::test] @@ -80,23 +73,6 @@ mod tests { assert_eq!(response.status(), StatusCode::OK); - /* - match response.into_body().collect().await { - Ok(o) => { - let parsed: String = match String::from_utf8(o.to_bytes()) { - Ok(s) => s, - Err(err) => { - String::new() - } - }; - } - Err(err) => { - assert!(false, - "Error: {:?}", err.to_string()); - } - } - */ - let body = response.into_body().collect().await.unwrap().to_bytes(); assert_eq!(&body[..], b"Hello, World!"); } -- 2.43.0 From dba7d23a40abe07066e9d5d4b7b04931a4e117c0 Mon Sep 17 00:00:00 2001 From: KD Date: Thu, 3 Apr 2025 16:57:31 -0400 Subject: [PATCH 10/31] Updating workflow changes --- .gitea/workflows/workflow.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitea/workflows/workflow.yml b/.gitea/workflows/workflow.yml index acfa95b..bf591c4 100644 --- a/.gitea/workflows/workflow.yml +++ b/.gitea/workflows/workflow.yml @@ -78,8 +78,8 @@ jobs: echo "Running database migrations..." # ===> IMPORTANT: Replace placeholder below with your actual migration command <=== # Example: Install and run sqlx-cli - # cargo install sqlx-cli --no-default-features --features native-tls,postgres - # sqlx database setup --database-url $TEST_DATABASE_URL + cargo install sqlx-cli --no-default-features --features native-tls,postgres + sqlx database setup --database-url $TEST_DATABASE_URL # Example: Install and run diesel_cli # cargo install diesel_cli --no-default-features --features postgres -- 2.43.0 From fe97131e7c53f17aa488cf803588419d7af40843 Mon Sep 17 00:00:00 2001 From: phoenix Date: Thu, 3 Apr 2025 17:27:57 -0400 Subject: [PATCH 11/31] Workflow changes --- .gitea/workflows/workflow.yml | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/.gitea/workflows/workflow.yml b/.gitea/workflows/workflow.yml index bf591c4..992cc5e 100644 --- a/.gitea/workflows/workflow.yml +++ b/.gitea/workflows/workflow.yml @@ -76,17 +76,8 @@ jobs: SSH_AUTH_SOCK: ${{ env.SSH_AUTH_SOCK }} run: | echo "Running database migrations..." - # ===> IMPORTANT: Replace placeholder below with your actual migration command <=== - # Example: Install and run sqlx-cli cargo install sqlx-cli --no-default-features --features native-tls,postgres sqlx database setup --database-url $TEST_DATABASE_URL - - # Example: Install and run diesel_cli - # cargo install diesel_cli --no-default-features --features postgres - # diesel migration run --database-url $TEST_DATABASE_URL - - # echo "[Placeholder] Your migration command goes here." - # ===> End of Placeholder <=== - name: Run tests env: # Define TEST_DATABASE_URL for tests to use @@ -159,4 +150,3 @@ jobs: eval $(ssh-agent -s) ssh-add -v ~/.ssh/icarus_models_deploy_key cargo build --release - -- 2.43.0 From b8e5b65704b71dba3c12bff0b0c09adae105d061 Mon Sep 17 00:00:00 2001 From: phoenix Date: Fri, 4 Apr 2025 10:09:54 -0400 Subject: [PATCH 12/31] Added dependencies to hash passwords --- Cargo.toml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 80fcf2e..f699178 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,9 +14,11 @@ hyper = { version = "1.6.0" } sqlx = { version = "0.8.3", features = ["postgres", "runtime-tokio-native-tls", "uuid"] } dotenvy = { version = "0.15.7" } uuid = { version = "1.16.0", features = ["v4", "serde"] } +argon2 = { version = "0.5.3", features = ["std"] } # Use the latest 0.5.x version +rand = { version = "0.9" } icarus_models = { git = "ssh://git@git.kundeng.us/phoenix/icarus_models.git", tag = "v0.2.0" } [dev-dependencies] -http-body-util = "0.1.3" +http-body-util = { version = "0.1.3" } reqwest = { version = "0.12.5", features = ["json"] } # For making HTTP requests in tests -once_cell = "1.19" # Useful for lazy initialization in tests/app setup +once_cell = { version = "1.19" } # Useful for lazy initialization in tests/app setup -- 2.43.0 From 6eed51a87653a839e273b4645b9e351fd67f9637 Mon Sep 17 00:00:00 2001 From: phoenix Date: Fri, 4 Apr 2025 10:29:36 -0400 Subject: [PATCH 13/31] Added hashing code --- src/hashing/mod.rs | 73 ++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 1 + 2 files changed, 74 insertions(+) create mode 100644 src/hashing/mod.rs diff --git a/src/hashing/mod.rs b/src/hashing/mod.rs new file mode 100644 index 0000000..eb7ed39 --- /dev/null +++ b/src/hashing/mod.rs @@ -0,0 +1,73 @@ +use argon2::{ + Argon2, // The Argon2 algorithm struct + PasswordVerifier, + password_hash::{ + PasswordHasher, + SaltString, + rand_core::OsRng, // Secure random number generator + }, +}; + +pub fn hash_password(password: &String) -> Result { + let password_bytes = password.as_bytes(); + + // Generate a random salt + // SaltString::generate uses OsRng internally for cryptographic security + let salt = SaltString::generate(&mut OsRng); + + // Create an Argon2 instance with default parameters (recommended) + // You could customize parameters here if needed, but defaults are strong + let argon2 = Argon2::default(); + + // Hash the password with the salt + // The output is a PasswordHash string format that includes algorithm, version, + // parameters, salt, and the hash itself. + let password_hash = argon2.hash_password(password_bytes, &salt)?.to_string(); + + Ok(password_hash) +} + +pub fn verify_password( + password_attempt: &String, + stored_hash: String, +) -> Result { + let password_bytes = password_attempt.as_bytes(); + + // Parse the stored hash string + // This extracts the salt, parameters, and hash digest + let parsed_hash = argon2::PasswordHash::new(stored_hash.as_str())?; + + // Create an Argon2 instance (it will use the parameters from the parsed hash) + let argon2 = Argon2::default(); + + // Verify the password against the parsed hash + // This automatically uses the correct salt and parameters embedded in `parsed_hash` + match argon2.verify_password(password_bytes, &parsed_hash) { + Ok(()) => Ok(true), // Passwords match + Err(argon2::password_hash::Error::Password) => Ok(false), // Passwords don't match + Err(e) => Err(e), // Some other error occurred (e.g., invalid hash format) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_hash_password() { + let some_password = String::from("somethingrandom"); + match hash_password(&some_password) { + Ok(p) => match verify_password(&some_password, p.clone()) { + Ok(res) => { + assert_eq!(res, true); + } + Err(err) => { + assert!(false, "Error: {:?}", err.to_string()); + } + }, + Err(eerr) => { + assert!(false, "Error: {:?}", eerr.to_string()); + } + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 641a39d..f1f9d66 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,6 @@ pub mod callers; pub mod config; +pub mod hashing; pub mod models; mod keys { -- 2.43.0 From 92ef6a5064f9a4afc2f875f4c66f4b29bdbc9dd2 Mon Sep 17 00:00:00 2001 From: phoenix Date: Fri, 4 Apr 2025 10:31:20 -0400 Subject: [PATCH 14/31] Updated migrations --- migrations/20250402221858_init_migrate.sql | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/migrations/20250402221858_init_migrate.sql b/migrations/20250402221858_init_migrate.sql index 9bf6818..16796d7 100644 --- a/migrations/20250402221858_init_migrate.sql +++ b/migrations/20250402221858_init_migrate.sql @@ -1,8 +1,4 @@ -- Add migration script here --- CREATE DATABASE icarus_auth_test; - --- ALTER DATABASE icarus_auth_test OWNER TO icarus_op_test; - CREATE EXTENSION IF NOT EXISTS pgcrypto; CREATE TABLE IF NOT EXISTS "user" ( @@ -10,4 +6,4 @@ CREATE TABLE IF NOT EXISTS "user" ( username TEXT NOT NULL, password TEXT NOT NULL, date_created TIMESTAMPTZ NOT NULL DEFAULT NOW() -); \ No newline at end of file +); -- 2.43.0 From 9d42981cd4cd4de3d2a7b91fc2b89708a099eed5 Mon Sep 17 00:00:00 2001 From: phoenix Date: Fri, 4 Apr 2025 11:11:46 -0400 Subject: [PATCH 15/31] Updated icarus_models --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index f699178..c014972 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ dotenvy = { version = "0.15.7" } uuid = { version = "1.16.0", features = ["v4", "serde"] } argon2 = { version = "0.5.3", features = ["std"] } # Use the latest 0.5.x version rand = { version = "0.9" } -icarus_models = { git = "ssh://git@git.kundeng.us/phoenix/icarus_models.git", tag = "v0.2.0" } +icarus_models = { git = "ssh://git@git.kundeng.us/phoenix/icarus_models.git", tag = "v0.3.0" } [dev-dependencies] http-body-util = { version = "0.1.3" } -- 2.43.0 From 24feec56af03723eb352dcda9dd38612fdaadbd4 Mon Sep 17 00:00:00 2001 From: phoenix Date: Fri, 4 Apr 2025 11:12:00 -0400 Subject: [PATCH 16/31] Cleanup --- src/callers/register.rs | 62 +++++++++++++++++------------------------ src/lib.rs | 1 + src/models/common.rs | 2 +- src/repo/mod.rs | 20 +++++++++++++ 4 files changed, 48 insertions(+), 37 deletions(-) create mode 100644 src/repo/mod.rs diff --git a/src/callers/register.rs b/src/callers/register.rs index 1330ef4..4436a98 100644 --- a/src/callers/register.rs +++ b/src/callers/register.rs @@ -1,52 +1,42 @@ use axum::{Json, http::StatusCode}; -// use sqlx::{Executor, PgPool, Row, postgres::PgPoolOptions}; // Added Row for potential use use crate::models; +use crate::repo; + +mod response { + use serde::{Deserialize, Serialize}; + + use crate::models; + + #[derive(Deserialize, Serialize)] + pub struct Response { + pub message: String, + pub data: models::common::User, + } +} pub async fn register_user( axum::Extension(pool): axum::Extension, Json(payload): Json, -) -> (StatusCode, Json) { +) -> (StatusCode, Json) { let mut user = models::common::User { id: uuid::Uuid::nil(), username: payload.username.clone(), password: payload.password.clone(), }; - let insert_sql = "INSERT INTO \"user\" (username, password) VALUES ($1, $2) RETURNING id"; - println!("SQL: {:?}", insert_sql); - /* - sqlx::query(insert_sql) - .bind(&user.username) - .bind(&user.password) - .execute(&pool) - .await; - */ - - /* - let returned_id: uuid::Uuid = sqlx::query_scalar(insert_sql) - .bind(&user.username) - .bind(&user.password) - .fetch_one(&pool).await? // fetch_one expects exactly one row - */ - let id = match sqlx::query_scalar(insert_sql) - .bind(&user.username) // Bind the input message securely - .bind(&user.password) - .fetch_one(&pool) // Execute and expect exactly ONE row with ONE column back - .await - { - Ok(o) => o, - _ => { - uuid::Uuid::nil() - // (StatusCode::BAD_REQUEST, Json(user)) + match repo::user::insert(&pool, &user).await { + Ok(id) => { + println!("User inserted."); + user.id = id; + (StatusCode::CREATED, Json(response::Response{ + message: String::from("User inserted"), + data: user, + })) } - }; - - if id != uuid::Uuid::nil() { - println!("User inserted."); - user.id = id; - (StatusCode::CREATED, Json(user)) - } else { - (StatusCode::BAD_REQUEST, Json(user)) + Err(err) => (StatusCode::BAD_REQUEST, Json(response::Response{ + message: err.to_string(), + data: user, + })) } } diff --git a/src/lib.rs b/src/lib.rs index f1f9d66..ab8bf15 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,6 +2,7 @@ pub mod callers; pub mod config; pub mod hashing; pub mod models; +pub mod repo; mod keys { pub const DBURL: &str = "DATABASE_URL"; diff --git a/src/models/common.rs b/src/models/common.rs index 6838cfb..8bf5ab7 100644 --- a/src/models/common.rs +++ b/src/models/common.rs @@ -6,7 +6,7 @@ pub struct CreateUser { pub password: String, } -#[derive(Serialize)] +#[derive(Deserialize, Serialize)] pub struct User { pub id: uuid::Uuid, pub username: String, diff --git a/src/repo/mod.rs b/src/repo/mod.rs new file mode 100644 index 0000000..95d3c7a --- /dev/null +++ b/src/repo/mod.rs @@ -0,0 +1,20 @@ +pub mod user { + use crate::models; + + pub async fn insert( + pool: &sqlx::PgPool, + user: &models::common::User, + ) -> Result { + let insert_sql = "INSERT INTO \"user\" (username, password) VALUES ($1, $2) RETURNING id"; + + match sqlx::query_scalar(insert_sql) + .bind(&user.username) // Bind the input message securely + .bind(&user.password) + .fetch_one(pool) // Execute and expect exactly ONE row with ONE column back + .await + { + Ok(o) => Ok(o), + Err(err) => Err(err), // _ => uuid::Uuid::nil(), + } + } +} -- 2.43.0 From 5cd45aa643fcdb09f8ed0025427fc3762a9b819a Mon Sep 17 00:00:00 2001 From: phoenix Date: Fri, 4 Apr 2025 11:15:55 -0400 Subject: [PATCH 17/31] Removed print statement --- src/callers/register.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/callers/register.rs b/src/callers/register.rs index 4436a98..0a569d4 100644 --- a/src/callers/register.rs +++ b/src/callers/register.rs @@ -27,7 +27,6 @@ pub async fn register_user( match repo::user::insert(&pool, &user).await { Ok(id) => { - println!("User inserted."); user.id = id; (StatusCode::CREATED, Json(response::Response{ message: String::from("User inserted"), -- 2.43.0 From 32e6355040faec9a1d7b4fa9a7315685e68a7624 Mon Sep 17 00:00:00 2001 From: phoenix Date: Fri, 4 Apr 2025 11:16:43 -0400 Subject: [PATCH 18/31] Code formatting --- src/callers/register.rs | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/callers/register.rs b/src/callers/register.rs index 0a569d4..1462583 100644 --- a/src/callers/register.rs +++ b/src/callers/register.rs @@ -28,14 +28,20 @@ pub async fn register_user( match repo::user::insert(&pool, &user).await { Ok(id) => { user.id = id; - (StatusCode::CREATED, Json(response::Response{ - message: String::from("User inserted"), - data: user, - })) + ( + StatusCode::CREATED, + Json(response::Response { + message: String::from("User inserted"), + data: user, + }), + ) } - Err(err) => (StatusCode::BAD_REQUEST, Json(response::Response{ - message: err.to_string(), - data: user, - })) + Err(err) => ( + StatusCode::BAD_REQUEST, + Json(response::Response { + message: err.to_string(), + data: user, + }), + ), } } -- 2.43.0 From 08d35c36805db40448311b74aa3e60de5bccaa70 Mon Sep 17 00:00:00 2001 From: phoenix Date: Fri, 4 Apr 2025 11:21:49 -0400 Subject: [PATCH 19/31] Updated helpful instructions --- run_migrations.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/run_migrations.txt b/run_migrations.txt index 66d3518..927b280 100644 --- a/run_migrations.txt +++ b/run_migrations.txt @@ -3,6 +3,12 @@ ALTER ROLE username_that_needs_permission CREATEDB; # Install migrations cargo install sqlx-cli + +# Make sure to populate DATABASE_URL with correct value. +# By default, the DATABASE_URL found in .env file will be used +export DATABASE_URL="postgres://icarus_op_test:password@localhost/icarus_auth_test" + +# init sqlx migrate add init_migration sqlx migrate run -- 2.43.0 From c9f17b936f08efa3cfbfac4aee9e3285d48287f7 Mon Sep 17 00:00:00 2001 From: phoenix Date: Fri, 4 Apr 2025 18:59:46 -0400 Subject: [PATCH 20/31] Added test for register endpoint with transactions --- src/main.rs | 137 ++++++++++++++++++++++++++++++++++--------- src/models/common.rs | 2 +- 2 files changed, 110 insertions(+), 29 deletions(-) diff --git a/src/main.rs b/src/main.rs index 64534e0..63a0e79 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,3 @@ -use axum::{ - Router, - routing::{get, post}, -}; - use icarus_auth::callers; use icarus_auth::config; @@ -11,7 +6,7 @@ async fn main() { // initialize tracing tracing_subscriber::fmt::init(); - let app = app().await; + let app = init::app().await; // run our app with hyper, listening globally on port 3000 let url = config::get_full(); @@ -19,30 +14,46 @@ async fn main() { axum::serve(listener, app).await.unwrap(); } -async fn routes() -> Router { - // build our application with a route - Router::new() - .route(callers::endpoints::DBTEST, get(callers::common::db_ping)) - .route(callers::endpoints::ROOT, get(callers::common::root)) - .route( - callers::endpoints::REGISTER, - post(callers::register::register_user), - ) +mod db { + pub async fn migrations(pool: &sqlx::PgPool) { + // Run migrations using the sqlx::migrate! macro + // Assumes your migrations are in a ./migrations folder relative to Cargo.toml + sqlx::migrate!("./migrations") + .run(pool) + .await + .expect("Failed to run migrations on testcontainer DB"); + } } -async fn app() -> Router { - let pool = icarus_auth::db_pool::create_pool() - .await - .expect("Failed to create pool"); +mod init { + use axum::{ + Router, + routing::{get, post}, + }; - // Run migrations using the sqlx::migrate! macro - // Assumes your migrations are in a ./migrations folder relative to Cargo.toml - sqlx::migrate!("./migrations") - .run(&pool) - .await - .expect("Failed to run migrations on testcontainer DB"); + use crate::callers; + use crate::db; - routes().await.layer(axum::Extension(pool)) + pub async fn routes() -> Router { + // build our application with a route + Router::new() + .route(callers::endpoints::DBTEST, get(callers::common::db_ping)) + .route(callers::endpoints::ROOT, get(callers::common::root)) + .route( + callers::endpoints::REGISTER, + post(callers::register::register_user), + ) + } + + pub async fn app() -> Router { + let pool = icarus_auth::db_pool::create_pool() + .await + .expect("Failed to create pool"); + + db::migrations(&pool).await; + + routes().await.layer(axum::Extension(pool)) + } } #[cfg(test)] @@ -53,11 +64,13 @@ mod tests { http::{Request, StatusCode}, }; use http_body_util::BodyExt; + // use reqwest; + use serde_json::json; use tower::ServiceExt; // for `call`, `oneshot`, and `ready` #[tokio::test] - async fn hello_world() { - let app = app().await; + async fn test_hello_world() { + let app = init::app().await; // `Router` implements `tower::Service>` so we can // call it like any tower service, no need to run an HTTP server. @@ -76,4 +89,72 @@ mod tests { let body = response.into_body().collect().await.unwrap().to_bytes(); assert_eq!(&body[..], b"Hello, World!"); } + + #[tokio::test] + async fn test_register_user() { + let pool = icarus_auth::db_pool::create_pool() + .await + .expect("Failed to create pool"); + db::migrations(&pool).await; + + let mut tx = pool.begin().await.unwrap(); + let app = init::routes().await.layer(axum::Extension(pool)); + + let usr = icarus_auth::models::common::CreateUser { + username: String::from("somethingsss"), + password: String::from("Raindown!"), + }; + + /* + let client = reqwest::Client::new(); + let url = icarus_auth::callers::endpoints::REGISTER; + let response = app.oneshot( + println!("Errr") + ) + .await.unwrap(); + */ + + /* + match client.post(url).json(&usr).send().await { + Ok(response) => {} + Err(err) => { + assert!(false, "Error: {:?}", err.to_string()); + } + } + */ + + let payload = json!({ + "username": usr.username, + "password": usr.password, + }); + + assert!(true, "Info: {:?}", payload); + println!("Info: {:?}", payload); + + let response = app + .oneshot( + Request::builder() + .method(axum::http::Method::POST) + .uri(callers::endpoints::REGISTER) + .header(axum::http::header::CONTENT_TYPE, "application/json") + // .body(Body::new(axum::Json(usr))) + // .body(Body::empty()) + .body(Body::from(payload.to_string())) + // .body(Body::from("{\"username\": \"sssss\",\"theanswer\"}")) + .unwrap(), + ) + .await; + // .unwrap(); + + match response { + Ok(resp) => { + assert_eq!(resp.status(), StatusCode::CREATED, "Message: {:?}", resp); + } + Err(err) => { + assert!(false, "Error: {:?}", err.to_string()); + } + }; + + tx.rollback().await.unwrap(); + } } diff --git a/src/models/common.rs b/src/models/common.rs index 8bf5ab7..7b978d5 100644 --- a/src/models/common.rs +++ b/src/models/common.rs @@ -1,6 +1,6 @@ use serde::{Deserialize, Serialize}; -#[derive(Deserialize)] +#[derive(Deserialize, Serialize)] pub struct CreateUser { pub username: String, pub password: String, -- 2.43.0 From 63ecc90bb597ae0a38bb0b7c3f5810192874f9a7 Mon Sep 17 00:00:00 2001 From: phoenix Date: Fri, 4 Apr 2025 19:02:01 -0400 Subject: [PATCH 21/31] Cleanup --- src/main.rs | 27 +-------------------------- 1 file changed, 1 insertion(+), 26 deletions(-) diff --git a/src/main.rs b/src/main.rs index 63a0e79..dcf1074 100644 --- a/src/main.rs +++ b/src/main.rs @@ -97,7 +97,7 @@ mod tests { .expect("Failed to create pool"); db::migrations(&pool).await; - let mut tx = pool.begin().await.unwrap(); + let tx = pool.begin().await.unwrap(); let app = init::routes().await.layer(axum::Extension(pool)); let usr = icarus_auth::models::common::CreateUser { @@ -105,46 +105,21 @@ mod tests { password: String::from("Raindown!"), }; - /* - let client = reqwest::Client::new(); - let url = icarus_auth::callers::endpoints::REGISTER; - let response = app.oneshot( - println!("Errr") - ) - .await.unwrap(); - */ - - /* - match client.post(url).json(&usr).send().await { - Ok(response) => {} - Err(err) => { - assert!(false, "Error: {:?}", err.to_string()); - } - } - */ - let payload = json!({ "username": usr.username, "password": usr.password, }); - assert!(true, "Info: {:?}", payload); - println!("Info: {:?}", payload); - let response = app .oneshot( Request::builder() .method(axum::http::Method::POST) .uri(callers::endpoints::REGISTER) .header(axum::http::header::CONTENT_TYPE, "application/json") - // .body(Body::new(axum::Json(usr))) - // .body(Body::empty()) .body(Body::from(payload.to_string())) - // .body(Body::from("{\"username\": \"sssss\",\"theanswer\"}")) .unwrap(), ) .await; - // .unwrap(); match response { Ok(resp) => { -- 2.43.0 From 076fbad5785682d9acef90df1a20104fbe4d5640 Mon Sep 17 00:00:00 2001 From: phoenix Date: Fri, 4 Apr 2025 19:17:15 -0400 Subject: [PATCH 22/31] Added --- src/main.rs | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/main.rs b/src/main.rs index dcf1074..f4d0849 100644 --- a/src/main.rs +++ b/src/main.rs @@ -64,10 +64,16 @@ mod tests { http::{Request, StatusCode}, }; use http_body_util::BodyExt; - // use reqwest; + use serde::{Deserialize, Serialize}; use serde_json::json; use tower::ServiceExt; // for `call`, `oneshot`, and `ready` + #[derive(Deserialize, Serialize)] + struct Response { + pub message: String, + pub data: icarus_auth::models::common::User, + } + #[tokio::test] async fn test_hello_world() { let app = init::app().await; @@ -106,8 +112,8 @@ mod tests { }; let payload = json!({ - "username": usr.username, - "password": usr.password, + "username": &usr.username, + "password": &usr.password, }); let response = app @@ -124,6 +130,15 @@ mod tests { match response { Ok(resp) => { assert_eq!(resp.status(), StatusCode::CREATED, "Message: {:?}", resp); + let body = axum::body::to_bytes(resp.into_body(), usize::MAX) + .await + .unwrap(); + let parsed_body: Response = serde_json::from_slice(&body).unwrap(); + + assert_eq!( + usr.username, parsed_body.data.username, + "Usernames do not match" + ); } Err(err) => { assert!(false, "Error: {:?}", err.to_string()); -- 2.43.0 From a8baf6d0f9f7e35319df43a0b450bc0b0c168f5d Mon Sep 17 00:00:00 2001 From: phoenix Date: Fri, 4 Apr 2025 20:33:30 -0400 Subject: [PATCH 23/31] Making tests more independent --- Cargo.toml | 1 + src/main.rs | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 80 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c014972..7cbd4f0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,5 +20,6 @@ icarus_models = { git = "ssh://git@git.kundeng.us/phoenix/icarus_models.git", ta [dev-dependencies] http-body-util = { version = "0.1.3" } +url = { version = "2.5" } reqwest = { version = "0.12.5", features = ["json"] } # For making HTTP requests in tests once_cell = { version = "1.19" } # Useful for lazy initialization in tests/app setup diff --git a/src/main.rs b/src/main.rs index f4d0849..7da81f2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -59,6 +59,9 @@ mod init { #[cfg(test)] mod tests { use super::*; + use std::{env, str::FromStr}; + use uuid::Uuid; + use axum::{ body::Body, http::{Request, StatusCode}, @@ -74,6 +77,58 @@ mod tests { pub data: icarus_auth::models::common::User, } + async fn connect_to_db(db_name: &str) -> Result { + let db_url = + env::var("TEST_DATABASE_URL").expect("TEST_DATABASE_URL must be set for tests"); + let options = sqlx::postgres::PgConnectOptions::from_str(&db_url)?.database(db_name); + sqlx::PgPool::connect_with(options).await + } + + 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), + } + // Ok(()) + } + + // Function to drop a database + 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(()) + } + + fn get_database_name() -> Result> { + dotenvy::dotenv().ok(); // Load .env file if it exists + + match std::env::var("TEST_DATABASE_URL") { + Ok(database_url) => { + 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()) + } + } + Err(_) => { + // TEST_DATABASE_URL environment variable not found + Err("Error parsing".into()) + } + } + } + #[tokio::test] async fn test_hello_world() { let app = init::app().await; @@ -98,12 +153,32 @@ mod tests { #[tokio::test] async fn test_register_user() { + let tm_db_url = env::var("DATABASE_URL").expect("DATABASE_URL must be present"); + let tm_options = sqlx::postgres::PgConnectOptions::from_str(&tm_db_url).unwrap(); + let tm_pool = sqlx::PgPool::connect_with(tm_options).await.unwrap(); + + let db_name = get_database_name().unwrap() + &"_" + &uuid::Uuid::new_v4().to_string()[..5]; + // assert_eq!(true, db_name.is_empty(), "{:?} {:?}", db_name, tm_db_url); + // assert!(db_name.is_empty(), "eee {:?}", tm_db_url); + match create_database(&tm_pool, &db_name).await { + Ok(_) => { + println!("Success"); + } + Err(e) => { + assert!(false, "Error: {:?}", e.to_string()); + } + } + + let pool = connect_to_db(&db_name).await.unwrap(); + + /* let pool = icarus_auth::db_pool::create_pool() .await .expect("Failed to create pool"); + */ db::migrations(&pool).await; - let tx = pool.begin().await.unwrap(); + // let mut tx = pool.begin().await.unwrap(); let app = init::routes().await.layer(axum::Extension(pool)); let usr = icarus_auth::models::common::CreateUser { @@ -145,6 +220,8 @@ mod tests { } }; - tx.rollback().await.unwrap(); + drop_database(&tm_pool, &db_name).await; + + // tx.rollback().await.unwrap(); } } -- 2.43.0 From 0dca3259d7ff4b9199fd6cff9037b97e8880f390 Mon Sep 17 00:00:00 2001 From: phoenix Date: Fri, 4 Apr 2025 20:46:19 -0400 Subject: [PATCH 24/31] Saving changes --- src/main.rs | 125 +++++++++++++++++++++++++++------------------------- 1 file changed, 66 insertions(+), 59 deletions(-) diff --git a/src/main.rs b/src/main.rs index 7da81f2..5e72437 100644 --- a/src/main.rs +++ b/src/main.rs @@ -59,8 +59,6 @@ mod init { #[cfg(test)] mod tests { use super::*; - use std::{env, str::FromStr}; - use uuid::Uuid; use axum::{ body::Body, @@ -77,55 +75,75 @@ mod tests { pub data: icarus_auth::models::common::User, } - async fn connect_to_db(db_name: &str) -> Result { - let db_url = - env::var("TEST_DATABASE_URL").expect("TEST_DATABASE_URL must be set for tests"); - let options = sqlx::postgres::PgConnectOptions::from_str(&db_url)?.database(db_name); - sqlx::PgPool::connect_with(options).await - } + mod db_mgr { + use std::str::FromStr; - 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), + pub const LIMIT: usize = 6; + + pub async fn eeee() -> Result { + let tm_db_url = std::env::var("DATABASE_URL").expect("DATABASE_URL must be present"); + let tm_options = sqlx::postgres::PgConnectOptions::from_str(&tm_db_url).unwrap(); + sqlx::PgPool::connect_with(tm_options).await } - // Ok(()) - } - // Function to drop a database - 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 generate_db_name() -> String { + let db_name = + get_database_name().unwrap() + &"_" + &uuid::Uuid::new_v4().to_string()[..LIMIT]; + db_name + } - fn get_database_name() -> Result> { - dotenvy::dotenv().ok(); // Load .env file if it exists + pub async fn connect_to_db(db_name: &str) -> Result { + let db_url = std::env::var("TEST_DATABASE_URL") + .expect("TEST_DATABASE_URL must be set for tests"); + let options = sqlx::postgres::PgConnectOptions::from_str(&db_url)?.database(db_name); + sqlx::PgPool::connect_with(options).await + } - match std::env::var("TEST_DATABASE_URL") { - Ok(database_url) => { - 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()), + 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 fn get_database_name() -> Result> { + dotenvy::dotenv().ok(); // Load .env file if it exists + + match std::env::var("TEST_DATABASE_URL") { + Ok(database_url) => { + 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()) } - } else { - // Handle other database types if needed + } + Err(_) => { + // TEST_DATABASE_URL environment variable not found Err("Error parsing".into()) } } - Err(_) => { - // TEST_DATABASE_URL environment variable not found - Err("Error parsing".into()) - } } } @@ -153,14 +171,11 @@ mod tests { #[tokio::test] async fn test_register_user() { - let tm_db_url = env::var("DATABASE_URL").expect("DATABASE_URL must be present"); - let tm_options = sqlx::postgres::PgConnectOptions::from_str(&tm_db_url).unwrap(); - let tm_pool = sqlx::PgPool::connect_with(tm_options).await.unwrap(); + let tm_pool = db_mgr::eeee().await.unwrap(); - let db_name = get_database_name().unwrap() + &"_" + &uuid::Uuid::new_v4().to_string()[..5]; - // assert_eq!(true, db_name.is_empty(), "{:?} {:?}", db_name, tm_db_url); - // assert!(db_name.is_empty(), "eee {:?}", tm_db_url); - match create_database(&tm_pool, &db_name).await { + let db_name = db_mgr::generate_db_name().await; + + match db_mgr::create_database(&tm_pool, &db_name).await { Ok(_) => { println!("Success"); } @@ -169,16 +184,10 @@ mod tests { } } - let pool = connect_to_db(&db_name).await.unwrap(); + let pool = db_mgr::connect_to_db(&db_name).await.unwrap(); - /* - let pool = icarus_auth::db_pool::create_pool() - .await - .expect("Failed to create pool"); - */ db::migrations(&pool).await; - // let mut tx = pool.begin().await.unwrap(); let app = init::routes().await.layer(axum::Extension(pool)); let usr = icarus_auth::models::common::CreateUser { @@ -220,8 +229,6 @@ mod tests { } }; - drop_database(&tm_pool, &db_name).await; - - // tx.rollback().await.unwrap(); + let _ = db_mgr::drop_database(&tm_pool, &db_name).await; } } -- 2.43.0 From 40832484750272374ab37c74f5713ac4bacb2b30 Mon Sep 17 00:00:00 2001 From: phoenix Date: Fri, 4 Apr 2025 20:54:05 -0400 Subject: [PATCH 25/31] Making it simpler --- .env.sample | 1 - .gitea/workflows/workflow.yml | 10 +++++----- src/lib.rs | 13 +------------ src/main.rs | 7 +++---- 4 files changed, 9 insertions(+), 22 deletions(-) diff --git a/.env.sample b/.env.sample index 5cad34d..135f9aa 100644 --- a/.env.sample +++ b/.env.sample @@ -1,2 +1 @@ DATABASE_URL=postgres://username:password@localhost/database_name -TEST_DATABASE_URL=postgres://icarus_op_test:password@localhost/icarus_auth_test diff --git a/.gitea/workflows/workflow.yml b/.gitea/workflows/workflow.yml index 992cc5e..f1c9706 100644 --- a/.gitea/workflows/workflow.yml +++ b/.gitea/workflows/workflow.yml @@ -70,18 +70,18 @@ jobs: # --- Optional but Recommended: Database Migrations Step --- - name: Run Database Migrations env: - # Define TEST_DATABASE_URL using service details and secrets - TEST_DATABASE_URL: postgresql://${{ secrets.DB_TEST_USER || 'testuser' }}:${{ secrets.DB_TEST_PASSWORD || 'testpassword' }}@postgres:5432/${{ secrets.DB_TEST_NAME || 'testdb' }} + # Define DATABASE_URL using service details and secrets + DATABASE_URL: postgresql://${{ secrets.DB_TEST_USER || 'testuser' }}:${{ secrets.DB_TEST_PASSWORD || 'testpassword' }}@postgres:5432/${{ secrets.DB_TEST_NAME || 'testdb' }} # Make SSH agent available if migrations fetch private dependencies SSH_AUTH_SOCK: ${{ env.SSH_AUTH_SOCK }} run: | echo "Running database migrations..." cargo install sqlx-cli --no-default-features --features native-tls,postgres - sqlx database setup --database-url $TEST_DATABASE_URL + sqlx database setup --database-url $DATABASE_URL - name: Run tests env: - # Define TEST_DATABASE_URL for tests to use - TEST_DATABASE_URL: postgresql://${{ secrets.DB_TEST_USER || 'testuser' }}:${{ secrets.DB_TEST_PASSWORD || 'testpassword' }}@postgres:5432/${{ secrets.DB_TEST_NAME || 'testdb' }} + # Define DATABASE_URL for tests to use + DATABASE_URL: postgresql://${{ secrets.DB_TEST_USER || 'testuser' }}:${{ secrets.DB_TEST_PASSWORD || 'testpassword' }}@postgres:5432/${{ secrets.DB_TEST_NAME || 'testdb' }} RUST_LOG: info # Optional: configure test log level # Make SSH agent available if tests fetch private dependencies SSH_AUTH_SOCK: ${{ env.SSH_AUTH_SOCK }} diff --git a/src/lib.rs b/src/lib.rs index ab8bf15..d7c6e20 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,13 +10,6 @@ mod keys { pub mod error { pub const ERROR: &str = "DATABASE_URL must be set in .env"; } - - pub mod test { - pub const DBURL: &str = "TEST_DATABASE_URL"; - pub mod error { - pub const ERROR: &str = "TEST_DATABASE_URL must be set in .env"; - } - } } mod connection_settings { @@ -44,10 +37,6 @@ pub mod db_pool { #[cfg(debug_assertions)] // Example: Only load .env in debug builds dotenvy::dotenv().ok(); - if cfg!(debug_assertions) { - env::var(keys::test::DBURL).expect(keys::test::error::ERROR) - } else { - env::var(keys::DBURL).expect(keys::error::ERROR) - } + env::var(keys::DBURL).expect(keys::error::ERROR) } } diff --git a/src/main.rs b/src/main.rs index 5e72437..e9482ef 100644 --- a/src/main.rs +++ b/src/main.rs @@ -93,8 +93,7 @@ mod tests { } pub async fn connect_to_db(db_name: &str) -> Result { - let db_url = std::env::var("TEST_DATABASE_URL") - .expect("TEST_DATABASE_URL must be set for tests"); + let db_url = std::env::var("DATABASE_URL").expect("DATABASE_URL must be set for tests"); let options = sqlx::postgres::PgConnectOptions::from_str(&db_url)?.database(db_name); sqlx::PgPool::connect_with(options).await } @@ -123,7 +122,7 @@ mod tests { pub fn get_database_name() -> Result> { dotenvy::dotenv().ok(); // Load .env file if it exists - match std::env::var("TEST_DATABASE_URL") { + match std::env::var("DATABASE_URL") { Ok(database_url) => { let parsed_url = url::Url::parse(&database_url)?; if parsed_url.scheme() == "postgres" || parsed_url.scheme() == "postgresql" { @@ -140,7 +139,7 @@ mod tests { } } Err(_) => { - // TEST_DATABASE_URL environment variable not found + // DATABASE_URL environment variable not found Err("Error parsing".into()) } } -- 2.43.0 From f0f4e1197a62d61c539775e6475b016b525e9fee Mon Sep 17 00:00:00 2001 From: phoenix Date: Fri, 4 Apr 2025 21:00:35 -0400 Subject: [PATCH 26/31] Correction --- src/lib.rs | 2 +- src/main.rs | 12 +++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index d7c6e20..891aac4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,7 +4,7 @@ pub mod hashing; pub mod models; pub mod repo; -mod keys { +pub mod keys { pub const DBURL: &str = "DATABASE_URL"; pub mod error { diff --git a/src/main.rs b/src/main.rs index e9482ef..dfe28f5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -78,10 +78,12 @@ mod tests { mod db_mgr { use std::str::FromStr; + use icarus_auth::keys; + pub const LIMIT: usize = 6; - pub async fn eeee() -> Result { - let tm_db_url = std::env::var("DATABASE_URL").expect("DATABASE_URL must be present"); + pub async fn get_pool() -> Result { + let tm_db_url = std::env::var(keys::DBURL).expect("DATABASE_URL must be present"); let tm_options = sqlx::postgres::PgConnectOptions::from_str(&tm_db_url).unwrap(); sqlx::PgPool::connect_with(tm_options).await } @@ -93,7 +95,7 @@ mod tests { } pub async fn connect_to_db(db_name: &str) -> Result { - let db_url = std::env::var("DATABASE_URL").expect("DATABASE_URL must be set for tests"); + let db_url = std::env::var(keys::DBURL).expect("DATABASE_URL must be set for tests"); let options = sqlx::postgres::PgConnectOptions::from_str(&db_url)?.database(db_name); sqlx::PgPool::connect_with(options).await } @@ -122,7 +124,7 @@ mod tests { pub fn get_database_name() -> Result> { dotenvy::dotenv().ok(); // Load .env file if it exists - match std::env::var("DATABASE_URL") { + match std::env::var(keys::DBURL) { Ok(database_url) => { let parsed_url = url::Url::parse(&database_url)?; if parsed_url.scheme() == "postgres" || parsed_url.scheme() == "postgresql" { @@ -170,7 +172,7 @@ mod tests { #[tokio::test] async fn test_register_user() { - let tm_pool = db_mgr::eeee().await.unwrap(); + let tm_pool = db_mgr::get_pool().await.unwrap(); let db_name = db_mgr::generate_db_name().await; -- 2.43.0 From c2d283c9428a7c83c3d90419c223c082aeb48fb9 Mon Sep 17 00:00:00 2001 From: phoenix Date: Fri, 4 Apr 2025 21:05:36 -0400 Subject: [PATCH 27/31] Trying this out --- .gitea/workflows/workflow.yml | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/.gitea/workflows/workflow.yml b/.gitea/workflows/workflow.yml index f1c9706..8cfc842 100644 --- a/.gitea/workflows/workflow.yml +++ b/.gitea/workflows/workflow.yml @@ -17,15 +17,11 @@ jobs: steps: - uses: actions/checkout@v4 - uses: actions-rust-lang/setup-rust-toolchain@v1 + env: + SSH_AUTH_SOCK: ${{ env.SSH_AUTH_SOCK }} with: toolchain: 1.85.0 - run: | - mkdir -p ~/.ssh - echo "${{ secrets.MYREPO_TOKEN }}" > ~/.ssh/icarus_models_deploy_key - chmod 600 ~/.ssh/icarus_models_deploy_key - ssh-keyscan ${{ vars.MYHOST }} >> ~/.ssh/known_hosts - - eval $(ssh-agent -s) ssh-add -v ~/.ssh/icarus_models_deploy_key cargo check -- 2.43.0 From 3748c8f30988f245dbce7711224423892e2de328 Mon Sep 17 00:00:00 2001 From: phoenix Date: Fri, 4 Apr 2025 21:07:35 -0400 Subject: [PATCH 28/31] Correction - another one --- .gitea/workflows/workflow.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitea/workflows/workflow.yml b/.gitea/workflows/workflow.yml index 8cfc842..f9062df 100644 --- a/.gitea/workflows/workflow.yml +++ b/.gitea/workflows/workflow.yml @@ -22,7 +22,6 @@ jobs: with: toolchain: 1.85.0 - run: | - ssh-add -v ~/.ssh/icarus_models_deploy_key cargo check test: -- 2.43.0 From 665d3d5edf266c4318e3dbffd5ad6e1c3069953e Mon Sep 17 00:00:00 2001 From: phoenix Date: Fri, 4 Apr 2025 21:13:46 -0400 Subject: [PATCH 29/31] Workflow fix --- .gitea/workflows/workflow.yml | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/.gitea/workflows/workflow.yml b/.gitea/workflows/workflow.yml index f9062df..cef844a 100644 --- a/.gitea/workflows/workflow.yml +++ b/.gitea/workflows/workflow.yml @@ -17,11 +17,17 @@ jobs: steps: - uses: actions/checkout@v4 - uses: actions-rust-lang/setup-rust-toolchain@v1 - env: - SSH_AUTH_SOCK: ${{ env.SSH_AUTH_SOCK }} with: toolchain: 1.85.0 - run: | + mkdir -p ~/.ssh + echo "${{ secrets.MYREPO_TOKEN }}" > ~/.ssh/icarus_models_deploy_key + chmod 600 ~/.ssh/icarus_models_deploy_key + ssh-keyscan ${{ vars.MYHOST }} >> ~/.ssh/known_hosts + + eval $(ssh-agent -s) + ssh-add -v ~/.ssh/icarus_models_deploy_key + cargo check test: @@ -81,13 +87,6 @@ jobs: # Make SSH agent available if tests fetch private dependencies SSH_AUTH_SOCK: ${{ env.SSH_AUTH_SOCK }} run: | - mkdir -p ~/.ssh - echo "${{ secrets.MYREPO_TOKEN }}" > ~/.ssh/icarus_models_deploy_key - chmod 600 ~/.ssh/icarus_models_deploy_key - ssh-keyscan ${{ vars.MYHOST }} >> ~/.ssh/known_hosts - - eval $(ssh-agent -s) - ssh-add -v ~/.ssh/icarus_models_deploy_key cargo test fmt: -- 2.43.0 From a933f4d11c6be0e2a923f4025dbfa36da48a8028 Mon Sep 17 00:00:00 2001 From: phoenix Date: Fri, 4 Apr 2025 21:18:31 -0400 Subject: [PATCH 30/31] Workflow fix --- .gitea/workflows/workflow.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.gitea/workflows/workflow.yml b/.gitea/workflows/workflow.yml index cef844a..162b870 100644 --- a/.gitea/workflows/workflow.yml +++ b/.gitea/workflows/workflow.yml @@ -87,6 +87,14 @@ jobs: # Make SSH agent available if tests fetch private dependencies SSH_AUTH_SOCK: ${{ env.SSH_AUTH_SOCK }} run: | + mkdir -p ~/.ssh + echo "${{ secrets.MYREPO_TOKEN }}" > ~/.ssh/icarus_models_deploy_key + chmod 600 ~/.ssh/icarus_models_deploy_key + ssh-keyscan ${{ vars.MYHOST }} >> ~/.ssh/known_hosts + + eval $(ssh-agent -s) + ssh-add -v ~/.ssh/icarus_models_deploy_key + cargo test fmt: -- 2.43.0 From 34be27211b906c3800d5c5228caba5d5e7539b8c Mon Sep 17 00:00:00 2001 From: phoenix Date: Fri, 4 Apr 2025 21:20:59 -0400 Subject: [PATCH 31/31] Removing migrations --- .gitea/workflows/workflow.yml | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/.gitea/workflows/workflow.yml b/.gitea/workflows/workflow.yml index 162b870..087d74e 100644 --- a/.gitea/workflows/workflow.yml +++ b/.gitea/workflows/workflow.yml @@ -69,16 +69,6 @@ jobs: # NOTE: Do NOT use continue-on-error here. # If Docker isn't working as expected, the job SHOULD fail here. # --- Optional but Recommended: Database Migrations Step --- - - name: Run Database Migrations - env: - # Define DATABASE_URL using service details and secrets - DATABASE_URL: postgresql://${{ secrets.DB_TEST_USER || 'testuser' }}:${{ secrets.DB_TEST_PASSWORD || 'testpassword' }}@postgres:5432/${{ secrets.DB_TEST_NAME || 'testdb' }} - # Make SSH agent available if migrations fetch private dependencies - SSH_AUTH_SOCK: ${{ env.SSH_AUTH_SOCK }} - run: | - echo "Running database migrations..." - cargo install sqlx-cli --no-default-features --features native-tls,postgres - sqlx database setup --database-url $DATABASE_URL - name: Run tests env: # Define DATABASE_URL for tests to use -- 2.43.0