agent-procs 0.6.3

Concurrent process runner for AI agents
Documentation
mod helpers;
use helpers::TestContext;

#[test]
fn test_run_and_status() {
    let ctx = TestContext::new("test-run-status");

    let output = ctx
        .cmd()
        .args([
            "--session",
            &ctx.session,
            "run",
            "sleep 60",
            "--name",
            "sleeper",
        ])
        .output()
        .unwrap();
    assert!(
        output.status.success(),
        "run failed: {}",
        String::from_utf8_lossy(&output.stderr)
    );
    assert!(String::from_utf8_lossy(&output.stdout).contains("sleeper"));

    let output = ctx
        .cmd()
        .args(["--session", &ctx.session, "status"])
        .output()
        .unwrap();
    assert!(output.status.success());
    let stdout = String::from_utf8_lossy(&output.stdout);
    assert!(stdout.contains("sleeper"));
    assert!(stdout.contains("running"));

    let output = ctx
        .cmd()
        .args(["--session", &ctx.session, "stop", "sleeper"])
        .output()
        .unwrap();
    assert!(output.status.success());

    // Cleanup daemon
    let _ = ctx
        .cmd()
        .args(["--session", &ctx.session, "stop-all"])
        .output();
}

#[test]
fn test_stop_nonexistent_returns_error() {
    let ctx = TestContext::new("test-stop-missing");

    let _ = ctx
        .cmd()
        .args(["--session", &ctx.session, "run", "sleep 60", "--name", "bg"])
        .output()
        .unwrap();

    let output = ctx
        .cmd()
        .args(["--session", &ctx.session, "stop", "nonexistent"])
        .output()
        .unwrap();
    let stderr = String::from_utf8_lossy(&output.stderr);
    assert!(stderr.contains("not found") || !output.status.success());

    let _ = ctx
        .cmd()
        .args(["--session", &ctx.session, "stop-all"])
        .output();
}

#[test]
fn test_restart_process() {
    let ctx = TestContext::new("t-restart");

    // Start a process
    let output = ctx
        .cmd()
        .args([
            "--session",
            &ctx.session,
            "run",
            "sleep 60",
            "--name",
            "srv",
        ])
        .output()
        .unwrap();
    assert!(output.status.success());

    // Get original PID from status
    let output = ctx
        .cmd()
        .args(["--session", &ctx.session, "status", "--json"])
        .output()
        .unwrap();
    let stdout = String::from_utf8_lossy(&output.stdout);
    let procs: Vec<serde_json::Value> = serde_json::from_str(&stdout).unwrap();
    let original_pid = procs[0]["pid"].as_u64().unwrap();

    // Restart it
    let output = ctx
        .cmd()
        .args(["--session", &ctx.session, "restart", "srv"])
        .output()
        .unwrap();
    assert!(output.status.success());
    assert!(String::from_utf8_lossy(&output.stdout).contains("restarted"));

    // Verify it's running with a new PID
    let output = ctx
        .cmd()
        .args(["--session", &ctx.session, "status", "--json"])
        .output()
        .unwrap();
    let stdout = String::from_utf8_lossy(&output.stdout);
    let procs: Vec<serde_json::Value> = serde_json::from_str(&stdout).unwrap();
    let new_pid = procs[0]["pid"].as_u64().unwrap();
    assert_ne!(original_pid, new_pid, "PID should change after restart");

    let _ = ctx
        .cmd()
        .args(["--session", &ctx.session, "stop-all"])
        .output();
}