use shep_core::protocol::Response;
use super::*;
#[tokio::test]
async fn get_metrics_carries_the_host_sample() {
let dir = tempfile::tempdir().unwrap();
let socket = shep_client::testing::control_address(dir.path());
let served = shep_client::testing::serve_one_request(
&socket,
matching_ack(),
Response::Flock(vec![shep_client::testing::sample_info()]),
)
.await;
let whistle = whistle_at(socket, dir.path().join("barks.jsonl"));
let result = tokio::time::timeout(
TEST_TIMEOUT,
whistle.get_metrics(Parameters(MetricsParams { host: None })),
)
.await
.expect("get_metrics must return within the test timeout")
.expect("a scripted daemon must not produce a tool error");
assert!(
result.0.host.is_some(),
"the host sample must survive the trip to the blocking pool"
);
assert_eq!(result.0.flock.len(), 1);
served.await.expect("the fake daemon task must not panic");
}
#[tokio::test]
async fn get_metrics_reports_the_version_and_pid_from_the_handshake() {
let dir = tempfile::tempdir().unwrap();
let socket = shep_client::testing::control_address(dir.path());
let mut sheep = shep_client::testing::sample_info();
sheep.pid = Some(9999);
let served = shep_client::testing::serve_one_request(
&socket,
matching_ack(),
Response::Flock(vec![sheep]),
)
.await;
let whistle = whistle_at(socket, dir.path().join("barks.jsonl"));
let result = tokio::time::timeout(
TEST_TIMEOUT,
whistle.get_metrics(Parameters(MetricsParams { host: None })),
)
.await
.expect("get_metrics must return within the test timeout")
.expect("a scripted daemon must not produce a tool error");
assert_eq!(
result.0.flock.first().and_then(|row| row.pid),
Some(9999),
"the sheep's own pid is on the same reply, so the two numbers \
are tellable apart there: {:?}",
result.0.flock.first().map(|row| row.pid)
);
assert_eq!(
result.0.daemon_pid, 4242,
"the ack's pid, not the sheep's 9999: {}",
result.0.daemon_pid
);
assert_eq!(
result.0.daemon_version,
env!("CARGO_PKG_VERSION"),
"filled from the handshake, not left at a placeholder: {}",
result.0.daemon_version
);
served.await.expect("the fake daemon task must not panic");
}
#[cfg(unix)]
fn remote_usage() -> shep_core::protocol::HostUsage {
shep_core::protocol::HostUsage {
cpu_percent: Some(12.5),
memory_used_bytes: 1_000,
memory_total_bytes: 2_000,
disk_bytes_per_second: None,
network_bytes_per_second: None,
}
}
#[cfg(unix)]
#[tokio::test]
async fn get_metrics_over_a_host_reads_host_usage_and_never_samples_this_machine() {
let dir = tempfile::tempdir().unwrap();
let program = ssh_stand_in_replying(
dir.path(),
Ok(matching_ack()),
vec![
Response::Flock(vec![shep_client::testing::sample_info()]),
Response::HostUsage(Some(remote_usage())),
],
);
let whistle = whistle_with_hosts(dir.path(), &["amp2"], &program);
let result = tokio::time::timeout(
TEST_TIMEOUT,
whistle.get_metrics(Parameters(MetricsParams {
host: Some("amp2".to_string()),
})),
)
.await
.expect("get_metrics must return within the test timeout")
.expect("a stand-in shepherd must not produce a tool error");
assert_eq!(result.0.host_name.as_deref(), Some("amp2"));
assert_eq!(result.0.flock.len(), 1);
let host = result.0.host.expect("the host's usage must be reported");
assert_eq!(
(host.memory_total_bytes, host.memory_used_bytes),
(2_000, 1_000),
"the stand-in's numbers, not this machine's: {host:?}"
);
let bytes = written_within(TEST_TIMEOUT, &stand_in_file(dir.path(), "request-2.bin")).await;
let envelope: shep_core::protocol::Envelope =
shep_core::protocol::decode_frame(&bytes).unwrap();
assert_eq!(envelope.body, Request::HostUsage);
}
#[cfg(unix)]
#[tokio::test]
async fn get_metrics_over_a_host_leaves_processes_and_uptime_out() {
let dir = tempfile::tempdir().unwrap();
let program = ssh_stand_in_replying(
dir.path(),
Ok(matching_ack()),
vec![
Response::Flock(vec![shep_client::testing::sample_info()]),
Response::HostUsage(Some(remote_usage())),
],
);
let whistle = whistle_with_hosts(dir.path(), &["amp2"], &program);
let result = tokio::time::timeout(
TEST_TIMEOUT,
whistle.get_metrics(Parameters(MetricsParams {
host: Some("amp2".to_string()),
})),
)
.await
.expect("get_metrics must return within the test timeout")
.expect("a stand-in shepherd must not produce a tool error");
assert_eq!(
serde_json::to_value(&result.0).unwrap()["host"],
serde_json::json!({"memory_total_bytes": 2000, "memory_used_bytes": 1000}),
);
}
#[tokio::test]
async fn get_metrics_without_a_host_keeps_its_local_shape() {
let dir = tempfile::tempdir().unwrap();
let socket = shep_client::testing::control_address(dir.path());
let served = shep_client::testing::serve_one_request(
&socket,
matching_ack(),
Response::Flock(vec![shep_client::testing::sample_info()]),
)
.await;
let whistle = whistle_at(socket, dir.path().join("barks.jsonl"));
let result = tokio::time::timeout(
TEST_TIMEOUT,
whistle.get_metrics(Parameters(MetricsParams { host: None })),
)
.await
.expect("get_metrics must return within the test timeout")
.expect("a scripted daemon must not produce a tool error");
let reading = serde_json::to_value(&result.0).unwrap();
assert!(reading.get("host_name").is_none(), "{reading}");
let host = &reading["host"];
assert!(host["processes"].is_u64(), "{host}");
assert!(host["uptime_seconds"].is_u64(), "{host}");
served.await.expect("the fake daemon task must not panic");
}