use matchy::Database;
use std::sync::Arc;
use std::thread;
#[test]
fn test_database_is_send_sync() {
fn assert_send<T: Send>() {}
fn assert_sync<T: Sync>() {}
assert_send::<Database>();
assert_sync::<Database>();
}
#[test]
fn test_concurrent_queries() {
let db = Arc::new(
Database::from("tests/data/GeoLite2-Country.mmdb")
.open()
.expect("Failed to open test database"),
);
let handles: Vec<_> = (0..8)
.map(|thread_id| {
let db = Arc::clone(&db);
thread::spawn(move || {
for i in 0..100 {
let ip = format!(
"{}.{}.{}.{}",
1 + thread_id,
i % 256,
(i / 256) % 256,
i % 128
);
let _ = db.lookup(&ip);
}
})
})
.collect();
for handle in handles {
handle.join().unwrap();
}
let stats = db.stats();
assert_eq!(stats.total_queries, 800, "Expected 800 total queries");
println!(
"Concurrent test passed: {} queries, {:.1}% cache hit rate",
stats.total_queries,
stats.cache_hit_rate() * 100.0
);
}
#[test]
fn test_shared_cache_locality() {
let db = Arc::new(
Database::from("tests/data/GeoLite2-Country.mmdb")
.cache_capacity(100)
.open()
.expect("Failed to open test database"),
);
let handles: Vec<_> = (0..4)
.map(|_| {
let db = Arc::clone(&db);
thread::spawn(move || {
for _ in 0..100 {
let _ = db.lookup("8.8.8.8");
}
})
})
.collect();
for handle in handles {
handle.join().unwrap();
}
let stats = db.stats();
assert_eq!(stats.total_queries, 400);
assert_eq!(
stats.cache_misses, 4,
"Expected 4 cache misses (one per thread)"
);
assert_eq!(stats.cache_hits, 396, "Expected 396 cache hits");
println!(
"Thread-local cache test passed: {:.1}% hit rate",
stats.cache_hit_rate() * 100.0
);
}