#[cfg(test)]
use docker_wrapper::testing::{ContainerGuard, ContainerGuardSet};
#[cfg(test)]
use docker_wrapper::{RedisTemplate, Template};
#[cfg(test)]
use std::sync::atomic::{AtomicU16, Ordering};
#[cfg(test)]
use std::time::Duration;
#[cfg(test)]
fn unique_name(prefix: &str) -> String {
format!("{}-{}", prefix, uuid::Uuid::new_v4().simple())
}
#[cfg(test)]
fn unique_port() -> u16 {
static PORT: AtomicU16 = AtomicU16::new(40000);
PORT.fetch_add(1, Ordering::SeqCst)
}
#[tokio::test]
async fn test_basic_container_guard() {
let name = unique_name("basic-redis");
let port = unique_port();
let guard = ContainerGuard::new(RedisTemplate::new(&name).port(port))
.wait_for_ready(true) .start()
.await
.expect("Failed to start Redis container");
assert!(
guard.is_running().await.expect("Failed to check status"),
"Container should be running"
);
let template = guard.template();
assert_eq!(template.config().name, name);
}
#[tokio::test]
async fn test_connection_string() {
let name = unique_name("conn-redis");
let port = unique_port();
let guard = ContainerGuard::new(RedisTemplate::new(&name).port(port))
.wait_for_ready(true)
.start()
.await
.expect("Failed to start Redis");
let conn = guard.connection_string();
assert!(
conn.starts_with("redis://"),
"Should be a Redis connection URL"
);
assert!(
conn.contains(&port.to_string()),
"Should include the configured port"
);
println!("Redis available at: {}", conn);
}
#[tokio::test]
async fn test_fast_cleanup() {
let name = unique_name("fast-redis");
let port = unique_port();
let guard = ContainerGuard::new(RedisTemplate::new(&name).port(port))
.wait_for_ready(true)
.stop_timeout(Duration::from_secs(1)) .start()
.await
.expect("Failed to start Redis");
assert!(guard.is_running().await.unwrap());
}
#[tokio::test]
async fn test_debug_mode() {
let name = unique_name("debug-redis");
let port = unique_port();
let guard = ContainerGuard::new(RedisTemplate::new(&name).port(port))
.keep_on_panic(true) .capture_logs(true) .wait_for_ready(true)
.start()
.await
.expect("Failed to start Redis");
assert!(guard.is_running().await.unwrap());
}
#[tokio::test]
async fn test_container_reuse() {
let name = unique_name("reuse-redis");
let port = unique_port();
let guard1 = ContainerGuard::new(RedisTemplate::new(&name).port(port))
.reuse_if_running(true)
.stop_on_drop(false) .remove_on_drop(false) .wait_for_ready(true)
.start()
.await
.expect("Failed to start Redis");
let was_reused_first = guard1.was_reused();
println!("First guard - was_reused: {}", was_reused_first);
let guard2 = ContainerGuard::new(RedisTemplate::new(&name).port(port))
.reuse_if_running(true)
.wait_for_ready(true)
.start()
.await
.expect("Failed to start/reuse Redis");
println!("Second guard - was_reused: {}", guard2.was_reused());
assert!(guard2.was_reused(), "Second guard should reuse container");
}
#[tokio::test]
async fn test_manual_cleanup() {
let name = unique_name("manual-redis");
let port = unique_port();
let guard = ContainerGuard::new(RedisTemplate::new(&name).port(port))
.wait_for_ready(true)
.start()
.await
.expect("Failed to start Redis");
assert!(guard.is_running().await.unwrap());
guard.cleanup().await.expect("Failed to cleanup");
}
#[tokio::test]
async fn test_multi_container_set() {
let network = unique_name("test-net");
let redis1_name = unique_name("redis-primary");
let redis2_name = unique_name("redis-replica");
let port1 = unique_port();
let port2 = unique_port();
let guards = ContainerGuardSet::new()
.with_network(&network) .add(RedisTemplate::new(&redis1_name).port(port1))
.add(RedisTemplate::new(&redis2_name).port(port2))
.keep_on_panic(true) .start_all()
.await
.expect("Failed to start container set");
assert!(guards.contains(&redis1_name));
assert!(guards.contains(&redis2_name));
assert_eq!(guards.len(), 2);
assert_eq!(guards.network(), Some(network.as_str()));
println!("Running containers:");
for name in guards.names() {
println!(" - {}", name);
}
}
#[tokio::test]
async fn test_guard_set_options() {
let network = unique_name("options-net");
let port = unique_port();
let guards = ContainerGuardSet::new()
.with_network(&network)
.create_network(true) .remove_network_on_drop(true) .wait_for_ready(true) .keep_on_panic(false) .add(RedisTemplate::new(&unique_name("opt-redis")).port(port))
.start_all()
.await
.expect("Failed to start");
assert_eq!(guards.len(), 1);
assert!(!guards.is_empty());
}
#[tokio::test]
async fn test_container_info() {
let name = unique_name("info-redis");
let port = unique_port();
let guard = ContainerGuard::new(RedisTemplate::new(&name).port(port))
.wait_for_ready(true)
.start()
.await
.expect("Failed to start Redis");
if let Some(id) = guard.container_id() {
println!("Container ID: {}", id);
assert!(!id.is_empty());
}
let conn = guard.connection_string();
println!("Connection string: {}", conn);
assert!(conn.contains(&port.to_string()));
let host_port = guard
.host_port(6379)
.await
.expect("Failed to get host port");
println!(
"Redis container port 6379 mapped to host port: {}",
host_port
);
assert_eq!(host_port, port);
let logs = guard.logs().await.expect("Failed to get logs");
println!("Container logs:\n{}", logs);
assert!(logs.contains("Ready to accept connections"));
assert!(guard.is_running().await.expect("Failed to check status"));
}
#[cfg(test)]
async fn redis_fixture(name: &str, port: u16) -> ContainerGuard<RedisTemplate> {
ContainerGuard::new(RedisTemplate::new(name).port(port))
.wait_for_ready(true)
.keep_on_panic(true)
.capture_logs(true)
.stop_timeout(Duration::from_secs(2))
.start()
.await
.expect("Failed to create Redis fixture")
}
#[tokio::test]
async fn test_with_fixture() {
let name = unique_name("fixture-redis");
let port = unique_port();
let redis = redis_fixture(&name, port).await;
let conn = redis.connection_string();
println!("Fixture ready at: {}", conn);
}
fn main() {
println!("Testing Utilities Example");
println!("=========================");
println!();
println!("This example demonstrates docker-wrapper's testing utilities");
println!("for integration testing with automatic container lifecycle management.");
println!();
println!("Run the tests with:");
println!(" cargo test --example testing_utilities --features testing");
println!();
println!("Run with output:");
println!(" cargo test --example testing_utilities --features testing -- --nocapture");
println!();
println!("Features demonstrated:");
println!(" - ContainerGuard: Single container RAII management");
println!(" - ContainerGuardSet: Multi-container test environments");
println!(" - Automatic cleanup on drop and panic");
println!(" - Ready checks and connection strings");
println!(" - Debug mode for failed tests");
println!(" - Container reuse for faster development");
println!(" - Test fixture patterns");
}