Files
boxmaker/crates/brokerd/tests/serve_pointers.rs
T
kyleandClaude Opus 5.5 6af89f7c60 brokerd: runbook pointers for startup failures, no thread panics, args_os
M3a review findings 3, 5 (the cast), 6, 7 (brokerd), 11. A config, directory
or socket failure at start now ends with docs/runbook.md#brokerd-start-failed,
and losing a listener with #brokerd-listener-lost; both entries are new.
Threads start through thread::Builder, so a refused thread is reported
instead of silently killing a listener; an aborted connection no longer stops
the daemon. brokerd reads args_os and keeps the config path as a path. The
"requester went away" result is recorded at the time it happens.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-22 21:07:59 -07:00

135 lines
4.0 KiB
Rust

//! `brokerd serve` fails closed at startup with a runbook pointer for every reason it cannot start,
//! and never panics on its own command line. Found in the M3a review (findings 3 and 7).
#[path = "support/tmp.rs"]
mod tmp;
use std::ffi::OsStr;
use std::os::unix::ffi::OsStrExt;
use std::path::Path;
use std::process::{Command, Output};
use tmp::TempDir;
const START_FAILED: &str = "see docs/runbook.md#brokerd-start-failed";
fn brokerd<I: IntoIterator<Item = S>, S: AsRef<OsStr>>(args: I) -> Output {
Command::new(env!("CARGO_BIN_EXE_brokerd"))
.args(args)
.output()
.unwrap()
}
fn stderr(out: &Output) -> String {
String::from_utf8_lossy(&out.stderr).into_owned()
}
/// A config whose home is `dir`, with `sockets` as the `[sockets]` table's body.
fn config(dir: &TempDir, sockets: &str) -> std::path::PathBuf {
let home = dir.path().join("home");
let grants = dir.path().join("grants");
std::fs::create_dir_all(&grants).unwrap();
std::fs::create_dir_all(&home).unwrap();
dir.write(
"brokerd.toml",
&format!(
"[paths]\nhome = \"{}\"\ngrants = \"{}\"\n[sockets]\n{sockets}\n",
home.display(),
grants.display()
),
)
}
fn fails_with_pointer(out: &Output) {
assert_eq!(out.status.code(), Some(1), "{}", stderr(out));
assert!(
stderr(out).trim_end().ends_with(START_FAILED),
"{:?} must end with {START_FAILED:?}",
stderr(out)
);
}
#[test]
fn a_missing_config_names_the_entry() {
let dir = TempDir::new("ptr-missing");
let out = brokerd([
OsStr::new("serve"),
OsStr::new("--config"),
dir.path().join("nope.toml").as_os_str(),
]);
fails_with_pointer(&out);
}
#[test]
fn an_invalid_config_names_the_entry() {
let dir = TempDir::new("ptr-invalid");
let path = dir.write("brokerd.toml", "[paths]\nhome = 3\n");
let out = brokerd([
OsStr::new("serve"),
OsStr::new("--config"),
path.as_os_str(),
]);
fails_with_pointer(&out);
}
#[test]
fn a_socket_that_cannot_be_bound_names_the_entry() {
let dir = TempDir::new("ptr-bind");
let long = dir.path().join("s".repeat(120)).join("broker.sock");
let path = config(&dir, &format!("broker = \"{}\"", long.display()));
fails_with_pointer(&brokerd([
OsStr::new("serve"),
OsStr::new("--config"),
path.as_os_str(),
]));
}
#[test]
fn a_socket_directory_that_cannot_be_made_names_the_entry() {
let dir = TempDir::new("ptr-dir");
let file = dir.write("a-file", "");
let path = config(
&dir,
&format!("broker = \"{}\"", file.join("run/broker.sock").display()),
);
fails_with_pointer(&brokerd([
OsStr::new("serve"),
OsStr::new("--config"),
path.as_os_str(),
]));
}
/// A config path that is not UTF-8 is still a path: it is read (here: not found), not a panic.
#[test]
fn a_config_path_that_is_not_utf8_is_read_as_a_path() {
let dir = TempDir::new("ptr-os");
let name = dir.path().join(OsStr::from_bytes(b"conf-\xff.toml"));
let out = brokerd([
OsStr::new("serve"),
OsStr::new("--config"),
name.as_os_str(),
]);
fails_with_pointer(&out);
}
/// A flag that is not UTF-8 is not a flag brokerd knows: usage, exit 2, no panic.
#[test]
fn a_flag_that_is_not_utf8_is_a_usage_error() {
let out = brokerd([OsStr::new("serve"), OsStr::from_bytes(b"--\xff")]);
assert_eq!(out.status.code(), Some(2), "{}", stderr(&out));
assert!(stderr(&out).starts_with("usage: brokerd serve"));
let out = brokerd([OsStr::from_bytes(b"\xff")]);
assert_eq!(out.status.code(), Some(2), "{}", stderr(&out));
}
#[test]
fn the_entries_exist() {
let runbook = std::fs::read_to_string(
Path::new(env!("CARGO_MANIFEST_DIR")).join("../../docs/runbook.md"),
)
.unwrap();
for entry in ["## brokerd-start-failed", "## brokerd-listener-lost"] {
assert!(runbook.lines().any(|l| l == entry), "{entry}");
}
}