From 8ed44e785d311b2436291f0fa8e74d7a6626f815 Mon Sep 17 00:00:00 2001 From: Miguel Palhas Date: Sun, 23 Aug 2026 22:55:52 +0100 Subject: [PATCH] test(maestro): add branch/project clients and config seeding to e2e harness --- crates/maestro-e2e/src/client.rs | 12 +++++++++++- crates/maestro-e2e/src/daemon.rs | 21 +++++++++++++++++++++ crates/maestro-e2e/src/lib.rs | 2 +- crates/maestro-protocol/src/client.rs | 9 +++++++-- 4 files changed, 40 insertions(+), 4 deletions(-) diff --git a/crates/maestro-e2e/src/client.rs b/crates/maestro-e2e/src/client.rs index e247222..8de967e 100644 --- a/crates/maestro-e2e/src/client.rs +++ b/crates/maestro-e2e/src/client.rs @@ -11,7 +11,9 @@ use std::sync::Arc; use std::time::Duration; use futures_util::{SinkExt, StreamExt}; -use maestro_protocol::{CatalogEvent, CreateSessionRequest, DaemonClient, Session}; +use maestro_protocol::{ + BranchInfo, CatalogEvent, CreateSessionRequest, DaemonClient, Project, Session, +}; use tokio_tungstenite::tungstenite::client::IntoClientRequest; use tokio_tungstenite::tungstenite::Message as WsMessage; use tokio_tungstenite::{connect_async, MaybeTlsStream, WebSocketStream}; @@ -62,6 +64,14 @@ impl TestClient { Ok(self.daemon.kill_session(id).await?) } + pub async fn list_projects(&self) -> Result, ClientError> { + Ok(self.daemon.list_projects().await?) + } + + pub async fn list_branches(&self, path: &str) -> Result, ClientError> { + Ok(self.daemon.list_branches(path).await?) + } + /// Connect to the daemon's per-session WS and return the stream. The /// caller drives the conversation. pub async fn attach( diff --git a/crates/maestro-e2e/src/daemon.rs b/crates/maestro-e2e/src/daemon.rs index 9c215a8..ca0e1b9 100644 --- a/crates/maestro-e2e/src/daemon.rs +++ b/crates/maestro-e2e/src/daemon.rs @@ -29,11 +29,32 @@ impl Daemon { Self::spawn_at(SocketAddr::from((Ipv4Addr::LOCALHOST, free_port()))).await } + /// Spawn with a config file pre-seeded at the daemon's expected path + /// (`$XDG_CONFIG_HOME/maestro/config.toml`). + pub async fn spawn_with_config(toml: &str) -> Self { + Self::spawn_config_at( + SocketAddr::from((Ipv4Addr::LOCALHOST, free_port())), + Some(toml), + ) + .await + } + /// Spawn on a caller-supplied bind address. pub async fn spawn_at(bind: SocketAddr) -> Self { + Self::spawn_config_at(bind, None).await + } + + /// Spawn on a caller-supplied bind address, with an optional config file. + async fn spawn_config_at(bind: SocketAddr, config: impl Into>) -> Self { let home = TempDir::new().expect("home tmpdir"); let tmux = TempDir::new().expect("tmux tmpdir"); + if let Some(toml) = config.into() { + let dir = home.path().join(".config").join("maestro"); + std::fs::create_dir_all(&dir).expect("config dir"); + std::fs::write(dir.join("config.toml"), toml).expect("write config.toml"); + } + let child = launch(bind, home.path(), tmux.path()); let me = Self { bind_addr: bind, diff --git a/crates/maestro-e2e/src/lib.rs b/crates/maestro-e2e/src/lib.rs index 9096913..630dc43 100644 --- a/crates/maestro-e2e/src/lib.rs +++ b/crates/maestro-e2e/src/lib.rs @@ -14,5 +14,5 @@ pub mod daemon; pub mod util; pub use build::workspace_target_bin; -pub use client::TestClient; +pub use client::{ClientError, TestClient}; pub use daemon::Daemon; diff --git a/crates/maestro-protocol/src/client.rs b/crates/maestro-protocol/src/client.rs index dd4203f..7d03e38 100644 --- a/crates/maestro-protocol/src/client.rs +++ b/crates/maestro-protocol/src/client.rs @@ -15,8 +15,8 @@ use uuid::Uuid; use crate::routes::{self, UrlError}; use crate::{ - ApiError, CreateSessionRequest, DaemonInfo, DirListing, ErrorInfo, GitRoot, Project, - RecentDirs, Session, + ApiError, BranchInfo, CreateSessionRequest, DaemonInfo, DirListing, ErrorInfo, GitRoot, + Project, RecentDirs, Session, }; /// Time budget for establishing a TCP connection to the daemon. @@ -143,6 +143,11 @@ impl DaemonClient { self.get(routes::PROJECTS, &[]).await } + pub async fn list_branches(&self, path: &str) -> Result, ClientError> { + self.get(routes::BRANCHES, &[(routes::PATH_QUERY, path)]) + .await + } + // -- plumbing ----------------------------------------------------------- async fn get(