test(maestro): e2e for CLI broker path + registry compat fallback (NAP-244)
ci / rust (push) Successful in 10m42s
ci / rust (push) Successful in 10m42s
Drives the real `maestro` binary: one test points `MAESTRO_HOME_DAEMON_URL` at a live daemon with no registry configured (proves the catalog read comes from the home daemon), the other points it at a dead port and asserts the CLI warns and falls back to the registry while still listing the session. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -694,6 +694,103 @@ async fn daemon_events_ws_streams_snapshot_then_session_added() {
|
||||
client.kill_session(session.id).await.expect("kill");
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// NAP-244 — CLI rewired through the home-daemon broker, with registry fallback
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/// Run the real `maestro` binary with an isolated env and capture its output.
|
||||
fn run_cli(args: &[&str], envs: &[(&str, &str)]) -> std::process::Output {
|
||||
let bin = maestro_e2e::workspace_target_bin("maestro", "maestro");
|
||||
let mut cmd = Command::new(&bin);
|
||||
cmd.args(args);
|
||||
cmd.env_clear().env(
|
||||
"PATH",
|
||||
std::env::var("PATH").unwrap_or_else(|_| "/usr/bin:/bin".into()),
|
||||
);
|
||||
for (k, v) in envs {
|
||||
cmd.env(k, v);
|
||||
}
|
||||
cmd.output().expect("run maestro cli")
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn cli_list_reads_from_home_daemon() {
|
||||
// Broker path: point the CLI at the daemon's local API and DON'T configure
|
||||
// a registry. Success proves the catalog read came from the home daemon —
|
||||
// the registry path would have errored with NoRegistryUrl.
|
||||
let (_reg, daemons, client) = bring_up(&["alpha"]).await;
|
||||
let cwd = TempDir::new().unwrap();
|
||||
let session = client
|
||||
.spawn_session(&create_req("alpha", cwd.path(), "sleep 30"))
|
||||
.await
|
||||
.expect("spawn");
|
||||
|
||||
let daemon_url = format!("http://{}", daemons[0].bind_addr);
|
||||
let home = TempDir::new().unwrap();
|
||||
let cfg_path = home.path().join("config.toml");
|
||||
let out = run_cli(
|
||||
&["list", "--json"],
|
||||
&[
|
||||
("HOME", home.path().to_str().unwrap()),
|
||||
("MAESTRO_CONFIG", cfg_path.to_str().unwrap()),
|
||||
("MAESTRO_HOME_DAEMON_URL", &daemon_url),
|
||||
],
|
||||
);
|
||||
let stdout = String::from_utf8_lossy(&out.stdout);
|
||||
let stderr = String::from_utf8_lossy(&out.stderr);
|
||||
assert!(out.status.success(), "list failed: {stderr}\n{stdout}");
|
||||
assert!(
|
||||
stdout.contains(&session.id.to_string()),
|
||||
"session not listed via home daemon: {stdout}"
|
||||
);
|
||||
assert!(
|
||||
!stderr.contains("falling back"),
|
||||
"unexpected registry fallback: {stderr}"
|
||||
);
|
||||
|
||||
client.kill_session(session.id).await.ok();
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn cli_list_falls_back_to_registry_when_daemon_down() {
|
||||
// Compat path: home daemon URL points at a dead port (connection refused).
|
||||
// The CLI must warn and fall back to the configured registry, still
|
||||
// returning the session.
|
||||
let (reg, _daemons, client) = bring_up(&["alpha"]).await;
|
||||
let cwd = TempDir::new().unwrap();
|
||||
let session = client
|
||||
.spawn_session(&create_req("alpha", cwd.path(), "sleep 30"))
|
||||
.await
|
||||
.expect("spawn");
|
||||
|
||||
let dead_daemon = format!("http://127.0.0.1:{}", maestro_e2e::util::free_port());
|
||||
let registry_url = reg.http_base();
|
||||
let home = TempDir::new().unwrap();
|
||||
let cfg_path = home.path().join("config.toml");
|
||||
let out = run_cli(
|
||||
&["list", "--json"],
|
||||
&[
|
||||
("HOME", home.path().to_str().unwrap()),
|
||||
("MAESTRO_CONFIG", cfg_path.to_str().unwrap()),
|
||||
("MAESTRO_HOME_DAEMON_URL", &dead_daemon),
|
||||
("MAESTRO_REGISTRY_URL", ®istry_url),
|
||||
],
|
||||
);
|
||||
let stdout = String::from_utf8_lossy(&out.stdout);
|
||||
let stderr = String::from_utf8_lossy(&out.stderr);
|
||||
assert!(out.status.success(), "list failed: {stderr}\n{stdout}");
|
||||
assert!(
|
||||
stdout.contains(&session.id.to_string()),
|
||||
"session not listed via registry fallback: {stdout}"
|
||||
);
|
||||
assert!(
|
||||
stderr.contains("falling back"),
|
||||
"expected a fallback warning on stderr: {stderr}"
|
||||
);
|
||||
|
||||
client.kill_session(session.id).await.ok();
|
||||
}
|
||||
|
||||
async fn next_event<S>(ws: &mut S) -> maestro_protocol::RegistryEvent
|
||||
where
|
||||
S: StreamExt<Item = Result<WsMessage, tokio_tungstenite::tungstenite::Error>> + Unpin,
|
||||
|
||||
Reference in New Issue
Block a user