use crate::prometheus::parse_prometheus;
#[test]
fn test_label_sets() {
use crate::{
MetricFamily, MetricNumber, PrometheusCounterValue, PrometheusType, PrometheusValue, Sample,
};
let family = MetricFamily::new(
String::from("test_metric"),
vec![
String::from("test_label"),
String::from("test_label_to_remove"),
],
PrometheusType::Counter,
String::from("HELP!!"),
String::new(),
)
.with_samples(vec![Sample::new(
vec![String::from("test1"), String::from("test2")],
None,
PrometheusValue::Counter(PrometheusCounterValue {
value: MetricNumber::Int(1),
exemplar: None,
}),
)])
.unwrap();
{
let metric = family.iter_samples().next().unwrap();
assert_eq!(
metric
.get_labelset()
.unwrap()
.get_label_value("test_label")
.unwrap(),
"test1"
);
assert_eq!(
metric
.get_labelset()
.unwrap()
.get_label_value("test_label_to_remove")
.unwrap(),
"test2"
);
}
let family = family.without_label("test_label_to_remove").unwrap();
{
let metric = family.iter_samples().next().unwrap();
assert_eq!(
metric
.get_labelset()
.unwrap()
.get_label_value("test_label")
.unwrap(),
"test1"
);
assert!(metric
.get_labelset()
.unwrap()
.get_label_value("test_label_to_remove")
.is_none());
}
}
#[test]
fn test_render() {
let test_str = include_str!("../prometheus/testdata/upstream_example.txt");
let exposition = parse_prometheus(test_str).unwrap();
let exposition_str = exposition.to_string();
assert!(parse_prometheus(&exposition_str).is_ok());
let test_str = include_str!("../prometheus/testdata/gravelgateway#5.txt");
let exposition = parse_prometheus(test_str).unwrap();
let exposition_str = exposition.to_string();
assert!(parse_prometheus(&exposition_str).is_ok());
}
#[test]
fn test_metric_number_operations() {
use crate::MetricNumber;
let a = MetricNumber::Int(1);
let b = MetricNumber::Int(2);
let c = MetricNumber::Float(0.5);
let d = MetricNumber::Float(1.5);
assert_eq!(a + b, MetricNumber::Int(3));
assert_eq!(a + c, MetricNumber::Float(1.5));
assert_eq!(a + d, MetricNumber::Float(2.5));
assert_eq!(b + c, MetricNumber::Float(2.5));
assert_eq!(b + d, MetricNumber::Float(3.5));
assert_eq!(c + d, MetricNumber::Float(2.0));
assert_eq!(a - b, MetricNumber::Int(-1));
assert_eq!(a - c, MetricNumber::Float(0.5));
assert_eq!(a - d, MetricNumber::Float(-0.5));
assert_eq!(b - c, MetricNumber::Float(1.5));
assert_eq!(b - d, MetricNumber::Float(0.5));
assert_eq!(c - d, MetricNumber::Float(-1.0));
assert_eq!(a * b, MetricNumber::Int(2));
assert_eq!(a * c, MetricNumber::Float(0.5));
assert_eq!(a * d, MetricNumber::Float(1.5));
assert_eq!(b * c, MetricNumber::Float(1.0));
assert_eq!(b * d, MetricNumber::Float(3.0));
assert_eq!(c * d, MetricNumber::Float(0.75));
assert_eq!(a / b, MetricNumber::Int(0));
assert_eq!(a / c, MetricNumber::Float(2.0));
assert_eq!(a / d, MetricNumber::Float(2.0 / 3.0));
assert_eq!(b / c, MetricNumber::Float(4.0));
assert_eq!(b / d, MetricNumber::Float(4.0 / 3.0));
assert_eq!(c / d, MetricNumber::Float(1.0 / 3.0));
{
let mut a = MetricNumber::Int(1);
a += b;
assert_eq!(a, MetricNumber::Int(3));
}
{
let mut a = MetricNumber::Int(1);
a += c;
assert_eq!(a, MetricNumber::Float(1.5));
}
{
let mut a = MetricNumber::Int(1);
a += d;
assert_eq!(a, MetricNumber::Float(2.5));
}
{
let mut a = MetricNumber::Float(0.5);
a += b;
assert_eq!(a, MetricNumber::Float(2.5));
}
{
let mut a = MetricNumber::Float(0.5);
a += c;
assert_eq!(a, MetricNumber::Float(1.0));
}
{
let mut a = MetricNumber::Float(0.5);
a += d;
assert_eq!(a, MetricNumber::Float(2.0));
}
{
let mut a = MetricNumber::Int(1);
a -= b;
assert_eq!(a, MetricNumber::Int(-1));
}
{
let mut a = MetricNumber::Int(1);
a -= c;
assert_eq!(a, MetricNumber::Float(0.5));
}
{
let mut a = MetricNumber::Int(1);
a -= d;
assert_eq!(a, MetricNumber::Float(-0.5));
}
{
let mut a = MetricNumber::Float(0.5);
a -= b;
assert_eq!(a, MetricNumber::Float(-1.5));
}
{
let mut a = MetricNumber::Float(0.5);
a -= c;
}
{
let mut a = MetricNumber::Int(1);
a *= b;
assert_eq!(a, MetricNumber::Int(2));
}
{
let mut a = MetricNumber::Int(1);
a *= c;
assert_eq!(a, MetricNumber::Float(0.5));
}
{
let mut a = MetricNumber::Int(1);
a *= d;
assert_eq!(a, MetricNumber::Float(1.5));
}
{
let mut a = MetricNumber::Float(0.5);
a *= b;
assert_eq!(a, MetricNumber::Float(1.0));
}
{
let mut a = MetricNumber::Float(0.5);
a *= c;
assert_eq!(a, MetricNumber::Float(0.25));
}
{
let mut a = MetricNumber::Float(0.5);
a *= d;
assert_eq!(a, MetricNumber::Float(0.75));
}
{
let mut a = MetricNumber::Int(1);
a /= b;
assert_eq!(a, MetricNumber::Int(0));
}
{
let mut a = MetricNumber::Int(1);
a /= c;
assert_eq!(a, MetricNumber::Float(2.0));
}
{
let mut a = MetricNumber::Int(1);
a /= d;
assert_eq!(a, MetricNumber::Float(2.0 / 3.0));
}
{
let mut a = MetricNumber::Float(0.5);
a /= b;
assert_eq!(a, MetricNumber::Float(0.25));
}
{
let mut a = MetricNumber::Float(0.5);
a /= c;
assert_eq!(a, MetricNumber::Float(1.0));
}
{
let mut a = MetricNumber::Float(0.5);
a /= d;
assert_eq!(a, MetricNumber::Float(1.0 / 3.0));
}
}
#[test]
fn test_exemplar_render() {
use crate::Exemplar;
use std::collections::HashMap;
let labels: HashMap<String, String> = [("trace_id", "abc"), ("span_id", "def")]
.iter()
.map(|(k, v)| (k.to_string(), v.to_string()))
.collect();
assert_eq!(
Exemplar::new(labels, 0.5, Some(123.)).to_string(),
" # {span_id=\"def\",trace_id=\"abc\"} 0.5 123"
);
assert_eq!(Exemplar::new(HashMap::new(), 1., None).to_string(), " # {} 1");
let test_str = "# TYPE foo_total counter\nfoo_total 1 # {trace_id=\"abc\"} 0.5\n";
let rendered = parse_prometheus(test_str).unwrap().to_string();
assert_eq!(rendered, test_str);
}
#[test]
fn test_render_keeps_timestamps() {
let test_str = r#"# TYPE h histogram
h_bucket{le="1"} 0 5
h_bucket{le="+Inf"} 1 5
h_sum 1 5
h_count 1 5
# TYPE s summary
s{quantile="0.5"} 1 5
s_sum 1 5
s_count 1 5
"#;
let rendered = parse_prometheus(test_str).unwrap().to_string();
for line in rendered.lines().filter(|l| !l.is_empty() && !l.starts_with('#')) {
assert!(line.ends_with(" 5"), "missing timestamp on `{}`", line);
}
}
#[test]
fn test_metric_number_operations_dont_panic() {
use crate::MetricNumber;
let max = MetricNumber::Int(i64::MAX);
let one = MetricNumber::Int(1);
let zero = MetricNumber::Int(0);
assert_eq!(max + one, MetricNumber::Float(i64::MAX as f64 + 1.));
assert_eq!(MetricNumber::Int(i64::MIN) - one, MetricNumber::Float(i64::MIN as f64 - 1.));
assert_eq!(max * MetricNumber::Int(2), MetricNumber::Float(i64::MAX as f64 * 2.));
assert_eq!(one / zero, MetricNumber::Float(f64::INFINITY));
assert!(matches!(zero / zero, MetricNumber::Float(f) if f.is_nan()));
assert_eq!(MetricNumber::Int(i64::MIN) / MetricNumber::Int(-1), MetricNumber::Float(-(i64::MIN as f64)));
let mut a = max;
a += one;
assert_eq!(a, MetricNumber::Float(i64::MAX as f64 + 1.));
let mut a = one;
a /= zero;
assert_eq!(a, MetricNumber::Float(f64::INFINITY));
}
#[test]
fn test_with_labels() {
use crate::{MetricFamily, MetricNumber, PrometheusType, PrometheusValue, Sample};
let gauge = |values: &[&str]| {
Sample::new(
values.iter().map(|v| v.to_string()).collect(),
None,
PrometheusValue::Gauge(MetricNumber::Int(1)),
)
};
let family = MetricFamily::new(
String::from("test_metric"),
vec![String::from("zone"), String::from("app")],
PrometheusType::Gauge,
String::new(),
String::new(),
)
.with_samples(vec![gauge(&["a", "web"]), gauge(&["b", "web"])])
.unwrap();
let relabelled = family.with_labels(vec![("app", "api"), ("env", "prod")]).unwrap();
let mut names = relabelled.get_label_names().to_vec();
names.sort();
assert_eq!(names, &["app", "env", "zone"]);
for sample in relabelled.iter_samples() {
let labelset = sample.get_labelset().unwrap();
assert_eq!(labelset.get_label_value("app"), Some("api"));
assert_eq!(labelset.get_label_value("env"), Some("prod"));
}
assert!(family.with_labels(vec![("zone", "c")]).is_err());
let sorted = MetricFamily::new(
String::from("test_metric"),
vec![String::from("app"), String::from("zone")],
PrometheusType::Gauge,
String::new(),
String::new(),
)
.with_samples(vec![gauge(&["web", "a"])])
.unwrap();
let relabelled = sorted.with_labels(vec![("env", "prod")]).unwrap();
assert_eq!(relabelled.get_label_names(), &["app", "env", "zone"]);
}