supermachine 0.4.13

Run any OCI/Docker image as a hardware-isolated microVM on macOS HVF (Linux KVM and Windows WHP in progress). Single library API, zero flags for the common case, sub-100 ms cold-restore from snapshot.
//! Smoke test for the v0.4.0 Pool API: explicit builder, auto-
//! grow, acquire timeout, stats.

use std::time::{Duration, Instant};
use supermachine::Image;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let snap = format!(
        "{}/.local/supermachine-snapshots/nginx_1v",
        std::env::var("HOME")?
    );
    let image = Image::from_snapshot(&snap)?;

    // === Test 1: lazy auto-grow ===
    println!("=== Test 1: pool with min=0, max=3, lazy spawn ===");
    let pool = image
        .pool()
        .min(0)
        .max(3)
        .acquire_timeout(Duration::from_secs(2))
        .build()?;
    let s0 = pool.stats();
    println!("  initial stats: alive={} idle={} max={}", s0.alive, s0.idle, s0.max);
    assert_eq!(s0.alive, 0, "min=0 should mean no eager spawn");

    let t0 = Instant::now();
    let vm1 = pool.acquire()?;
    println!(
        "  acquire #1 (lazy spawn from 0): {:?} stats={:?}",
        t0.elapsed(),
        pool.stats()
    );

    let t0 = Instant::now();
    let vm2 = pool.acquire()?;
    println!(
        "  acquire #2 (lazy spawn): {:?} stats={:?}",
        t0.elapsed(),
        pool.stats()
    );

    let t0 = Instant::now();
    let vm3 = pool.acquire()?;
    println!(
        "  acquire #3 (lazy spawn, hits max): {:?} stats={:?}",
        t0.elapsed(),
        pool.stats()
    );

    println!("=== Test 2: acquire at max → blocks then times out ===");
    let t0 = Instant::now();
    match pool.acquire() {
        Ok(_) => panic!("expected PoolExhausted, got worker"),
        Err(e) => {
            println!(
                "{} after {:?}",
                e,
                t0.elapsed()
            );
        }
    }

    drop(vm1);
    drop(vm2);
    drop(vm3);

    println!("=== Test 3: after drops, acquire is fast (recycled) ===");
    std::thread::sleep(Duration::from_millis(200)); // wait for restorer
    let t0 = Instant::now();
    let _vm = pool.acquire()?;
    println!("  acquire after drops: {:?}", t0.elapsed());
    println!("  final stats: {:?}", pool.stats());
    Ok(())
}