use super::*;
#[test]
fn a_staged_start_allows_the_daemon_its_slack_on_every_stage() {
let apps: Vec<AppConfig> = ["db", "api", "web"]
.iter()
.map(|name| {
let mut app = AppConfig::minimal(name, "/bin/sleep");
app.listen_timeout = shep_core::values::UpDuration::from_millis(20_000);
app
})
.collect();
assert_eq!(
staged_start_deadline(&apps),
Duration::from_secs(75),
"three 20s stages plus 5s of slack each"
);
}
#[tokio::test]
async fn a_start_asks_for_a_deadline_its_own_stages_fit_inside() {
let dir = tempfile::tempdir().unwrap();
let flockfile = dir.path().join("Flockfile.toml");
std::fs::write(
&flockfile,
"[[app]]\nname = \"db\"\nscript = \"/bin/sleep\"\nlisten_timeout = \"40s\"\n\
[[app]]\nname = \"api\"\nscript = \"/bin/sleep\"\nlisten_timeout = \"40s\"\n\
depends_on = [\"db\"]\n",
)
.unwrap();
let sock = shep_client::testing::control_address(dir.path());
let (client, mut envelopes) = fake_client_capturing_envelopes(&sock).await;
let mut out = Vec::new();
let mut err = Vec::new();
let args = StartArgs {
targets: vec![flockfile.to_string_lossy().into_owned()],
name: None,
fold: None,
cwd: None,
interpreter: None,
flockfile: false,
no_log_timestamps: false,
reset: None,
};
{
let mut streams = Streams {
out: &mut out,
err: &mut err,
style: crate::style::Presentation::BARE,
fmt: Format::Table,
};
let _ = start(&client, &mut streams, &args, None, &BTreeMap::new()).await;
}
let mut deadlines = Vec::new();
while let Ok(sent) = envelopes.try_recv() {
if matches!(sent.body, Request::Start { .. }) {
deadlines.push(sent.deadline_ms);
}
}
assert_eq!(
deadlines,
vec![Some(90_000)],
"two 40s stages plus STAGED_START_SLACK, not a fixed budget"
);
}
#[tokio::test]
async fn a_malformed_selector_exits_usage_without_a_round_trip() {
let dir = tempfile::tempdir().unwrap();
let path = shep_client::testing::control_address(dir.path());
let (client, mut envelopes) = fake_client_capturing_envelopes(&path).await;
let mut out = Vec::new();
let mut err = Vec::new();
let code = {
let mut streams = Streams {
out: &mut out,
err: &mut err,
style: crate::style::Presentation::BARE,
fmt: Format::Table,
};
stop(
&client,
&mut streams,
&SelectorArgs {
selectors: vec!["/[/".into()],
},
)
.await
};
assert_eq!(code, ExitCode::Usage);
assert!(
envelopes.try_recv().is_err(),
"a malformed selector must fail locally"
);
}
#[tokio::test]
async fn a_not_found_reply_exits_not_found_rather_than_being_swallowed() {
let dir = tempfile::tempdir().unwrap();
let path = shep_client::testing::control_address(dir.path());
let (client, _served) =
fake_client_replying_err(&path, RpcErrorCode::NotFound, "no sheep matched").await;
let mut out = Vec::new();
let mut err = Vec::new();
let mut streams = Streams {
out: &mut out,
err: &mut err,
style: crate::style::Presentation::BARE,
fmt: Format::Table,
};
let code = stop(
&client,
&mut streams,
&SelectorArgs {
selectors: vec!["ghost".into()],
},
)
.await;
assert_eq!(code, ExitCode::NotFound);
}
#[tokio::test]
async fn start_asks_for_the_longer_deadline() {
let dir = tempfile::tempdir().unwrap();
let path = shep_client::testing::control_address(dir.path());
let (client, mut envelopes) = fake_client_capturing_envelopes(&path).await;
let srv = dir.path().join("srv");
std::fs::write(&srv, "").unwrap();
let mut out = Vec::new();
let mut err = Vec::new();
let mut streams = Streams {
out: &mut out,
err: &mut err,
style: crate::style::Presentation::BARE,
fmt: Format::Table,
};
let _ = start(
&client,
&mut streams,
&start_args(srv.to_str().unwrap()),
None,
&BTreeMap::new(),
)
.await;
let sent = next_start(&mut envelopes).await;
assert_eq!(
sent.deadline_ms,
Some(u64::try_from(START_DEADLINE.as_millis()).unwrap())
);
let mut expected = AppConfig::minimal("srv", srv.to_str().unwrap());
expected.cwd = std::env::current_dir()
.ok()
.map(|dir| dir.to_string_lossy().into_owned());
assert_eq!(
sent.body,
Request::Start {
apps: vec![expected]
}
);
}
const STOP_NEEDS: Duration = Duration::from_secs(7);
#[tokio::test]
async fn a_stop_that_outlasts_the_default_deadline_still_answers_stopped() {
let dir = tempfile::tempdir().unwrap();
let path = shep_client::testing::control_address(dir.path());
let (client, _daemon) =
fake_client_needing_budget(&path, STOP_NEEDS, Response::Stopped(Vec::new())).await;
let mut out = Vec::new();
let mut err = Vec::new();
let mut streams = Streams {
out: &mut out,
err: &mut err,
style: crate::style::Presentation::BARE,
fmt: Format::Table,
};
let code = stop(
&client,
&mut streams,
&SelectorArgs {
selectors: vec!["web".into()],
},
)
.await;
assert_eq!(
code,
ExitCode::Success,
"stderr: {}",
String::from_utf8_lossy(&err)
);
}