use chrono::Utc;
use oxcache::database::mysql::MySQLPartitionManager;
use oxcache::database::partition::{PartitionConfig, PartitionManager};
use oxcache::database::postgresql::PostgresPartitionManager;
use oxcache::database::sqlite::SQLitePartitionManager;
use oxcache::database::PartitionStrategy;
use oxcache::error::Result;
use std::sync::Arc;
#[path = "./common/database_test_utils.rs"]
mod database_test_utils;
use database_test_utils::*;
fn should_run_database_tests() -> bool {
std::env::var("OXCACHE_TEST_DATABASE")
.map(|v| v == "1" || v.to_lowercase() == "true")
.unwrap_or(false)
}
#[tokio::test]
async fn test_postgres_partitioning() -> Result<()> {
if !should_run_database_tests() {
println!("⚠️ Database tests are disabled. Set OXCACHE_TEST_DATABASE=1 to enable.");
return Ok(());
}
let config = TestConfig::from_file();
let partition_config = create_partition_config(
config.partitioning_enabled,
config.strategy,
config.retention_months,
);
let manager_result = tokio::time::timeout(
std::time::Duration::from_secs(30),
PostgresPartitionManager::new(&config.postgres_url, partition_config),
)
.await;
let manager = match manager_result {
Ok(Ok(manager)) => manager,
Ok(Err(e)) => {
println!("⚠️ PostgreSQL connection failed: {}. Skipping test.", e);
return Ok(()); }
Err(_) => {
println!("⚠️ PostgreSQL connection timeout. Skipping test.");
return Ok(()); }
};
let test_table = "test_cache_entries";
cleanup_postgres_table("crawlrs_db", "crawlrs_db", "user", test_table);
let schema = format!(
"CREATE TABLE IF NOT EXISTS {} (
id SERIAL,
key VARCHAR(255) NOT NULL,
value TEXT,
timestamp TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
PRIMARY KEY (id, timestamp)
)",
test_table
);
manager.initialize_table(test_table, &schema).await?;
println!("✓ PostgreSQL table initialized with partitioning");
let partitions = verify_partition_creation(&manager, test_table, true, 1).await?;
if let Some(partition) = partitions.first() {
manager.drop_partition(test_table, &partition.name).await?;
println!("✓ PostgreSQL partition dropped");
}
Ok(())
}
#[tokio::test]
async fn test_mysql_partitioning() -> Result<()> {
if !should_run_database_tests() {
println!("⚠️ Database tests are disabled. Set OXCACHE_TEST_DATABASE=1 to enable.");
return Ok(());
}
let config = TestConfig::from_file();
let partition_config = create_partition_config(
config.partitioning_enabled,
config.strategy,
config.retention_months,
);
let manager_result = tokio::time::timeout(
std::time::Duration::from_secs(30),
MySQLPartitionManager::new(&config.mysql_url, partition_config),
)
.await;
let manager = match manager_result {
Ok(Ok(manager)) => manager,
Ok(Err(e)) => {
println!("⚠️ MySQL connection failed: {}. Skipping test.", e);
return Ok(()); }
Err(_) => {
println!("⚠️ MySQL connection timeout. Skipping test.");
return Ok(()); }
};
let test_table = "test_cache_entries";
let schema = format!(
"CREATE TABLE IF NOT EXISTS {} (
id INT NOT NULL AUTO_INCREMENT,
`key` VARCHAR(255) NOT NULL,
value TEXT,
created_at DATE NOT NULL,
timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id, created_at)
)",
test_table
);
let init_result = tokio::time::timeout(
std::time::Duration::from_secs(30),
manager.initialize_table(test_table, &schema),
)
.await;
match init_result {
Ok(Ok(_)) => println!("✓ MySQL table initialized with partitioning"),
Ok(Err(e)) => {
println!(
"⚠️ MySQL table initialization failed: {}. Skipping test.",
e
);
return Ok(());
}
Err(_) => {
println!("⚠️ MySQL table initialization timeout. Skipping test.");
return Ok(());
}
}
let test_date = Utc::now();
let partition_result = tokio::time::timeout(
std::time::Duration::from_secs(30),
manager.ensure_partition_exists(test_date, test_table),
)
.await;
match partition_result {
Ok(Ok(_)) => println!("✓ MySQL partition created"),
Ok(Err(e)) => {
println!("⚠️ MySQL partition creation failed: {}. Skipping test.", e);
return Ok(());
}
Err(_) => {
println!("⚠️ MySQL partition creation timeout. Skipping test.");
return Ok(());
}
}
let list_result = tokio::time::timeout(
std::time::Duration::from_secs(30),
manager.get_partitions(test_table),
)
.await;
let _partitions = match list_result {
Ok(Ok(partitions)) => {
println!("✓ MySQL partitions listed: {} found", partitions.len());
partitions
}
Ok(Err(e)) => {
println!("⚠️ MySQL partition listing failed: {}. Skipping test.", e);
return Ok(());
}
Err(_) => {
println!("⚠️ MySQL partition listing timeout. Skipping test.");
return Ok(());
}
};
Ok(())
}
#[tokio::test]
async fn test_sqlite_partitioning() -> Result<()> {
if !should_run_database_tests() {
println!("⚠️ Database tests are disabled. Set OXCACHE_TEST_DATABASE=1 to enable.");
return Ok(());
}
let db_path = "sqlite::memory:";
println!("Testing SQLite partitioning with in-memory database");
let partition_config = PartitionConfig {
enabled: true,
strategy: PartitionStrategy::Monthly,
retention_months: 6,
..Default::default()
};
let manager = SQLitePartitionManager::new(db_path, partition_config).await?;
let test_table = "cache_entries";
let schema = format!(
"CREATE TABLE IF NOT EXISTS {} (
id INTEGER PRIMARY KEY AUTOINCREMENT,
key TEXT NOT NULL,
value TEXT,
timestamp TEXT DEFAULT CURRENT_TIMESTAMP
)",
test_table
);
manager.initialize_table(test_table, &schema).await?;
println!("✓ SQLite table initialized with partitioning");
let mut partitions = manager.get_partitions(test_table).await?;
println!("✓ SQLite partitions listed: {} found", partitions.len());
if partitions.is_empty() {
let test_date = Utc::now();
let partition_name = manager
.ensure_partition_exists(test_date, test_table)
.await?;
println!("✓ SQLite partition ensured: {}", partition_name);
partitions = manager.get_partitions(test_table).await?;
println!(
"✓ SQLite partitions listed after creation: {} found",
partitions.len()
);
}
for partition in &partitions {
println!(
" Partition: {} ({} to {})",
partition.name,
partition.start_date.format("%Y-%m-%d"),
partition.end_date.format("%Y-%m-%d")
);
}
let test_date = Utc::now();
let partition_name = manager
.ensure_partition_exists(test_date, test_table)
.await?;
println!("✓ SQLite partition ensured: {}", partition_name);
let all_partitions = manager.get_partitions(test_table).await?;
println!("✓ Total partitions: {}", all_partitions.len());
println!("✓ SQLite partitioning test completed successfully");
Ok(())
}
#[tokio::test]
async fn test_partition_retention() -> Result<()> {
if !should_run_database_tests() {
println!("⚠️ Database tests are disabled. Set OXCACHE_TEST_DATABASE=1 to enable.");
return Ok(());
}
let config = TestConfig::from_file();
let partition_config = create_partition_config(
config.partitioning_enabled,
config.strategy,
2, );
let manager_result = tokio::time::timeout(
std::time::Duration::from_secs(30),
PostgresPartitionManager::new(&config.postgres_url, partition_config),
)
.await;
let manager = match manager_result {
Ok(Ok(manager)) => manager,
Ok(Err(e)) => {
println!("⚠️ PostgreSQL connection failed: {}. Skipping test.", e);
return Ok(()); }
Err(_) => {
println!("⚠️ PostgreSQL connection timeout. Skipping test.");
return Ok(()); }
};
let test_table = "test_retention_entries";
cleanup_postgres_table("crawlrs_db", "crawlrs_db", "user", test_table);
let schema = format!(
"CREATE TABLE IF NOT EXISTS {} (
id SERIAL,
key VARCHAR(255) NOT NULL,
value TEXT,
timestamp TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
PRIMARY KEY (id, timestamp)
)",
test_table
);
manager.initialize_table(test_table, &schema).await?;
verify_partition_cleanup(&manager, test_table, 2).await?;
Ok(())
}
#[tokio::test]
async fn test_invalid_configuration() -> Result<()> {
if !should_run_database_tests() {
println!("⚠️ Database tests are disabled. Set OXCACHE_TEST_DATABASE=1 to enable.");
return Ok(());
}
let _config = TestConfig::from_file();
let invalid_postgres_url = "postgresql://invalid:invalid@localhost:9999/invalid_db";
let partition_config = create_partition_config(true, PartitionStrategy::Monthly, 12);
let result = PostgresPartitionManager::new(invalid_postgres_url, partition_config).await;
assert!(result.is_err(), "Should fail with invalid PostgreSQL URL");
let invalid_mysql_url = "mysql://invalid:invalid@localhost:9999/invalid_db";
let partition_config = create_partition_config(true, PartitionStrategy::Monthly, 12);
let result = MySQLPartitionManager::new(invalid_mysql_url, partition_config).await;
assert!(result.is_err(), "Should fail with invalid MySQL URL");
Ok(())
}
#[tokio::test]
async fn test_concurrent_operations() -> Result<()> {
if !should_run_database_tests() {
println!("⚠️ Database tests are disabled. Set OXCACHE_TEST_DATABASE=1 to enable.");
return Ok(());
}
let config = TestConfig::from_file();
let partition_config = create_partition_config(
config.partitioning_enabled,
config.strategy,
config.retention_months,
);
let manager_result = tokio::time::timeout(
std::time::Duration::from_secs(30),
PostgresPartitionManager::new(&config.postgres_url, partition_config),
)
.await;
let manager = match manager_result {
Ok(Ok(manager)) => Arc::new(manager),
Ok(Err(e)) => {
println!("⚠️ PostgreSQL connection failed: {}. Skipping test.", e);
return Ok(()); }
Err(_) => {
println!("⚠️ PostgreSQL connection timeout. Skipping test.");
return Ok(()); }
};
let test_table = "test_concurrent_entries";
cleanup_postgres_table("crawlrs_db", "crawlrs_db", "user", test_table);
let schema = format!(
"CREATE TABLE IF NOT EXISTS {} (
id SERIAL,
key VARCHAR(255) NOT NULL,
value TEXT,
timestamp TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
PRIMARY KEY (id, timestamp)
)",
test_table
);
manager.initialize_table(test_table, &schema).await?;
test_concurrent_partition_operations(manager, test_table).await?;
Ok(())
}