chore(maestro): retarget installer, e2e harness, and docs at unified maestro binary (NAP-245)
- Installer: one `cargo install maestro` instead of two; ExecStart becomes `~/.cargo/bin/maestro daemon`; user unit renamed `maestrod.service` → `maestro.service`; configure step is `maestro daemon configure`. - E2E harness: both `Daemon` and `Registry` subprocess wrappers shell out to the unified `maestro` binary with the appropriate subcommand. - State dir: `~/.local/state/maestrod` → `~/.local/state/maestro`. - Docs: CLAUDE.md repo layout, design spec repo layout + "Daemon (`maestro daemon`)" heading, INSTALL.md (full rewrite of CLI references + new thin-builds section).
This commit is contained in:
@@ -245,7 +245,7 @@ pub fn default_state_dir() -> Result<PathBuf, ConfigError> {
|
||||
let base = dirs::state_dir()
|
||||
.or_else(dirs::data_local_dir)
|
||||
.ok_or(maestro_config::ConfigError::NoConfigDir)?;
|
||||
Ok(base.join("maestrod"))
|
||||
Ok(base.join("maestro"))
|
||||
}
|
||||
|
||||
/// Read the kernel hostname via `gethostname(2)`. Falls back to `"unknown"`
|
||||
@@ -285,7 +285,7 @@ daemon_url = "ws://localhost:7070"
|
||||
assert_eq!(cfg.daemon_url, "ws://localhost:7070");
|
||||
assert_eq!(cfg.token, "abc");
|
||||
assert_eq!(cfg.bind_addr, default_bind_addr());
|
||||
assert!(cfg.state_dir.ends_with("maestrod"));
|
||||
assert!(cfg.state_dir.ends_with("maestro"));
|
||||
assert!(cfg.worktree_root.ends_with("worktrees"));
|
||||
assert_eq!(cfg.daemon_id, cfg.hostname);
|
||||
assert!(!cfg.hostname.is_empty());
|
||||
|
||||
@@ -189,8 +189,9 @@ fn launch(
|
||||
tmux_tmpdir: &std::path::Path,
|
||||
opts: &DaemonOptions,
|
||||
) -> Child {
|
||||
let bin = workspace_target_bin("maestro-daemon", "maestrod");
|
||||
let bin = workspace_target_bin("maestro", "maestro");
|
||||
let mut cmd = Command::new(&bin);
|
||||
cmd.arg("daemon");
|
||||
cmd.env_clear()
|
||||
.env(
|
||||
"PATH",
|
||||
|
||||
@@ -27,8 +27,9 @@ impl Registry {
|
||||
let addr = SocketAddr::from((Ipv4Addr::LOCALHOST, port));
|
||||
let home = TempDir::new().expect("home tmpdir");
|
||||
|
||||
let bin = workspace_target_bin("maestro-registry", "maestro-registry");
|
||||
let bin = workspace_target_bin("maestro", "maestro");
|
||||
let child = Command::new(&bin)
|
||||
.arg("registry")
|
||||
.env_clear()
|
||||
// PATH so tmux etc. resolve. We need a few essentials.
|
||||
.env(
|
||||
|
||||
@@ -5,7 +5,7 @@ edition.workspace = true
|
||||
license.workspace = true
|
||||
repository.workspace = true
|
||||
publish.workspace = true
|
||||
description = "Interactive install wizard for maestrod + maestro: `cargo install` both binaries and (on systemd hosts) drop a user unit"
|
||||
description = "Interactive install wizard for the unified `maestro` binary; cargo-installs it and (on systemd hosts) drops a user unit"
|
||||
|
||||
[lib]
|
||||
path = "src/lib.rs"
|
||||
|
||||
@@ -101,14 +101,10 @@ mod tests {
|
||||
url: "https://git.naps.pt/naps62/maestro".into(),
|
||||
branch: None,
|
||||
};
|
||||
let args = cargo_install_args(&src, "maestro-daemon", false);
|
||||
let args = cargo_install_args(&src, "maestro", false);
|
||||
assert_eq!(
|
||||
args,
|
||||
vec![
|
||||
"--git",
|
||||
"https://git.naps.pt/naps62/maestro",
|
||||
"maestro-daemon",
|
||||
]
|
||||
vec!["--git", "https://git.naps.pt/naps62/maestro", "maestro",]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -118,7 +114,7 @@ mod tests {
|
||||
url: "https://git.example/x".into(),
|
||||
branch: Some("main".into()),
|
||||
};
|
||||
let args = cargo_install_args(&src, "maestro-cli", true);
|
||||
let args = cargo_install_args(&src, "maestro", true);
|
||||
assert_eq!(
|
||||
args,
|
||||
vec![
|
||||
@@ -126,7 +122,7 @@ mod tests {
|
||||
"https://git.example/x",
|
||||
"--branch",
|
||||
"main",
|
||||
"maestro-cli",
|
||||
"maestro",
|
||||
"--locked",
|
||||
]
|
||||
);
|
||||
@@ -135,41 +131,35 @@ mod tests {
|
||||
#[test]
|
||||
fn path_args_use_p_flag() {
|
||||
let src = CargoSource::Path(PathBuf::from("/repos/maestro"));
|
||||
let args = cargo_install_args(&src, "maestro-daemon", true);
|
||||
let args = cargo_install_args(&src, "maestro", true);
|
||||
assert_eq!(
|
||||
args,
|
||||
vec![
|
||||
"--path",
|
||||
"/repos/maestro",
|
||||
"-p",
|
||||
"maestro-daemon",
|
||||
"--locked",
|
||||
]
|
||||
vec!["--path", "/repos/maestro", "-p", "maestro", "--locked",]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn systemctl_daemon_reload_omits_unit() {
|
||||
let args = systemctl_user_args(SystemctlAction::DaemonReload, "maestrod.service");
|
||||
let args = systemctl_user_args(SystemctlAction::DaemonReload, "maestro.service");
|
||||
assert_eq!(args, vec!["--user", "daemon-reload"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn systemctl_enable_includes_unit() {
|
||||
let args = systemctl_user_args(SystemctlAction::Enable, "maestrod.service");
|
||||
assert_eq!(args, vec!["--user", "enable", "maestrod.service"]);
|
||||
let args = systemctl_user_args(SystemctlAction::Enable, "maestro.service");
|
||||
assert_eq!(args, vec!["--user", "enable", "maestro.service"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn systemctl_start_includes_unit() {
|
||||
let args = systemctl_user_args(SystemctlAction::Start, "maestrod.service");
|
||||
assert_eq!(args, vec!["--user", "start", "maestrod.service"]);
|
||||
let args = systemctl_user_args(SystemctlAction::Start, "maestro.service");
|
||||
assert_eq!(args, vec!["--user", "start", "maestro.service"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn systemctl_restart_includes_unit() {
|
||||
let args = systemctl_user_args(SystemctlAction::Restart, "maestrod.service");
|
||||
assert_eq!(args, vec!["--user", "restart", "maestrod.service"]);
|
||||
let args = systemctl_user_args(SystemctlAction::Restart, "maestro.service");
|
||||
assert_eq!(args, vec!["--user", "restart", "maestro.service"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
//! `maestro-installer` — install wizard for maestrod + maestro.
|
||||
//! `maestro-installer` — install wizard for the unified `maestro` binary
|
||||
//! (NAP-245).
|
||||
//!
|
||||
//! See `docs/INSTALL.md` for the user-facing flow. This crate exposes the
|
||||
//! testable pieces:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//! `maestro-install` — interactive wizard that installs `maestrod` + `maestro`
|
||||
//! via `cargo install`, optionally drops a systemd user unit, and optionally
|
||||
//! kicks off `maestrod configure`.
|
||||
//! `maestro-install` — interactive wizard that installs the unified `maestro`
|
||||
//! binary via `cargo install`, optionally drops a systemd user unit, and
|
||||
//! optionally kicks off `maestro daemon configure`.
|
||||
//!
|
||||
//! Intended bootstrap path:
|
||||
//!
|
||||
@@ -22,8 +22,8 @@ use maestro_installer::{
|
||||
};
|
||||
|
||||
const DEFAULT_GIT_URL: &str = "https://git.naps.pt/naps62/maestro";
|
||||
const DAEMON_CRATE: &str = "maestro-daemon";
|
||||
const CLI_CRATE: &str = "maestro-cli";
|
||||
/// Unified `maestro` crate — single `cargo install` covers CLI + daemon + registry.
|
||||
const MAESTRO_CRATE: &str = "maestro";
|
||||
const WEB_CRATE: &str = "maestro-web";
|
||||
const SYSTEMD_PROBE: &str = "/run/systemd/system";
|
||||
|
||||
@@ -31,7 +31,7 @@ const SYSTEMD_PROBE: &str = "/run/systemd/system";
|
||||
#[command(
|
||||
name = "maestro-install",
|
||||
version,
|
||||
about = "Install maestrod + maestro CLI, and (optionally) a systemd user unit"
|
||||
about = "Install the unified `maestro` binary, and (optionally) a systemd user unit"
|
||||
)]
|
||||
struct Args {
|
||||
/// Git URL to install from (default: this repo).
|
||||
@@ -59,12 +59,12 @@ struct Args {
|
||||
#[arg(long)]
|
||||
no_systemd: bool,
|
||||
|
||||
/// Skip the `maestrod configure` step.
|
||||
/// Skip the `maestro daemon configure` step.
|
||||
#[arg(long)]
|
||||
no_configure: bool,
|
||||
|
||||
/// Override the ExecStart path written to the systemd unit.
|
||||
/// Default: `~/.cargo/bin/maestrod`.
|
||||
/// Default: `~/.cargo/bin/maestro` (invoked as `maestro daemon`).
|
||||
#[arg(long, value_name = "PATH")]
|
||||
exec_start: Option<PathBuf>,
|
||||
|
||||
@@ -101,16 +101,15 @@ fn run(args: Args) -> Result<(), Box<dyn std::error::Error>> {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// 1. Install both binaries.
|
||||
// 1. Install the unified binary (NAP-245).
|
||||
let locked = !args.no_locked;
|
||||
install_crate(&source, DAEMON_CRATE, locked)?;
|
||||
install_crate(&source, CLI_CRATE, locked)?;
|
||||
install_crate(&source, MAESTRO_CRATE, locked)?;
|
||||
|
||||
// 2. Offer to run `maestrod configure` now (must happen before systemd
|
||||
// 2. Offer to run `maestro daemon configure` now (must happen before systemd
|
||||
// start, since the daemon refuses to run without registry_url / token).
|
||||
// Re-runs of the wizard auto-skip when the unified config already has a
|
||||
// [daemon] section; that's what makes "re-run to update" pleasant. In
|
||||
// non-interactive mode (--yes / no TTY) we also skip — `maestrod
|
||||
// non-interactive mode (--yes / no TTY) we also skip — `maestro daemon
|
||||
// configure` would prompt for required fields and we don't want to
|
||||
// surprise scripts.
|
||||
let configured = if let Some(path) = maestro_config_path() {
|
||||
@@ -119,7 +118,7 @@ fn run(args: Args) -> Result<(), Box<dyn std::error::Error>> {
|
||||
"\n[daemon] section already present in {} — skipping configure step.",
|
||||
path.display()
|
||||
);
|
||||
eprintln!("(run `maestrod configure --force` to rewrite it.)");
|
||||
eprintln!("(run `maestro daemon configure --force` to rewrite it.)");
|
||||
true
|
||||
} else {
|
||||
run_configure_step(&args, interactive)?
|
||||
@@ -165,8 +164,8 @@ fn print_banner(source: &CargoSource) {
|
||||
eprintln!("maestro installer");
|
||||
eprintln!();
|
||||
eprintln!("This wizard will:");
|
||||
eprintln!(" 1. cargo install both `{DAEMON_CRATE}` and `{CLI_CRATE}`");
|
||||
eprintln!(" 2. (optional) run `maestrod configure` to bootstrap the config file");
|
||||
eprintln!(" 1. cargo install `{MAESTRO_CRATE}` (unified CLI + daemon + registry)");
|
||||
eprintln!(" 2. (optional) run `maestro daemon configure` to bootstrap the config file");
|
||||
eprintln!(" 3. (optional) install a systemd user unit and enable it");
|
||||
eprintln!(" 4. (optional) install `{WEB_CRATE}` + its systemd unit (browser UI)");
|
||||
eprintln!();
|
||||
@@ -218,7 +217,7 @@ fn run_configure_step(args: &Args, interactive: bool) -> Result<bool, Box<dyn st
|
||||
let want = interactive
|
||||
&& !args.no_configure
|
||||
&& confirm(
|
||||
"Run `maestrod configure` now (writes ~/.config/maestro/config.toml)?",
|
||||
"Run `maestro daemon configure` now (writes ~/.config/maestro/config.toml)?",
|
||||
true,
|
||||
)?;
|
||||
if want {
|
||||
@@ -229,20 +228,22 @@ fn run_configure_step(args: &Args, interactive: bool) -> Result<bool, Box<dyn st
|
||||
}
|
||||
|
||||
fn run_configure_passthrough() -> Result<bool, Box<dyn std::error::Error>> {
|
||||
// Run the freshly-installed `maestrod configure` interactively. We don't
|
||||
// hard-code the path; rely on it being on PATH after `cargo install`.
|
||||
eprintln!("\n==> maestrod configure");
|
||||
let status = Command::new("maestrod").arg("configure").status();
|
||||
// Run the freshly-installed `maestro daemon configure` interactively. We
|
||||
// don't hard-code the path; rely on it being on PATH after `cargo install`.
|
||||
eprintln!("\n==> maestro daemon configure");
|
||||
let status = Command::new("maestro")
|
||||
.args(["daemon", "configure"])
|
||||
.status();
|
||||
match status {
|
||||
Ok(s) if s.success() => Ok(true),
|
||||
Ok(s) => {
|
||||
eprintln!("`maestrod configure` exited {s}");
|
||||
eprintln!("`maestro daemon configure` exited {s}");
|
||||
Ok(false)
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!(
|
||||
"couldn't launch `maestrod`: {e}. Make sure ~/.cargo/bin is on PATH, \
|
||||
then run `maestrod configure` manually."
|
||||
"couldn't launch `maestro`: {e}. Make sure ~/.cargo/bin is on PATH, \
|
||||
then run `maestro daemon configure` manually."
|
||||
);
|
||||
Ok(false)
|
||||
}
|
||||
@@ -297,7 +298,7 @@ fn handle_systemd(
|
||||
let want_enable = if !interactive {
|
||||
true
|
||||
} else {
|
||||
confirm("Enable maestrod.service (start on login)?", true)?
|
||||
confirm("Enable maestro.service (start on login)?", true)?
|
||||
};
|
||||
if want_enable {
|
||||
run_systemctl(SystemctlAction::Enable, UNIT_FILE_NAME)?;
|
||||
@@ -310,7 +311,7 @@ fn handle_systemd(
|
||||
let want = if !interactive {
|
||||
true
|
||||
} else {
|
||||
confirm("Restart maestrod.service to pick up the new binary?", true)?
|
||||
confirm("Restart maestro.service to pick up the new binary?", true)?
|
||||
};
|
||||
(SystemctlAction::Restart, want)
|
||||
} else {
|
||||
@@ -318,12 +319,12 @@ fn handle_systemd(
|
||||
false
|
||||
} else if !configured {
|
||||
eprintln!(
|
||||
"Note: starting now will fail until you run `maestrod configure` \
|
||||
"Note: starting now will fail until you run `maestro daemon configure` \
|
||||
(no registry_url / token yet)."
|
||||
);
|
||||
confirm("Start maestrod.service now anyway?", false)?
|
||||
confirm("Start maestro.service now anyway?", false)?
|
||||
} else {
|
||||
confirm("Start maestrod.service now?", true)?
|
||||
confirm("Start maestro.service now?", true)?
|
||||
};
|
||||
(SystemctlAction::Start, want)
|
||||
};
|
||||
@@ -335,7 +336,7 @@ fn handle_systemd(
|
||||
}
|
||||
|
||||
fn default_exec_start() -> Result<PathBuf, Box<dyn std::error::Error>> {
|
||||
maestro_installer::systemd::default_maestrod_path()
|
||||
maestro_installer::systemd::default_maestro_path()
|
||||
.ok_or_else(|| "could not resolve $HOME (needed for ExecStart)".into())
|
||||
}
|
||||
|
||||
@@ -378,7 +379,7 @@ fn handle_web(
|
||||
} else {
|
||||
eprintln!(
|
||||
"\nOptional: install the browser UI (`maestro-web`)?\n \
|
||||
Reverse-proxies a local maestrod and serves the SPA at \
|
||||
Reverse-proxies a local maestro daemon and serves the SPA at \
|
||||
http://127.0.0.1:8080/ by default.\n \
|
||||
Edit [web].bind_addr in ~/.config/maestro/config.toml \
|
||||
to expose it to your perimeter (e.g. WireGuard IP)."
|
||||
@@ -390,7 +391,7 @@ fn handle_web(
|
||||
}
|
||||
|
||||
// Install the binary. Even if cargo-install fails we keep going so the
|
||||
// operator can fix the cause and re-run; the existing maestrod work
|
||||
// operator can fix the cause and re-run; the existing daemon work
|
||||
// doesn't need to be undone.
|
||||
let source = build_source(args);
|
||||
let locked = !args.no_locked;
|
||||
@@ -491,13 +492,13 @@ fn print_summary(configured: bool, systemd_enabled: bool, web_installed: bool) {
|
||||
eprintln!();
|
||||
eprintln!("Next steps:");
|
||||
if !configured {
|
||||
eprintln!(" • Run `maestrod configure` to bootstrap your config file.");
|
||||
eprintln!(" • Run `maestro daemon configure` to bootstrap your config file.");
|
||||
}
|
||||
if systemd_enabled {
|
||||
eprintln!(" • Check status: `systemctl --user status maestrod`");
|
||||
eprintln!(" • Logs: `journalctl --user -u maestrod -f`");
|
||||
eprintln!(" • Check status: `systemctl --user status maestro`");
|
||||
eprintln!(" • Logs: `journalctl --user -u maestro -f`");
|
||||
} else {
|
||||
eprintln!(" • Start the daemon: `maestrod`");
|
||||
eprintln!(" • Start the daemon: `maestro daemon`");
|
||||
}
|
||||
eprintln!(" • Set the CLI's registry: `maestro set-registry <URL>`");
|
||||
if web_installed {
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
//! systemd detection + user-unit rendering.
|
||||
//!
|
||||
//! The wizard only ever writes a *user* unit (`~/.config/systemd/user/`), since
|
||||
//! `maestrod` runs per-user and uses tmux sockets in the user's runtime dir.
|
||||
//! `maestro daemon` runs per-user and uses tmux sockets in the user's runtime dir.
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
/// Standard probe path. Present on hosts booted under systemd.
|
||||
pub const SYSTEMD_PROBE_PATH: &str = "/run/systemd/system";
|
||||
|
||||
/// Filename written under `~/.config/systemd/user/` for the daemon.
|
||||
pub const UNIT_FILE_NAME: &str = "maestrod.service";
|
||||
/// Filename written under `~/.config/systemd/user/` for the daemon (NAP-245
|
||||
/// renamed this from `maestrod.service`).
|
||||
pub const UNIT_FILE_NAME: &str = "maestro.service";
|
||||
|
||||
/// Filename for the optional `maestro-web` browser UI unit (NAP-249).
|
||||
pub const WEB_UNIT_FILE_NAME: &str = "maestro-web.service";
|
||||
@@ -27,7 +28,7 @@ pub fn user_unit_path_for(unit_name: &str) -> Option<PathBuf> {
|
||||
Some(base.join("systemd").join("user").join(unit_name))
|
||||
}
|
||||
|
||||
/// Convenience: path for `maestrod.service`. Kept as a free function so
|
||||
/// Convenience: path for `maestro.service`. Kept as a free function so
|
||||
/// existing callers don't need to thread the unit name around.
|
||||
pub fn user_unit_path() -> Option<PathBuf> {
|
||||
user_unit_path_for(UNIT_FILE_NAME)
|
||||
@@ -35,23 +36,27 @@ pub fn user_unit_path() -> Option<PathBuf> {
|
||||
|
||||
/// Convenience: path for `maestro-web.service` (NAP-249).
|
||||
pub fn user_web_unit_path() -> Option<PathBuf> {
|
||||
user_unit_path_for(WEB_UNIT_FILE_NAME)
|
||||
user_web_unit_path_for(WEB_UNIT_FILE_NAME)
|
||||
}
|
||||
|
||||
/// Render the daemon unit. `exec_start` is the absolute path to `maestrod` —
|
||||
/// we default to `~/.cargo/bin/maestrod` because that's where `cargo install`
|
||||
fn user_web_unit_path_for(unit_name: &str) -> Option<PathBuf> {
|
||||
user_unit_path_for(unit_name)
|
||||
}
|
||||
|
||||
/// Render the daemon unit. `exec_start` is the absolute path to `maestro` —
|
||||
/// we default to `~/.cargo/bin/maestro` because that's where `cargo install`
|
||||
/// lands binaries; systemd doesn't inherit the user's PATH, so we can't rely
|
||||
/// on a bare `maestrod`.
|
||||
/// on a bare `maestro`. The unit runs `maestro daemon` (NAP-245).
|
||||
pub fn render_user_unit(exec_start: &Path) -> String {
|
||||
format!(
|
||||
"[Unit]\n\
|
||||
Description=Maestro per-host daemon (maestrod)\n\
|
||||
Description=Maestro per-host daemon\n\
|
||||
Documentation=https://git.naps.pt/naps62/maestro\n\
|
||||
After=network-online.target\n\
|
||||
\n\
|
||||
[Service]\n\
|
||||
Type=simple\n\
|
||||
ExecStart={exec}\n\
|
||||
ExecStart={exec} daemon\n\
|
||||
ExecReload=/bin/kill -HUP $MAINPID\n\
|
||||
Restart=on-failure\n\
|
||||
RestartSec=5\n\
|
||||
@@ -62,7 +67,7 @@ pub fn render_user_unit(exec_start: &Path) -> String {
|
||||
)
|
||||
}
|
||||
|
||||
/// Render the `maestro-web` user unit (NAP-249). Orders after `maestrod`
|
||||
/// Render the `maestro-web` user unit (NAP-249). Orders after `maestro.service`
|
||||
/// so the proxy doesn't return 502s on startup; `Wants=` keeps it best-effort
|
||||
/// — operators with daemon-less hosts can still install web alone if they
|
||||
/// later remove the dependency.
|
||||
@@ -71,8 +76,8 @@ pub fn render_web_unit(exec_start: &Path) -> String {
|
||||
"[Unit]\n\
|
||||
Description=Maestro web UI (maestro-web)\n\
|
||||
Documentation=https://git.naps.pt/naps62/maestro\n\
|
||||
After=network-online.target maestrod.service\n\
|
||||
Wants=maestrod.service\n\
|
||||
After=network-online.target maestro.service\n\
|
||||
Wants=maestro.service\n\
|
||||
\n\
|
||||
[Service]\n\
|
||||
Type=simple\n\
|
||||
@@ -86,15 +91,10 @@ pub fn render_web_unit(exec_start: &Path) -> String {
|
||||
)
|
||||
}
|
||||
|
||||
/// Default `ExecStart` target: `~/.cargo/bin/maestrod`. `None` if `$HOME` is
|
||||
/// Default `ExecStart` target: `~/.cargo/bin/maestro`. `None` if `$HOME` is
|
||||
/// unresolvable.
|
||||
pub fn default_maestrod_path() -> Option<PathBuf> {
|
||||
Some(
|
||||
dirs::home_dir()?
|
||||
.join(".cargo")
|
||||
.join("bin")
|
||||
.join("maestrod"),
|
||||
)
|
||||
pub fn default_maestro_path() -> Option<PathBuf> {
|
||||
Some(dirs::home_dir()?.join(".cargo").join("bin").join("maestro"))
|
||||
}
|
||||
|
||||
/// Default `ExecStart` target for the web unit: `~/.cargo/bin/maestro-web`.
|
||||
@@ -128,8 +128,8 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn unit_renders_with_absolute_exec_start() {
|
||||
let body = render_user_unit(Path::new("/home/alice/.cargo/bin/maestrod"));
|
||||
assert!(body.contains("ExecStart=/home/alice/.cargo/bin/maestrod"));
|
||||
let body = render_user_unit(Path::new("/home/alice/.cargo/bin/maestro"));
|
||||
assert!(body.contains("ExecStart=/home/alice/.cargo/bin/maestro daemon"));
|
||||
assert!(body.contains("[Unit]"));
|
||||
assert!(body.contains("[Service]"));
|
||||
assert!(body.contains("[Install]"));
|
||||
@@ -139,9 +139,9 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn unit_wires_execreload_to_sighup() {
|
||||
// NAP-237: `systemctl --user reload maestrod` must trigger our
|
||||
// NAP-237: `systemctl --user reload maestro` must trigger our
|
||||
// SIGHUP handler so operators can hot-reload `[daemon.policy]`.
|
||||
let body = render_user_unit(Path::new("/x/maestrod"));
|
||||
let body = render_user_unit(Path::new("/x/maestro"));
|
||||
assert!(body.contains("ExecReload=/bin/kill -HUP $MAINPID"));
|
||||
}
|
||||
|
||||
@@ -154,7 +154,7 @@ mod tests {
|
||||
#[test]
|
||||
fn user_unit_path_points_under_config_dir() {
|
||||
let p = user_unit_path().expect("config dir resolvable in test env");
|
||||
assert!(p.ends_with("systemd/user/maestrod.service"), "got {p:?}");
|
||||
assert!(p.ends_with("systemd/user/maestro.service"), "got {p:?}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -167,12 +167,18 @@ mod tests {
|
||||
fn web_unit_renders_with_dependency_on_daemon() {
|
||||
let body = render_web_unit(Path::new("/home/alice/.cargo/bin/maestro-web"));
|
||||
assert!(body.contains("ExecStart=/home/alice/.cargo/bin/maestro-web"));
|
||||
assert!(body.contains("After=network-online.target maestrod.service"));
|
||||
assert!(body.contains("Wants=maestrod.service"));
|
||||
assert!(body.contains("After=network-online.target maestro.service"));
|
||||
assert!(body.contains("Wants=maestro.service"));
|
||||
assert!(body.contains("WantedBy=default.target"));
|
||||
assert!(body.ends_with('\n'));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn default_maestro_path_under_cargo_bin() {
|
||||
let p = default_maestro_path().expect("HOME resolvable in test env");
|
||||
assert!(p.ends_with(".cargo/bin/maestro"), "got {p:?}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn default_maestro_web_path_under_cargo_bin() {
|
||||
let p = default_maestro_web_path().expect("HOME resolvable in test env");
|
||||
|
||||
Reference in New Issue
Block a user