use crate::lookout::app::{App, Control};
use crate::lookout::source::{HostSample, Local};
use crate::lookout::tail::Tail;
use crate::lookout::theme::Palette;
use shep_core::paths::ShepPaths;
use shep_core::protocol::ProcessInfo;
use std::path::Path;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::time::Instant;
pub(super) fn test_paths(home: &Path) -> ShepPaths {
let home_str = home.to_string_lossy().into_owned();
ShepPaths::resolve(&|key| (key == "SHEP_HOME").then(|| home_str.clone()), home)
}
pub(super) fn shared_test_paths() -> ShepPaths {
test_paths(Path::new("/tmp/shep-lookout-tests"))
}
pub(super) fn read_only_app() -> App {
App::new(
Palette::detect(None, None, None),
Control::ReadOnly,
"/tmp/shep".to_string(),
Instant::now(),
)
}
#[derive(Clone, Default)]
pub(super) struct FakeLocal {
pub(super) sample: Option<HostSample>,
pub(super) hosts: Arc<AtomicUsize>,
pub(super) tails: Arc<AtomicUsize>,
pub(super) log_sizes: Arc<AtomicUsize>,
pub(super) hint: Option<String>,
pub(super) hints: Arc<AtomicUsize>,
}
impl Local for FakeLocal {
fn host(&mut self) -> Option<HostSample> {
self.hosts.fetch_add(1, Ordering::Relaxed);
self.sample
}
fn tail(&mut self, _out: Option<&Path>, _err: Option<&Path>) -> Tail {
self.tails.fetch_add(1, Ordering::Relaxed);
Tail::default()
}
fn log_sizes(&mut self, _out: Option<&Path>, _err: Option<&Path>) -> Option<u64> {
self.log_sizes.fetch_add(1, Ordering::Relaxed);
None
}
fn hint(&mut self, _flock: &[ProcessInfo]) -> Option<String> {
self.hints.fetch_add(1, Ordering::Relaxed);
self.hint.clone()
}
}
#[cfg(unix)]
pub(super) fn sleeping_cargo(pid_file: &Path) -> String {
format!(
"#!/bin/sh\necho $$ > {}\nexec sleep 30\n",
pid_file.display()
)
}
#[cfg(unix)]
#[track_caller]
pub(super) fn is_gone(pid: u32) -> bool {
use nix::errno::Errno;
use nix::sys::wait::{WaitPidFlag, WaitStatus, waitpid};
use nix::unistd::Pid;
match waitpid(Pid::from_raw(cast_pid(pid)), Some(WaitPidFlag::WNOHANG)) {
Ok(WaitStatus::StillAlive) => false,
Ok(_) | Err(Errno::ECHILD) => true,
Err(err) => panic!("waitpid({pid}): {err}"),
}
}
#[cfg(unix)]
fn cast_pid(pid: u32) -> i32 {
i32::try_from(pid).expect("a pid fits an i32")
}
pub(super) fn kelpie_answer() -> serde_json::Value {
serde_json::from_str(include_str!("kelpie-schema.json")).expect("the recording is JSON")
}
pub(super) fn kelpie_sheep_schema() -> serde_json::Value {
super::probe_sheep_dogs::sheep_schema(&kelpie_answer()).expect("the answer names x-shep-sheep")
}