use std::path::Path;
use std::time::Duration;
use serde_json::{Value as Json, json};
use shep_client::Client;
use shep_client::testing::{control_address, fake_client_answering_refusals};
use shep_core::config::AppConfig;
use shep_core::dogs::manifest::{Manifest, Serves};
use shep_core::protocol::{
DogSectionToml, DogSource, Envelope, ProcessInfo, Request, Response, SheepConfigView,
};
use shep_core::status::ProcStatus;
use tokio::sync::mpsc::UnboundedReceiver;
use crate::commands::dogs::{ManifestRead, read_manifest};
#[cfg(unix)]
pub(crate) fn adopt_jobs(dir: &Path, serves: Serves) {
let mut manifest = Manifest::new("jobs", "1.0.0", 1);
manifest.serves = serves;
manifest.settings = Some(json!({
"type": "object",
"properties": {
"poll": { "type": "string", "x-shep-dog-wide": true },
"model": { "type": "string" },
"limit": { "type": "integer" },
},
}));
adopt(dir, &manifest);
}
#[cfg(unix)]
pub(crate) fn adopt_jobs_without_the_standard(dir: &Path, sheep_schema: bool) {
let mut manifest = Manifest::new("jobs", "1.0.0", 1);
let mut settings = json!({
"type": "object",
"properties": {
"poll": { "type": "string" },
"model": { "type": "string" },
"limit": { "type": "integer" },
},
});
if sheep_schema {
settings["x-shep-sheep"] = json!({
"type": "object",
"properties": { "model": { "type": "string" }, "limit": { "type": "integer" } },
});
}
manifest.settings = Some(settings);
let wire = serde_json::to_value(&manifest).unwrap();
assert!(wire.get("serves").is_none(), "the field is absent: {wire}");
adopt(dir, &manifest);
}
#[cfg(unix)]
fn adopt(dir: &Path, manifest: &Manifest) {
use std::os::unix::fs::PermissionsExt;
let script = dir.join("shep-jobs");
std::fs::write(
&script,
format!(
"#!/bin/sh\ncat <<'EOF'\n{}\nEOF\n",
serde_json::to_string(manifest).unwrap()
),
)
.unwrap();
std::fs::set_permissions(&script, std::fs::Permissions::from_mode(0o755)).unwrap();
std::fs::write(
dir.join("shep.toml"),
format!(
"[daemon.adopted_dogs]\njobs = {:?}\n",
script.display().to_string()
),
)
.unwrap();
let read = read_manifest(&script, dir, "jobs", Duration::from_secs(30));
assert!(matches!(read, Ok(ManifestRead::Read(_))), "{read:?}");
}
pub(crate) async fn shepherd(
dir: &Path,
own: Option<Json>,
section: &str,
) -> (Client, UnboundedReceiver<Envelope>) {
let flock = vec![
ProcessInfo::builder(1, "api", ProcStatus::Online).build(),
ProcessInfo::builder(3, "web", ProcStatus::Online).build(),
ProcessInfo::builder(2, "jobs", ProcStatus::Online)
.dog(Some(DogSource::BuiltIn {
grants: None,
events: Vec::new(),
}))
.build(),
];
let mut config = AppConfig {
name: "api".into(),
..AppConfig::default()
};
if let Some(own) = own {
config
.dogs
.insert("jobs".into(), own.as_object().cloned().unwrap().into());
}
let view = SheepConfigView::new(config, Vec::new(), Vec::new());
let section = section.to_string();
fake_client_answering_refusals(&control_address(dir), move |request| match request {
Request::ListFlock => Ok(Response::Flock(flock.clone())),
Request::SheepConfig { .. } => Ok(Response::SheepConfig(Box::new(view.clone()))),
Request::DogConfig { .. } => Ok(Response::DogSection {
toml: DogSectionToml::from(section.clone()),
}),
Request::SetSheepDogSettings { name, dog, .. } => Ok(Response::SheepDogSettingsSet {
name: name.clone(),
dog: dog.clone(),
}),
_other => Ok(Response::Pong),
})
.await
}