120 lines
3.7 KiB
Rust
120 lines
3.7 KiB
Rust
//! Smoke tests for the umbrella `maestro` binary's dispatch surface (NAP-271).
|
|
//!
|
|
//! These run against the real built binary via Cargo's `CARGO_BIN_EXE_maestro`
|
|
//! env var. Integration tests are compiled with the package's active feature
|
|
//! set, so the per-subcommand checks are `#[cfg]`-gated and the suite is
|
|
//! meaningful under every feature subset (`cli` / `daemon` / `tui`)
|
|
//! as well as the default all-features build. The asserts only inspect
|
|
//! `--help`/`--version` output and exit codes, so nothing is actually started.
|
|
|
|
use std::process::Command;
|
|
|
|
fn maestro() -> Command {
|
|
Command::new(env!("CARGO_BIN_EXE_maestro"))
|
|
}
|
|
|
|
fn run(args: &[&str]) -> (bool, String) {
|
|
let out = maestro().args(args).output().expect("run maestro");
|
|
let combined = format!(
|
|
"{}{}",
|
|
String::from_utf8_lossy(&out.stdout),
|
|
String::from_utf8_lossy(&out.stderr)
|
|
);
|
|
(out.status.success(), combined)
|
|
}
|
|
|
|
/// Subcommands expected in `--help`, derived from the active feature set.
|
|
fn expected_subcommands() -> Vec<&'static str> {
|
|
let mut subs: Vec<&'static str> = Vec::new();
|
|
#[cfg(feature = "cli")]
|
|
subs.extend(["list", "spawn", "attach", "kill"]);
|
|
#[cfg(feature = "daemon")]
|
|
subs.extend(["daemon"]);
|
|
#[cfg(feature = "tui")]
|
|
subs.extend(["tui"]);
|
|
subs
|
|
}
|
|
|
|
#[test]
|
|
fn top_level_help_lists_subcommands() {
|
|
let (ok, text) = run(&["--help"]);
|
|
assert!(ok, "--help should exit 0:\n{text}");
|
|
for sub in expected_subcommands() {
|
|
assert!(
|
|
text.contains(sub),
|
|
"--help missing subcommand `{sub}`:\n{text}"
|
|
);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn version_flag_succeeds() {
|
|
let (ok, text) = run(&["--version"]);
|
|
assert!(ok, "--version should exit 0:\n{text}");
|
|
assert!(text.contains("maestro"), "--version output: {text}");
|
|
}
|
|
|
|
/// A bare `maestro` must never fall back to help on a build that has a TUI:
|
|
/// the missing subcommand defaults to `tui` (#119). Point at a port with
|
|
/// nothing listening so the TUI's health probe fails fast instead of blocking
|
|
/// on a terminal.
|
|
#[cfg(feature = "tui")]
|
|
#[test]
|
|
fn bare_invocation_dispatches_to_the_tui() {
|
|
let (ok, text) = run(&["--daemon-url", "http://127.0.0.1:9"]);
|
|
assert!(
|
|
!ok,
|
|
"TUI against a dead daemon should exit non-zero:\n{text}"
|
|
);
|
|
assert!(
|
|
text.contains("daemon unreachable"),
|
|
"bare invocation should have run the TUI's daemon probe:\n{text}"
|
|
);
|
|
assert!(
|
|
!text.contains("Usage"),
|
|
"bare invocation must not print help when a TUI exists:\n{text}"
|
|
);
|
|
}
|
|
|
|
/// Builds without the `tui` feature keep the historical behaviour: no args =>
|
|
/// help, exit 0 (#119).
|
|
#[cfg(not(feature = "tui"))]
|
|
#[test]
|
|
fn bare_invocation_prints_help_and_exits_zero() {
|
|
let (ok, text) = run(&[]);
|
|
assert!(ok, "bare invocation should exit 0:\n{text}");
|
|
assert!(text.contains("Usage"), "expected usage text:\n{text}");
|
|
}
|
|
|
|
#[test]
|
|
fn unknown_subcommand_fails() {
|
|
let (ok, text) = run(&["definitely-not-a-subcommand"]);
|
|
assert!(!ok, "unknown subcommand should fail:\n{text}");
|
|
}
|
|
|
|
#[cfg(feature = "cli")]
|
|
#[test]
|
|
fn cli_subcommand_help_works() {
|
|
// A representative CLI subcommand resolves and renders help.
|
|
let (ok, text) = run(&["spawn", "--help"]);
|
|
assert!(ok, "spawn --help should exit 0:\n{text}");
|
|
assert!(
|
|
text.contains("--daemon-url"),
|
|
"spawn help missing flags:\n{text}"
|
|
);
|
|
}
|
|
|
|
#[cfg(feature = "daemon")]
|
|
#[test]
|
|
fn daemon_subcommand_help_works() {
|
|
let (ok, text) = run(&["daemon", "--help"]);
|
|
assert!(ok, "daemon --help should exit 0:\n{text}");
|
|
}
|
|
|
|
#[cfg(feature = "tui")]
|
|
#[test]
|
|
fn tui_subcommand_help_works() {
|
|
let (ok, text) = run(&["tui", "--help"]);
|
|
assert!(ok, "tui --help should exit 0:\n{text}");
|
|
}
|