#![allow(clippy::literal_string_with_formatting_args)]
use std::{env, process::Command};
use anyhow::Context;
use ntest::timeout;
mod support;
use crate::support::daemon::DaemonArgs;
#[test]
#[timeout(30000)]
fn no_daemon() -> anyhow::Result<()> {
support::dump_err(|| {
let out = Command::new(support::shpool_bin()?)
.arg("--socket")
.arg("/fake/does/not/exist/shpool.socket")
.arg("--no-daemonize")
.arg("kill")
.output()
.context("spawning kill proc")?;
assert!(!out.status.success(), "kill proc exited successfully");
let stderr = String::from_utf8_lossy(&out.stderr[..]);
assert!(stderr.contains("could not connect to daemon"));
Ok(())
})
}
#[test]
#[timeout(30000)]
fn empty() -> anyhow::Result<()> {
support::dump_err(|| {
let mut daemon_proc = support::daemon::Proc::new(
"norc.toml",
DaemonArgs { listen_events: false, ..DaemonArgs::default() },
)
.context("starting daemon proc")?;
env::remove_var("SHPOOL_SESSION_NAME");
let out = daemon_proc.kill(vec![])?;
assert!(!out.status.success());
let stderr = String::from_utf8_lossy(&out.stderr[..]);
eprintln!("stderr: {}", stderr);
assert!(stderr.contains("no session to kill"));
Ok(())
})
}
#[test]
#[timeout(30000)]
fn version_mismatch_client_newer() -> anyhow::Result<()> {
support::dump_err(|| {
let mut daemon_proc = support::daemon::Proc::new(
"norc.toml",
DaemonArgs {
extra_env: vec![(
String::from("SHPOOL_TEST__OVERRIDE_VERSION"),
String::from("0.0.0"),
)],
..DaemonArgs::default()
},
)
.context("starting daemon proc")?;
let waiter = daemon_proc.events.take().unwrap().waiter(["daemon-bidi-stream-enter"]);
let mut attach_proc =
daemon_proc.attach("sh1", Default::default()).context("starting attach proc")?;
attach_proc.run_cmd("")?;
daemon_proc.events = Some(waiter.wait_final_event("daemon-bidi-stream-enter")?);
let out = daemon_proc.kill(vec![String::from("sh1")])?;
assert!(out.status.success());
let stderr = String::from_utf8_lossy(&out.stderr[..]);
println!("stderr: {}", stderr);
assert!(stderr.contains("is newer"));
assert!(stderr.contains("try restarting"));
Ok(())
})
}
#[test]
#[timeout(30000)]
fn single_attached() -> anyhow::Result<()> {
support::dump_err(|| {
let mut daemon_proc = support::daemon::Proc::new("norc.toml", DaemonArgs::default())
.context("starting daemon proc")?;
let waiter = daemon_proc.events.take().unwrap().waiter(["daemon-bidi-stream-enter"]);
let _attach_proc =
daemon_proc.attach("sh1", Default::default()).context("starting attach proc")?;
daemon_proc.events = Some(waiter.wait_final_event("daemon-bidi-stream-enter")?);
let out = daemon_proc.kill(vec![String::from("sh1")])?;
assert!(out.status.success());
let stdout = String::from_utf8_lossy(&out.stdout[..]);
assert!(stdout.is_empty());
let stderr = String::from_utf8_lossy(&out.stderr[..]);
assert!(stderr.is_empty());
Ok(())
})
}
#[test]
#[timeout(30000)]
fn multiple_attached() -> anyhow::Result<()> {
support::dump_err(|| {
let mut daemon_proc = support::daemon::Proc::new("norc.toml", DaemonArgs::default())
.context("starting daemon proc")?;
let mut waiter = daemon_proc
.events
.take()
.unwrap()
.waiter(["daemon-bidi-stream-enter", "daemon-bidi-stream-enter"]);
let _sess1 =
daemon_proc.attach("sh1", Default::default()).context("starting attach proc")?;
let _sess2 =
daemon_proc.attach("sh2", Default::default()).context("starting attach proc")?;
waiter.wait_event("daemon-bidi-stream-enter")?;
daemon_proc.events = Some(waiter.wait_final_event("daemon-bidi-stream-enter")?);
let out = daemon_proc.kill(vec![String::from("sh1"), String::from("sh2")])?;
assert!(out.status.success());
let stdout = String::from_utf8_lossy(&out.stdout[..]);
assert!(stdout.is_empty());
let stderr = String::from_utf8_lossy(&out.stderr[..]);
assert!(stderr.is_empty());
Ok(())
})
}
#[test]
#[timeout(30000)]
fn reattach_after_kill() -> anyhow::Result<()> {
support::dump_err(|| {
let mut daemon_proc = support::daemon::Proc::new("norc.toml", DaemonArgs::default())
.context("starting daemon proc")?;
let mut waiter = daemon_proc
.events
.take()
.unwrap()
.waiter(["daemon-handle-kill-removed-shells", "daemon-bidi-stream-done"]);
let mut sess1 =
daemon_proc.attach("sh1", Default::default()).context("starting attach proc")?;
let mut lm1 = sess1.line_matcher()?;
sess1.run_cmd("export MYVAR=first")?;
sess1.run_cmd("echo $MYVAR")?;
lm1.scan_until_re("first$")?;
let out = daemon_proc.kill(vec![String::from("sh1")])?;
assert!(out.status.success());
let stdout = String::from_utf8_lossy(&out.stdout[..]);
assert!(stdout.is_empty());
let stderr = String::from_utf8_lossy(&out.stderr[..]);
assert!(stderr.is_empty());
waiter.wait_event("daemon-handle-kill-removed-shells")?;
waiter.wait_event("daemon-bidi-stream-done")?;
let mut sess2 =
daemon_proc.attach("sh1", Default::default()).context("starting attach proc")?;
let mut lm2 = sess2.line_matcher()?;
sess2.run_cmd("echo ${MYVAR:-second}")?;
lm2.scan_until_re(".*second.*")?;
Ok(())
})
}
#[test]
#[timeout(30000)]
fn single_detached() -> anyhow::Result<()> {
support::dump_err(|| {
let mut daemon_proc = support::daemon::Proc::new("norc.toml", DaemonArgs::default())
.context("starting daemon proc")?;
let mut waiter = daemon_proc
.events
.take()
.unwrap()
.waiter(["daemon-bidi-stream-enter", "daemon-bidi-stream-done"]);
{
let _attach_proc =
daemon_proc.attach("sh1", Default::default()).context("starting attach proc")?;
waiter.wait_event("daemon-bidi-stream-enter")?;
}
daemon_proc.events = Some(waiter.wait_final_event("daemon-bidi-stream-done")?);
let out = daemon_proc.kill(vec![String::from("sh1")])?;
assert!(out.status.success());
let stdout = String::from_utf8_lossy(&out.stdout[..]);
assert!(stdout.is_empty());
let stderr = String::from_utf8_lossy(&out.stderr[..]);
assert!(stderr.is_empty());
Ok(())
})
}
#[test]
#[timeout(30000)]
fn multiple_detached() -> anyhow::Result<()> {
support::dump_err(|| {
let mut daemon_proc = support::daemon::Proc::new("norc.toml", DaemonArgs::default())
.context("starting daemon proc")?;
let mut waiter = daemon_proc.events.take().unwrap().waiter([
"daemon-bidi-stream-enter",
"daemon-bidi-stream-enter",
"daemon-bidi-stream-done",
"daemon-bidi-stream-done",
]);
{
let _sess1 =
daemon_proc.attach("sh1", Default::default()).context("starting attach proc")?;
let _sess2 =
daemon_proc.attach("sh2", Default::default()).context("starting attach proc")?;
waiter.wait_event("daemon-bidi-stream-enter")?;
waiter.wait_event("daemon-bidi-stream-enter")?;
}
waiter.wait_event("daemon-bidi-stream-done")?;
daemon_proc.events = Some(waiter.wait_final_event("daemon-bidi-stream-done")?);
let out = daemon_proc.kill(vec![String::from("sh1"), String::from("sh2")])?;
assert!(out.status.success());
let stdout = String::from_utf8_lossy(&out.stdout[..]);
assert!(stdout.is_empty());
let stderr = String::from_utf8_lossy(&out.stderr[..]);
assert!(stderr.is_empty());
Ok(())
})
}
#[test]
#[timeout(30000)]
fn multiple_mixed() -> anyhow::Result<()> {
support::dump_err(|| {
let mut daemon_proc = support::daemon::Proc::new("norc.toml", DaemonArgs::default())
.context("starting daemon proc")?;
let mut waiter = daemon_proc.events.take().unwrap().waiter([
"daemon-bidi-stream-enter",
"daemon-bidi-stream-done",
"daemon-bidi-stream-enter",
]);
{
let _sess1 =
daemon_proc.attach("sh1", Default::default()).context("starting attach proc")?;
waiter.wait_event("daemon-bidi-stream-enter")?;
}
waiter.wait_event("daemon-bidi-stream-done")?;
let _sess2 =
daemon_proc.attach("sh2", Default::default()).context("starting attach proc")?;
daemon_proc.events = Some(waiter.wait_final_event("daemon-bidi-stream-enter")?);
let out = daemon_proc.kill(vec![String::from("sh1"), String::from("sh2")])?;
assert!(out.status.success());
let stdout = String::from_utf8_lossy(&out.stdout[..]);
assert!(stdout.is_empty());
let stderr = String::from_utf8_lossy(&out.stderr[..]);
assert!(stderr.is_empty());
Ok(())
})
}
#[test]
#[timeout(30000)]
fn running_env_var() -> anyhow::Result<()> {
support::dump_err(|| {
let mut daemon_proc = support::daemon::Proc::new("norc.toml", DaemonArgs::default())
.context("starting daemon proc")?;
let mut waiter = daemon_proc
.events
.take()
.unwrap()
.waiter(["daemon-bidi-stream-enter", "daemon-bidi-stream-done"]);
let _attach_proc =
daemon_proc.attach("sh1", Default::default()).context("starting attach proc")?;
waiter.wait_event("daemon-bidi-stream-enter")?;
let out = Command::new(support::shpool_bin()?)
.arg("--socket")
.arg(&daemon_proc.socket_path)
.arg("kill")
.env("SHPOOL_SESSION_NAME", "sh1")
.output()
.context("spawning detach cmd")?;
assert!(out.status.success(), "not successful");
let stderr = String::from_utf8_lossy(&out.stderr[..]);
assert_eq!(stderr.len(), 0, "expected no stderr");
let stdout = String::from_utf8_lossy(&out.stdout[..]);
assert_eq!(stdout.len(), 0, "expected no stdout");
daemon_proc.events = Some(waiter.wait_final_event("daemon-bidi-stream-done")?);
Ok(())
})
}
#[test]
#[timeout(30000)]
fn missing() -> anyhow::Result<()> {
support::dump_err(|| {
let mut daemon_proc = support::daemon::Proc::new("norc.toml", DaemonArgs::default())
.context("starting daemon proc")?;
let out = daemon_proc.kill(vec![String::from("missing")])?;
assert!(!out.status.success());
let stderr = String::from_utf8_lossy(&out.stderr[..]);
assert!(stderr.contains("not found: missing"));
Ok(())
})
}