isothrum-runner 0.11.0

The Isothrum runner: executes the run manifest Isoloom writes next to a target's files (lifecycle, state and locks, drivers, checks, events).
Documentation
//! What an embedder shares between threads: the runner's types are `Send` and `Sync`, and an
//! operation's future is `Send` (a desktop app spawns operations onto its runtime).

use std::error::Error;

use isothrum_runner::{CheckReport, Event, Lab, LoopbackPorts, Park, Recorder, Run, RunOptions, Runner, RunnerConfig, Status, SystemProcesses};

/// A test's outcome: a failed step is its report.
type Outcome<T = ()> = Result<T, Box<dyn Error>>;

fn send_sync<T: Send + Sync>() {}

fn send<T: Send>(_: &T) {}

#[test]
fn the_types_an_embedder_shares_between_threads_are_send_and_sync() {
    send_sync::<Runner>();
    send_sync::<RunnerConfig>();
    send_sync::<Lab<'_>>();
    send_sync::<RunOptions>();
    send_sync::<Event>();
    send_sync::<Recorder>();
    send_sync::<isothrum_runner::Error>();
    send_sync::<Status>();
    send_sync::<Run>();
    send_sync::<CheckReport>();
    send_sync::<SystemProcesses>();
    send_sync::<LoopbackPorts>();
}

#[test]
fn an_operation_can_run_on_any_thread() -> Outcome {
    let home = tempfile::tempdir()?;
    let dir = tempfile::tempdir()?;
    let manifest = dir.path().join("run.json");
    std::fs::write(&manifest, include_str!("fixtures/flag-portal.run.json"))?;
    let runner = Runner::new(RunnerConfig::new(home.path()))?;
    let lab = runner.open(&manifest, None)?;
    let (opts, events) = (RunOptions::new(), Recorder::new());
    send(&lab.up(&opts, &events));
    send(&lab.down(&opts, &events));
    send(&lab.park(Park::Pause, &events));
    send(&lab.resume(&opts, &events));
    send(&lab.check(&opts, &events));
    send(&lab.status());
    Ok(())
}