refactor(tests): reformat code and update dependency management

- Reorganized import statements in adapter tests for better readability
- Replaced or_insert_with(Vec::new) with or_default() in test closures
- Updated Cargo.lock with new dependency versions and checksums
- Added TLS features to tonic dependency configuration
- Included sqlx, chrono, and uuid dependencies with specific features
- Added jsonwebtoken and arc-swap as project dependencies
- Reformatted assertion statements to comply with line length limits
- Adjusted base64 import order in engine codec module
- Updated protobuf include statement formatting
This commit is contained in:
zhenyi
2026-06-11 12:11:05 +08:00
parent 06e8ee96a5
commit 821537186e
111 changed files with 10458 additions and 385 deletions
+71
View File
@@ -0,0 +1,71 @@
//! PostgreSQL connection pool configuration.
//!
//! Reads settings from environment variables with sensible defaults.
use std::env;
/// PostgreSQL connection configuration, sourced from environment variables.
#[derive(Debug, Clone)]
pub struct DatabaseConfig {
/// PostgreSQL connection URL (e.g. `postgres://user:pass@host/db`).
pub url: String,
/// Maximum number of connections in the pool.
pub max_connections: u32,
/// Minimum number of idle connections maintained.
pub min_connections: u32,
/// Timeout for acquiring a new connection (seconds).
pub connect_timeout_secs: u64,
/// Timeout for idle connections before they are closed (seconds).
pub idle_timeout_secs: u64,
}
impl DatabaseConfig {
/// Build config by reading environment variables, falling back to defaults.
pub fn from_env() -> Self {
Self {
url: env::var("DATABASE_URL")
.unwrap_or_else(|_| "postgres://localhost/imks".to_string()),
max_connections: env::var("DATABASE_MAX_CONNECTIONS")
.ok()
.and_then(|v| v.parse().ok())
.unwrap_or(10),
min_connections: env::var("DATABASE_MIN_CONNECTIONS")
.ok()
.and_then(|v| v.parse().ok())
.unwrap_or(2),
connect_timeout_secs: env::var("DATABASE_CONNECT_TIMEOUT")
.ok()
.and_then(|v| v.parse().ok())
.unwrap_or(30),
idle_timeout_secs: env::var("DATABASE_IDLE_TIMEOUT")
.ok()
.and_then(|v| v.parse().ok())
.unwrap_or(600),
}
}
}
impl Default for DatabaseConfig {
fn default() -> Self {
Self::from_env()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_config_has_sane_values() {
// Without env vars set, defaults should be applied.
let cfg = DatabaseConfig {
url: "postgres://localhost/test".to_string(),
max_connections: 10,
min_connections: 2,
connect_timeout_secs: 30,
idle_timeout_secs: 600,
};
assert_eq!(cfg.max_connections, 10);
assert_eq!(cfg.min_connections, 2);
}
}
+37
View File
@@ -0,0 +1,37 @@
//! SQL migration runner.
//!
//! Reads migration files from the `migrate/` directory and applies them
//! in lexicographic order using sqlx's built-in migration infrastructure.
use sqlx::PgPool;
use sqlx::migrate::Migrator;
use std::path::Path;
use crate::{ImksError, ImksResult};
/// Run all pending SQL migrations from the `migrate/` directory.
///
/// Migrations are applied in filename order (e.g. `001_…sql` before `002_…sql`).
/// sqlx tracks applied migrations in a `_sqlx_migrations` table so that
/// only new migrations are executed on subsequent runs.
pub async fn run_migrations(pool: &PgPool) -> ImksResult<()> {
let migrations_dir = Path::new("migrate");
if !migrations_dir.exists() {
tracing::warn!("No migrate/ directory found — skipping migrations");
return Ok(());
}
let migrator = Migrator::new(migrations_dir)
.await
.map_err(|e| ImksError::Internal(format!("Failed to load migrations: {e}")))?;
migrator
.run(pool)
.await
.map_err(|e| ImksError::Internal(format!("Migration failed: {e}")))?;
tracing::info!("Database migrations completed");
Ok(())
}
+7
View File
@@ -0,0 +1,7 @@
pub mod config;
pub mod migration;
pub mod pool;
pub use config::DatabaseConfig;
pub use migration::run_migrations;
pub use pool::Database;
+75
View File
@@ -0,0 +1,75 @@
//! PostgreSQL connection pool wrapper.
//!
//! Provides [`Database`] — a thin, cloneable wrapper around `sqlx::PgPool`
//! with health-check and graceful shutdown.
use std::time::Duration;
use sqlx::Row;
use sqlx::postgres::{PgPool, PgPoolOptions};
use crate::ImksResult;
use super::config::DatabaseConfig;
/// Cloneable handle to the PostgreSQL connection pool.
///
/// All query execution goes through `pool()` which returns a `&PgPool`.
#[derive(Clone)]
pub struct Database {
pool: PgPool,
}
impl Database {
/// Create a new pool from config and verify connectivity with a ping.
pub async fn connect(config: &DatabaseConfig) -> ImksResult<Self> {
let pool = PgPoolOptions::new()
.max_connections(config.max_connections)
.min_connections(config.min_connections)
.acquire_timeout(Duration::from_secs(config.connect_timeout_secs))
.idle_timeout(Duration::from_secs(config.idle_timeout_secs))
.connect(&config.url)
.await?;
tracing::info!(
max_connections = config.max_connections,
min_connections = config.min_connections,
"PostgreSQL pool created"
);
let db = Self { pool };
db.health_check().await?;
Ok(db)
}
/// Wrap an existing `PgPool` (useful for tests with shared pools).
pub fn from_pool(pool: PgPool) -> Self {
Self { pool }
}
/// Access the inner `PgPool` for query execution.
pub fn pool(&self) -> &PgPool {
&self.pool
}
/// Verify the database is reachable by executing `SELECT 1`.
pub async fn health_check(&self) -> ImksResult<()> {
let row = sqlx::query("SELECT 1 AS alive")
.fetch_one(&self.pool)
.await?;
let alive: i32 = row.get("alive");
if alive != 1 {
return Err(crate::ImksError::Internal(
"Database health check returned unexpected value".into(),
));
}
tracing::debug!("Database health check passed");
Ok(())
}
/// Gracefully close all connections in the pool.
pub async fn close(&self) {
self.pool.close().await;
tracing::info!("Database pool closed");
}
}