use super::*;
fn spawn() -> Spawn {
Spawn {
listen: crate::daemon::LOOPBACK,
http_port: crate::daemon::Port::Exact(3123),
parent_pid: None,
debug: false,
peer_port: 7717,
}
}
fn record_for(workspace: &str) -> Record {
let root = PathBuf::from(workspace);
Record {
executable: PathBuf::from("/home/op/.cargo/bin/wsb-daemon"),
arguments: crate::daemon::daemon_arguments(&root, &spawn())
.expect("an exact port resolves without probing"),
workspace_root: root,
log: PathBuf::from("/home/op/.wsb/daemon.log"),
path: "/home/op/.cargo/bin:/usr/bin".to_string(),
autostart: false,
}
}
#[test]
fn test11208_the_unit_starts_the_daemon_with_the_arguments_the_daemon_takes() {
let record = record_for("/home/op/ws/machinefabric");
let unit = render(Supervisor::Systemd, &record);
let exec = unit
.lines()
.find_map(|line| line.strip_prefix("ExecStart="))
.expect("the unit must say what to start");
let expected = crate::daemon::daemon_arguments(
&PathBuf::from("/home/op/ws/machinefabric"),
&spawn(),
)
.expect("an exact port resolves without probing");
assert_eq!(
exec,
format!("/home/op/.cargo/bin/wsb-daemon {}", expected.join(" ")),
"the unit's ExecStart is not the daemon's own argument vector"
);
let plist = render(Supervisor::Launchd, &record);
for argument in &expected {
assert!(
plist.contains(&format!("<string>{argument}</string>")),
"the plist does not pass {argument} to the daemon"
);
}
}
#[test]
fn test11209_a_path_with_a_space_is_quoted_for_the_supervisor() {
let record = record_for("/home/op/My Work/machinefabric");
let unit = render(Supervisor::Systemd, &record);
let exec = unit
.lines()
.find_map(|line| line.strip_prefix("ExecStart="))
.expect("the unit must say what to start");
assert!(
exec.contains("\"/home/op/My Work/machinefabric\""),
"the workspace path is not quoted: {exec}"
);
assert!(
exec.contains(" --workspace "),
"flags that need no quoting were quoted anyway: {exec}"
);
let plist = render(Supervisor::Launchd, &record);
assert!(
plist.contains("<string>/home/op/My Work/machinefabric</string>"),
"the plist mangled a path that needs nothing done to it"
);
}
#[test]
fn test11210_autostart_is_the_only_difference_between_enabled_and_disabled() {
let mut off = record_for("/home/op/ws/machinefabric");
off.autostart = false;
let mut on = off.clone();
on.autostart = true;
let plist_off = render(Supervisor::Launchd, &off);
let plist_on = render(Supervisor::Launchd, &on);
assert!(
plist_off.contains("<key>RunAtLoad</key>\n <false/>"),
"a disabled agent still says it starts at load"
);
assert!(
plist_on.contains("<key>RunAtLoad</key>\n <true/>"),
"an enabled agent does not say it starts at load"
);
assert_eq!(
plist_off.replace("<key>RunAtLoad</key>\n <false/>", "<key>RunAtLoad</key>\n <TOGGLE/>"),
plist_on.replace("<key>RunAtLoad</key>\n <true/>", "<key>RunAtLoad</key>\n <TOGGLE/>"),
"enabling changed something other than whether it starts at login"
);
assert_eq!(
render(Supervisor::Systemd, &off),
render(Supervisor::Systemd, &on),
"the systemd unit encodes autostart, which belongs to the manager"
);
}
#[test]
fn test11211_the_plist_escapes_what_xml_cannot_carry() {
let mut record = record_for("/home/op/R&D/machinefabric");
record.path = "/opt/A&B/bin:/usr/bin".to_string();
let plist = render(Supervisor::Launchd, &record);
assert!(
plist.contains("<string>/home/op/R&D/machinefabric</string>"),
"an ampersand in the workspace path reached the plist raw"
);
assert!(
plist.contains("<string>/opt/A&B/bin:/usr/bin</string>"),
"an ampersand in PATH reached the plist raw"
);
assert!(
!plist.contains("R&D"),
"the plist is not well-formed XML"
);
}
#[test]
fn test11212_a_definition_that_is_not_the_render_reads_as_drift() {
let record = record_for("/home/op/ws/machinefabric");
let current = render(Supervisor::Systemd, &record);
assert!(
!drifted(Supervisor::Systemd, &record, Some(¤t)),
"an untouched definition reads as drifted"
);
let moved = current.replace("/home/op/.cargo/bin", "/usr/local/bin");
assert!(
drifted(Supervisor::Systemd, &record, Some(&moved)),
"a unit naming an executable that is not the recorded one reads as current"
);
assert!(
!drifted(Supervisor::Systemd, &record, None),
"a missing definition was reported as drift rather than as absent"
);
}
#[test]
fn test11213_a_service_writes_to_the_log_the_daemon_command_reads() {
let record = record_for("/home/op/ws/machinefabric");
let log = record.log.display().to_string();
let unit = render(Supervisor::Systemd, &record);
assert!(
unit.contains(&format!("StandardOutput=append:{log}")),
"the unit does not append the daemon's output to its log"
);
assert!(
unit.contains(&format!("StandardError=append:{log}")),
"the unit does not append the daemon's errors to its log"
);
let plist = render(Supervisor::Launchd, &record);
assert!(
plist.contains("<key>StandardOutPath</key>"),
"the agent does not say where its output goes"
);
assert_eq!(
plist.matches(&format!("<string>{log}</string>")).count(),
2,
"the agent does not send both streams to the daemon's log"
);
}
#[test]
fn test11214_the_definition_carries_the_path_the_daemon_needs() {
let record = record_for("/home/op/ws/machinefabric");
assert!(
render(Supervisor::Systemd, &record)
.contains(&format!("Environment=PATH={}", record.path)),
"the unit does not give the daemon a PATH"
);
let plist = render(Supervisor::Launchd, &record);
assert!(
plist.contains("<key>PATH</key>") && plist.contains(&format!("<string>{}</string>", record.path)),
"the agent does not give the daemon a PATH"
);
}
#[test]
fn test11215_the_supervisor_restarts_a_failure_and_not_a_deliberate_stop() {
let record = record_for("/home/op/ws/machinefabric");
let unit = render(Supervisor::Systemd, &record);
assert!(
unit.contains("Restart=on-failure"),
"the unit does not restart the daemon when it fails"
);
assert!(
!unit.contains("Restart=always"),
"the unit would restart a daemon that was deliberately stopped"
);
let plist = render(Supervisor::Launchd, &record);
assert!(
plist.contains("<key>SuccessfulExit</key>\n <false/>"),
"the agent would restart a daemon that exited cleanly"
);
}