test for get by position

This commit is contained in:
filipriec
2025-03-05 19:36:48 +01:00
parent af37c6c0bb
commit 70038feb49
4 changed files with 320 additions and 0 deletions

View File

@@ -120,6 +120,8 @@ pub async fn post_table_data(
.ok_or_else(|| Status::invalid_argument(format!("Column not found: {}", col)))?
};
// TODO This needs heavy adjustement. More stuff to be added for user to only pick
// preprogrammed functions
match sql_type {
"TEXT" | "VARCHAR(15)" | "VARCHAR(255)" => {
if let Some(max_len) = sql_type.strip_prefix("VARCHAR(")

View File

@@ -103,6 +103,7 @@ pub async fn put_table_data(
.ok_or_else(|| Status::invalid_argument(format!("Column not found: {}", col)))?
};
// TODO strong testing by user pick in the future
match sql_type {
"TEXT" | "VARCHAR(15)" | "VARCHAR(255)" => {
if let Some(max_len) = sql_type.strip_prefix("VARCHAR(")

View File

@@ -0,0 +1,316 @@
// tests/tables_data/handlers/get_table_data_by_position_test.rs
use rstest::{fixture, rstest};
use sqlx::PgPool;
use common::proto::multieko2::tables_data::{GetTableDataByPositionRequest, GetTableDataResponse};
use server::tables_data::handlers::get_table_data_by_position;
use crate::common::setup_test_db;
use tonic;
use std::sync::Arc;
use tokio::sync::Mutex;
// Global mutex to prevent test interference
lazy_static::lazy_static! {
static ref TEST_MUTEX: Arc<Mutex<()>> = Arc::new(Mutex::new(()));
}
#[fixture]
async fn pool() -> PgPool {
setup_test_db().await
}
#[fixture]
async fn closed_pool(#[future] pool: PgPool) -> PgPool {
let pool = pool.await;
pool.close().await;
pool
}
async fn setup_profile_and_table(pool: &PgPool) {
// Create default profile
sqlx::query!(
"INSERT INTO profiles (name) VALUES ('default') ON CONFLICT DO NOTHING"
)
.execute(pool)
.await
.unwrap();
// Create table definition
let columns_json = serde_json::json!([
r#""id" BIGSERIAL PRIMARY KEY"#,
r#""firma" TEXT NOT NULL"#,
r#""deleted" BOOLEAN NOT NULL DEFAULT FALSE"#,
r#""created_at" TIMESTAMPTZ DEFAULT NOW()"#
]);
sqlx::query!(
r#"INSERT INTO table_definitions (profile_id, table_name, columns)
SELECT id, '2025_adresar', $1
FROM profiles WHERE name = 'default'
ON CONFLICT DO NOTHING"#,
columns_json
)
.execute(pool)
.await
.unwrap();
}
async fn create_test_record(pool: &PgPool, firma: &str, deleted: bool) -> i64 {
sqlx::query_scalar!(
r#"INSERT INTO "2025_adresar" (firma, deleted) VALUES ($1, $2) RETURNING id"#,
firma,
deleted
)
.fetch_one(pool)
.await
.unwrap()
}
async fn cleanup_test_records(pool: &PgPool, prefix: &str) {
sqlx::query!(
r#"DELETE FROM "2025_adresar" WHERE firma LIKE $1"#,
format!("{}%", prefix)
)
.execute(pool)
.await
.unwrap();
}
async fn find_position_of_record(pool: &PgPool, id: i64) -> Option<i64> {
let records = sqlx::query_scalar!(
r#"SELECT id FROM "2025_adresar" WHERE deleted = FALSE ORDER BY id ASC"#
)
.fetch_all(pool)
.await
.unwrap();
records.iter()
.position(|&record_id| record_id == id)
.map(|pos| (pos + 1) as i64)
}
#[rstest]
#[tokio::test]
async fn test_position_validation(
#[future] pool: PgPool,
) {
let pool = pool.await;
let _guard = TEST_MUTEX.lock().await;
setup_profile_and_table(&pool).await;
// Test position 0
let request = GetTableDataByPositionRequest {
profile_name: "default".to_string(),
table_name: "2025_adresar".to_string(),
position: 0,
};
let result = get_table_data_by_position(&pool, request).await;
assert!(result.is_err());
assert_eq!(result.unwrap_err().code(), tonic::Code::InvalidArgument);
// Test negative position
let request = GetTableDataByPositionRequest {
profile_name: "default".to_string(),
table_name: "2025_adresar".to_string(),
position: -1,
};
let result = get_table_data_by_position(&pool, request).await;
assert!(result.is_err());
assert_eq!(result.unwrap_err().code(), tonic::Code::InvalidArgument);
}
#[rstest]
#[tokio::test]
async fn test_profile_table_validation(
#[future] pool: PgPool,
) {
let pool = pool.await;
let _guard = TEST_MUTEX.lock().await;
setup_profile_and_table(&pool).await;
// Test non-existent profile
let request = GetTableDataByPositionRequest {
profile_name: "ghost_profile".to_string(),
table_name: "2025_adresar".to_string(),
position: 1,
};
let result = get_table_data_by_position(&pool, request).await;
assert!(result.is_err());
assert_eq!(result.unwrap_err().code(), tonic::Code::NotFound);
// Test non-existent table
let request = GetTableDataByPositionRequest {
profile_name: "default".to_string(),
table_name: "ghost_table".to_string(),
position: 1,
};
let result = get_table_data_by_position(&pool, request).await;
assert!(result.is_err());
assert_eq!(result.unwrap_err().code(), tonic::Code::NotFound);
}
#[rstest]
#[tokio::test]
async fn test_basic_position_retrieval(
#[future] pool: PgPool,
) {
let pool = pool.await;
let _guard = TEST_MUTEX.lock().await;
setup_profile_and_table(&pool).await;
cleanup_test_records(&pool, "PosBasicTest").await;
// Create test records
let id1 = create_test_record(&pool, "PosBasicTest_1", false).await;
let id2 = create_test_record(&pool, "PosBasicTest_2", false).await;
let id3 = create_test_record(&pool, "PosBasicTest_3", false).await;
// Verify positions
let pos1 = find_position_of_record(&pool, id1).await.unwrap();
let pos2 = find_position_of_record(&pool, id2).await.unwrap();
let pos3 = find_position_of_record(&pool, id3).await.unwrap();
// Test retrieval
let request = GetTableDataByPositionRequest {
profile_name: "default".to_string(),
table_name: "2025_adresar".to_string(),
position: pos1 as i32,
};
let response = get_table_data_by_position(&pool, request).await.unwrap();
assert_eq!(response.data["id"], id1.to_string());
let request = GetTableDataByPositionRequest {
profile_name: "default".to_string(),
table_name: "2025_adresar".to_string(),
position: pos2 as i32,
};
let response = get_table_data_by_position(&pool, request).await.unwrap();
assert_eq!(response.data["id"], id2.to_string());
let request = GetTableDataByPositionRequest {
profile_name: "default".to_string(),
table_name: "2025_adresar".to_string(),
position: pos3 as i32,
};
let response = get_table_data_by_position(&pool, request).await.unwrap();
assert_eq!(response.data["id"], id3.to_string());
cleanup_test_records(&pool, "PosBasicTest").await;
}
#[rstest]
#[tokio::test]
async fn test_deleted_records_excluded(
#[future] pool: PgPool,
) {
let pool = pool.await;
let _guard = TEST_MUTEX.lock().await;
setup_profile_and_table(&pool).await;
cleanup_test_records(&pool, "PosDeletedTest").await;
// Create records
let id1 = create_test_record(&pool, "PosDeletedTest_1", false).await;
let _deleted_id = create_test_record(&pool, "PosDeletedTest_deleted", true).await;
let id2 = create_test_record(&pool, "PosDeletedTest_2", false).await;
// Verify positions
let pos1 = find_position_of_record(&pool, id1).await.unwrap();
let pos2 = find_position_of_record(&pool, id2).await.unwrap();
assert_eq!(pos2, pos1 + 1);
// Test retrieval
let request = GetTableDataByPositionRequest {
profile_name: "default".to_string(),
table_name: "2025_adresar".to_string(),
position: pos1 as i32,
};
let response = get_table_data_by_position(&pool, request).await.unwrap();
assert_eq!(response.data["id"], id1.to_string());
let request = GetTableDataByPositionRequest {
profile_name: "default".to_string(),
table_name: "2025_adresar".to_string(),
position: pos2 as i32,
};
let response = get_table_data_by_position(&pool, request).await.unwrap();
assert_eq!(response.data["id"], id2.to_string());
cleanup_test_records(&pool, "PosDeletedTest").await;
}
#[rstest]
#[tokio::test]
async fn test_position_after_deletion(
#[future] pool: PgPool,
) {
let pool = pool.await;
let _guard = TEST_MUTEX.lock().await;
setup_profile_and_table(&pool).await;
cleanup_test_records(&pool, "PosDeletionTest").await;
// Create records
let id1 = create_test_record(&pool, "PosDeletionTest_1", false).await;
let id2 = create_test_record(&pool, "PosDeletionTest_2", false).await;
let id3 = create_test_record(&pool, "PosDeletionTest_3", false).await;
// Delete middle record
sqlx::query!(
r#"UPDATE "2025_adresar" SET deleted = TRUE WHERE id = $1"#,
id2
)
.execute(&pool)
.await
.unwrap();
// Verify new positions
let pos1 = find_position_of_record(&pool, id1).await.unwrap();
let pos3 = find_position_of_record(&pool, id3).await.unwrap();
assert_eq!(pos3, pos1 + 1);
// Test retrieval
let request = GetTableDataByPositionRequest {
profile_name: "default".to_string(),
table_name: "2025_adresar".to_string(),
position: pos3 as i32,
};
let response = get_table_data_by_position(&pool, request).await.unwrap();
assert_eq!(response.data["id"], id3.to_string());
cleanup_test_records(&pool, "PosDeletionTest").await;
}
#[rstest]
#[tokio::test]
async fn test_database_error(
#[future] closed_pool: PgPool,
) {
let pool = closed_pool.await;
let request = GetTableDataByPositionRequest {
profile_name: "default".to_string(),
table_name: "2025_adresar".to_string(),
position: 1,
};
let result = get_table_data_by_position(&pool, request).await;
assert!(result.is_err());
assert_eq!(result.unwrap_err().code(), tonic::Code::Internal);
}
#[rstest]
#[tokio::test]
async fn test_empty_table(
#[future] pool: PgPool,
) {
let pool = pool.await;
let _guard = TEST_MUTEX.lock().await;
setup_profile_and_table(&pool).await;
cleanup_test_records(&pool, "").await;
let request = GetTableDataByPositionRequest {
profile_name: "default".to_string(),
table_name: "2025_adresar".to_string(),
position: 1,
};
let result = get_table_data_by_position(&pool, request).await;
assert!(result.is_err());
assert_eq!(result.unwrap_err().code(), tonic::Code::NotFound);
}

View File

@@ -4,4 +4,5 @@ pub mod put_table_data_test;
pub mod delete_table_data_test;
pub mod get_table_data_test;
pub mod get_table_data_count_test;
pub mod get_table_data_by_position_test;