//! The CLI against a daemon. It had no such tests: `maestro list`'s formatting //! was unit-tested, but nothing exercised the client, the error decoding, or //! the unreachable-daemon path without compiling and forking a real daemon. use maestro_protocol::{DaemonClient, DaemonInfo}; use maestro_testing::{session, MockDaemon}; use uuid::Uuid; #[tokio::test] async fn list_reads_the_daemon_catalog() { let mock = MockDaemon::start().await; mock.add_session(session(Uuid::from_u128(1), "/home/mock/work", "claude")); let sessions = mock.client().list_sessions().await.expect("list"); assert_eq!(sessions.len(), 1); assert_eq!(sessions[0].command, "claude"); } #[tokio::test] async fn info_carries_version_and_presets() { let mock = MockDaemon::start().await; mock.set_info(DaemonInfo { hostname: "konishi".into(), version: "9.9.9".into(), home_dir: "/home/naps".into(), presets: vec![maestro_protocol::SpawnPreset { id: "claude".into(), label: "Claude".into(), command: "claude".into(), }], }); let info = mock.client().daemon_info().await.expect("info"); // The CLI's own DaemonInfo used to drop both of these fields. assert_eq!(info.version, "9.9.9"); assert_eq!(info.presets.len(), 1); } #[tokio::test] async fn a_structured_failure_surfaces_the_daemon_message() { let mock = MockDaemon::start().await; mock.force_error(502, "tmux_failed", "no server running"); let err = mock .client() .list_sessions() .await .expect_err("should fail"); assert_eq!( err.daemon_message(), Some("no server running"), "the daemon's own message must survive: {err}" ); assert!(!err.is_unreachable()); } #[tokio::test] async fn an_unreachable_daemon_is_distinguishable_from_a_rejection() { // Port 1 has nothing listening on it. let client = DaemonClient::new("http://127.0.0.1:1"); let err = client.list_sessions().await.expect_err("should fail"); assert!( err.is_unreachable(), "connection refused must not read as an HTTP rejection: {err}" ); } #[tokio::test] async fn killing_an_unknown_session_reports_the_daemon_reason() { let mock = MockDaemon::start().await; let err = mock .client() .kill_session(Uuid::new_v4(), false) .await .expect_err("should fail"); assert_eq!(err.daemon_message(), Some("no such session on this daemon")); } #[tokio::test] async fn spawn_round_trips_through_the_daemon() { let mock = MockDaemon::start().await; let created = mock .client() .create_session(&maestro_protocol::CreateSessionRequest { cwd: "/home/mock".into(), command: "bash".into(), env: Default::default(), metadata: Default::default(), worktree: None, }) .await .expect("create"); assert_eq!(created.command, "bash"); assert_eq!(mock.session_count(), 1); mock.client() .kill_session(created.id, false) .await .expect("kill"); assert_eq!(mock.session_count(), 0); }