crates/monetize-server/tests/no_bearer_no_server.rs
//! **No bearer, no server** (stinky #9) — the binary's own start path.
//!
//! An empty bearer is what `nornir_service::auth_interceptor` reads as OPEN:
//! every gRPC call let in unauthenticated. So a `monetize-server` whose
//! `--token`, `$MONETIZE_SERVER_TOKEN` and token file are all missing or empty
//! refuses to start, with ONE alert line that names the token file (and never
//! a bearer). Open mode is asked for by name, `--insecure-open-mode-for-tests`,
//! and only by tests.
use std::io::{BufRead, BufReader};
use std::path::{Path, PathBuf};
use std::process::{Child, Command, Stdio};
use std::sync::mpsc;
use std::time::Duration;
fn scratch(name: &str) -> PathBuf {
let dir = std::env::temp_dir().join(format!("monetize-{name}-{}", std::process::id()));
let _ = std::fs::remove_dir_all(&dir);
std::fs::create_dir_all(&dir).unwrap();
dir
}
fn config(dir: &Path) -> PathBuf {
let path = dir.join("monetize.toml");
let text = format!("grpc_addr = \"127.0.0.1:0\"\ndata_dir = \"{}\"\ntoken_file = \"{}\"\n", dir.join("data").display(), dir.join("token").display());
std::fs::write(&path, text).unwrap();
path
}
fn server(config: &Path, extra: &[&str]) -> Child {
Command::new(env!("CARGO_BIN_EXE_monetize-server"))
.arg("--config")
.arg(config)
.args(extra)
.env_remove("MONETIZE_SERVER_TOKEN")
.stdin(Stdio::null())
.stdout(Stdio::null())
.stderr(Stdio::piped())
.spawn()
.unwrap()
}
/// Every stderr line, as it comes, on a channel.
fn lines(child: &mut Child) -> mpsc::Receiver<String> {
let (tx, rx) = mpsc::channel();
let err = child.stderr.take().unwrap();
std::thread::spawn(move || {
for l in BufReader::new(err).lines().map_while(Result::ok) {
if tx.send(l).is_err() {
break;
}
}
});
rx
}
/// The process's exit and all it said — or `None` (and it is killed) if it is
/// still up after `limit`, i.e. it is SERVING.
fn exits_within(mut child: Child, limit: Duration) -> Option<(std::process::ExitStatus, Vec<String>)> {
let rx = lines(&mut child);
let until = std::time::Instant::now() + limit;
while std::time::Instant::now() < until {
if let Some(status) = child.try_wait().unwrap() {
std::thread::sleep(Duration::from_millis(100));
return Some((status, rx.try_iter().collect()));
}
std::thread::sleep(Duration::from_millis(50));
}
let _ = child.kill();
let _ = child.wait();
None
}
#[test]
fn a_missing_or_empty_bearer_refuses_to_start_with_one_alert_that_names_the_token_file() {
for (i, content) in [None, Some(""), Some(" \n\t")].into_iter().enumerate() {
let dir = scratch(&format!("no-bearer-{i}"));
let token = dir.join("token");
if let Some(c) = content {
std::fs::write(&token, c).unwrap();
}
let (status, said) = exits_within(server(&config(&dir), &[]), Duration::from_secs(30)).unwrap_or_else(|| panic!("{content:?}: no bearer, and the server is SERVING (open mode)"));
assert!(!status.success(), "{content:?}: refused is a failed start: {status:?}");
let alerts: Vec<&String> = said.iter().filter(|l| l.contains("ALERT")).collect();
assert_eq!(alerts.len(), 1, "{content:?}: ONE alert line: {said:#?}");
assert!(alerts[0].contains(&token.display().to_string()), "{content:?}: the alert names the token file: {}", alerts[0]);
assert!(!said.iter().any(|l| l.contains("OPEN (dev mode)")), "{content:?}: never served open: {said:#?}");
let _ = std::fs::remove_dir_all(&dir);
}
}
#[test]
fn open_mode_is_only_by_its_test_flag_and_never_over_a_configured_bearer() {
let dir = scratch("open-by-name");
let cfg = config(&dir);
let mut child = server(&cfg, &["--insecure-open-mode-for-tests"]);
let rx = lines(&mut child);
let mut said = Vec::new();
let saw_open = loop {
match rx.recv_timeout(Duration::from_secs(30)) {
Ok(l) => {
let open = l.contains("--insecure-open-mode-for-tests") && l.contains("OPEN");
said.push(l);
if open {
break true;
}
}
Err(_) => break false,
}
};
let still_up = child.try_wait().unwrap().is_none();
let _ = child.kill();
let _ = child.wait();
assert!(saw_open && still_up, "the test flag serves OPEN and says so by name: {said:#?}");
std::fs::write(dir.join("token"), "a-configured-bearer-of-enough-length-0123456789").unwrap();
let (status, said) = exits_within(server(&cfg, &["--insecure-open-mode-for-tests"]), Duration::from_secs(30)).expect("a configured bearer is never served open");
assert!(!status.success(), "{status:?}");
assert!(said.iter().any(|l| l.contains("--insecure-open-mode-for-tests")), "the refusal names the flag: {said:#?}");
assert!(!said.iter().any(|l| l.contains("a-configured-bearer")), "never the bearer: {said:#?}");
let _ = std::fs::remove_dir_all(&dir);
}