soft3/neuron/cli/tests/process.rs

use serde_json::Value;
use std::process::Command;
use std::sync::atomic::{AtomicUsize, Ordering};

struct Store(std::path::PathBuf);
impl Store {
    fn new() -> Self {
        static NEXT: AtomicUsize = AtomicUsize::new(0);
        let path = std::env::temp_dir().join(format!(
            "cell-cli-{}-{}",
            std::process::id(),
            NEXT.fetch_add(1, Ordering::Relaxed)
        ));
        std::fs::create_dir(&path).unwrap();
        Self(path)
    }
    fn call(&self, args: &[&str]) -> (bool, Value) {
        let output = Command::new(env!("CARGO_BIN_EXE_cell"))
            .arg("--store")
            .arg(self.0.join("bbg"))
            .args(args)
            .output()
            .unwrap();
        let bytes = if output.status.success() {
            &output.stdout
        } else {
            &output.stderr
        };
        (
            output.status.success(),
            serde_json::from_slice(bytes)
                .unwrap_or_else(|_| panic!("{}", String::from_utf8_lossy(bytes))),
        )
    }
    fn ok(&self, args: &[&str]) -> Value {
        let (ok, value) = self.call(args);
        assert!(ok, "{value}");
        value
    }
    fn source(&self, text: &str) -> String {
        let path = self.0.join("cell.rune");
        std::fs::write(&path, text).unwrap();
        path.to_str().unwrap().to_owned()
    }
}
impl Drop for Store {
    fn drop(&mut self) {
        let _ = std::fs::remove_dir_all(&self.0);
    }
}

#[test]
fn counter_and_history_survive_separate_processes() {
    let store = Store::new();
    let source = store.source("~mem + event");
    let created = store.ok(&["create", &source]);
    let cell = created["cell"].as_str().unwrap();
    let nonce = "01".repeat(32);
    assert_eq!(
        store.ok(&["submit", cell, "7", "--nonce", &nonce])["state"],
        "7"
    );
    assert_eq!(
        store.ok(&["submit", cell, "7", "--nonce", &nonce])["state"],
        "7"
    );
    assert!(!store.call(&["submit", cell, "8", "--nonce", &nonce]).0);
    assert_eq!(store.ok(&["submit", cell, "5"])["state"], "12");
    let history = store.ok(&["history", cell]);
    assert_eq!(history["history"][0]["index"], 0);
    assert_eq!(history["history"].as_array().unwrap().len(), 8);
    assert_eq!(store.ok(&["inspect", cell])["state"], "12");
}

#[test]
fn executor_recovery_requires_correlated_outcome_and_pause_keeps_it() {
    let store = Store::new();
    let source = store.source("let x = host(event); ~mem + x");
    let created = store.ok(&["create", &source, "--initial", "10", "--allow", "host"]);
    let cell = created["cell"].as_str().unwrap();
    let pending = store.ok(&["submit", cell, "7", "--context", cell]);
    let operation = pending["operation"].as_str().unwrap();
    assert_eq!(pending["status"], "awaiting-executor");
    let receipt = store.ok(&["take", cell, operation]);
    let attempt = receipt["attempt"].as_str().unwrap();
    assert_eq!(store.ok(&["run", cell])["status"], "unknown-outcome");
    assert!(!store.call(&["take", cell, operation]).0);
    assert!(!store.call(&["cancel", cell]).0);
    store.ok(&["pause", cell]);
    assert_eq!(
        store.ok(&["outcome", cell, operation, attempt, "32"])["state"],
        "10"
    );
    assert_eq!(store.ok(&["resume", cell])["state"], "42");
    assert_eq!(
        store.ok(&["outcome", cell, operation, attempt, "32"])["state"],
        "42"
    );
    assert!(!store.call(&["outcome", cell, operation, attempt, "99"]).0);
    assert_eq!(store.ok(&["retire", cell])["lifecycle"], "retired");
    assert!(!store.call(&["resume", cell]).0);
}

#[test]
fn denied_effect_cannot_turn_into_successful_zero() {
    let store = Store::new();
    let source = store.source("let x = emit(event); 99");
    let created = store.ok(&["create", &source, "--initial", "10"]);
    let cell = created["cell"].as_str().unwrap();
    assert!(!store.call(&["submit", cell, "7"]).0);
    assert_eq!(store.ok(&["inspect", cell])["state"], "10");
    assert!(
        store.ok(&["history", cell])["history"]
            .as_array()
            .unwrap()
            .iter()
            .any(|h| h["events"]
                .as_array()
                .unwrap()
                .iter()
                .any(|e| e["entry"] == "$denied"))
    );
}

#[test]
fn definite_failure_closes_attempt_and_retains_diagnostic() {
    let store = Store::new();
    let source = store.source("let x = host(event); 99");
    let created = store.ok(&["create", &source, "--initial", "10", "--allow", "host"]);
    let cell = created["cell"].as_str().unwrap();
    let pending = store.ok(&["submit", cell, "7"]);
    let operation = pending["operation"].as_str().unwrap();
    let taken = store.ok(&["take", cell, operation]);
    let attempt = taken["attempt"].as_str().unwrap();
    store.ok(&[
        "fail",
        cell,
        operation,
        attempt,
        "executor rejected request",
    ]);
    assert!(!store.call(&["run", cell]).0);
    let final_state = store.ok(&["inspect", cell]);
    assert_eq!(final_state["state"], "10");
    assert_eq!(final_state["fault"], "executor rejected request");
    assert!(final_state["invocation"].is_null());
    store.ok(&[
        "fail",
        cell,
        operation,
        attempt,
        "executor rejected request",
    ]);
    assert!(!store.call(&["outcome", cell, operation, attempt, "1"]).0);
    store.ok(&["retire", cell]);
}

Homonyms

neural/rs/darwin-sys/src/process.rs
neural/rs/darwin-sys/src/ffi/process.rs

Graph