-
Notifications
You must be signed in to change notification settings - Fork 0
test: use separate database for testing #227
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 6 commits
b86943b
917a86c
92cdbda
59124ad
c3e1d79
10dd63e
837e9eb
ec276fc
eca0861
e1a459a
1b7fb5e
c3ee363
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,103 @@ | ||
| use std::env; | ||
| use tokio_postgres::NoTls; | ||
| use tracing::{error, info, warn}; | ||
|
|
||
| /// Get test database name from environment or default | ||
| pub fn get_test_db_name() -> String { | ||
| env::var("DATABASE_TEST_NAME").unwrap_or_else(|_| "platform_api_test".to_string()) | ||
| } | ||
|
|
||
| /// Get admin database name - try 'postgres' first, fallback to 'template1' if not available | ||
| async fn get_admin_db_name( | ||
| host: &str, | ||
| port: u16, | ||
| username: &str, | ||
| password: &str, | ||
| ) -> Result<String, String> { | ||
| // Try 'postgres' first (most common) | ||
| if can_connect_to_db(host, port, username, password, "postgres").await { | ||
| return Ok("postgres".to_string()); | ||
| } | ||
|
|
||
| // Fallback to 'template1' (always exists in PostgreSQL) | ||
| if can_connect_to_db(host, port, username, password, "template1").await { | ||
| warn!("'postgres' database not found, using 'template1' as admin database"); | ||
| return Ok("template1".to_string()); | ||
| } | ||
|
|
||
| Err("Neither 'postgres' nor 'template1' database found".to_string()) | ||
| } | ||
|
|
||
| async fn can_connect_to_db( | ||
| host: &str, | ||
| port: u16, | ||
| username: &str, | ||
| password: &str, | ||
| dbname: &str, | ||
| ) -> bool { | ||
| let conn_string = | ||
| format!("host={host} port={port} user={username} password={password} dbname={dbname}"); | ||
| tokio_postgres::connect(&conn_string, NoTls).await.is_ok() | ||
| } | ||
|
|
||
| pub async fn reset_test_database(config: &config::DatabaseConfig) -> Result<(), String> { | ||
| let test_db_name = get_test_db_name(); | ||
|
|
||
| // Safety check - only allow resetting test database | ||
| if !test_db_name.contains("test") { | ||
| panic!("Safety: Can only reset databases with 'test' in the name. Got: {test_db_name}"); | ||
| } | ||
|
|
||
| let host = config | ||
| .host | ||
| .clone() | ||
| .unwrap_or_else(|| "localhost".to_string()); | ||
| let port = config.port; | ||
| let username = config.username.clone(); | ||
| let password = config.password.clone(); | ||
|
|
||
| // Find available admin database | ||
| let admin_db = get_admin_db_name(&host, port, &username, &password).await?; | ||
|
|
||
| let conn_string = | ||
| format!("host={host} port={port} user={username} password={password} dbname={admin_db}"); | ||
|
|
||
| let (client, connection) = tokio_postgres::connect(&conn_string, NoTls) | ||
| .await | ||
| .map_err(|e| format!("Failed to connect to admin database: {e}"))?; | ||
|
|
||
| tokio::spawn(async move { | ||
| if let Err(e) = connection.await { | ||
| error!("Database connection error: {}", e); | ||
| } | ||
| }); | ||
|
|
||
| // Terminate existing connections to allow DROP | ||
| let _ = client | ||
| .execute( | ||
| &format!( | ||
| "SELECT pg_terminate_backend(pid) FROM pg_stat_activity | ||
| WHERE datname = '{test_db_name}' AND pid <> pg_backend_pid()" | ||
| ), | ||
| &[], | ||
| ) | ||
| .await; | ||
|
|
||
| // Drop database if exists | ||
| let drop_result = client | ||
| .execute(&format!("DROP DATABASE IF EXISTS {test_db_name}"), &[]) | ||
| .await; | ||
|
|
||
| if let Err(e) = drop_result { | ||
| warn!("Failed to drop test database (may not exist): {}", e); | ||
| } | ||
|
|
||
| // Create fresh database | ||
| client | ||
| .execute(&format!("CREATE DATABASE {test_db_name}"), &[]) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bug: SQL injection vulnerability via unsanitized database nameThe Additional Locations (1) |
||
| .await | ||
| .map_err(|e| format!("Failed to create test database: {e}"))?; | ||
|
Comment on lines
+76
to
+99
|
||
|
|
||
| info!("Test database '{}' reset successfully", test_db_name); | ||
| Ok(()) | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -173,6 +173,7 @@ | |
| #[tokio::test] | ||
| async fn test_responses_api() { | ||
| let server = setup_test_server().await; | ||
| setup_qwen_model(&server).await; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why add
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The test calls /v1/models API and asserts that at least one model is available (assert!(!models.data.is_empty())). Without setup_qwen_model(), no models are registered in the database, causing the endpoint to return an empty list and the test to fail immediately. |
||
| let org = setup_org_with_credits(&server, 10000000000i64).await; // $10.00 USD | ||
| let api_key = get_api_key_for_org(&server, org.id).await; | ||
|
|
||
|
|
@@ -249,6 +250,7 @@ | |
| #[tokio::test] | ||
| async fn test_streaming_responses_api() { | ||
| let server = setup_test_server().await; | ||
| setup_qwen_model(&server).await; | ||
| let org = setup_org_with_credits(&server, 10000000000i64).await; // $10.00 USD | ||
| let api_key = get_api_key_for_org(&server, org.id).await; | ||
|
|
||
|
|
@@ -1121,6 +1123,7 @@ | |
| #[tokio::test] | ||
| async fn test_conversation_items_pagination() { | ||
| let server = setup_test_server().await; | ||
| setup_qwen_model(&server).await; | ||
| let org = setup_org_with_credits(&server, 10000000000i64).await; | ||
| let api_key = get_api_key_for_org(&server, org.id).await; | ||
| let models = list_models(&server, api_key.clone()).await; | ||
|
|
@@ -1412,6 +1415,7 @@ | |
| #[tokio::test] | ||
| async fn test_response_previous_next_relationships_streaming() { | ||
| let server = setup_test_server().await; | ||
| setup_qwen_model(&server).await; | ||
| let org = setup_org_with_credits(&server, 10000000000i64).await; // $10.00 USD | ||
| let api_key = get_api_key_for_org(&server, org.id).await; | ||
|
|
||
|
|
@@ -1943,6 +1947,7 @@ | |
| #[tokio::test] | ||
| async fn test_clone_conversation_with_responses_and_items() { | ||
| let server = setup_test_server().await; | ||
| setup_qwen_model(&server).await; | ||
| let org = setup_org_with_credits(&server, 10000000000i64).await; // $10.00 USD | ||
| let api_key = get_api_key_for_org(&server, org.id).await; | ||
|
|
||
|
|
@@ -2698,6 +2703,7 @@ | |
| #[tokio::test] | ||
| async fn test_conversation_items_model_with_streaming() { | ||
| let server = setup_test_server().await; | ||
| setup_qwen_model(&server).await; | ||
| let org = setup_org_with_credits(&server, 10000000000i64).await; // $10.00 USD | ||
| let api_key = get_api_key_for_org(&server, org.id).await; | ||
|
|
||
|
|
@@ -3035,7 +3041,7 @@ | |
| async fn test_conversation_title_strips_thinking_tags() { | ||
| use inference_providers::mock::ResponseTemplate; | ||
|
|
||
| let (server, _pool, mock_provider) = setup_test_server_with_pool().await; | ||
| let org = setup_org_with_credits(&server, 10000000000i64).await; | ||
| let api_key = get_api_key_for_org(&server, org.id).await; | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the environment variable needed? I think it's fine to use a fixed test database name for testing.
We may rename the default test database name to
cloud_api_testas the project has been renamed.