fn alba() -> assert_cmd::Command {
assert_cmd::Command::cargo_bin("alba").unwrap()
}
fn project(beamfile: &str) -> tempfile::TempDir {
let dir = tempfile::tempdir().unwrap();
std::fs::write(dir.path().join("Beamfile"), beamfile).unwrap();
dir
}
fn plugin_path() -> (std::ffi::OsString, tempfile::TempDir) {
let example = assert_cmd::cargo::cargo_bin("alba-executor-example");
let name = example
.file_name()
.expect("a binary path always has a file name");
let isolated = tempfile::tempdir().unwrap();
let linked = isolated.path().join(name);
#[cfg(unix)]
std::os::unix::fs::symlink(&example, &linked).unwrap();
#[cfg(windows)]
std::fs::copy(&example, &linked).unwrap();
let existing = std::env::var_os("PATH").unwrap_or_default();
let mut dirs = vec![isolated.path().to_path_buf()];
dirs.extend(std::env::split_paths(&existing));
let path = std::env::join_paths(dirs).expect("the augmented PATH must join into one OsString");
(path, isolated)
}
#[test]
fn a_plugin_beam_runs_end_to_end() {
let dir =
project("beam hello { executor example run \"echo carried by the example plugin\" }\n");
let (path, _plugin_dir) = plugin_path();
alba()
.current_dir(&dir)
.env("PATH", path)
.args(["run", "hello"])
.assert()
.success()
.stdout(predicates::str::contains("carried by the example plugin"));
}
#[test]
fn a_plugin_beams_failure_is_an_ordinary_beam_failure() {
let dir = project("beam boom { executor example run \"fail 3\" }\n");
let (path, _plugin_dir) = plugin_path();
alba()
.current_dir(&dir)
.env("PATH", path)
.args(["run", "boom"])
.assert()
.code(1)
.stderr(predicates::str::contains("1 failed"));
}
#[test]
fn a_missing_plugin_is_a_clean_plan_time_error() {
let dir = project("beam ghost { executor nosuchthing run \"echo nope\" }\n");
alba()
.current_dir(&dir)
.args(["run", "ghost"])
.assert()
.code(2)
.stderr(predicates::str::contains(
"neither a built-in executor nor `alba-executor-nosuchthing`",
));
}
#[test]
fn plugin_check_passes_the_example_plugin() {
let example = assert_cmd::cargo::cargo_bin("alba-executor-example");
alba()
.args([
"plugin",
"check",
example.to_str().expect("a utf-8 target path"),
"--command",
"echo probe",
"--cancel-command",
"sleep 30000",
])
.assert()
.success()
.stdout(predicates::str::contains("\u{2713} handshake"))
.stdout(predicates::str::contains("\u{2713} execute"))
.stdout(predicates::str::contains("\u{2713} cancel"))
.stdout(predicates::str::contains("answered in"))
.stdout(predicates::str::contains("\u{2713} close"))
.stdout(predicates::str::contains("conformant"));
}
#[test]
fn plugin_check_default_cancel_command_actually_exercises_cancel() {
let example = assert_cmd::cargo::cargo_bin("alba-executor-example");
alba()
.args([
"plugin",
"check",
example.to_str().expect("a utf-8 target path"),
])
.assert()
.success()
.stdout(predicates::str::contains("\u{2713} cancel"))
.stdout(predicates::str::contains("answered in"))
.stdout(predicates::str::contains("conformant"));
}
#[test]
fn plugin_check_rejects_a_cancel_command_that_finishes_before_cancel_is_sent() {
let example = assert_cmd::cargo::cargo_bin("alba-executor-example");
alba()
.args([
"plugin",
"check",
example.to_str().expect("a utf-8 target path"),
"--cancel-command",
"sleep 5",
])
.assert()
.code(1)
.stdout(predicates::str::contains("\u{2717} cancel"))
.stdout(predicates::str::contains("before"))
.stdout(predicates::str::contains("not conformant"));
}
#[cfg(unix)]
#[test]
fn plugin_check_sends_empty_options_not_null() {
use std::os::unix::fs::PermissionsExt;
let dir = tempfile::tempdir().unwrap();
let script = dir.path().join("options-shape-executor");
std::fs::write(
&script,
r#"#!/bin/sh
while IFS= read -r line; do
case "$line" in
*'"options":{}'*)
printf '%s\n' '{"type":"ready"}'
;;
*'"type":"open"'*)
printf '%s\n' '{"type":"error","message":"expected options as {}"}'
exit 1
;;
*'"command":"echo'*)
printf '%s\n' '{"type":"exit","code":0}'
;;
*'"command":"sleep'*)
while IFS= read -r inner; do
case "$inner" in
*'"type":"cancel"'*)
printf '%s\n' '{"type":"exit","code":-1}'
break
;;
esac
done
;;
*'"type":"close"'*)
exit 0
;;
esac
done
"#,
)
.unwrap();
std::fs::set_permissions(&script, std::fs::Permissions::from_mode(0o755)).unwrap();
alba()
.args(["plugin", "check", script.to_str().expect("a utf-8 path")])
.assert()
.success()
.stdout(predicates::str::contains("\u{2713} handshake"))
.stdout(predicates::str::contains("conformant"));
}
#[cfg(unix)]
#[test]
fn plugin_check_reports_a_cancel_deaf_plugin() {
use std::os::unix::fs::PermissionsExt;
let dir = tempfile::tempdir().unwrap();
let script = dir.path().join("cancel-deaf-executor");
std::fs::write(
&script,
r#"#!/bin/sh
while IFS= read -r line; do
case "$line" in
*'"type":"open"'*)
printf '%s\n' '{"type":"ready"}'
;;
*'"command":"echo'*)
printf '%s\n' '{"type":"exit","code":0}'
;;
*'"type":"close"'*)
exit 0
;;
esac
done
"#,
)
.unwrap();
std::fs::set_permissions(&script, std::fs::Permissions::from_mode(0o755)).unwrap();
alba()
.args([
"plugin",
"check",
script.to_str().expect("a utf-8 path"),
"--command",
"echo probe",
"--cancel-command",
"sleep 30000",
])
.assert()
.code(1)
.stdout(predicates::str::contains("\u{2713} handshake"))
.stdout(predicates::str::contains("\u{2713} execute"))
.stdout(predicates::str::contains("\u{2717} cancel"))
.stdout(predicates::str::contains("not conformant"));
}
#[cfg(unix)]
#[test]
fn plugin_check_reports_a_mute_binary() {
use std::os::unix::fs::PermissionsExt;
let dir = tempfile::tempdir().unwrap();
let script = dir.path().join("mute-executor");
std::fs::write(&script, "#!/bin/sh\nsleep 30\n").unwrap();
std::fs::set_permissions(&script, std::fs::Permissions::from_mode(0o755)).unwrap();
alba()
.args(["plugin", "check", script.to_str().expect("a utf-8 path")])
.assert()
.code(1)
.stdout(predicates::str::contains("\u{2717} handshake"));
}
#[test]
fn plugin_check_rejects_a_missing_binary_as_an_alba_error() {
alba()
.args(["plugin", "check", "/no/such/binary"])
.assert()
.code(2);
}