From 967915d734ceb9de5ba5fe244f5c782b533ed36e Mon Sep 17 00:00:00 2001 From: filipriec Date: Tue, 4 Mar 2025 21:19:50 +0100 Subject: [PATCH] get is failing --- .../handlers/get_table_data_test.rs | 204 ++++++++++-------- 1 file changed, 119 insertions(+), 85 deletions(-) diff --git a/server/tests/tables_data/handlers/get_table_data_test.rs b/server/tests/tables_data/handlers/get_table_data_test.rs index 410d0df..50312a4 100644 --- a/server/tests/tables_data/handlers/get_table_data_test.rs +++ b/server/tests/tables_data/handlers/get_table_data_test.rs @@ -8,12 +8,6 @@ use tonic; use chrono::Utc; use serde_json::json; use std::collections::HashMap; -use std::sync::Arc; -use tokio::sync::Mutex; - -lazy_static::lazy_static! { - static ref TEST_MUTEX: Arc> = Arc::new(Mutex::new(())); -} #[fixture] async fn pool() -> PgPool { @@ -28,10 +22,10 @@ async fn closed_pool(#[future] pool: PgPool) -> PgPool { } #[fixture] -async fn existing_profile(#[future] pool: PgPool) -> (PgPool, String, i64) { - let _guard = TEST_MUTEX.lock().await; +async fn profile(#[future] pool: PgPool) -> (PgPool, String, i64) { let pool = pool.await; let profile_name = format!("TestProfile_{}", Utc::now().timestamp_nanos_opt().unwrap_or_default()); + let profile = sqlx::query!( "INSERT INTO profiles (name) VALUES ($1) RETURNING id", profile_name @@ -39,15 +33,13 @@ async fn existing_profile(#[future] pool: PgPool) -> (PgPool, String, i64) { .fetch_one(&pool) .await .unwrap(); + (pool, profile_name, profile.id) } #[fixture] -async fn existing_table( - #[future] existing_profile: (PgPool, String, i64), -) -> (PgPool, String, String) { - let _guard = TEST_MUTEX.lock().await; - let (pool, profile_name, profile_id) = existing_profile.await; +async fn table_definition(#[future] profile: (PgPool, String, i64)) -> (PgPool, String, String, i64) { + let (pool, profile_name, profile_id) = profile.await; let table_name = format!("test_table_{}", Utc::now().timestamp_nanos_opt().unwrap_or_default()); // Define columns for the table @@ -58,13 +50,13 @@ async fn existing_table( "\"is_active\" BOOLEAN" ]); - sqlx::query!( - "INSERT INTO table_definitions (profile_id, table_name, columns) VALUES ($1, $2, $3)", + let table_def = sqlx::query!( + "INSERT INTO table_definitions (profile_id, table_name, columns) VALUES ($1, $2, $3) RETURNING id", profile_id, table_name, columns ) - .execute(&pool) + .fetch_one(&pool) .await .unwrap(); @@ -89,16 +81,14 @@ async fn existing_table( .await .unwrap(); - (pool, profile_name, table_name) + (pool, profile_name, table_name, table_def.id) } #[fixture] -async fn existing_record( - #[future] existing_table: (PgPool, String, String), -) -> (PgPool, String, String, i64) { - let _guard = TEST_MUTEX.lock().await; - let (pool, profile_name, table_name) = existing_table.await; - +async fn regular_record(#[future] table_definition: (PgPool, String, String, i64)) -> (PgPool, String, String, i64) { + let (pool, profile_name, table_name, _) = table_definition.await; + + // Insert a record with all fields let query = format!( r#"INSERT INTO "{}" (firma, name, age, email, is_active) VALUES ($1, $2, $3, $4, $5) @@ -121,36 +111,10 @@ async fn existing_record( } #[fixture] -async fn existing_deleted_record( - #[future] existing_table: (PgPool, String, String), -) -> (PgPool, String, String, i64) { - let _guard = TEST_MUTEX.lock().await; - let (pool, profile_name, table_name) = existing_table.await; - - let query = format!( - r#"INSERT INTO "{}" (firma, deleted) - VALUES ($1, true) - RETURNING id"#, - table_name - ); +async fn null_fields_record(#[future] table_definition: (PgPool, String, String, i64)) -> (PgPool, String, String, i64) { + let (pool, profile_name, table_name, _) = table_definition.await; - let record = sqlx::query(&query) - .bind("Deleted Company") - .fetch_one(&pool) - .await - .unwrap(); - - let id: i64 = record.get("id"); - (pool, profile_name, table_name, id) -} - -#[fixture] -async fn existing_record_with_nulls( - #[future] existing_table: (PgPool, String, String), -) -> (PgPool, String, String, i64) { - let _guard = TEST_MUTEX.lock().await; - let (pool, profile_name, table_name) = existing_table.await; - + // Insert a record with only required fields let query = format!( r#"INSERT INTO "{}" (firma) VALUES ($1) @@ -168,30 +132,81 @@ async fn existing_record_with_nulls( (pool, profile_name, table_name, id) } -async fn cleanup_test_data(pool: &PgPool, table_name: &str) { - sqlx::query(&format!(r#"DROP TABLE IF EXISTS "{}" CASCADE"#, table_name)) - .execute(pool) +#[fixture] +async fn deleted_record(#[future] table_definition: (PgPool, String, String, i64)) -> (PgPool, String, String, i64) { + let (pool, profile_name, table_name, _) = table_definition.await; + + // Insert a deleted record + let query = format!( + r#"INSERT INTO "{}" (firma, deleted) + VALUES ($1, true) + RETURNING id"#, + table_name + ); + + let record = sqlx::query(&query) + .bind("Deleted Company") + .fetch_one(&pool) .await .unwrap(); - sqlx::query!("DELETE FROM table_definitions WHERE table_name = $1", table_name) - .execute(pool) + let id: i64 = record.get("id"); + (pool, profile_name, table_name, id) +} + +async fn assert_response_matches(pool: &PgPool, table_name: &str, id: i64, response: &HashMap) { + let columns = format!( + "id, deleted, firma, name, age, email, is_active" + ); + let query = format!(r#"SELECT {} FROM "{}" WHERE id = $1"#, columns, table_name); + + let row = sqlx::query(&query) + .bind(id) + .fetch_one(pool) .await .unwrap(); + + assert_eq!(row.get::("id").to_string(), response["id"]); + assert_eq!(row.get::("deleted").to_string(), response["deleted"]); + assert_eq!(row.get::("firma"), response["firma"]); + + // Check optional fields + let name: Option = row.try_get("name").unwrap_or(None); + assert_eq!(name.unwrap_or_default(), response["name"]); + + let age: Option = row.try_get("age").unwrap_or(None); + assert_eq!(age.map(|v| v.to_string()).unwrap_or_default(), response["age"]); + + let email: Option = row.try_get("email").unwrap_or(None); + assert_eq!(email.unwrap_or_default(), response["email"]); + + let is_active: Option = row.try_get("is_active").unwrap_or(None); + assert_eq!(is_active.map(|v| v.to_string()).unwrap_or_default(), response["is_active"]); +} + +async fn cleanup_test_data(pool: &PgPool, table_name: &str) { + let _ = sqlx::query(&format!(r#"DROP TABLE IF EXISTS "{}" CASCADE"#, table_name)) + .execute(pool) + .await; + + let _ = sqlx::query!("DELETE FROM table_definitions WHERE table_name = $1", table_name) + .execute(pool) + .await; } #[rstest] #[tokio::test] async fn test_get_table_data_success( - #[future] existing_record: (PgPool, String, String, i64), + #[future] regular_record: (PgPool, String, String, i64), ) { - let (pool, profile_name, table_name, id) = existing_record.await; + let (pool, profile_name, table_name, id) = regular_record.await; + let request = GetTableDataRequest { profile_name: profile_name.clone(), table_name: table_name.clone(), id, }; - + let response = get_table_data(&pool, request).await.unwrap(); assert_eq!(response.data["id"], id.to_string()); @@ -201,16 +216,19 @@ async fn test_get_table_data_success( assert_eq!(response.data["email"], "john@example.com"); assert_eq!(response.data["is_active"], "true"); assert_eq!(response.data["deleted"], "false"); - + + assert_response_matches(&pool, &table_name, id, &response.data).await; + cleanup_test_data(&pool, &table_name).await; } #[rstest] #[tokio::test] async fn test_get_optional_fields_null( - #[future] existing_record_with_nulls: (PgPool, String, String, i64), + #[future] null_fields_record: (PgPool, String, String, i64), ) { - let (pool, profile_name, table_name, id) = existing_record_with_nulls.await; + let (pool, profile_name, table_name, id) = null_fields_record.await; + let request = GetTableDataRequest { profile_name: profile_name.clone(), table_name: table_name.clone(), @@ -224,16 +242,19 @@ async fn test_get_optional_fields_null( assert_eq!(response.data["email"], ""); assert_eq!(response.data["is_active"], ""); assert_eq!(response.data["deleted"], "false"); - + + assert_response_matches(&pool, &table_name, id, &response.data).await; + cleanup_test_data(&pool, &table_name).await; } #[rstest] #[tokio::test] async fn test_get_nonexistent_id( - #[future] existing_table: (PgPool, String, String), + #[future] table_definition: (PgPool, String, String, i64), ) { - let (pool, profile_name, table_name) = existing_table.await; + let (pool, profile_name, table_name, _) = table_definition.await; + let request = GetTableDataRequest { profile_name: profile_name.clone(), table_name: table_name.clone(), @@ -241,18 +262,20 @@ async fn test_get_nonexistent_id( }; let result = get_table_data(&pool, request).await; + assert!(result.is_err()); assert_eq!(result.unwrap_err().code(), tonic::Code::NotFound); - + cleanup_test_data(&pool, &table_name).await; } #[rstest] #[tokio::test] async fn test_get_deleted_record( - #[future] existing_deleted_record: (PgPool, String, String, i64), + #[future] deleted_record: (PgPool, String, String, i64), ) { - let (pool, profile_name, table_name, id) = existing_deleted_record.await; + let (pool, profile_name, table_name, id) = deleted_record.await; + let request = GetTableDataRequest { profile_name: profile_name.clone(), table_name: table_name.clone(), @@ -260,9 +283,10 @@ async fn test_get_deleted_record( }; let result = get_table_data(&pool, request).await; + assert!(result.is_err()); assert_eq!(result.unwrap_err().code(), tonic::Code::NotFound); - + cleanup_test_data(&pool, &table_name).await; } @@ -272,6 +296,7 @@ async fn test_get_database_error( #[future] closed_pool: PgPool, ) { let closed_pool = closed_pool.await; + let request = GetTableDataRequest { profile_name: "test".into(), table_name: "test".into(), @@ -279,6 +304,7 @@ async fn test_get_database_error( }; let result = get_table_data(&closed_pool, request).await; + assert!(result.is_err()); assert_eq!(result.unwrap_err().code(), tonic::Code::Internal); } @@ -286,10 +312,10 @@ async fn test_get_database_error( #[rstest] #[tokio::test] async fn test_get_special_characters( - #[future] existing_table: (PgPool, String, String), + #[future] table_definition: (PgPool, String, String, i64), ) { - let (pool, profile_name, table_name) = existing_table.await; - + let (pool, profile_name, table_name, _) = table_definition.await; + let query = format!( r#"INSERT INTO "{}" (firma, name, email) VALUES ($1, $2, $3) @@ -317,17 +343,19 @@ async fn test_get_special_characters( assert_eq!(response.data["name"], "Náměstí ČR"); assert_eq!(response.data["email"], "čšěř@example.com"); - + + assert_response_matches(&pool, &table_name, id, &response.data).await; + cleanup_test_data(&pool, &table_name).await; } #[rstest] #[tokio::test] async fn test_get_max_length_fields( - #[future] existing_table: (PgPool, String, String), + #[future] table_definition: (PgPool, String, String, i64), ) { - let (pool, profile_name, table_name) = existing_table.await; - + let (pool, profile_name, table_name, _) = table_definition.await; + let long_name = "a".repeat(255); let query = format!( r#"INSERT INTO "{}" (firma, name) @@ -355,7 +383,9 @@ async fn test_get_max_length_fields( assert_eq!(response.data["name"], long_name); assert_eq!(response.data["name"].len(), 255); - + + assert_response_matches(&pool, &table_name, id, &response.data).await; + cleanup_test_data(&pool, &table_name).await; } @@ -365,6 +395,7 @@ async fn test_get_invalid_profile( #[future] pool: PgPool, ) { let pool = pool.await; + let request = GetTableDataRequest { profile_name: "non_existent_profile".into(), table_name: "test_table".into(), @@ -372,6 +403,7 @@ async fn test_get_invalid_profile( }; let result = get_table_data(&pool, request).await; + assert!(result.is_err()); assert_eq!(result.unwrap_err().code(), tonic::Code::NotFound); } @@ -379,9 +411,10 @@ async fn test_get_invalid_profile( #[rstest] #[tokio::test] async fn test_get_invalid_table( - #[future] existing_profile: (PgPool, String, i64), + #[future] profile: (PgPool, String, i64), ) { - let (pool, profile_name, _) = existing_profile.await; + let (pool, profile_name, _) = profile.await; + let request = GetTableDataRequest { profile_name, table_name: "non_existent_table".into(), @@ -389,6 +422,7 @@ async fn test_get_invalid_table( }; let result = get_table_data(&pool, request).await; + assert!(result.is_err()); assert_eq!(result.unwrap_err().code(), tonic::Code::NotFound); } @@ -396,19 +430,19 @@ async fn test_get_invalid_table( #[rstest] #[tokio::test] async fn test_get_invalid_column( - #[future] existing_record: (PgPool, String, String, i64), + #[future] regular_record: (PgPool, String, String, i64), ) { - let (pool, profile_name, table_name, id) = existing_record.await; + let (pool, profile_name, table_name, id) = regular_record.await; - // Try to request a column that doesn't exist in the table definition - let mut request = GetTableDataRequest { + let request = GetTableDataRequest { profile_name: profile_name.clone(), table_name: table_name.clone(), id, }; let result = get_table_data(&pool, request).await; + assert!(result.is_ok()); // Should still succeed as we're not filtering columns - + cleanup_test_data(&pool, &table_name).await; }