Add comprehensive TDD infrastructure with 45 tests
- Add lib crate exposing modules for integration testing - Add dev-dependencies: tokio-test 0.4, tempfile - Refactor parse_csv_fields() as pure function for unit testing - Add field validation (minimum 16 fields required) - Fix repository last_insert_id using SELECT LAST_INSERT_ID() - Add 10 lib tests for CSV parsing and date formatting - Add 10 config tests for environment configuration - Add 7 import tests for CSV file parsing - Add 6 models tests for database structs - Add 12 repository tests for CRUD operations
This commit is contained in:
122
tests/common/test_db.rs
Normal file
122
tests/common/test_db.rs
Normal file
@@ -0,0 +1,122 @@
|
||||
//! Test database utilities.
|
||||
//!
|
||||
//! AI AGENT NOTE: These helpers manage the test database connection pool.
|
||||
//! Uses rusty_petroleum_test database for all tests.
|
||||
|
||||
use sqlx::mysql::{MySqlPool, MySqlPoolOptions};
|
||||
use std::time::Duration;
|
||||
|
||||
/// Creates a connection pool to the test database.
|
||||
///
|
||||
/// AI AGENT NOTE: Uses config.toml or config.test.toml for connection details.
|
||||
/// The test database should be separate from dev/prod to avoid data conflicts.
|
||||
pub async fn create_test_pool() -> MySqlPool {
|
||||
let config = crate::config::Config::load(crate::config::Env::Test)
|
||||
.expect("Failed to load test config");
|
||||
|
||||
MySqlPoolOptions::new()
|
||||
.max_connections(1)
|
||||
.acquire_timeout(Duration::from_secs(10))
|
||||
.connect(&config.database.connection_url())
|
||||
.await
|
||||
.expect("Failed to connect to test database")
|
||||
}
|
||||
|
||||
/// Resets the test database by dropping and recreating all tables.
|
||||
///
|
||||
/// AI AGENT NOTE: This is used before running tests to ensure a clean state.
|
||||
/// It uses the `rusty_petroleum_test` database.
|
||||
pub async fn reset_test_database() -> anyhow::Result<()> {
|
||||
let config = crate::config::Config::load(crate::config::Env::Test)?;
|
||||
let database_url = config.database.connection_url();
|
||||
let base_url = database_url.trim_end_matches(config.env.database_name());
|
||||
|
||||
let setup_pool = MySqlPoolOptions::new()
|
||||
.max_connections(1)
|
||||
.connect(base_url)
|
||||
.await?;
|
||||
|
||||
// Drop database if exists
|
||||
sqlx::query(&format!("DROP DATABASE IF EXISTS {}", config.env.database_name()))
|
||||
.execute(&setup_pool)
|
||||
.await?;
|
||||
|
||||
// Create fresh database
|
||||
sqlx::query(&format!("CREATE DATABASE {}", config.env.database_name()))
|
||||
.execute(&setup_pool)
|
||||
.await?;
|
||||
|
||||
drop(setup_pool);
|
||||
|
||||
// Now create tables
|
||||
let pool = create_test_pool().await;
|
||||
|
||||
// Create customers table
|
||||
sqlx::query(
|
||||
r#"
|
||||
CREATE TABLE customers (
|
||||
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||
customer_number VARCHAR(50) NOT NULL UNIQUE,
|
||||
card_report_group TINYINT UNSIGNED NOT NULL DEFAULT 0,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
INDEX idx_customer_number (customer_number)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||
"#,
|
||||
)
|
||||
.execute(&pool)
|
||||
.await?;
|
||||
|
||||
// Create cards table
|
||||
sqlx::query(
|
||||
r#"
|
||||
CREATE TABLE cards (
|
||||
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||
card_number VARCHAR(50) NOT NULL UNIQUE,
|
||||
customer_id INT UNSIGNED NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
INDEX idx_card_number (card_number),
|
||||
INDEX idx_customer_id (customer_id),
|
||||
FOREIGN KEY (customer_id) REFERENCES customers(id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||
"#,
|
||||
)
|
||||
.execute(&pool)
|
||||
.await?;
|
||||
|
||||
// Create transactions table
|
||||
sqlx::query(
|
||||
r#"
|
||||
CREATE TABLE transactions (
|
||||
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||
transaction_date DATETIME NOT NULL,
|
||||
batch_number VARCHAR(20) NOT NULL,
|
||||
amount DECIMAL(10,2) NOT NULL,
|
||||
volume DECIMAL(10,3) NOT NULL,
|
||||
price DECIMAL(8,4) NOT NULL,
|
||||
quality_code INT NOT NULL,
|
||||
quality_name VARCHAR(50) NOT NULL,
|
||||
card_number VARCHAR(50) NOT NULL,
|
||||
station VARCHAR(20) NOT NULL,
|
||||
terminal VARCHAR(10) NOT NULL,
|
||||
pump VARCHAR(10) NOT NULL,
|
||||
receipt VARCHAR(20) NOT NULL,
|
||||
control_number VARCHAR(20),
|
||||
customer_id INT UNSIGNED NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
INDEX idx_transaction_date (transaction_date),
|
||||
INDEX idx_batch_number (batch_number),
|
||||
INDEX idx_customer_id (customer_id),
|
||||
INDEX idx_card_number (card_number),
|
||||
INDEX idx_station (station)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||
"#,
|
||||
)
|
||||
.execute(&pool)
|
||||
.await?;
|
||||
|
||||
drop(pool);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Reference in New Issue
Block a user