mirror of
https://github.com/openobserve/openobserve.git
synced 2026-11-05 00:09:35 +00:00
test(promql): drop redundant and no-op unit tests (#15285)
This commit is contained in:
@@ -113,30 +113,6 @@ mod tests {
|
||||
use super::*;
|
||||
use crate::aggregations::eval_aggregate;
|
||||
|
||||
#[test]
|
||||
fn test_avg_value_none_input() {
|
||||
let timestamp = 1640995200;
|
||||
let eval_ctx = EvalContext::new(timestamp, timestamp + 1, 1, "test".to_string());
|
||||
let result = eval_aggregate(&None, Value::None, Avg, &eval_ctx).unwrap();
|
||||
assert!(matches!(result, Value::None));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_avg_invalid_input_returns_err() {
|
||||
let timestamp = 1640995200;
|
||||
let eval_ctx = EvalContext::new(timestamp, timestamp + 1, 1, "test".to_string());
|
||||
let result = eval_aggregate(&None, Value::Float(1.0), Avg, &eval_ctx);
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_avg_empty_matrix_returns_none() {
|
||||
let timestamp = 1640995200;
|
||||
let eval_ctx = EvalContext::new(timestamp, timestamp + 1, 1, "test".to_string());
|
||||
let result = eval_aggregate(&None, Value::Matrix(vec![]), Avg, &eval_ctx).unwrap();
|
||||
assert!(matches!(result, Value::None));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_avg_range_function() {
|
||||
let timestamp = 1640995200; // 2022-01-01 00:00:00 UTC
|
||||
|
||||
@@ -82,30 +82,6 @@ mod tests {
|
||||
use super::*;
|
||||
use crate::aggregations::eval_aggregate;
|
||||
|
||||
#[test]
|
||||
fn test_count_value_none_input() {
|
||||
let timestamp = 1640995200;
|
||||
let eval_ctx = EvalContext::new(timestamp, timestamp + 1, 1, "test".to_string());
|
||||
let result = eval_aggregate(&None, Value::None, Count, &eval_ctx).unwrap();
|
||||
assert!(matches!(result, Value::None));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_count_invalid_input_returns_err() {
|
||||
let timestamp = 1640995200;
|
||||
let eval_ctx = EvalContext::new(timestamp, timestamp + 1, 1, "test".to_string());
|
||||
let result = eval_aggregate(&None, Value::Float(1.0), Count, &eval_ctx);
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_count_empty_matrix_returns_none() {
|
||||
let timestamp = 1640995200;
|
||||
let eval_ctx = EvalContext::new(timestamp, timestamp + 1, 1, "test".to_string());
|
||||
let result = eval_aggregate(&None, Value::Matrix(vec![]), Count, &eval_ctx).unwrap();
|
||||
assert!(matches!(result, Value::None));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_count_range_function() {
|
||||
let timestamp = 1640995200; // 2022-01-01 00:00:00 UTC
|
||||
|
||||
@@ -78,16 +78,3 @@ impl<const IS_MAX: bool> Accumulate for ExtremaAccumulator<IS_MAX> {
|
||||
group_series(group_labels, samples)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_min_and_max_have_distinct_accumulator_types() {
|
||||
assert_ne!(
|
||||
std::any::TypeId::of::<ExtremaAccumulator<false>>(),
|
||||
std::any::TypeId::of::<ExtremaAccumulator<true>>(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,30 +83,6 @@ mod tests {
|
||||
use super::*;
|
||||
use crate::aggregations::eval_aggregate;
|
||||
|
||||
#[test]
|
||||
fn test_group_value_none_input() {
|
||||
let timestamp = 1640995200;
|
||||
let eval_ctx = EvalContext::new(timestamp, timestamp + 1, 1, "test".to_string());
|
||||
let result = eval_aggregate(&None, Value::None, Group, &eval_ctx).unwrap();
|
||||
assert!(matches!(result, Value::None));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_group_invalid_input_returns_err() {
|
||||
let timestamp = 1640995200;
|
||||
let eval_ctx = EvalContext::new(timestamp, timestamp + 1, 1, "test".to_string());
|
||||
let result = eval_aggregate(&None, Value::Float(1.0), Group, &eval_ctx);
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_group_empty_matrix_returns_none() {
|
||||
let timestamp = 1640995200;
|
||||
let eval_ctx = EvalContext::new(timestamp, timestamp + 1, 1, "test".to_string());
|
||||
let result = eval_aggregate(&None, Value::Matrix(vec![]), Group, &eval_ctx).unwrap();
|
||||
assert!(matches!(result, Value::None));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_group_range_function() {
|
||||
let timestamp = 1640995200; // 2022-01-01 00:00:00 UTC
|
||||
|
||||
@@ -39,30 +39,6 @@ mod tests {
|
||||
use super::*;
|
||||
use crate::aggregations::eval_aggregate;
|
||||
|
||||
#[test]
|
||||
fn test_max_value_none_input() {
|
||||
let timestamp = 1640995200;
|
||||
let eval_ctx = EvalContext::new(timestamp, timestamp + 1, 1, "test".to_string());
|
||||
let result = eval_aggregate(&None, Value::None, Max, &eval_ctx).unwrap();
|
||||
assert!(matches!(result, Value::None));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_max_invalid_input_returns_err() {
|
||||
let timestamp = 1640995200;
|
||||
let eval_ctx = EvalContext::new(timestamp, timestamp + 1, 1, "test".to_string());
|
||||
let result = eval_aggregate(&None, Value::Float(1.0), Max, &eval_ctx);
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_max_empty_matrix_returns_none() {
|
||||
let timestamp = 1640995200;
|
||||
let eval_ctx = EvalContext::new(timestamp, timestamp + 1, 1, "test".to_string());
|
||||
let result = eval_aggregate(&None, Value::Matrix(vec![]), Max, &eval_ctx).unwrap();
|
||||
assert!(matches!(result, Value::None));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_max_range_function() {
|
||||
let timestamp = 1640995200; // 2022-01-01 00:00:00 UTC
|
||||
|
||||
@@ -39,30 +39,6 @@ mod tests {
|
||||
use super::*;
|
||||
use crate::aggregations::eval_aggregate;
|
||||
|
||||
#[test]
|
||||
fn test_min_value_none_input() {
|
||||
let timestamp = 1640995200;
|
||||
let eval_ctx = EvalContext::new(timestamp, timestamp + 1, 1, "test".to_string());
|
||||
let result = eval_aggregate(&None, Value::None, Min, &eval_ctx).unwrap();
|
||||
assert!(matches!(result, Value::None));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_min_invalid_input_returns_err() {
|
||||
let timestamp = 1640995200;
|
||||
let eval_ctx = EvalContext::new(timestamp, timestamp + 1, 1, "test".to_string());
|
||||
let result = eval_aggregate(&None, Value::Float(1.0), Min, &eval_ctx);
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_min_empty_matrix_returns_none() {
|
||||
let timestamp = 1640995200;
|
||||
let eval_ctx = EvalContext::new(timestamp, timestamp + 1, 1, "test".to_string());
|
||||
let result = eval_aggregate(&None, Value::Matrix(vec![]), Min, &eval_ctx).unwrap();
|
||||
assert!(matches!(result, Value::None));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_min_range_function() {
|
||||
let timestamp = 1640995200; // 2022-01-01 00:00:00 UTC
|
||||
|
||||
@@ -537,14 +537,6 @@ mod tests {
|
||||
use super::*;
|
||||
|
||||
// Test data helpers
|
||||
fn create_test_labels() -> Labels {
|
||||
vec![
|
||||
Arc::new(Label::new("instance", "localhost:9090")),
|
||||
Arc::new(Label::new("job", "prometheus")),
|
||||
Arc::new(Label::new("__name__", "http_requests_total")),
|
||||
]
|
||||
}
|
||||
|
||||
fn labels_to_include(
|
||||
include_labels: &[String],
|
||||
mut actual_labels: Vec<Arc<Label>>,
|
||||
@@ -562,19 +554,6 @@ mod tests {
|
||||
actual_labels
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_labels_to_include() {
|
||||
let actual_labels = create_test_labels();
|
||||
let include_labels = vec!["instance".to_string(), "job".to_string()];
|
||||
|
||||
let result = labels_to_include(&include_labels, actual_labels.clone());
|
||||
|
||||
assert_eq!(result.len(), 2);
|
||||
assert!(result.iter().any(|l| l.name == "instance"));
|
||||
assert!(result.iter().any(|l| l.name == "job"));
|
||||
assert!(!result.iter().any(|l| l.name == "__name__"));
|
||||
}
|
||||
|
||||
/// One value of a label-less series, for the scalar accumulators that never read labels.
|
||||
fn push<A: Accumulate>(acc: &mut A, slot: usize, value: f64) {
|
||||
acc.push_series(std::iter::once((slot, value)), Labels::default);
|
||||
@@ -986,34 +965,6 @@ mod tests {
|
||||
assert_eq!(eval_chunked_single_group(&values, Avg), -2.0 / n as f64);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_labels_to_exclude_removes_name_label() {
|
||||
let actual_labels = create_test_labels();
|
||||
let exclude_labels = vec!["instance".to_string()];
|
||||
|
||||
let result = labels_to_exclude(&exclude_labels, actual_labels.clone());
|
||||
|
||||
// Should not contain __name__ label (which is NAME_LABEL)
|
||||
assert!(!result.iter().any(|l| l.name == "__name__"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_labels_to_include_empty_include_list() {
|
||||
let actual_labels = create_test_labels();
|
||||
let result = labels_to_include(&[], actual_labels);
|
||||
assert_eq!(result.len(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_labels_to_exclude_empty_exclude_list() {
|
||||
let actual_labels = create_test_labels();
|
||||
let result = labels_to_exclude(&[], actual_labels);
|
||||
// NAME_LABEL (__name__) is always excluded
|
||||
assert!(!result.iter().any(|l| l.name == "__name__"));
|
||||
assert!(result.iter().any(|l| l.name == "instance"));
|
||||
assert!(result.iter().any(|l| l.name == "job"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_projected_labels_signature_matches_materialized_projection() {
|
||||
use promql_parser::label::Labels as ParserLabels;
|
||||
|
||||
@@ -246,22 +246,6 @@ mod tests {
|
||||
assert_eq!(result[1].samples[0].value, 30.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_quantile_value_none_input() {
|
||||
let timestamp = 1640995200;
|
||||
let eval_ctx = EvalContext::new(timestamp, timestamp + 1, 1, "test".to_string());
|
||||
let result = quantile(ScalarParam::Const(0.5), &None, Value::None, &eval_ctx).unwrap();
|
||||
assert!(matches!(result, Value::None));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_quantile_invalid_input_returns_err() {
|
||||
let timestamp = 1640995200;
|
||||
let eval_ctx = EvalContext::new(timestamp, timestamp + 1, 1, "test".to_string());
|
||||
let result = quantile(ScalarParam::Const(0.5), &None, Value::Float(1.0), &eval_ctx);
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_quantile_out_of_range_phi_is_per_group() {
|
||||
let ts = 1000;
|
||||
|
||||
@@ -44,30 +44,6 @@ mod tests {
|
||||
use super::*;
|
||||
use crate::aggregations::eval_aggregate;
|
||||
|
||||
#[test]
|
||||
fn test_stddev_value_none_input() {
|
||||
let timestamp = 1640995200;
|
||||
let eval_ctx = EvalContext::new(timestamp, timestamp + 1, 1, "test".to_string());
|
||||
let result = eval_aggregate(&None, Value::None, Stddev, &eval_ctx).unwrap();
|
||||
assert!(matches!(result, Value::None));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_stddev_invalid_input_returns_err() {
|
||||
let timestamp = 1640995200;
|
||||
let eval_ctx = EvalContext::new(timestamp, timestamp + 1, 1, "test".to_string());
|
||||
let result = eval_aggregate(&None, Value::Float(1.0), Stddev, &eval_ctx);
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_stddev_empty_matrix_returns_none() {
|
||||
let timestamp = 1640995200;
|
||||
let eval_ctx = EvalContext::new(timestamp, timestamp + 1, 1, "test".to_string());
|
||||
let result = eval_aggregate(&None, Value::Matrix(vec![]), Stddev, &eval_ctx).unwrap();
|
||||
assert!(matches!(result, Value::None));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_stddev_range_function() {
|
||||
let timestamp = 1640995200; // 2022-01-01 00:00:00 UTC
|
||||
|
||||
@@ -44,30 +44,6 @@ mod tests {
|
||||
use super::*;
|
||||
use crate::aggregations::eval_aggregate;
|
||||
|
||||
#[test]
|
||||
fn test_stdvar_value_none_input() {
|
||||
let timestamp = 1640995200;
|
||||
let eval_ctx = EvalContext::new(timestamp, timestamp + 1, 1, "test".to_string());
|
||||
let result = eval_aggregate(&None, Value::None, Stdvar, &eval_ctx).unwrap();
|
||||
assert!(matches!(result, Value::None));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_stdvar_invalid_input_returns_err() {
|
||||
let timestamp = 1640995200;
|
||||
let eval_ctx = EvalContext::new(timestamp, timestamp + 1, 1, "test".to_string());
|
||||
let result = eval_aggregate(&None, Value::Float(1.0), Stdvar, &eval_ctx);
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_stdvar_empty_matrix_returns_none() {
|
||||
let timestamp = 1640995200;
|
||||
let eval_ctx = EvalContext::new(timestamp, timestamp + 1, 1, "test".to_string());
|
||||
let result = eval_aggregate(&None, Value::Matrix(vec![]), Stdvar, &eval_ctx).unwrap();
|
||||
assert!(matches!(result, Value::None));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_stdvar_range_function() {
|
||||
let timestamp = 1640995200; // 2022-01-01 00:00:00 UTC
|
||||
|
||||
@@ -148,30 +148,6 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sum_value_none_input() {
|
||||
let ts = 1640995200;
|
||||
let eval_ctx = EvalContext::new(ts, ts + 1, 1, "test".to_string());
|
||||
let result = eval_aggregate(&None, Value::None, Sum, &eval_ctx).unwrap();
|
||||
assert!(matches!(result, Value::None));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sum_invalid_input_returns_err() {
|
||||
let ts = 1640995200;
|
||||
let eval_ctx = EvalContext::new(ts, ts + 1, 1, "test".to_string());
|
||||
let result = eval_aggregate(&None, Value::Float(1.0), Sum, &eval_ctx);
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sum_empty_matrix_returns_none() {
|
||||
let ts = 1640995200;
|
||||
let eval_ctx = EvalContext::new(ts, ts + 1, 1, "test".to_string());
|
||||
let result = eval_aggregate(&None, Value::Matrix(vec![]), Sum, &eval_ctx).unwrap();
|
||||
assert!(matches!(result, Value::None));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sum_range_function() {
|
||||
// Create test matrix data with multiple series and timestamps
|
||||
|
||||
@@ -85,12 +85,6 @@ mod tests {
|
||||
assert_eq!(visitor.name.len(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_name_visitor_new_starts_empty() {
|
||||
let visitor = MetricNameVisitor::new();
|
||||
assert!(visitor.name.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_name_visitor_resolves_name_label_matcher() {
|
||||
let promql = r#"sum(rate({__name__="http_requests_total"}[1m]))"#;
|
||||
|
||||
@@ -66,53 +66,6 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_match_placeholder_equal_op() {
|
||||
let placeholder = get_config().common.dashboard_placeholder.to_string();
|
||||
let matcher = create_test_matcher("label", MatchOp::Equal, &placeholder);
|
||||
assert!(match_placeholder(&matcher, &placeholder));
|
||||
|
||||
let non_matching_matcher = create_test_matcher("label", MatchOp::Equal, "other_value");
|
||||
assert!(!match_placeholder(&non_matching_matcher, &placeholder));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_match_placeholder_not_equal_op() {
|
||||
let placeholder = get_config().common.dashboard_placeholder.to_string();
|
||||
let matcher = create_test_matcher("label", MatchOp::NotEqual, &placeholder);
|
||||
assert!(match_placeholder(&matcher, &placeholder));
|
||||
|
||||
let non_matching_matcher = create_test_matcher("label", MatchOp::NotEqual, "other_value");
|
||||
assert!(!match_placeholder(&non_matching_matcher, &placeholder));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_match_placeholder_regex_op() {
|
||||
let placeholder = get_config().common.dashboard_placeholder.to_string();
|
||||
let matcher =
|
||||
create_test_matcher("label", MatchOp::Re(Regex::new("").unwrap()), &placeholder);
|
||||
assert!(match_placeholder(&matcher, &placeholder));
|
||||
|
||||
let non_matching_matcher =
|
||||
create_test_matcher("label", MatchOp::Re(Regex::new("").unwrap()), "other.*");
|
||||
assert!(!match_placeholder(&non_matching_matcher, &placeholder));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_match_placeholder_not_regex_op() {
|
||||
let placeholder = get_config().common.dashboard_placeholder.to_string();
|
||||
let matcher = create_test_matcher(
|
||||
"label",
|
||||
MatchOp::NotRe(Regex::new("").unwrap()),
|
||||
&placeholder,
|
||||
);
|
||||
assert!(match_placeholder(&matcher, &placeholder));
|
||||
|
||||
let non_matching_matcher =
|
||||
create_test_matcher("label", MatchOp::NotRe(Regex::new("").unwrap()), "other.*");
|
||||
assert!(!match_placeholder(&non_matching_matcher, &placeholder));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_remove_filter_all_removes_placeholder_matchers() {
|
||||
let placeholder = get_config().common.dashboard_placeholder.to_string();
|
||||
|
||||
@@ -89,12 +89,6 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_selector_visitor_empty() {
|
||||
let visitor = MetricSelectorVisitor::default();
|
||||
assert!(visitor.exprs.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_selector_visitor_non_selector_expr_not_collected() {
|
||||
// Scalar arithmetic has no VectorSelector or MatrixSelector
|
||||
|
||||
@@ -600,19 +600,10 @@ pub fn vector_bin_op(
|
||||
mod tests {
|
||||
use std::sync::Arc;
|
||||
|
||||
use config::meta::promql::value::{Label, Sample, signature};
|
||||
use config::meta::promql::value::{Label, Sample};
|
||||
|
||||
use super::*;
|
||||
|
||||
// Helper function to create test data for matrix operations
|
||||
fn create_test_matrix_data() -> Vec<RangeValue> {
|
||||
vec![
|
||||
create_test_range_value(vec![1.0], vec![("instance", "localhost"), ("job", "node")]),
|
||||
create_test_range_value(vec![2.0], vec![("instance", "localhost"), ("job", "node")]),
|
||||
create_test_range_value(vec![3.0], vec![("instance", "remote"), ("job", "api")]),
|
||||
]
|
||||
}
|
||||
|
||||
fn create_test_range_value(values: Vec<f64>, labels: Vec<(&str, &str)>) -> RangeValue {
|
||||
let labels = labels
|
||||
.into_iter()
|
||||
@@ -634,353 +625,6 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
// Simple tests that don't require complex BinaryExpr construction
|
||||
#[test]
|
||||
fn test_range_value_creation() {
|
||||
let range = create_test_range_value(vec![42.0], vec![("instance", "localhost")]);
|
||||
assert_eq!(range.samples[0].value, 42.0);
|
||||
assert_eq!(range.samples[0].timestamp, 1640995200000000i64);
|
||||
assert_eq!(range.labels.len(), 1);
|
||||
assert_eq!(range.labels[0].name, "instance");
|
||||
assert_eq!(range.labels[0].value, "localhost");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_range_value_with_multiple_labels() {
|
||||
let range = create_test_range_value(
|
||||
vec![100.0],
|
||||
vec![("env", "prod"), ("region", "us-west"), ("service", "api")],
|
||||
);
|
||||
assert_eq!(range.samples[0].value, 100.0);
|
||||
assert_eq!(range.labels.len(), 3);
|
||||
|
||||
let label_names: Vec<&str> = range.labels.iter().map(|l| l.name.as_str()).collect();
|
||||
assert!(label_names.contains(&"env"));
|
||||
assert!(label_names.contains(&"region"));
|
||||
assert!(label_names.contains(&"service"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_range_value_empty_labels() {
|
||||
let range = create_test_range_value(vec![0.0], vec![]);
|
||||
assert_eq!(range.samples[0].value, 0.0);
|
||||
assert!(range.labels.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_range_value_numeric_values() {
|
||||
let test_cases = [
|
||||
(0.0, "zero"),
|
||||
(1.0, "positive integer"),
|
||||
(-1.0, "negative integer"),
|
||||
(1.234, "positive float"),
|
||||
(-1.234, "negative float"),
|
||||
(f64::MAX, "max value"),
|
||||
(f64::MIN, "min value"),
|
||||
];
|
||||
|
||||
for (value, description) in test_cases {
|
||||
let range = create_test_range_value(vec![value], vec![("test", description)]);
|
||||
assert_eq!(range.samples[0].value, value, "Failed for: {description}");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_range_value_timestamp_consistency() {
|
||||
let range1 = create_test_range_value(vec![1.0], vec![("a", "1")]);
|
||||
let range2 = create_test_range_value(vec![2.0], vec![("b", "2")]);
|
||||
|
||||
// Both should have the same starting timestamp
|
||||
assert_eq!(range1.samples[0].timestamp, range2.samples[0].timestamp);
|
||||
assert_eq!(range1.samples[0].timestamp, 1640995200000000i64);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_label_creation() {
|
||||
let labels = vec![
|
||||
("cpu", "0"),
|
||||
("mode", "idle"),
|
||||
("instance", "localhost:9100"),
|
||||
];
|
||||
let range = create_test_range_value(vec![75.5], labels.clone());
|
||||
|
||||
for (i, (expected_name, expected_value)) in labels.iter().enumerate() {
|
||||
assert_eq!(range.labels[i].name, *expected_name);
|
||||
assert_eq!(range.labels[i].value, *expected_value);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_label_modification() {
|
||||
let mut labels = vec![
|
||||
Arc::new(Label::new("env", "prod")),
|
||||
Arc::new(Label::new("region", "us-west")),
|
||||
Arc::new(Label::new("service", "api")),
|
||||
];
|
||||
|
||||
// Test label modification
|
||||
labels[0] = Arc::new(Label::new("env", "staging"));
|
||||
assert_eq!(labels[0].value, "staging");
|
||||
|
||||
// Test label filtering (simulate what vector operations do)
|
||||
let filtered_labels: Vec<Arc<Label>> = labels
|
||||
.into_iter()
|
||||
.filter(|label| label.name != "env")
|
||||
.collect();
|
||||
|
||||
assert_eq!(filtered_labels.len(), 2);
|
||||
assert_eq!(filtered_labels[0].name, "region");
|
||||
assert_eq!(filtered_labels[1].name, "service");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_matrix_operations_parallel_processing() {
|
||||
// Test that we can process matrices in parallel (simulating what the actual functions do)
|
||||
let matrix = vec![
|
||||
create_test_range_value(vec![1.0], vec![("a", "1")]),
|
||||
create_test_range_value(vec![2.0], vec![("a", "2")]),
|
||||
create_test_range_value(vec![3.0], vec![("a", "3")]),
|
||||
create_test_range_value(vec![4.0], vec![("a", "4")]),
|
||||
create_test_range_value(vec![5.0], vec![("a", "5")]),
|
||||
];
|
||||
|
||||
// Simulate parallel processing by mapping over the matrix
|
||||
let processed: Vec<f64> = matrix
|
||||
.par_iter()
|
||||
.map(|range| range.samples[0].value * 2.0)
|
||||
.collect();
|
||||
|
||||
assert_eq!(processed.len(), 5);
|
||||
assert_eq!(processed[0], 2.0);
|
||||
assert_eq!(processed[1], 4.0);
|
||||
assert_eq!(processed[2], 6.0);
|
||||
assert_eq!(processed[3], 8.0);
|
||||
assert_eq!(processed[4], 10.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_matrix_operations_error_scenarios() {
|
||||
// Test scenarios that could lead to errors in matrix operations
|
||||
|
||||
// Test with very large numbers
|
||||
let large_matrix = [
|
||||
create_test_range_value(vec![f64::MAX], vec![("a", "1")]),
|
||||
create_test_range_value(vec![f64::MIN], vec![("a", "2")]),
|
||||
];
|
||||
|
||||
assert!(large_matrix[0].samples[0].value.is_finite());
|
||||
assert!(large_matrix[1].samples[0].value.is_finite());
|
||||
|
||||
// Test with NaN values
|
||||
let nan_matrix = [create_test_range_value(vec![f64::NAN], vec![("a", "1")])];
|
||||
|
||||
// Should handle NaN gracefully
|
||||
assert!(nan_matrix[0].samples[0].value.is_nan());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_matrix_operations_data_structures() {
|
||||
// Test RangeValue creation and properties
|
||||
let value =
|
||||
create_test_range_value(vec![42.0], vec![("label1", "value1"), ("label2", "value2")]);
|
||||
assert_eq!(value.samples[0].value, 42.0);
|
||||
assert_eq!(value.labels.len(), 2);
|
||||
assert_eq!(value.labels[0].name, "label1");
|
||||
assert_eq!(value.labels[0].value, "value1");
|
||||
assert_eq!(value.labels[1].name, "label2");
|
||||
assert_eq!(value.labels[1].value, "value2");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_matrix_operations_timestamp_consistency() {
|
||||
let timestamp = 1640995200000000i64;
|
||||
let value = create_test_range_value(vec![10.0], vec![("test", "value")]);
|
||||
assert_eq!(value.samples[0].timestamp, timestamp);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_matrix_operations_label_handling() {
|
||||
let value = create_test_range_value(vec![5.0], vec![("a", "1"), ("b", "2"), ("c", "3")]);
|
||||
assert_eq!(value.labels.len(), 3);
|
||||
|
||||
// Test label ordering and values
|
||||
let labels = &value.labels;
|
||||
assert_eq!(labels[0].name, "a");
|
||||
assert_eq!(labels[0].value, "1");
|
||||
assert_eq!(labels[1].name, "b");
|
||||
assert_eq!(labels[1].value, "2");
|
||||
assert_eq!(labels[2].name, "c");
|
||||
assert_eq!(labels[2].value, "3");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_matrix_operations_empty_labels() {
|
||||
let value = create_test_range_value(vec![0.0], vec![]);
|
||||
assert_eq!(value.labels.len(), 0);
|
||||
assert_eq!(value.samples[0].value, 0.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_matrix_operations_negative_values() {
|
||||
let value = create_test_range_value(vec![-15.5], vec![("negative", "test")]);
|
||||
assert_eq!(value.samples[0].value, -15.5);
|
||||
assert_eq!(value.labels.len(), 1);
|
||||
assert_eq!(value.labels[0].name, "negative");
|
||||
assert_eq!(value.labels[0].value, "test");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_matrix_operations_large_numbers() {
|
||||
let value = create_test_range_value(vec![1e15], vec![("large", "number")]);
|
||||
assert_eq!(value.samples[0].value, 1e15);
|
||||
assert_eq!(value.labels.len(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_matrix_operations_special_floats() {
|
||||
let value = create_test_range_value(vec![f64::INFINITY], vec![("inf", "test")]);
|
||||
assert!(value.samples[0].value.is_infinite());
|
||||
assert!(value.samples[0].value.is_sign_positive());
|
||||
|
||||
let value = create_test_range_value(vec![f64::NEG_INFINITY], vec![("neg_inf", "test")]);
|
||||
assert!(value.samples[0].value.is_infinite());
|
||||
assert!(value.samples[0].value.is_sign_negative());
|
||||
|
||||
let value = create_test_range_value(vec![f64::NAN], vec![("nan", "test")]);
|
||||
assert!(value.samples[0].value.is_nan());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_matrix_operations_unicode_labels() {
|
||||
let value = create_test_range_value(
|
||||
vec![1.0],
|
||||
vec![("🚀", "🚀"), ("测试", "测试"), ("🎉", "🎉")],
|
||||
);
|
||||
assert_eq!(value.labels.len(), 3);
|
||||
assert_eq!(value.labels[0].name, "🚀");
|
||||
assert_eq!(value.labels[0].value, "🚀");
|
||||
assert_eq!(value.labels[1].name, "测试");
|
||||
assert_eq!(value.labels[1].value, "测试");
|
||||
assert_eq!(value.labels[2].name, "🎉");
|
||||
assert_eq!(value.labels[2].value, "🎉");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_matrix_operations_long_labels() {
|
||||
let long_name = "a".repeat(1000);
|
||||
let long_value = "b".repeat(1000);
|
||||
let value = create_test_range_value(vec![1.0], vec![(&long_name, &long_value)]);
|
||||
assert_eq!(value.labels.len(), 1);
|
||||
assert_eq!(value.labels[0].name, long_name);
|
||||
assert_eq!(value.labels[0].value, long_value);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_matrix_operations_duplicate_labels() {
|
||||
let value = create_test_range_value(vec![1.0], vec![("a", "1"), ("a", "2"), ("a", "3")]);
|
||||
assert_eq!(value.labels.len(), 3);
|
||||
// All labels should be preserved even if names are duplicate
|
||||
assert_eq!(value.labels[0].name, "a");
|
||||
assert_eq!(value.labels[0].value, "1");
|
||||
assert_eq!(value.labels[1].name, "a");
|
||||
assert_eq!(value.labels[1].value, "2");
|
||||
assert_eq!(value.labels[2].name, "a");
|
||||
assert_eq!(value.labels[2].value, "3");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_matrix_operations_edge_case_values() {
|
||||
let value = create_test_range_value(vec![f64::EPSILON], vec![("epsilon", "test")]);
|
||||
assert_eq!(value.samples[0].value, f64::EPSILON);
|
||||
|
||||
let value =
|
||||
create_test_range_value(vec![f64::MIN_POSITIVE], vec![("min_positive", "test")]);
|
||||
assert_eq!(value.samples[0].value, f64::MIN_POSITIVE);
|
||||
|
||||
let value = create_test_range_value(vec![f64::MAX], vec![("max", "test")]);
|
||||
assert_eq!(value.samples[0].value, f64::MAX);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_matrix_operations_matrix_data() {
|
||||
let matrix_data = create_test_matrix_data();
|
||||
assert_eq!(matrix_data.len(), 3);
|
||||
|
||||
// Test first element
|
||||
assert_eq!(matrix_data[0].samples[0].value, 1.0);
|
||||
assert_eq!(matrix_data[0].labels.len(), 2);
|
||||
assert_eq!(matrix_data[0].labels[0].name, "instance");
|
||||
assert_eq!(matrix_data[0].labels[0].value, "localhost");
|
||||
|
||||
// Test second element
|
||||
assert_eq!(matrix_data[1].samples[0].value, 2.0);
|
||||
assert_eq!(matrix_data[1].labels.len(), 2);
|
||||
|
||||
// Test third element
|
||||
assert_eq!(matrix_data[2].samples[0].value, 3.0);
|
||||
assert_eq!(matrix_data[2].labels.len(), 2);
|
||||
assert_eq!(matrix_data[2].labels[0].name, "instance");
|
||||
assert_eq!(matrix_data[2].labels[0].value, "remote");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_matrix_operations_label_signatures() {
|
||||
let value1 = create_test_range_value(vec![1.0], vec![("a", "1"), ("b", "2")]);
|
||||
let value2 = create_test_range_value(vec![2.0], vec![("a", "1"), ("b", "2")]);
|
||||
let value3 = create_test_range_value(vec![3.0], vec![("a", "1"), ("b", "3")]);
|
||||
|
||||
// value1 and value2 should have the same signature (same labels)
|
||||
let sig1 = signature(&value1.labels);
|
||||
let sig2 = signature(&value2.labels);
|
||||
let sig3 = signature(&value3.labels);
|
||||
|
||||
assert_eq!(sig1, sig2);
|
||||
assert_ne!(sig1, sig3);
|
||||
assert_ne!(sig2, sig3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_matrix_operations_empty_matrix() {
|
||||
let empty_matrix: Vec<RangeValue> = vec![];
|
||||
assert_eq!(empty_matrix.len(), 0);
|
||||
|
||||
// Test that we can create an empty matrix and it doesn't panic
|
||||
let empty_matrix_with_capacity: Vec<RangeValue> = Vec::with_capacity(100);
|
||||
assert_eq!(empty_matrix_with_capacity.len(), 0);
|
||||
assert_eq!(empty_matrix_with_capacity.capacity(), 100);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_matrix_operations_single_element() {
|
||||
let single_element = [create_test_range_value(
|
||||
vec![42.0],
|
||||
vec![("single", "test")],
|
||||
)];
|
||||
assert_eq!(single_element.len(), 1);
|
||||
assert_eq!(single_element[0].samples[0].value, 42.0);
|
||||
assert_eq!(single_element[0].labels.len(), 1);
|
||||
assert_eq!(single_element[0].labels[0].name, "single");
|
||||
assert_eq!(single_element[0].labels[0].value, "test");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_matrix_operations_multiple_samples() {
|
||||
// Test RangeValue with multiple samples
|
||||
let value =
|
||||
create_test_range_value(vec![1.0, 2.0, 3.0, 4.0, 5.0], vec![("metric", "test")]);
|
||||
assert_eq!(value.samples.len(), 5);
|
||||
assert_eq!(value.samples[0].value, 1.0);
|
||||
assert_eq!(value.samples[1].value, 2.0);
|
||||
assert_eq!(value.samples[2].value, 3.0);
|
||||
assert_eq!(value.samples[3].value, 4.0);
|
||||
assert_eq!(value.samples[4].value, 5.0);
|
||||
|
||||
// Check timestamps are incrementing
|
||||
for i in 1..value.samples.len() {
|
||||
assert!(value.samples[i].timestamp > value.samples[i - 1].timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
fn try_eval_bin_op(
|
||||
query: &str,
|
||||
left: Vec<RangeValue>,
|
||||
|
||||
@@ -186,18 +186,6 @@ mod tests {
|
||||
assert_eq!(quantile(&infinite, 0.75), Some(f64::INFINITY));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_quantile() {
|
||||
let data = vec![4.0, 2.0, 1.0, 3.0, 5.0];
|
||||
let phi_quantile = 0.5;
|
||||
let result = quantile(&data, phi_quantile);
|
||||
let expected = 3.0;
|
||||
match result {
|
||||
Some(got) => assert_eq!(got, expected),
|
||||
None => panic!(),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_quantile_comprehensive() {
|
||||
// Test basic quartiles
|
||||
@@ -414,68 +402,6 @@ mod tests {
|
||||
assert_eq!(result, None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_calculate_trend() {
|
||||
// Test first iteration (index == 0)
|
||||
let result = calculate_trend(0, 0.1, 10.0, 12.0, 1.0);
|
||||
assert_eq!(result, 1.0);
|
||||
|
||||
// Test normal case
|
||||
let result = calculate_trend(1, 0.1, 10.0, 12.0, 1.0);
|
||||
// trend_factor * (current_smoothed - previous_smoothed) + (1.0 - trend_factor) *
|
||||
// previous_trend 0.1 * (12.0 - 10.0) + 0.9 * 1.0 = 0.2 + 0.9 = 1.1
|
||||
assert!((result - 1.1).abs() < 1e-10);
|
||||
|
||||
// Test with zero trend factor
|
||||
let result = calculate_trend(1, 0.0, 10.0, 12.0, 1.0);
|
||||
assert_eq!(result, 1.0);
|
||||
|
||||
// Test with one trend factor
|
||||
let result = calculate_trend(1, 1.0, 10.0, 12.0, 1.0);
|
||||
assert_eq!(result, 2.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_linear_regression() {
|
||||
// Test with constant y values
|
||||
let samples = vec![
|
||||
Sample::new(1000, 5.0),
|
||||
Sample::new(2000, 5.0),
|
||||
Sample::new(3000, 5.0),
|
||||
];
|
||||
let result = linear_regression(&samples, 0);
|
||||
assert!(result.is_some());
|
||||
let (slope, intercept) = result.unwrap();
|
||||
assert_eq!(slope, 0.0);
|
||||
assert_eq!(intercept, 5.0);
|
||||
|
||||
// Test with linear relationship
|
||||
let samples = vec![
|
||||
Sample::new(1000, 1.0),
|
||||
Sample::new(2000, 2.0),
|
||||
Sample::new(3000, 3.0),
|
||||
];
|
||||
let result = linear_regression(&samples, 0);
|
||||
assert!(result.is_some());
|
||||
let (slope, intercept) = result.unwrap();
|
||||
// Slope should be 1000.0 (y increases by 1 for each 0.001 increase in x)
|
||||
assert!((slope - 1000.0).abs() < 1e-6);
|
||||
assert!((intercept - 0.0).abs() < 1e-6);
|
||||
|
||||
// Test with infinite values
|
||||
let samples = vec![
|
||||
Sample::new(1000, f64::INFINITY),
|
||||
Sample::new(2000, f64::INFINITY),
|
||||
];
|
||||
let (slope, intercept) = linear_regression(&samples, 0).unwrap();
|
||||
assert!(slope.is_nan() && intercept.is_nan());
|
||||
|
||||
// Test with empty samples
|
||||
let samples: Vec<Sample> = vec![];
|
||||
let result = linear_regression(&samples, 0);
|
||||
assert!(result.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_kahan_sum_increment() {
|
||||
// Test basic increment
|
||||
|
||||
@@ -346,27 +346,6 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fused_agg_shape_ignores_the_parameter() {
|
||||
assert_eq!(
|
||||
shape("topk(3, rate(m[5m]))"),
|
||||
Some((
|
||||
"rate".to_string(),
|
||||
true,
|
||||
Some(Some(Duration::from_secs(300)))
|
||||
))
|
||||
);
|
||||
assert_eq!(
|
||||
shape("bottomk by(instance) (2, m{job=\"a\"} offset 1m)"),
|
||||
Some(("last_over_time".to_string(), false, Some(None)))
|
||||
);
|
||||
assert_eq!(
|
||||
shape("topk(scalar(m), m)"),
|
||||
Some(("last_over_time".to_string(), false, Some(None)))
|
||||
);
|
||||
assert_eq!(shape("topk(3, abs(m))"), None);
|
||||
}
|
||||
|
||||
/// `n` series `{instance="<i>", job="api"|"db"}` whose values differ at every step.
|
||||
fn requests(n: usize) -> String {
|
||||
(0..n)
|
||||
|
||||
@@ -803,161 +803,6 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_call_expr_first_arg() {
|
||||
let trace_id = "test_trace";
|
||||
let org_id = "test_org";
|
||||
let mut engine = Engine::new(
|
||||
trace_id,
|
||||
Arc::new(PromqlContext::new(
|
||||
create_test_query_ctx(trace_id, org_id, 30),
|
||||
SimpleMockProvider,
|
||||
vec![],
|
||||
)),
|
||||
create_test_eval_ctx(),
|
||||
);
|
||||
|
||||
let args = FunctionArgs {
|
||||
args: vec![Box::new(PromExpr::NumberLiteral(NumberLiteral {
|
||||
val: 42.0,
|
||||
}))],
|
||||
};
|
||||
let result = engine.call_expr_arg(&args, 0).await;
|
||||
assert!(result.is_ok());
|
||||
|
||||
if let Ok(Value::Float(val)) = result {
|
||||
assert_eq!(val, 42.0);
|
||||
} else {
|
||||
panic!("Expected Value::Float");
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_call_expr_second_arg() {
|
||||
let trace_id = "test_trace";
|
||||
let org_id = "test_org";
|
||||
let mut engine = Engine::new(
|
||||
trace_id,
|
||||
Arc::new(PromqlContext::new(
|
||||
create_test_query_ctx(trace_id, org_id, 30),
|
||||
SimpleMockProvider,
|
||||
vec![],
|
||||
)),
|
||||
create_test_eval_ctx(),
|
||||
);
|
||||
|
||||
let args = FunctionArgs {
|
||||
args: vec![
|
||||
Box::new(PromExpr::NumberLiteral(NumberLiteral { val: 10.0 })),
|
||||
Box::new(PromExpr::NumberLiteral(NumberLiteral { val: 42.0 })),
|
||||
],
|
||||
};
|
||||
let result = engine.call_expr_arg(&args, 1).await;
|
||||
assert!(result.is_ok());
|
||||
|
||||
if let Ok(Value::Float(val)) = result {
|
||||
assert_eq!(val, 42.0);
|
||||
} else {
|
||||
panic!("Expected Value::Float");
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_call_expr_third_arg() {
|
||||
let trace_id = "test_trace";
|
||||
let org_id = "test_org";
|
||||
let mut engine = Engine::new(
|
||||
trace_id,
|
||||
Arc::new(PromqlContext::new(
|
||||
create_test_query_ctx(trace_id, org_id, 30),
|
||||
SimpleMockProvider,
|
||||
vec![],
|
||||
)),
|
||||
create_test_eval_ctx(),
|
||||
);
|
||||
|
||||
let args = FunctionArgs {
|
||||
args: vec![
|
||||
Box::new(PromExpr::NumberLiteral(NumberLiteral { val: 10.0 })),
|
||||
Box::new(PromExpr::NumberLiteral(NumberLiteral { val: 20.0 })),
|
||||
Box::new(PromExpr::NumberLiteral(NumberLiteral { val: 42.0 })),
|
||||
],
|
||||
};
|
||||
let result = engine.call_expr_arg(&args, 2).await;
|
||||
assert!(result.is_ok());
|
||||
|
||||
if let Ok(Value::Float(val)) = result {
|
||||
assert_eq!(val, 42.0);
|
||||
} else {
|
||||
panic!("Expected Value::Float");
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_call_expr_fourth_arg() {
|
||||
let trace_id = "test_trace";
|
||||
let org_id = "test_org";
|
||||
let mut engine = Engine::new(
|
||||
trace_id,
|
||||
Arc::new(PromqlContext::new(
|
||||
create_test_query_ctx(trace_id, org_id, 30),
|
||||
SimpleMockProvider,
|
||||
vec![],
|
||||
)),
|
||||
create_test_eval_ctx(),
|
||||
);
|
||||
|
||||
let args = FunctionArgs {
|
||||
args: vec![
|
||||
Box::new(PromExpr::NumberLiteral(NumberLiteral { val: 10.0 })),
|
||||
Box::new(PromExpr::NumberLiteral(NumberLiteral { val: 20.0 })),
|
||||
Box::new(PromExpr::NumberLiteral(NumberLiteral { val: 30.0 })),
|
||||
Box::new(PromExpr::NumberLiteral(NumberLiteral { val: 42.0 })),
|
||||
],
|
||||
};
|
||||
let result = engine.call_expr_arg(&args, 3).await;
|
||||
assert!(result.is_ok());
|
||||
|
||||
if let Ok(Value::Float(val)) = result {
|
||||
assert_eq!(val, 42.0);
|
||||
} else {
|
||||
panic!("Expected Value::Float");
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_call_expr_fifth_arg() {
|
||||
let trace_id = "test_trace";
|
||||
let org_id = "test_org";
|
||||
let mut engine = Engine::new(
|
||||
trace_id,
|
||||
Arc::new(PromqlContext::new(
|
||||
create_test_query_ctx(trace_id, org_id, 30),
|
||||
SimpleMockProvider,
|
||||
vec![],
|
||||
)),
|
||||
create_test_eval_ctx(),
|
||||
);
|
||||
|
||||
let args = FunctionArgs {
|
||||
args: vec![
|
||||
Box::new(PromExpr::NumberLiteral(NumberLiteral { val: 10.0 })),
|
||||
Box::new(PromExpr::NumberLiteral(NumberLiteral { val: 20.0 })),
|
||||
Box::new(PromExpr::NumberLiteral(NumberLiteral { val: 30.0 })),
|
||||
Box::new(PromExpr::NumberLiteral(NumberLiteral { val: 40.0 })),
|
||||
Box::new(PromExpr::NumberLiteral(NumberLiteral { val: 42.0 })),
|
||||
],
|
||||
};
|
||||
let result = engine.call_expr_arg(&args, 4).await;
|
||||
assert!(result.is_ok());
|
||||
|
||||
if let Ok(Value::Float(val)) = result {
|
||||
assert_eq!(val, 42.0);
|
||||
} else {
|
||||
panic!("Expected Value::Float");
|
||||
}
|
||||
}
|
||||
|
||||
const SECOND: i64 = 1_000_000;
|
||||
const BASE: i64 = 1_640_995_200;
|
||||
|
||||
|
||||
@@ -226,11 +226,10 @@ pub(crate) mod tests {
|
||||
use std::{sync::Arc, time::Duration};
|
||||
|
||||
use promql_parser::{
|
||||
label::{MatchOp, Matchers},
|
||||
label::Matchers,
|
||||
parser::{
|
||||
AggregateExpr, BinaryExpr, Call, EvalStmt, Extension, Function, FunctionArgs,
|
||||
MatrixSelector, NumberLiteral, Offset, ParenExpr, StringLiteral, SubqueryExpr,
|
||||
UnaryExpr, VectorSelector, token, value::ValueType,
|
||||
AggregateExpr, BinaryExpr, EvalStmt, Extension, NumberLiteral, ParenExpr,
|
||||
StringLiteral, SubqueryExpr, UnaryExpr, token, value::ValueType,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -426,26 +425,6 @@ pub(crate) mod tests {
|
||||
TwoInstanceProvider(ctx, vec![])
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_engine_new() {
|
||||
// Test basic engine creation with a simple mock
|
||||
let trace_id = "test_trace";
|
||||
let org_id = "test_org";
|
||||
let engine = Engine::new(
|
||||
trace_id,
|
||||
Arc::new(PromqlContext::new(
|
||||
create_test_query_ctx(trace_id, org_id, 30),
|
||||
SimpleMockProvider,
|
||||
vec![],
|
||||
)),
|
||||
create_test_eval_ctx(),
|
||||
);
|
||||
|
||||
assert_eq!(engine.trace_id, trace_id.to_string());
|
||||
assert!(engine.label_selector.is_empty());
|
||||
assert!(engine.result_type.is_none());
|
||||
}
|
||||
|
||||
/// The guard must not fire on a query that merely LOOKS adjacent — `offset`
|
||||
/// is genuinely implemented and must keep working.
|
||||
#[tokio::test]
|
||||
@@ -475,31 +454,6 @@ pub(crate) mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_exec_expr_number_literal() {
|
||||
let trace_id = "test_trace";
|
||||
let org_id = "test_org";
|
||||
let mut engine = Engine::new(
|
||||
trace_id,
|
||||
Arc::new(PromqlContext::new(
|
||||
create_test_query_ctx(trace_id, org_id, 30),
|
||||
SimpleMockProvider,
|
||||
vec![],
|
||||
)),
|
||||
create_test_eval_ctx(),
|
||||
);
|
||||
|
||||
let expr = PromExpr::NumberLiteral(NumberLiteral { val: 42.0 });
|
||||
let result = engine.exec_expr(&expr).await;
|
||||
assert!(result.is_ok());
|
||||
|
||||
if let Ok(Value::Float(val)) = result {
|
||||
assert_eq!(val, 42.0);
|
||||
} else {
|
||||
panic!("Expected Value::Float");
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_exec_expr_string_literal() {
|
||||
let trace_id = "test_trace";
|
||||
@@ -626,39 +580,6 @@ pub(crate) mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_exec_expr_unary_vector() {
|
||||
let trace_id = "test_trace";
|
||||
let org_id = "test_org";
|
||||
let mut engine = Engine::new(
|
||||
trace_id,
|
||||
Arc::new(PromqlContext::new(
|
||||
create_test_query_ctx(trace_id, org_id, 30),
|
||||
SimpleMockProvider,
|
||||
vec![],
|
||||
)),
|
||||
create_test_eval_ctx(),
|
||||
);
|
||||
|
||||
let sample = Sample::new(1640995200000000i64, 42.0);
|
||||
let instant = InstantValue {
|
||||
labels: vec![Arc::new(Label::new("env", "prod"))],
|
||||
sample,
|
||||
};
|
||||
let _vector = Value::Vector(vec![instant]);
|
||||
let vector_expr = PromExpr::Extension(Extension {
|
||||
expr: Arc::new(TestExtension),
|
||||
});
|
||||
|
||||
let expr = PromExpr::Unary(UnaryExpr {
|
||||
expr: Box::new(vector_expr),
|
||||
});
|
||||
|
||||
let result = engine.exec_expr(&expr).await;
|
||||
// This will fail because Extension is not implemented, but we're testing the unary logic
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_exec_expr_binary_float_float() {
|
||||
let trace_id = "test_trace";
|
||||
@@ -897,38 +818,6 @@ pub(crate) mod tests {
|
||||
assert_eq!(series[0].samples[0].value, 1.0);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_exec_expr_binary_none_none() {
|
||||
let trace_id = "test_trace";
|
||||
let org_id = "test_org";
|
||||
let mut engine = Engine::new(
|
||||
trace_id,
|
||||
Arc::new(PromqlContext::new(
|
||||
create_test_query_ctx(trace_id, org_id, 30),
|
||||
SimpleMockProvider,
|
||||
vec![],
|
||||
)),
|
||||
create_test_eval_ctx(),
|
||||
);
|
||||
|
||||
let lhs = PromExpr::Extension(Extension {
|
||||
expr: Arc::new(TestExtension),
|
||||
});
|
||||
let rhs = PromExpr::Extension(Extension {
|
||||
expr: Arc::new(TestExtension),
|
||||
});
|
||||
let expr = PromExpr::Binary(BinaryExpr {
|
||||
lhs: Box::new(lhs),
|
||||
rhs: Box::new(rhs),
|
||||
op: create_test_token(),
|
||||
modifier: None,
|
||||
});
|
||||
|
||||
let result = engine.exec_expr(&expr).await;
|
||||
// This will fail because Extension is not implemented, but we're testing the binary logic
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_exec_expr_subquery() {
|
||||
let trace_id = "test_trace";
|
||||
@@ -963,108 +852,6 @@ pub(crate) mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_exec_expr_subquery_with_offset() {
|
||||
let trace_id = "test_trace";
|
||||
let org_id = "test_org";
|
||||
let mut engine = Engine::new(
|
||||
trace_id,
|
||||
Arc::new(PromqlContext::new(
|
||||
create_test_query_ctx(trace_id, org_id, 30),
|
||||
SimpleMockProvider,
|
||||
vec![],
|
||||
)),
|
||||
create_test_eval_ctx(),
|
||||
);
|
||||
|
||||
let expr = PromExpr::NumberLiteral(NumberLiteral { val: 42.0 });
|
||||
let offset = Some(Offset::Pos(Duration::from_secs(60)));
|
||||
let subquery_expr = PromExpr::Subquery(SubqueryExpr {
|
||||
expr: Box::new(expr),
|
||||
range: Duration::from_secs(300),
|
||||
offset,
|
||||
step: None,
|
||||
at: None,
|
||||
});
|
||||
|
||||
let result = engine.exec_expr(&subquery_expr).await;
|
||||
// Subquery with float input should fail because subquery expects matrix input
|
||||
assert!(result.is_err());
|
||||
assert!(
|
||||
result
|
||||
.unwrap_err()
|
||||
.to_string()
|
||||
.contains("Unsupported subquery")
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_exec_expr_subquery_vector() {
|
||||
let trace_id = "test_trace";
|
||||
let org_id = "test_org";
|
||||
let mut engine = Engine::new(
|
||||
trace_id,
|
||||
Arc::new(PromqlContext::new(
|
||||
create_test_query_ctx(trace_id, org_id, 30),
|
||||
SimpleMockProvider,
|
||||
vec![],
|
||||
)),
|
||||
create_test_eval_ctx(),
|
||||
);
|
||||
|
||||
let sample = Sample::new(1640995200000000i64, 42.0);
|
||||
let _instant = InstantValue {
|
||||
labels: vec![Arc::new(Label::new("env", "prod"))],
|
||||
sample,
|
||||
};
|
||||
let vector = PromExpr::Extension(Extension {
|
||||
expr: Arc::new(TestExtension),
|
||||
});
|
||||
|
||||
let subquery_expr = PromExpr::Subquery(SubqueryExpr {
|
||||
expr: Box::new(vector),
|
||||
range: Duration::from_secs(300),
|
||||
offset: None,
|
||||
step: None,
|
||||
at: None,
|
||||
});
|
||||
|
||||
let result = engine.exec_expr(&subquery_expr).await;
|
||||
// This will fail because Extension is not implemented, but we're testing the subquery logic
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_exec_expr_subquery_float() {
|
||||
let trace_id = "test_trace";
|
||||
let org_id = "test_org";
|
||||
let mut engine = Engine::new(
|
||||
trace_id,
|
||||
Arc::new(PromqlContext::new(
|
||||
create_test_query_ctx(trace_id, org_id, 30),
|
||||
SimpleMockProvider,
|
||||
vec![],
|
||||
)),
|
||||
create_test_eval_ctx(),
|
||||
);
|
||||
|
||||
let float_expr = PromExpr::Extension(Extension {
|
||||
expr: Arc::new(TestExtension),
|
||||
});
|
||||
|
||||
let subquery_expr = PromExpr::Subquery(SubqueryExpr {
|
||||
expr: Box::new(float_expr),
|
||||
range: Duration::from_secs(300),
|
||||
offset: None,
|
||||
step: None,
|
||||
at: None,
|
||||
});
|
||||
|
||||
let result = engine.exec_expr(&subquery_expr).await;
|
||||
// This will fail because Extension is not implemented, but we're testing the subquery logic
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_exec_expr_aggregate() {
|
||||
let trace_id = "test_trace";
|
||||
@@ -1093,34 +880,6 @@ pub(crate) mod tests {
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_exec_expr_call() {
|
||||
let trace_id = "test_trace";
|
||||
let org_id = "test_org";
|
||||
let mut engine = Engine::new(
|
||||
trace_id,
|
||||
Arc::new(PromqlContext::new(
|
||||
create_test_query_ctx(trace_id, org_id, 30),
|
||||
SimpleMockProvider,
|
||||
vec![],
|
||||
)),
|
||||
create_test_eval_ctx(),
|
||||
);
|
||||
|
||||
let args = FunctionArgs { args: vec![] };
|
||||
let func = Function {
|
||||
name: "time",
|
||||
arg_types: vec![],
|
||||
variadic: 0,
|
||||
experimental: false,
|
||||
return_type: ValueType::Scalar,
|
||||
};
|
||||
let expr = PromExpr::Call(Call { func, args });
|
||||
|
||||
let result = engine.exec_expr(&expr).await;
|
||||
assert!(result.is_ok());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_exec_expr_extension() {
|
||||
let trace_id = "test_trace";
|
||||
@@ -1149,87 +908,6 @@ pub(crate) mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_exec_expr_vector_selector() {
|
||||
let trace_id = "test_trace";
|
||||
let org_id = "test_org";
|
||||
let mut engine = Engine::new(
|
||||
trace_id,
|
||||
Arc::new(PromqlContext::new(
|
||||
create_test_query_ctx(trace_id, org_id, 30),
|
||||
SimpleMockProvider,
|
||||
vec![],
|
||||
)),
|
||||
create_test_eval_ctx(),
|
||||
);
|
||||
|
||||
let matchers = Matchers {
|
||||
matchers: vec![promql_parser::label::Matcher {
|
||||
name: "env".to_string(),
|
||||
op: MatchOp::Equal,
|
||||
value: "prod".to_string(),
|
||||
}],
|
||||
or_matchers: vec![],
|
||||
};
|
||||
|
||||
let selector = VectorSelector {
|
||||
name: Some("test_metric".to_string()),
|
||||
matchers,
|
||||
offset: None,
|
||||
at: None,
|
||||
};
|
||||
|
||||
let expr = PromExpr::VectorSelector(selector);
|
||||
|
||||
let result = engine.exec_expr(&expr).await;
|
||||
// This will fail because the mock provider doesn't have real data, but we're testing the
|
||||
// vector selector logic
|
||||
assert!(result.is_ok());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_exec_expr_matrix_selector() {
|
||||
let trace_id = "test_trace";
|
||||
let org_id = "test_org";
|
||||
let mut engine = Engine::new(
|
||||
trace_id,
|
||||
Arc::new(PromqlContext::new(
|
||||
create_test_query_ctx(trace_id, org_id, 30),
|
||||
SimpleMockProvider,
|
||||
vec![],
|
||||
)),
|
||||
create_test_eval_ctx(),
|
||||
);
|
||||
|
||||
let matchers = Matchers {
|
||||
matchers: vec![promql_parser::label::Matcher {
|
||||
name: "env".to_string(),
|
||||
op: MatchOp::Equal,
|
||||
value: "prod".to_string(),
|
||||
}],
|
||||
or_matchers: vec![],
|
||||
};
|
||||
|
||||
let selector = VectorSelector {
|
||||
name: Some("test_metric".to_string()),
|
||||
matchers,
|
||||
offset: None,
|
||||
at: None,
|
||||
};
|
||||
|
||||
let matrix_selector = MatrixSelector {
|
||||
vs: selector,
|
||||
range: Duration::from_secs(300),
|
||||
};
|
||||
|
||||
let expr = PromExpr::MatrixSelector(matrix_selector);
|
||||
|
||||
let result = engine.exec_expr(&expr).await;
|
||||
// This will fail because the mock provider doesn't have real data, but we're testing the
|
||||
// matrix selector logic
|
||||
assert!(result.is_ok());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_exec() {
|
||||
let trace_id = "test_trace";
|
||||
|
||||
@@ -682,7 +682,7 @@ mod tests {
|
||||
use datafusion::{arrow::datatypes::Schema, prelude::SessionContext};
|
||||
use promql_parser::{
|
||||
label::{MatchOp, Matchers},
|
||||
parser::{Offset, VectorSelector},
|
||||
parser::VectorSelector,
|
||||
};
|
||||
|
||||
use super::*;
|
||||
@@ -775,158 +775,6 @@ mod tests {
|
||||
assert_eq!(matchers.matchers[0].name, "env");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_eval_vector_selector_basic() {
|
||||
let trace_id = "test_trace";
|
||||
let org_id = "test_org";
|
||||
let mut engine = Engine::new(
|
||||
trace_id,
|
||||
Arc::new(PromqlContext::new(
|
||||
create_test_query_ctx(trace_id, org_id, 30),
|
||||
SimpleMockProvider,
|
||||
vec![],
|
||||
)),
|
||||
create_test_eval_ctx(),
|
||||
);
|
||||
|
||||
let matchers = Matchers {
|
||||
matchers: vec![promql_parser::label::Matcher {
|
||||
name: "env".to_string(),
|
||||
op: MatchOp::Equal,
|
||||
value: "prod".to_string(),
|
||||
}],
|
||||
or_matchers: vec![],
|
||||
};
|
||||
|
||||
let selector = VectorSelector {
|
||||
name: Some("test_metric".to_string()),
|
||||
matchers,
|
||||
offset: None,
|
||||
at: None,
|
||||
};
|
||||
|
||||
let result = engine
|
||||
.eval_vector_selector(&selector, None, SelectorOutput::Value)
|
||||
.await;
|
||||
assert!(result.is_ok());
|
||||
let values = result.unwrap();
|
||||
assert_eq!(values.len(), 0); // Mock provider returns empty data
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_eval_vector_selector_with_offset() {
|
||||
let trace_id = "test_trace";
|
||||
let org_id = "test_org";
|
||||
let mut engine = Engine::new(
|
||||
trace_id,
|
||||
Arc::new(PromqlContext::new(
|
||||
create_test_query_ctx(trace_id, org_id, 30),
|
||||
SimpleMockProvider,
|
||||
vec![],
|
||||
)),
|
||||
create_test_eval_ctx(),
|
||||
);
|
||||
|
||||
let matchers = Matchers {
|
||||
matchers: vec![promql_parser::label::Matcher {
|
||||
name: "env".to_string(),
|
||||
op: MatchOp::Equal,
|
||||
value: "prod".to_string(),
|
||||
}],
|
||||
or_matchers: vec![],
|
||||
};
|
||||
|
||||
let selector = VectorSelector {
|
||||
name: Some("test_metric".to_string()),
|
||||
matchers,
|
||||
offset: Some(Offset::Pos(Duration::from_secs(60))),
|
||||
at: None,
|
||||
};
|
||||
|
||||
let result = engine
|
||||
.eval_vector_selector(&selector, None, SelectorOutput::Value)
|
||||
.await;
|
||||
assert!(result.is_ok());
|
||||
let values = result.unwrap();
|
||||
assert_eq!(values.len(), 0); // Mock provider returns empty data
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_eval_vector_selector_with_negative_offset() {
|
||||
let trace_id = "test_trace";
|
||||
let org_id = "test_org";
|
||||
let mut engine = Engine::new(
|
||||
trace_id,
|
||||
Arc::new(PromqlContext::new(
|
||||
create_test_query_ctx(trace_id, org_id, 30),
|
||||
SimpleMockProvider,
|
||||
vec![],
|
||||
)),
|
||||
create_test_eval_ctx(),
|
||||
);
|
||||
|
||||
let matchers = Matchers {
|
||||
matchers: vec![promql_parser::label::Matcher {
|
||||
name: "env".to_string(),
|
||||
op: MatchOp::Equal,
|
||||
value: "prod".to_string(),
|
||||
}],
|
||||
or_matchers: vec![],
|
||||
};
|
||||
|
||||
let selector = VectorSelector {
|
||||
name: Some("test_metric".to_string()),
|
||||
matchers,
|
||||
offset: Some(Offset::Neg(Duration::from_secs(60))),
|
||||
at: None,
|
||||
};
|
||||
|
||||
let result = engine
|
||||
.eval_vector_selector(&selector, None, SelectorOutput::Value)
|
||||
.await;
|
||||
assert!(result.is_ok());
|
||||
let values = result.unwrap();
|
||||
assert_eq!(values.len(), 0); // Mock provider returns empty data
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_eval_matrix_selector_basic() {
|
||||
let trace_id = "test_trace";
|
||||
let org_id = "test_org";
|
||||
let mut engine = Engine::new(
|
||||
trace_id,
|
||||
Arc::new(PromqlContext::new(
|
||||
create_test_query_ctx(trace_id, org_id, 30),
|
||||
SimpleMockProvider,
|
||||
vec![],
|
||||
)),
|
||||
create_test_eval_ctx(),
|
||||
);
|
||||
|
||||
let matchers = Matchers {
|
||||
matchers: vec![promql_parser::label::Matcher {
|
||||
name: "env".to_string(),
|
||||
op: MatchOp::Equal,
|
||||
value: "prod".to_string(),
|
||||
}],
|
||||
or_matchers: vec![],
|
||||
};
|
||||
|
||||
let selector = VectorSelector {
|
||||
name: Some("test_metric".to_string()),
|
||||
matchers,
|
||||
offset: None,
|
||||
at: None,
|
||||
};
|
||||
|
||||
let result = engine
|
||||
.eval_matrix_selector(&selector, Duration::from_secs(300), None)
|
||||
.await;
|
||||
assert!(result.is_ok());
|
||||
let values = result.unwrap();
|
||||
assert_eq!(values.len(), 0); // Mock provider returns empty data
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_eval_vector_selector_without_a_metric_name_is_an_error() {
|
||||
let trace_id = "test_trace";
|
||||
@@ -1013,44 +861,6 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_eval_matrix_selector_with_offset() {
|
||||
let trace_id = "test_trace";
|
||||
let org_id = "test_org";
|
||||
let mut engine = Engine::new(
|
||||
trace_id,
|
||||
Arc::new(PromqlContext::new(
|
||||
create_test_query_ctx(trace_id, org_id, 30),
|
||||
SimpleMockProvider,
|
||||
vec![],
|
||||
)),
|
||||
create_test_eval_ctx(),
|
||||
);
|
||||
|
||||
let matchers = Matchers {
|
||||
matchers: vec![promql_parser::label::Matcher {
|
||||
name: "env".to_string(),
|
||||
op: MatchOp::Equal,
|
||||
value: "prod".to_string(),
|
||||
}],
|
||||
or_matchers: vec![],
|
||||
};
|
||||
|
||||
let selector = VectorSelector {
|
||||
name: Some("test_metric".to_string()),
|
||||
matchers,
|
||||
offset: Some(Offset::Pos(Duration::from_secs(120))),
|
||||
at: None,
|
||||
};
|
||||
|
||||
let result = engine
|
||||
.eval_matrix_selector(&selector, Duration::from_secs(300), None)
|
||||
.await;
|
||||
assert!(result.is_ok());
|
||||
let values = result.unwrap();
|
||||
assert_eq!(values.len(), 0); // Mock provider returns empty data
|
||||
}
|
||||
|
||||
/// Serves one series that carries only an exemplar, as the exemplar loader produces.
|
||||
struct ExemplarProvider;
|
||||
|
||||
|
||||
@@ -74,24 +74,6 @@ mod tests {
|
||||
avg_over_time(data, &eval_ctx)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_avg_over_time_value_none_input() {
|
||||
let result = avg_over_time_test_helper(Value::None).unwrap();
|
||||
assert!(matches!(result, Value::None));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_avg_over_time_invalid_input_returns_err() {
|
||||
let result = avg_over_time_test_helper(Value::Float(1.0));
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_avg_over_time_exec_empty_samples_returns_none() {
|
||||
let func = AvgOverTimeFunc;
|
||||
assert!(func.exec(&[], 0, &Duration::ZERO).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_avg_over_time_function() {
|
||||
// Create a range value with sample data
|
||||
|
||||
@@ -57,18 +57,6 @@ mod tests {
|
||||
changes(data, &eval_ctx)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_changes_value_none_input() {
|
||||
let result = changes_test_helper(Value::None).unwrap();
|
||||
assert!(matches!(result, Value::None));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_changes_invalid_input_returns_err() {
|
||||
let result = changes_test_helper(Value::Float(1.0));
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_changes_no_changes() {
|
||||
let func = ChangesFunc;
|
||||
|
||||
@@ -52,24 +52,6 @@ mod tests {
|
||||
count_over_time(data, &eval_ctx)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_count_over_time_value_none_input() {
|
||||
let result = count_over_time_test_helper(Value::None).unwrap();
|
||||
assert!(matches!(result, Value::None));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_count_over_time_invalid_input_returns_err() {
|
||||
let result = count_over_time_test_helper(Value::Float(1.0));
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_count_over_time_exec_empty_samples_returns_none() {
|
||||
let func = CountOverTimeFunc;
|
||||
assert!(func.exec(&[], 0, &Duration::ZERO).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_count_over_time_function() {
|
||||
// Create a range value with sample data
|
||||
|
||||
@@ -54,18 +54,6 @@ mod tests {
|
||||
deriv(data, &eval_ctx)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_deriv_value_none_input() {
|
||||
let result = deriv_test_helper(Value::None).unwrap();
|
||||
assert!(matches!(result, Value::None));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_deriv_invalid_input_returns_err() {
|
||||
let result = deriv_test_helper(Value::Float(1.0));
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_deriv_exec_fewer_than_two_samples_returns_none() {
|
||||
let func = DerivFunc;
|
||||
|
||||
@@ -44,17 +44,6 @@ impl RangeFunc for ExtrapolationKind {
|
||||
mod rate_tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_rate_name() {
|
||||
assert_eq!(ExtrapolationKind::Rate.name(), "rate");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rate_empty_samples() {
|
||||
let func = ExtrapolationKind::Rate;
|
||||
assert!(func.exec(&[], 0, &Duration::from_secs(60)).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rate_single_sample() {
|
||||
let func = ExtrapolationKind::Rate;
|
||||
@@ -107,18 +96,6 @@ mod increase_tests {
|
||||
increase(data, &eval_ctx)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_increase_value_none_input() {
|
||||
let result = increase_test_helper(Value::None).unwrap();
|
||||
assert!(matches!(result, Value::None));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_increase_invalid_input_returns_err() {
|
||||
let result = increase_test_helper(Value::Float(1.0));
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_increase_function() {
|
||||
// Create a range value with increasing counter values
|
||||
@@ -218,12 +195,6 @@ mod delta_tests {
|
||||
_ => panic!("Expected Matrix result"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_delta_function_name() {
|
||||
let func = ExtrapolationKind::Delta;
|
||||
assert_eq!(func.name(), "delta");
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -118,18 +118,6 @@ mod tests {
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_holt_winters_value_none_input() {
|
||||
let result = holt_winters_test_helper(Value::None, 0.5, 0.3).unwrap();
|
||||
assert!(matches!(result, Value::None));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_holt_winters_invalid_input_returns_err() {
|
||||
let result = holt_winters_test_helper(Value::Float(1.0), 0.5, 0.3);
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_holt_winters_calculation_fewer_than_two_samples() {
|
||||
assert!(holt_winters_calculation(&[], 0.5, 0.3).is_none());
|
||||
|
||||
@@ -52,18 +52,6 @@ mod tests {
|
||||
idelta(data, &eval_ctx)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_idelta_value_none_input() {
|
||||
let result = idelta_test_helper(Value::None).unwrap();
|
||||
assert!(matches!(result, Value::None));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_idelta_invalid_input_returns_err() {
|
||||
let result = idelta_test_helper(Value::Float(1.0));
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_idelta_exec_fewer_than_two_samples_returns_none() {
|
||||
let func = IdeltaFunc;
|
||||
|
||||
@@ -62,18 +62,6 @@ mod tests {
|
||||
irate(data, &eval_ctx)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_irate_value_none_input() {
|
||||
let result = irate_test_helper(Value::None).unwrap();
|
||||
assert!(matches!(result, Value::None));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_irate_invalid_input_returns_err() {
|
||||
let result = irate_test_helper(Value::Float(1.0));
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_irate_function() {
|
||||
// Create a range value with increasing counter values
|
||||
|
||||
@@ -180,58 +180,4 @@ mod tests {
|
||||
let result = label_join(Value::Float(1.0), "dst", "-", vec![]);
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_label_join_function() {
|
||||
use config::meta::promql::value::{RangeValue, Sample};
|
||||
|
||||
let eval_ts = 1000;
|
||||
|
||||
// Create range values with labels
|
||||
let labels1 = vec![
|
||||
Arc::new(Label::new("instance", "server1")),
|
||||
Arc::new(Label::new("job", "web")),
|
||||
];
|
||||
|
||||
let range_value1 = RangeValue {
|
||||
labels: labels1,
|
||||
samples: vec![Sample::new(eval_ts, 42.0)],
|
||||
exemplars: None,
|
||||
time_window: None,
|
||||
};
|
||||
|
||||
let labels2 = vec![
|
||||
Arc::new(Label::new("instance", "server2")),
|
||||
Arc::new(Label::new("job", "web")),
|
||||
];
|
||||
|
||||
let range_value2 = RangeValue {
|
||||
labels: labels2,
|
||||
samples: vec![Sample::new(eval_ts, 43.0)],
|
||||
exemplars: None,
|
||||
time_window: None,
|
||||
};
|
||||
|
||||
let matrix = Value::Matrix(vec![range_value1, range_value2]);
|
||||
let source_labels = vec!["instance".to_string(), "job".to_string()];
|
||||
let result = label_join(matrix, "combined", "-", source_labels).unwrap();
|
||||
|
||||
// Should return a matrix with joined labels
|
||||
match result {
|
||||
Value::Matrix(m) => {
|
||||
assert_eq!(m.len(), 2);
|
||||
// Check that the combined label was added
|
||||
let combined_label1 = m[0].labels.iter().find(|l| l.name == "combined");
|
||||
let combined_label2 = m[1].labels.iter().find(|l| l.name == "combined");
|
||||
assert!(combined_label1.is_some());
|
||||
assert!(combined_label2.is_some());
|
||||
assert_eq!(combined_label1.unwrap().value, "server1-web");
|
||||
assert_eq!(combined_label2.unwrap().value, "server2-web");
|
||||
// Verify samples are preserved
|
||||
assert_eq!(m[0].samples[0].value, 42.0);
|
||||
assert_eq!(m[1].samples[0].value, 43.0);
|
||||
}
|
||||
_ => panic!("Expected Matrix result"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -253,116 +253,4 @@ mod tests {
|
||||
let result = label_replace(Value::Float(1.0), "dst", "$1", "src", ".*");
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_label_replace_function() {
|
||||
use config::meta::promql::value::{RangeValue, Sample};
|
||||
|
||||
let eval_ts = 1000;
|
||||
|
||||
// Create range values with labels
|
||||
let labels = vec![
|
||||
Arc::new(Label::new("instance", "server-123.example.com")),
|
||||
Arc::new(Label::new("job", "web")),
|
||||
];
|
||||
|
||||
let range_value = RangeValue {
|
||||
labels,
|
||||
samples: vec![Sample::new(eval_ts, 42.0)],
|
||||
exemplars: None,
|
||||
time_window: None,
|
||||
};
|
||||
|
||||
let matrix = Value::Matrix(vec![range_value]);
|
||||
let result = label_replace(
|
||||
matrix,
|
||||
"hostname",
|
||||
"$1",
|
||||
"instance",
|
||||
r"server-(\d+)\.example\.com",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// Should return a matrix with replaced label
|
||||
match result {
|
||||
Value::Matrix(m) => {
|
||||
assert_eq!(m.len(), 1);
|
||||
// Check that the hostname label was added
|
||||
let hostname_label = m[0].labels.iter().find(|l| l.name == "hostname");
|
||||
assert!(hostname_label.is_some());
|
||||
assert_eq!(hostname_label.unwrap().value, "123");
|
||||
// Verify samples are preserved
|
||||
assert_eq!(m[0].samples[0].value, 42.0);
|
||||
}
|
||||
_ => panic!("Expected Matrix result"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_label_replace_empty_replacement_removes_dest_label() {
|
||||
use config::meta::promql::value::{RangeValue, Sample};
|
||||
|
||||
let labels = vec![
|
||||
Arc::new(Label::new("dst", "old_value")),
|
||||
Arc::new(Label::new("src", "source_val")),
|
||||
];
|
||||
let range_value = RangeValue {
|
||||
labels,
|
||||
samples: vec![Sample::new(1000, 1.0)],
|
||||
exemplars: None,
|
||||
time_window: None,
|
||||
};
|
||||
let matrix = Value::Matrix(vec![range_value]);
|
||||
let result = label_replace(matrix, "dst", "", "src", ".*").unwrap();
|
||||
|
||||
match result {
|
||||
Value::Matrix(m) => {
|
||||
assert_eq!(m.len(), 1);
|
||||
// Empty replacement removes dst label
|
||||
assert!(m[0].labels.iter().all(|l| l.name != "dst"));
|
||||
}
|
||||
_ => panic!("Expected Matrix result"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_label_replace_no_regex_match_leaves_labels_unchanged() {
|
||||
use config::meta::promql::value::{RangeValue, Sample};
|
||||
|
||||
let labels = vec![Arc::new(Label::new("instance", "prod-server"))];
|
||||
let range_value = RangeValue {
|
||||
labels,
|
||||
samples: vec![Sample::new(1000, 1.0)],
|
||||
exemplars: None,
|
||||
time_window: None,
|
||||
};
|
||||
let matrix = Value::Matrix(vec![range_value]);
|
||||
// Regex won't match "prod-server"
|
||||
let result = label_replace(matrix, "hostname", "$1", "instance", r"(\d+)").unwrap();
|
||||
|
||||
match result {
|
||||
Value::Matrix(m) => {
|
||||
assert_eq!(m.len(), 1);
|
||||
// hostname label NOT added since regex didn't match
|
||||
assert!(m[0].labels.iter().all(|l| l.name != "hostname"));
|
||||
// instance label preserved
|
||||
assert!(m[0].labels.iter().any(|l| l.name == "instance"));
|
||||
}
|
||||
_ => panic!("Expected Matrix result"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_label_replace_invalid_dest_label_returns_err() {
|
||||
let matrix = Value::Matrix(vec![]);
|
||||
let result = label_replace(matrix, "123invalid", "$1", "src", ".*");
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_label_replace_invalid_regex_returns_err() {
|
||||
let matrix = Value::Matrix(vec![]);
|
||||
let result = label_replace(matrix, "dst", "$1", "src", "[invalid");
|
||||
assert!(result.is_err());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,24 +75,6 @@ mod tests {
|
||||
last_over_time(data, &eval_ctx)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_last_over_time_value_none_input() {
|
||||
let result = last_over_time_test_helper(Value::None).unwrap();
|
||||
assert!(matches!(result, Value::None));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_last_over_time_invalid_input_returns_err() {
|
||||
let result = last_over_time_test_helper(Value::Float(1.0));
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_last_over_time_exec_empty_samples_returns_none() {
|
||||
let func = LastOverTimeFunc;
|
||||
assert!(func.exec(&[], 0, &Duration::ZERO).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_last_over_time_function() {
|
||||
// Create a range value with sample data
|
||||
|
||||
@@ -223,161 +223,6 @@ mod tests {
|
||||
assert_eq!(apply(sgn, -5.0), -1.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_abs() {
|
||||
let eval_ts = 1000;
|
||||
let value = create_matrix(eval_ts, vec![-5.0, 3.0]);
|
||||
let result = abs(value).unwrap();
|
||||
|
||||
if let Value::Matrix(result_matrix) = result {
|
||||
assert_eq!(result_matrix.len(), 2);
|
||||
assert_eq!(result_matrix[0].samples[0].value, 5.0);
|
||||
assert_eq!(result_matrix[1].samples[0].value, 3.0);
|
||||
} else {
|
||||
panic!("Expected Matrix result");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ceil() {
|
||||
let eval_ts = 1000;
|
||||
let value = create_matrix(eval_ts, vec![3.2, -3.2]);
|
||||
let result = ceil(value).unwrap();
|
||||
|
||||
if let Value::Matrix(result_matrix) = result {
|
||||
assert_eq!(result_matrix.len(), 2);
|
||||
assert_eq!(result_matrix[0].samples[0].value, 4.0);
|
||||
assert_eq!(result_matrix[1].samples[0].value, -3.0);
|
||||
} else {
|
||||
panic!("Expected Matrix result");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_floor() {
|
||||
let eval_ts = 1000;
|
||||
let value = create_matrix(eval_ts, vec![3.2, -3.2]);
|
||||
let result = floor(value).unwrap();
|
||||
|
||||
if let Value::Matrix(result_matrix) = result {
|
||||
assert_eq!(result_matrix.len(), 2);
|
||||
assert_eq!(result_matrix[0].samples[0].value, 3.0);
|
||||
assert_eq!(result_matrix[1].samples[0].value, -4.0);
|
||||
} else {
|
||||
panic!("Expected Matrix result");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_exp() {
|
||||
let eval_ts = 1000;
|
||||
let value = create_matrix(eval_ts, vec![0.0, 1.0]);
|
||||
let result = exp(value).unwrap();
|
||||
|
||||
if let Value::Matrix(result_matrix) = result {
|
||||
assert_eq!(result_matrix.len(), 2);
|
||||
assert_eq!(result_matrix[0].samples[0].value, 1.0);
|
||||
assert_eq!(result_matrix[1].samples[0].value, std::f64::consts::E);
|
||||
} else {
|
||||
panic!("Expected Matrix result");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ln() {
|
||||
let eval_ts = 1000;
|
||||
let value = create_matrix(eval_ts, vec![1.0, std::f64::consts::E]);
|
||||
let result = ln(value).unwrap();
|
||||
|
||||
if let Value::Matrix(result_matrix) = result {
|
||||
assert_eq!(result_matrix.len(), 2);
|
||||
assert_eq!(result_matrix[0].samples[0].value, 0.0);
|
||||
assert_eq!(result_matrix[1].samples[0].value, 1.0);
|
||||
} else {
|
||||
panic!("Expected Matrix result");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_log2() {
|
||||
let eval_ts = 1000;
|
||||
let value = create_matrix(eval_ts, vec![1.0, 2.0, 4.0]);
|
||||
let result = log2(value).unwrap();
|
||||
|
||||
if let Value::Matrix(result_matrix) = result {
|
||||
assert_eq!(result_matrix.len(), 3);
|
||||
assert_eq!(result_matrix[0].samples[0].value, 0.0);
|
||||
assert_eq!(result_matrix[1].samples[0].value, 1.0);
|
||||
assert_eq!(result_matrix[2].samples[0].value, 2.0);
|
||||
} else {
|
||||
panic!("Expected Matrix result");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_log10() {
|
||||
let eval_ts = 1000;
|
||||
let value = create_matrix(eval_ts, vec![1.0, 10.0, 100.0]);
|
||||
let result = log10(value).unwrap();
|
||||
|
||||
if let Value::Matrix(result_matrix) = result {
|
||||
assert_eq!(result_matrix.len(), 3);
|
||||
assert_eq!(result_matrix[0].samples[0].value, 0.0);
|
||||
assert_eq!(result_matrix[1].samples[0].value, 1.0);
|
||||
assert_eq!(result_matrix[2].samples[0].value, 2.0);
|
||||
} else {
|
||||
panic!("Expected Matrix result");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sqrt() {
|
||||
let eval_ts = 1000;
|
||||
let value = create_matrix(eval_ts, vec![0.0, 1.0, 4.0]);
|
||||
let result = sqrt(value).unwrap();
|
||||
|
||||
if let Value::Matrix(result_matrix) = result {
|
||||
assert_eq!(result_matrix.len(), 3);
|
||||
assert_eq!(result_matrix[0].samples[0].value, 0.0);
|
||||
assert_eq!(result_matrix[1].samples[0].value, 1.0);
|
||||
assert_eq!(result_matrix[2].samples[0].value, 2.0);
|
||||
} else {
|
||||
panic!("Expected Matrix result");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_round() {
|
||||
let eval_ts = 1000;
|
||||
let value = create_matrix(eval_ts, vec![3.2, 3.5, -3.2]);
|
||||
let result = round(value, &ScalarParam::Const(1.0)).unwrap();
|
||||
|
||||
if let Value::Matrix(result_matrix) = result {
|
||||
assert_eq!(result_matrix.len(), 3);
|
||||
assert_eq!(result_matrix[0].samples[0].value, 3.0);
|
||||
assert_eq!(result_matrix[1].samples[0].value, 4.0);
|
||||
assert_eq!(result_matrix[2].samples[0].value, -3.0);
|
||||
} else {
|
||||
panic!("Expected Matrix result");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sgn() {
|
||||
let eval_ts = 1000;
|
||||
let value = create_matrix(eval_ts, vec![5.0, -5.0, 0.0]);
|
||||
let result = sgn(value).unwrap();
|
||||
|
||||
if let Value::Matrix(result_matrix) = result {
|
||||
assert_eq!(result_matrix.len(), 3);
|
||||
assert_eq!(result_matrix[0].samples[0].value, 1.0);
|
||||
assert_eq!(result_matrix[1].samples[0].value, -1.0);
|
||||
assert_eq!(result_matrix[2].samples[0].value, 0.0);
|
||||
} else {
|
||||
panic!("Expected Matrix result");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_none_value() {
|
||||
let value = Value::None;
|
||||
|
||||
@@ -49,24 +49,6 @@ mod tests {
|
||||
max_over_time(data, &eval_ctx)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_max_over_time_value_none_input() {
|
||||
let result = max_over_time_test_helper(Value::None).unwrap();
|
||||
assert!(matches!(result, Value::None));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_max_over_time_invalid_input_returns_err() {
|
||||
let result = max_over_time_test_helper(Value::Float(1.0));
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_max_over_time_exec_empty_samples_returns_none() {
|
||||
let func = MaxOverTimeFunc;
|
||||
assert!(func.exec(&[], 0, &Duration::ZERO).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_max_over_time_function() {
|
||||
// Create a range value with sample data
|
||||
|
||||
@@ -55,24 +55,6 @@ mod tests {
|
||||
min_over_time(data, &eval_ctx)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_min_over_time_value_none_input() {
|
||||
let result = min_over_time_test_helper(Value::None).unwrap();
|
||||
assert!(matches!(result, Value::None));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_min_over_time_invalid_input_returns_err() {
|
||||
let result = min_over_time_test_helper(Value::Float(1.0));
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_min_over_time_exec_empty_samples_returns_none() {
|
||||
let func = MinOverTimeFunc;
|
||||
assert!(func.exec(&[], 0, &Duration::ZERO).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_min_over_time_function() {
|
||||
// Create a range value with sample data
|
||||
|
||||
@@ -762,19 +762,6 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_func_enum_parsing_known_functions() {
|
||||
assert_eq!("abs".parse::<Func>().unwrap(), Func::Abs);
|
||||
assert_eq!("rate".parse::<Func>().unwrap(), Func::Rate);
|
||||
assert_eq!("avg_over_time".parse::<Func>().unwrap(), Func::AvgOverTime);
|
||||
assert_eq!(
|
||||
"histogram_quantile".parse::<Func>().unwrap(),
|
||||
Func::HistogramQuantile
|
||||
);
|
||||
assert_eq!("label_join".parse::<Func>().unwrap(), Func::LabelJoin);
|
||||
assert_eq!("label_replace".parse::<Func>().unwrap(), Func::LabelReplace);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_func_enum_unknown_returns_err() {
|
||||
assert!("unknown_function".parse::<Func>().is_err());
|
||||
|
||||
@@ -71,18 +71,6 @@ mod tests {
|
||||
predict_linear(data, ScalarParam::Const(duration), &eval_ctx, None)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_predict_linear_value_none_input() {
|
||||
let result = predict_linear_test_helper(Value::None, 10.0).unwrap();
|
||||
assert!(matches!(result, Value::None));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_predict_linear_invalid_input_returns_err() {
|
||||
let result = predict_linear_test_helper(Value::Float(1.0), 10.0);
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_predict_linear_needs_two_samples_to_predict() {
|
||||
let one_sample = RangeValue {
|
||||
|
||||
@@ -59,11 +59,6 @@ mod tests {
|
||||
assert!(present_over_time(Value::Float(1.0)).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_present_over_time_exec_empty_samples_returns_none() {
|
||||
assert!(PresentOverTimeFunc.exec(&[], 0, &Duration::ZERO).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_present_over_time_is_one_regardless_of_sample_values() {
|
||||
let range_value = RangeValue {
|
||||
|
||||
@@ -71,20 +71,6 @@ mod tests {
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_quantile_over_time_name() {
|
||||
assert_eq!(
|
||||
QuantileOverTimeFunc::new(ScalarParam::Const(0.5)).name(),
|
||||
"quantile_over_time"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_quantile_over_time_empty() {
|
||||
let func = QuantileOverTimeFunc::new(ScalarParam::Const(0.5));
|
||||
assert!(func.exec(&[], 0, &Duration::from_secs(1)).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_quantile_over_time_median() {
|
||||
let func = QuantileOverTimeFunc::new(ScalarParam::Const(0.5));
|
||||
|
||||
@@ -47,17 +47,6 @@ mod tests {
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_stddev_over_time_name() {
|
||||
assert_eq!(StddevOverTimeFunc.name(), "stddev_over_time");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_stddev_over_time_empty() {
|
||||
let func = StddevOverTimeFunc;
|
||||
assert!(func.exec(&[], 0, &Duration::from_secs(1)).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_stddev_over_time_constant() {
|
||||
let func = StddevOverTimeFunc;
|
||||
|
||||
@@ -47,17 +47,6 @@ mod tests {
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_stdvar_over_time_name() {
|
||||
assert_eq!(StdvarOverTimeFunc.name(), "stdvar_over_time");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_stdvar_over_time_empty() {
|
||||
let func = StdvarOverTimeFunc;
|
||||
assert!(func.exec(&[], 0, &Duration::from_secs(1)).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_stdvar_over_time_constant() {
|
||||
let func = StdvarOverTimeFunc;
|
||||
|
||||
@@ -53,17 +53,6 @@ mod tests {
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sum_over_time_name() {
|
||||
assert_eq!(SumOverTimeFunc.name(), "sum_over_time");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sum_over_time_empty() {
|
||||
let func = SumOverTimeFunc;
|
||||
assert!(func.exec(&[], 0, &Duration::from_secs(1)).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sum_over_time_single() {
|
||||
let func = SumOverTimeFunc;
|
||||
|
||||
@@ -2352,101 +2352,6 @@ mod tests {
|
||||
assert_eq!(fixture.calls.load(Ordering::SeqCst), 0);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn legacy_new_mixed_and_disabled_sources_preserve_same_series_fragments() {
|
||||
use datafusion::arrow::{array::UInt32Array, ipc::writer::FileWriter};
|
||||
let rows = [
|
||||
(1, 10, 1.0, Some("x")),
|
||||
(1, 20, -0.0, Some("x")),
|
||||
(1, 30, 3.0, Some("x")),
|
||||
(1, 40, 4.0, Some("x")),
|
||||
];
|
||||
let legacy_schema = Arc::new(Schema::new(vec![
|
||||
Field::new("__oo_midx_row_count", DataType::UInt32, false),
|
||||
Field::new("group", DataType::Utf8, true),
|
||||
]));
|
||||
let legacy_batch = RecordBatch::try_new(
|
||||
Arc::clone(&legacy_schema),
|
||||
vec![
|
||||
Arc::new(UInt32Array::from(vec![2])),
|
||||
Arc::new(StringArray::from(vec!["x"])),
|
||||
],
|
||||
)
|
||||
.unwrap();
|
||||
let mut legacy = Vec::new();
|
||||
let mut writer = FileWriter::try_new(&mut legacy, &legacy_schema).unwrap();
|
||||
writer.write(&legacy_batch).unwrap();
|
||||
writer.finish().unwrap();
|
||||
for legacy_count in [0, 1, 2] {
|
||||
for enabled in [false, true] {
|
||||
let mut files = vec![file(&rows[..2]), file(&rows[2..])];
|
||||
for source in files.iter_mut().take(legacy_count) {
|
||||
source.1 = legacy.clone();
|
||||
}
|
||||
let fixture = Fixture::new(&files, false).await;
|
||||
let source = if enabled {
|
||||
ScanSource::Blocks(Arc::new(fixture.scan(files.iter().map(|v| v.0.clone()))))
|
||||
} else {
|
||||
ScanSource::HashSorted
|
||||
};
|
||||
let ctx =
|
||||
SessionContext::new_with_config(SessionConfig::new().with_target_partitions(2));
|
||||
let table = MemTable::try_new(schema(), vec![vec![batch(&rows)]])
|
||||
.unwrap()
|
||||
.with_sort_order(vec![vec![
|
||||
col("__hash__").sort(true, false),
|
||||
col("_timestamp").sort(true, false),
|
||||
]]);
|
||||
ctx.register_table("m", Arc::new(table)).unwrap();
|
||||
let matchers = Matchers::empty();
|
||||
let selector = StreamingSelector {
|
||||
table_name: "m",
|
||||
matchers: &matchers,
|
||||
offset: 0,
|
||||
};
|
||||
let result = execute_partitioned(
|
||||
&ctx,
|
||||
&source,
|
||||
&selector,
|
||||
LabelColumns::grouped(vec!["group".into()]),
|
||||
20,
|
||||
&EvalContext::new(10, 40, 10, "compatibility".into()),
|
||||
)
|
||||
.await;
|
||||
if enabled && legacy_count > 0 {
|
||||
assert!(result.is_err());
|
||||
assert_eq!(fixture.calls.load(Ordering::SeqCst), 0);
|
||||
continue;
|
||||
}
|
||||
let sources = result.unwrap();
|
||||
let mut actual = Vec::new();
|
||||
for source in sources {
|
||||
let mut source = source.await.unwrap();
|
||||
assert_eq!(
|
||||
matches!(&source, SeriesSource::Block(_)),
|
||||
enabled && legacy_count == 0
|
||||
);
|
||||
while source.advance().await.unwrap().is_some() {
|
||||
let mut samples = Vec::new();
|
||||
source.consume(&mut samples).await.unwrap();
|
||||
actual.extend(samples.iter().map(|s| (s.timestamp, s.value.to_bits())));
|
||||
}
|
||||
}
|
||||
actual.sort_unstable();
|
||||
assert_eq!(
|
||||
actual,
|
||||
rows.iter()
|
||||
.map(|r| (r.1, r.2.to_bits()))
|
||||
.collect::<Vec<_>>()
|
||||
);
|
||||
assert_eq!(
|
||||
fixture.calls.load(Ordering::SeqCst) > 0,
|
||||
enabled && legacy_count == 0
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn schema_evolution_distinguishes_absent_null_and_empty_labels() {
|
||||
let original = batch(&[(1, 10, 1.0, None), (1, 20, 2.0, None)]);
|
||||
|
||||
Reference in New Issue
Block a user