init port
This commit is contained in:
commit
f825488351
17 changed files with 3513 additions and 0 deletions
237
tests/checks.rs
Normal file
237
tests/checks.rs
Normal file
|
|
@ -0,0 +1,237 @@
|
|||
use scriptherder::check::Check;
|
||||
use scriptherder::job::Job;
|
||||
|
||||
// Helper mirroring test_checks.py::_run
|
||||
fn run_check(cmd: &[&str], ok: &str, warn: &str, run: bool, runtime_mode_off: bool) -> Job {
|
||||
let mut job = Job::new("unittest_job", cmd.iter().map(|s| s.to_string()).collect()).unwrap();
|
||||
if run {
|
||||
job.run();
|
||||
}
|
||||
let check = Check::new(ok, warn, "unit_testing", true).unwrap();
|
||||
job.check(&check);
|
||||
if runtime_mode_off {
|
||||
let check = Check::new(ok, warn, "unit_testing", false).unwrap();
|
||||
job.check(&check);
|
||||
}
|
||||
job
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn exit_status_ok() {
|
||||
let job = run_check(&["/bin/echo", "test"], "exit_status=0", "", true, false);
|
||||
assert!(job.is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn exit_status_critical() {
|
||||
let job = run_check(
|
||||
&["/usr/bin/true", "test"],
|
||||
"exit_status=1",
|
||||
"exit_status=2",
|
||||
true,
|
||||
false,
|
||||
);
|
||||
assert!(!job.is_ok());
|
||||
assert!(!job.is_warning());
|
||||
assert_eq!(job.check_status(), Some("CRITICAL"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn file_exists_fail_reason() {
|
||||
let job = run_check(
|
||||
&["/usr/bin/false"],
|
||||
"exit_status=0,OR_file_exists=/this_file_should_not_exist",
|
||||
"",
|
||||
true,
|
||||
true,
|
||||
);
|
||||
assert!(!job.is_ok());
|
||||
assert_eq!(job.check_status(), Some("CRITICAL"));
|
||||
assert_eq!(
|
||||
job.check_reason(),
|
||||
Some("file_does_not_exist=/this_file_should_not_exist, stored_status=OK==False")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn output_contains_reason() {
|
||||
let job = run_check(
|
||||
&["/bin/echo", "STATUS_TESTING_OK"],
|
||||
"exit_status=0,output_contains=TESTING",
|
||||
"",
|
||||
true,
|
||||
false,
|
||||
);
|
||||
assert!(job.is_ok());
|
||||
assert_eq!(
|
||||
job.check_reason(),
|
||||
Some("exit=0, output_contains=TESTING==True")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn output_not_contains_obsolete_reason() {
|
||||
let job = run_check(
|
||||
&["/bin/echo", "STATUS_TESTING_OK"],
|
||||
"exit_status=0,output_not_contains=ERROR",
|
||||
"",
|
||||
true,
|
||||
false,
|
||||
);
|
||||
assert!(job.is_ok());
|
||||
assert_eq!(
|
||||
job.check_reason(),
|
||||
Some("exit=0, !output_contains=ERROR==True")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn output_matches_reason() {
|
||||
let job = run_check(
|
||||
&["/bin/echo", "STATUS_TESTING_OK"],
|
||||
"exit_status=0,output_matches=.*TESTING.*",
|
||||
"",
|
||||
true,
|
||||
false,
|
||||
);
|
||||
assert!(job.is_ok());
|
||||
assert_eq!(
|
||||
job.check_reason(),
|
||||
Some("exit=0, output_matches=.*TESTING.*==True")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn exit_status_warning() {
|
||||
let job = run_check(
|
||||
&["/bin/echo", "test"],
|
||||
"exit_status=1",
|
||||
"exit_status=0",
|
||||
true,
|
||||
false,
|
||||
);
|
||||
assert!(!job.is_ok());
|
||||
assert!(job.is_warning());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn exit_status_negated1() {
|
||||
let job = run_check(&["/usr/bin/false"], "!exit_status=0", "", true, false);
|
||||
assert!(job.is_ok());
|
||||
assert!(!job.is_warning());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn max_age() {
|
||||
let job = run_check(
|
||||
&["/bin/echo", "test"],
|
||||
"exit_status=0, max_age=10s",
|
||||
"exit_status=0, max_age=3h",
|
||||
true,
|
||||
true,
|
||||
);
|
||||
assert!(job.is_ok());
|
||||
assert!(!job.is_warning());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn max_age_negated() {
|
||||
let job = run_check(
|
||||
&["/bin/echo", "test"],
|
||||
"exit_status=0, !max_age=10s",
|
||||
"exit_status=0, max_age=3h",
|
||||
true,
|
||||
true,
|
||||
);
|
||||
assert!(!job.is_ok());
|
||||
assert!(job.is_warning());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn file_exists() {
|
||||
// exit_status=1 so ok fails; warn has OR_file_exists=/etc/services which exists
|
||||
let job = run_check(
|
||||
&["/bin/echo", "test"],
|
||||
"exit_status=1",
|
||||
"exit_status=1,OR_file_exists=/etc/services",
|
||||
true,
|
||||
true,
|
||||
);
|
||||
assert!(!job.is_ok());
|
||||
assert!(job.is_warning());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn file_exists_negated() {
|
||||
// /usr/bin/false exits 1; ok = exit_status=0,!OR_file_exists=<nonexistent>
|
||||
// negated file_exists on a missing file → criterion passes
|
||||
let job = run_check(
|
||||
&["/usr/bin/false"],
|
||||
"exit_status=0,!OR_file_exists=/this_could_be_a_FAIL_file",
|
||||
"",
|
||||
true,
|
||||
true,
|
||||
);
|
||||
assert!(job.is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn or_running() {
|
||||
// /bin/echo exits 0; ok = exit_status=1,OR_running → OR_running is True while running
|
||||
let job = run_check(
|
||||
&["/bin/echo", "test"],
|
||||
"exit_status=1,OR_running",
|
||||
"exit_status=0",
|
||||
true,
|
||||
false,
|
||||
);
|
||||
assert!(job.is_ok());
|
||||
assert!(!job.is_warning());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn or_running_negated() {
|
||||
// run=false so job never ran; ok = exit_status=1,OR_running (OR_running False, exit_status=1 not run)
|
||||
// warn = !OR_running → negated OR_running is True when not running
|
||||
let job = run_check(
|
||||
&["/bin/echo", "test"],
|
||||
"exit_status=1,OR_running",
|
||||
"!OR_running",
|
||||
false,
|
||||
false,
|
||||
);
|
||||
assert!(!job.is_ok());
|
||||
assert!(job.is_warning());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn output_contains_negated() {
|
||||
let job = run_check(
|
||||
&["/bin/echo", "STATUS_TESTING_OK"],
|
||||
"exit_status=0,!output_contains=ERROR",
|
||||
"",
|
||||
true,
|
||||
false,
|
||||
);
|
||||
assert!(job.is_ok());
|
||||
assert_eq!(
|
||||
job.check_reason(),
|
||||
Some("exit=0, !output_contains=ERROR==True")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn output_matches_negated() {
|
||||
let job = run_check(
|
||||
&["/bin/echo", "STATUS_TESTING_OK"],
|
||||
"exit_status=0,!output_matches=.*ERROR.*",
|
||||
"",
|
||||
true,
|
||||
false,
|
||||
);
|
||||
assert!(job.is_ok());
|
||||
assert_eq!(
|
||||
job.check_reason(),
|
||||
Some("exit=0, !output_matches=.*ERROR.*==True")
|
||||
);
|
||||
}
|
||||
132
tests/checkstatus.rs
Normal file
132
tests/checkstatus.rs
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
use scriptherder::check::Check;
|
||||
use scriptherder::checkstatus::CheckStatus;
|
||||
use scriptherder::job::Job;
|
||||
use scriptherder::jobs_list::JobsList;
|
||||
use std::collections::HashMap;
|
||||
|
||||
fn move_back(job: &mut Job, seconds: f64) {
|
||||
let s = job.start_time().unwrap();
|
||||
let e = job.end_time().unwrap();
|
||||
job.set_times_for_test(s - seconds, e - seconds);
|
||||
}
|
||||
|
||||
fn make_checkstatus(jobs: Vec<Job>, ok: &str, warn: &str) -> CheckStatus {
|
||||
let mut checks = HashMap::new();
|
||||
checks.insert(
|
||||
"test1".to_string(),
|
||||
Check::new(ok, warn, "unit_testing", false).unwrap(),
|
||||
);
|
||||
let mut cs = CheckStatus::new(false, String::new(), checks);
|
||||
cs.check_jobs(JobsList::from_jobs(jobs, false));
|
||||
cs
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn two_delayed_jobs_critical() {
|
||||
let ok = "exit_status=0, max_age=1m";
|
||||
let warn = "exit_status=0, max_age=5m";
|
||||
let mut j1 = Job::new("test1", vec!["/usr/bin/true".into()]).unwrap();
|
||||
let mut j2 = Job::new("test1", vec!["/usr/bin/true".into()]).unwrap();
|
||||
j1.run();
|
||||
j2.run();
|
||||
let rc = Check::new(ok, warn, "unit_testing", true).unwrap();
|
||||
j1.check(&rc);
|
||||
j2.check(&rc);
|
||||
move_back(&mut j1, 19.0 * 60.0);
|
||||
move_back(&mut j2, 20.0 * 60.0);
|
||||
let cs = make_checkstatus(vec![j1, j2], ok, warn);
|
||||
assert_eq!(cs.num_jobs(), 1);
|
||||
assert_eq!(
|
||||
cs.aggregate_status(),
|
||||
(
|
||||
"CRITICAL".to_string(),
|
||||
Some("age=19m>1m, age=19m>5m".to_string())
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn two_delayed_jobs_warning() {
|
||||
let ok = "exit_status=0, max_age=1m";
|
||||
let warn = "exit_status=0, max_age=2h";
|
||||
let mut j1 = Job::new("test1", vec!["/usr/bin/true".into()]).unwrap();
|
||||
let mut j2 = Job::new("test1", vec!["/usr/bin/true".into()]).unwrap();
|
||||
j1.run();
|
||||
j2.run();
|
||||
let rc = Check::new(ok, warn, "unit_testing", true).unwrap();
|
||||
j1.check(&rc);
|
||||
j2.check(&rc);
|
||||
move_back(&mut j1, 2.0 * 60.0);
|
||||
move_back(&mut j2, 4.0 * 60.0);
|
||||
let cs = make_checkstatus(vec![j1, j2], ok, warn);
|
||||
assert_eq!(cs.num_jobs(), 1);
|
||||
assert_eq!(
|
||||
cs.aggregate_status(),
|
||||
(
|
||||
"WARNING".to_string(),
|
||||
Some("age=2m>1m, max_age=2h, stored_status=OK==True".to_string())
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn positive_then_negative_critical() {
|
||||
let ok = "exit_status=0";
|
||||
let warn = "exit_status=0";
|
||||
let mut j1 = Job::new("test1", vec!["/usr/bin/true".into()]).unwrap();
|
||||
let mut j2 = Job::new("test1", vec!["/usr/bin/false".into()]).unwrap();
|
||||
j1.run();
|
||||
j2.run();
|
||||
let rc = Check::new(ok, warn, "unit_testing", true).unwrap();
|
||||
j1.check(&rc);
|
||||
j2.check(&rc);
|
||||
let cs = make_checkstatus(vec![j1, j2], ok, warn);
|
||||
assert_eq!(cs.num_jobs(), 1);
|
||||
assert_eq!(
|
||||
cs.aggregate_status(),
|
||||
(
|
||||
"CRITICAL".to_string(),
|
||||
Some("stored_status=OK==False".to_string())
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn job_failed_job() {
|
||||
let ok = "exit_status=0,max_age=50m";
|
||||
let warn = "exit_status=0,max_age=1h";
|
||||
let mut j1 = Job::new("test1", vec!["/usr/bin/false".into()]).unwrap();
|
||||
j1.run();
|
||||
move_back(&mut j1, 10.0);
|
||||
let rc = Check::new(ok, warn, "unit_testing", true).unwrap();
|
||||
j1.check(&rc);
|
||||
let cs = make_checkstatus(vec![j1], ok, warn);
|
||||
assert_eq!(cs.num_jobs(), 1);
|
||||
assert_eq!(
|
||||
cs.aggregate_status(),
|
||||
(
|
||||
"CRITICAL".to_string(),
|
||||
Some("stored_status=OK==False".to_string())
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn misconfigured_criteria() {
|
||||
let ok = "exit_status=0,max_age=50m";
|
||||
let warn = "exit_status=0,max_age=1";
|
||||
let mut j1 = Job::new("test1", vec!["/usr/bin/false".into()]).unwrap();
|
||||
j1.run();
|
||||
move_back(&mut j1, 10.0);
|
||||
let rc = Check::new(ok, warn, "unit_testing", true).unwrap();
|
||||
j1.check(&rc);
|
||||
let cs = make_checkstatus(vec![j1], ok, warn);
|
||||
assert_eq!(cs.num_jobs(), 1);
|
||||
assert_eq!(
|
||||
cs.aggregate_status(),
|
||||
(
|
||||
"CRITICAL".to_string(),
|
||||
Some("stored_status=OK==False, age=10s>1s".to_string())
|
||||
)
|
||||
);
|
||||
}
|
||||
79
tests/cli_smoke.rs
Normal file
79
tests/cli_smoke.rs
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
use std::process::Command;
|
||||
|
||||
fn bin() -> Command {
|
||||
Command::new(env!("CARGO_BIN_EXE_scriptherder"))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ls_empty_datadir_runs() {
|
||||
let dir = std::env::temp_dir().join(format!("sh_cli_{}", std::process::id()));
|
||||
std::fs::create_dir_all(&dir).unwrap();
|
||||
let out = bin()
|
||||
.arg("-d")
|
||||
.arg(&dir)
|
||||
.arg("--checkdir")
|
||||
.arg(&dir)
|
||||
.arg("ls")
|
||||
.output()
|
||||
.unwrap();
|
||||
assert!(out.status.success());
|
||||
std::fs::remove_dir_all(&dir).ok();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wrap_then_check_roundtrip() {
|
||||
let dir = std::env::temp_dir().join(format!("sh_cli2_{}", std::process::id()));
|
||||
let checkdir = dir.join("check");
|
||||
std::fs::create_dir_all(&checkdir).unwrap();
|
||||
std::fs::write(
|
||||
checkdir.join("smoke.ini"),
|
||||
"[check]\nok = exit_status=0, max_age=8h\n",
|
||||
)
|
||||
.unwrap();
|
||||
// wrap a successful command
|
||||
let w = bin()
|
||||
.arg("-d")
|
||||
.arg(&dir)
|
||||
.arg("--checkdir")
|
||||
.arg(&checkdir)
|
||||
.arg("wrap")
|
||||
.arg("-N")
|
||||
.arg("smoke")
|
||||
.arg("--")
|
||||
.arg("/bin/true")
|
||||
.output()
|
||||
.unwrap();
|
||||
assert!(w.status.success());
|
||||
// check should report OK (exit 0)
|
||||
let c = bin()
|
||||
.arg("-d")
|
||||
.arg(&dir)
|
||||
.arg("--checkdir")
|
||||
.arg(&checkdir)
|
||||
.arg("check")
|
||||
.arg("smoke")
|
||||
.output()
|
||||
.unwrap();
|
||||
let stdout = String::from_utf8_lossy(&c.stdout);
|
||||
assert!(stdout.starts_with("OK:"), "got: {stdout}");
|
||||
assert_eq!(c.status.code(), Some(0));
|
||||
std::fs::remove_dir_all(&dir).ok();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lastlog_empty_datadir_no_jobs_exits_1() {
|
||||
let dir = std::env::temp_dir().join(format!("sh_cli3_{}", std::process::id()));
|
||||
std::fs::create_dir_all(&dir).unwrap();
|
||||
let out = bin()
|
||||
.arg("-d")
|
||||
.arg(&dir)
|
||||
.arg("--checkdir")
|
||||
.arg(&dir)
|
||||
.arg("lastlog")
|
||||
.output()
|
||||
.unwrap();
|
||||
let stdout = String::from_utf8_lossy(&out.stdout);
|
||||
assert_eq!(stdout.trim(), "No jobs found", "got: {stdout}");
|
||||
assert_eq!(out.status.code(), Some(1));
|
||||
std::fs::remove_dir_all(&dir).ok();
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue