use log::Level;
use metrics_util::debugging::DebugValue;
use super::{Labels, ObservabilityHandle, SnapshotEntry};
impl ObservabilityHandle {
pub fn assert_counter(
&self,
name: &str,
labels: impl Into<Labels>,
expected: u64,
) -> Result<(), String> {
let labels = labels.into();
let actual = find_counter(&self.captured, name, &labels.as_str_pairs());
if actual == expected {
Ok(())
} else {
Err(format!(
"counter {name} with labels {labels:?}: expected {expected}, got {actual}"
))
}
}
pub fn assert_no_metric(&self, name: &str) -> Result<(), String> {
let found = self
.captured
.iter()
.any(|(key, ..)| key.key().name() == name);
if found {
Err(format!("expected no metric named {name}, but found one"))
} else {
Ok(())
}
}
pub fn assert_codec_error_counter(
&self,
error_type: &str,
recovery_policy: &str,
expected: u64,
) -> Result<(), String> {
let actual = self.codec_error_counter(error_type, recovery_policy);
if actual == expected {
Ok(())
} else {
Err(format!(
"codec error counter (error_type={error_type}, \
recovery_policy={recovery_policy}): expected {expected}, got {actual}"
))
}
}
pub fn assert_log_contains(&mut self, substring: &str) -> Result<(), String> {
self.assert_log_matches(
|record| record.args().to_string().contains(substring),
|record| record.args().to_string(),
|records| format!("no log record containing {substring:?}; captured: {records:?}"),
)
}
pub fn assert_log_at_level(&mut self, level: Level, substring: &str) -> Result<(), String> {
self.assert_log_matches(
|record| record.level() == level && record.args().to_string().contains(substring),
|record| format!("[{}] {}", record.level(), record.args()),
|records| format!("no {level} log containing {substring:?}; captured: {records:?}"),
)
}
fn assert_log_matches<F, G>(
&mut self,
predicate: F,
format_record: G,
error_msg: impl FnOnce(&[String]) -> String,
) -> Result<(), String>
where
F: Fn(&logtest::Record) -> bool,
G: Fn(&logtest::Record) -> String,
{
let mut matched = false;
let mut records = Vec::new();
while let Some(record) = self.logger.pop() {
if !matched && predicate(&record) {
matched = true;
} else {
records.push(format_record(&record));
}
}
if matched {
Ok(())
} else {
Err(error_msg(&records))
}
}
}
pub(super) fn find_counter(snapshot: &[SnapshotEntry], name: &str, labels: &[(&str, &str)]) -> u64 {
snapshot
.iter()
.filter(|(key, ..)| key.key().name() == name)
.filter(|(key, ..)| {
labels
.iter()
.all(|(k, v)| key.key().labels().any(|l| l.key() == *k && l.value() == *v))
})
.filter_map(|(.., value)| match value {
DebugValue::Counter(c) => Some(*c),
_ => None,
})
.sum()
}