kopi 0.2.1

Kopi is a JDK version management tool
Documentation
use kopi::config::LockingConfig;
use kopi::error::KopiError;
use kopi::locking::{
    CancellationToken, LockAcquisitionRequest, LockController, LockScope, LockTimeoutValue,
    PollingBackoff,
};
use std::thread;
use std::time::Duration;
use tempfile::TempDir;

#[test]
fn timeout_smoke_respects_zero_config() {
    let temp = TempDir::new().unwrap();
    let scope = LockScope::CacheWriter;

    let holder_config = LockingConfig::default();
    let holder = LockController::with_default_inspector(temp.path().to_path_buf(), &holder_config);
    let held = holder
        .acquire(scope.clone())
        .expect("initial lock acquisition should succeed");

    let mut timeout_config = LockingConfig::default();
    timeout_config.set_timeout_value(LockTimeoutValue::from_secs(0));
    let waiter = LockController::with_default_inspector(temp.path().to_path_buf(), &timeout_config);

    let err = waiter
        .acquire(scope.clone())
        .expect_err("zero-second timeout should fail when lock is held");
    match err {
        KopiError::LockingTimeout { timeout_value, .. } => {
            assert_eq!(timeout_value, LockTimeoutValue::from_secs(0))
        }
        other => panic!("expected timeout error, got {other:?}"),
    }

    holder.release(held).expect("should release held lock");
}

#[test]
fn cancellation_smoke_respects_token() {
    let temp = TempDir::new().unwrap();
    let scope = LockScope::CacheWriter;

    let holder_config = LockingConfig::default();
    let holder = LockController::with_default_inspector(temp.path().to_path_buf(), &holder_config);
    let held = holder
        .acquire(scope.clone())
        .expect("initial lock acquisition should succeed");

    let mut waiter_config = LockingConfig::default();
    waiter_config.set_timeout_value(LockTimeoutValue::from_secs(5));
    let cancel_token = CancellationToken::new();
    let cancel_clone = cancel_token.clone();
    let scope_for_thread = scope.clone();
    let path = temp.path().to_path_buf();

    let handle = thread::spawn(move || {
        let waiter = LockController::with_default_inspector(path, &waiter_config);
        let request = LockAcquisitionRequest::new(scope_for_thread, LockTimeoutValue::from_secs(5))
            .with_cancellation(cancel_clone)
            .with_backoff(PollingBackoff::default());
        waiter.acquire_with(request)
    });

    thread::sleep(Duration::from_millis(150));
    cancel_token.cancel();

    match handle.join().expect("thread should finish acquiring") {
        Err(KopiError::LockingCancelled { .. }) => {}
        other => panic!("expected cancellation error, got {other:?}"),
    }

    holder.release(held).expect("should release held lock");
}