enh(generic-snmp): threshold works almost. Some error cases are still to implement

This commit is contained in:
David Boucher 2025-05-10 16:28:02 +02:00
parent 0f50c51366
commit 069167fc27
2 changed files with 130 additions and 17 deletions

View File

@ -5,6 +5,7 @@ use std::f64::INFINITY;
pub struct Threshold { pub struct Threshold {
start: f64, start: f64,
end: f64, end: f64,
negation: bool,
} }
impl Threshold { impl Threshold {
@ -14,7 +15,8 @@ impl Threshold {
let mut in_number = false; let mut in_number = false;
let mut current = 0; let mut current = 0;
let mut value = [-INFINITY, INFINITY]; let mut value = [-INFINITY, INFINITY];
let mut in_range = false; let mut in_range = 0;
let mut negation = 0;
for (idx, c) in expr.char_indices() { for (idx, c) in expr.char_indices() {
if in_number { if in_number {
match c { match c {
@ -24,10 +26,7 @@ impl Threshold {
in_number = false; in_number = false;
value[current] = match expr[start..idx].parse() { value[current] = match expr[start..idx].parse() {
Ok(x) => x, Ok(x) => x,
Err(err) => { Err(_) => return Err(Error::BadThreshold),
error!("parse error: {}", err);
std::process::exit(3);
}
} }
} }
} }
@ -35,7 +34,14 @@ impl Threshold {
/* No else here, because we can continue the previous match */ /* No else here, because we can continue the previous match */
if !in_number { if !in_number {
match c { match c {
'@' => {
negation += 1;
}
' ' => continue, ' ' => continue,
'-' => {
in_number = true;
start = idx;
}
'0'..='9' => { '0'..='9' => {
in_number = true; in_number = true;
start = idx; start = idx;
@ -44,25 +50,25 @@ impl Threshold {
value[0] = -INFINITY; value[0] = -INFINITY;
} }
':' => { ':' => {
in_range = true; in_range += 1;
current = 1; current = 1;
} }
_ => break, _ => return Err(Error::BadThreshold),
} }
} }
} }
if negation > 1 {
return Err(Error::BadThreshold);
}
if in_number { if in_number {
value[current] = match expr[start..].parse() { value[current] = match expr[start..].parse() {
Ok(x) => x, Ok(x) => x,
Err(err) => { Err(_) => return Err(Error::BadThreshold),
error!("parse error: {}", err);
std::process::exit(3);
}
} }
} }
/* We have noticed a ':' character, so the threshold is a range */ /* We have noticed a ':' character, so the threshold is a range */
if in_range { if in_range == 1 {
if value[0] > value[1] { if value[0] > value[1] {
return Err(Error::BadThresholdRange { return Err(Error::BadThresholdRange {
start: value[0], start: value[0],
@ -72,7 +78,10 @@ impl Threshold {
return Ok(Threshold { return Ok(Threshold {
start: value[0], start: value[0],
end: value[1], end: value[1],
negation: negation > 0,
}); });
} else if in_range > 1 {
return Err(Error::BadThreshold);
} else { } else {
if value[0] <= 0_f64 { if value[0] <= 0_f64 {
return Err(Error::NegativeSimpleThreshold { value: value[0] }); return Err(Error::NegativeSimpleThreshold { value: value[0] });
@ -80,15 +89,24 @@ impl Threshold {
return Ok(Threshold { return Ok(Threshold {
start: 0_f64, start: 0_f64,
end: value[0], end: value[0],
negation: negation > 0,
}); });
} }
} }
fn in_alert(&self, value: f64) -> bool { fn in_alert(&self, value: f64) -> bool {
if value < self.start || value > self.end { if value < self.start || value > self.end {
if self.negation {
return false;
} else {
return true; return true;
}
}
if self.negation {
true
} else {
false
} }
false
} }
} }
@ -178,9 +196,101 @@ mod Test {
Err(err) => { Err(err) => {
assert_eq!( assert_eq!(
err.to_string(), err.to_string(),
"The start value 30 must be less than the end value 20" "Threshold: The start value 30 must be less than the end value 20"
); );
} }
} }
} }
#[test]
fn test_bad_range() {
let expr = "10:20:30";
let threshold = Threshold::parse(expr);
match threshold {
Ok(_) => {
panic!("The threshold '{}' should not be valid", expr);
}
Err(err) => {
assert_eq!(
err.to_string(),
"Threshold: Threshold not of the form '[@]start:end'"
);
}
}
}
#[test]
fn test_threshold_foobar() {
let expr = "foobar";
let threshold = Threshold::parse(expr);
match threshold {
Ok(_) => {
panic!("The threshold '{}' should not be valid", expr);
}
Err(err) => {
assert_eq!(err.to_string(),
"Threshold: Threshold not of the form '[@]start:end'");
}
}
}
#[test]
fn test_threshold_12foo() {
let expr = "12foo";
let threshold = Threshold::parse(expr);
match threshold {
Ok(_) => {
panic!("The threshold '{}' should not be valid", expr);
}
Err(err) => {
assert_eq!(err.to_string(),
"Threshold: Threshold not of the form '[@]start:end'");
}
}
}
#[test]
fn test_threshold_bad_number() {
let expr = "12e.1.e28";
let threshold = Threshold::parse(expr);
match threshold {
Ok(_) => {
panic!("The threshold '{}' should not be valid", expr);
}
Err(err) => {
assert_eq!(err.to_string(),
"Threshold: Threshold not of the form '[@]start:end'");
}
}
}
#[test]
fn test_threshold_bad_number_and_range() {
let expr = "12e.1.e28:1.2.3.4";
let threshold = Threshold::parse(expr);
match threshold {
Ok(_) => {
panic!("The threshold '{}' should not be valid", expr);
}
Err(err) => {
assert_eq!(err.to_string(),
"Threshold: Threshold not of the form '[@]start:end'");
}
}
}
#[test]
fn test_threshold_not_allowed_negative() {
let expr = "-12";
let threshold = Threshold::parse(expr);
match threshold {
Ok(_) => {
panic!("The threshold '{}' should not be valid", expr);
}
Err(err) => {
assert_eq!(err.to_string(),
"Threshold: This syntax is a shortcut of '0:-12', so -12 must be greater than 0.");
}
}
}
} }

View File

@ -4,18 +4,21 @@ use std::{fs, io, path::PathBuf};
#[derive(Debug, Snafu)] #[derive(Debug, Snafu)]
pub enum Error { pub enum Error {
#[snafu(display( #[snafu(display(
"This syntax is a shortcut of '0:{}', so {} must be greater than 0.", "Threshold: This syntax is a shortcut of '0:{}', so {} must be greater than 0.",
value, value,
value value
))] ))]
NegativeSimpleThreshold { value: f64 }, NegativeSimpleThreshold { value: f64 },
#[snafu(display("The start value {} must be less than the end value {}", start, end))] #[snafu(display("Threshold: The start value {} must be less than the end value {}", start, end))]
BadThresholdRange { start: f64, end: f64 }, BadThresholdRange { start: f64, end: f64 },
#[snafu(display("Unable to read configuration from {}", path.display()))] #[snafu(display("Threshold: Unable to read configuration from {}", path.display()))]
ReadConfiguration { source: io::Error, path: PathBuf }, ReadConfiguration { source: io::Error, path: PathBuf },
#[snafu(display("Threshold: Threshold not of the form '[@]start:end'"))]
BadThreshold,
#[snafu(display("Unable to write result to {}", path.display()))] #[snafu(display("Unable to write result to {}", path.display()))]
WriteResult { source: io::Error, path: PathBuf }, WriteResult { source: io::Error, path: PathBuf },
} }