use lz4::threadpool::TPool;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::{Arc, Barrier};
use std::time::Duration;
#[test]
fn new_returns_none_for_zero_threads() {
let pool = TPool::new(0, 1);
assert!(pool.is_none(), "nb_threads=0 should return None");
}
#[test]
fn new_returns_none_for_zero_queue_size() {
let pool = TPool::new(1, 0);
assert!(pool.is_none(), "queue_size=0 should return None");
}
#[test]
fn new_returns_none_for_both_zero() {
let pool = TPool::new(0, 0);
assert!(pool.is_none());
}
#[test]
fn new_returns_some_for_single_thread_single_queue() {
let pool = TPool::new(1, 1);
assert!(pool.is_some());
}
#[test]
fn new_returns_some_for_multiple_threads() {
let pool = TPool::new(4, 8);
assert!(pool.is_some());
}
#[test]
fn submit_job_executes_closure() {
let pool = TPool::new(1, 4).expect("valid pool");
let counter = Arc::new(AtomicUsize::new(0));
let c = Arc::clone(&counter);
pool.submit_job(Box::new(move || {
c.fetch_add(1, Ordering::SeqCst);
}));
pool.jobs_completed();
assert_eq!(counter.load(Ordering::SeqCst), 1);
}
#[test]
fn submit_multiple_jobs_all_execute() {
let pool = TPool::new(2, 8).expect("valid pool");
let counter = Arc::new(AtomicUsize::new(0));
const N: usize = 16;
for _ in 0..N {
let c = Arc::clone(&counter);
pool.submit_job(Box::new(move || {
c.fetch_add(1, Ordering::SeqCst);
}));
}
pool.jobs_completed();
assert_eq!(counter.load(Ordering::SeqCst), N);
}
#[test]
fn submit_job_captures_closure_environment() {
let pool = TPool::new(1, 4).expect("valid pool");
let expected: u64 = 0xDEAD_BEEF_CAFE_1234;
let result = Arc::new(std::sync::Mutex::new(0u64));
let r = Arc::clone(&result);
pool.submit_job(Box::new(move || {
*r.lock().unwrap() = expected;
}));
pool.jobs_completed();
assert_eq!(*result.lock().unwrap(), expected);
}
#[test]
fn jobs_completed_returns_immediately_when_no_jobs() {
let pool = TPool::new(2, 4).expect("valid pool");
let done = Arc::new(AtomicUsize::new(0));
let d = Arc::clone(&done);
let handle = std::thread::spawn(move || {
pool.jobs_completed();
d.store(1, Ordering::SeqCst);
});
handle
.join()
.expect("jobs_completed should not deadlock on idle pool");
assert_eq!(done.load(Ordering::SeqCst), 1);
}
#[test]
fn jobs_completed_waits_for_slow_job() {
let pool = TPool::new(1, 4).expect("valid pool");
let flag = Arc::new(AtomicUsize::new(0));
let f = Arc::clone(&flag);
pool.submit_job(Box::new(move || {
std::thread::sleep(Duration::from_millis(50));
f.store(1, Ordering::SeqCst);
}));
pool.jobs_completed();
assert_eq!(flag.load(Ordering::SeqCst), 1);
}
#[test]
fn jobs_completed_is_reusable() {
let pool = TPool::new(2, 4).expect("valid pool");
let counter = Arc::new(AtomicUsize::new(0));
for _ in 0..4 {
let c = Arc::clone(&counter);
pool.submit_job(Box::new(move || {
c.fetch_add(1, Ordering::SeqCst);
}));
}
pool.jobs_completed();
assert_eq!(counter.load(Ordering::SeqCst), 4);
for _ in 0..4 {
let c = Arc::clone(&counter);
pool.submit_job(Box::new(move || {
c.fetch_add(1, Ordering::SeqCst);
}));
}
pool.jobs_completed();
assert_eq!(counter.load(Ordering::SeqCst), 8);
}
#[test]
fn drop_waits_for_in_flight_jobs() {
let flag = Arc::new(AtomicUsize::new(0));
{
let pool = TPool::new(1, 4).expect("valid pool");
let f = Arc::clone(&flag);
pool.submit_job(Box::new(move || {
std::thread::sleep(Duration::from_millis(50));
f.store(1, Ordering::SeqCst);
}));
}
assert_eq!(flag.load(Ordering::SeqCst), 1);
}
#[test]
fn jobs_run_concurrently_across_threads() {
const N: usize = 4;
let pool = TPool::new(N, N).expect("valid pool");
let barrier = Arc::new(Barrier::new(N));
let counter = Arc::new(AtomicUsize::new(0));
for _ in 0..N {
let b = Arc::clone(&barrier);
let c = Arc::clone(&counter);
pool.submit_job(Box::new(move || {
b.wait(); c.fetch_add(1, Ordering::SeqCst);
}));
}
pool.jobs_completed();
assert_eq!(counter.load(Ordering::SeqCst), N);
}
#[test]
fn submit_many_jobs_small_pool() {
let pool = TPool::new(2, 2).expect("valid pool");
let counter = Arc::new(AtomicUsize::new(0));
const N: usize = 50;
for _ in 0..N {
let c = Arc::clone(&counter);
pool.submit_job(Box::new(move || {
c.fetch_add(1, Ordering::SeqCst);
}));
}
pool.jobs_completed();
assert_eq!(counter.load(Ordering::SeqCst), N);
}