From 4139e584f42ac3476bd01768f569e50e6974614b Mon Sep 17 00:00:00 2001 From: zz_y Date: Fri, 4 Sep 2026 06:00:56 -0600 Subject: [PATCH 1/2] test(promql): compare every range step with instant evaluation --- .../asapquery_compatibility_process_e2e.rs | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/data_plane/tests/asapquery_compatibility_process_e2e.rs b/data_plane/tests/asapquery_compatibility_process_e2e.rs index 3fc29c3d..a62f03d3 100644 --- a/data_plane/tests/asapquery_compatibility_process_e2e.rs +++ b/data_plane/tests/asapquery_compatibility_process_e2e.rs @@ -402,6 +402,10 @@ async fn collector_free_profile_serves_complete_matrix_and_falls_back_exactly() "topk(5, sum_over_time(asap_demo_gauge[5s]))", "topk by (job) (5, count_over_time(asap_demo_gauge[5s]))", ] { + let first_instant = + wait_for_warm_instant(&client, &backend, query, first_eval, &backend_log).await; + let second_instant = + wait_for_warm_instant(&client, &backend, query, second_eval, &backend_log).await; let response: Value = client .get(format!("{backend}/api/v1/query_range")) .query(&[ @@ -427,6 +431,32 @@ async fn collector_free_profile_serves_complete_matrix_and_falls_back_exactly() assert_eq!(values.len(), 2, "wrong step count for {query}: {response}"); assert_eq!(values[0][0], first_eval); assert_eq!(values[1][0], second_eval); + assert_eq!( + response["data"]["result"][0]["metric"], first_instant["data"]["result"][0]["metric"], + "range/instant labels differ at first step for {query}" + ); + assert_eq!( + response["data"]["result"][0]["metric"], second_instant["data"]["result"][0]["metric"], + "range/instant labels differ at second step for {query}" + ); + let range_first = values[0][1] + .as_str() + .and_then(|value| value.parse::().ok()) + .expect("first range value"); + let range_second = values[1][1] + .as_str() + .and_then(|value| value.parse::().ok()) + .expect("second range value"); + assert_eq!( + range_first, + first_value(&first_instant, "value").expect("first instant value"), + "range value differs from an independent instant evaluation at first step for {query}" + ); + assert_eq!( + range_second, + first_value(&second_instant, "value").expect("second instant value"), + "range value differs from an independent instant evaluation at second step for {query}" + ); } let fallback_instant: Value = client From 370cabe13af7fec2901b96705fc134dc02c8908a Mon Sep 17 00:00:00 2001 From: zz_y Date: Tue, 8 Sep 2026 07:09:51 -0600 Subject: [PATCH 2/2] test: compare complete range vectors including changing TopK membership --- .../asapquery_compatibility_process_e2e.rs | 65 +++++++++++-------- 1 file changed, 39 insertions(+), 26 deletions(-) diff --git a/data_plane/tests/asapquery_compatibility_process_e2e.rs b/data_plane/tests/asapquery_compatibility_process_e2e.rs index d6657adb..55418936 100644 --- a/data_plane/tests/asapquery_compatibility_process_e2e.rs +++ b/data_plane/tests/asapquery_compatibility_process_e2e.rs @@ -676,6 +676,45 @@ async fn collector_free_profile_serves_complete_matrix_and_falls_back_exactly() is_warm(&response), "{query} did not use warm tier: {response}" ); + // Compare the complete vector at each step, including changing Top-K + // membership. Sorting labels makes response ordering irrelevant. + for (timestamp, instant) in [(first_eval, &first_instant), (second_eval, &second_instant)] { + let mut expected = instant["data"]["result"] + .as_array() + .expect("instant vector") + .iter() + .map(|series| { + ( + serde_json::to_string(&series["metric"]).unwrap(), + series["value"][1].as_str().unwrap().parse::().unwrap(), + ) + }) + .collect::>(); + let mut actual = response["data"]["result"] + .as_array() + .expect("range matrix") + .iter() + .flat_map(|series| { + series["values"] + .as_array() + .unwrap() + .iter() + .filter(move |point| point[0].as_f64() == Some(timestamp)) + .map(move |point| { + ( + serde_json::to_string(&series["metric"]).unwrap(), + point[1].as_str().unwrap().parse::().unwrap(), + ) + }) + }) + .collect::>(); + expected.sort_by(|a, b| a.0.cmp(&b.0)); + actual.sort_by(|a, b| a.0.cmp(&b.0)); + assert_eq!( + actual, expected, + "complete range/instant vector differs for {query} at {timestamp}" + ); + } if query.starts_with("topk(") { let mut ranked_points = response["data"]["result"] .as_array() @@ -716,32 +755,6 @@ async fn collector_free_profile_serves_complete_matrix_and_falls_back_exactly() assert_eq!(values.len(), 2, "wrong step count for {query}: {response}"); assert_eq!(values[0][0], first_eval); assert_eq!(values[1][0], second_eval); - assert_eq!( - response["data"]["result"][0]["metric"], first_instant["data"]["result"][0]["metric"], - "range/instant labels differ at first step for {query}" - ); - assert_eq!( - response["data"]["result"][0]["metric"], second_instant["data"]["result"][0]["metric"], - "range/instant labels differ at second step for {query}" - ); - let range_first = values[0][1] - .as_str() - .and_then(|value| value.parse::().ok()) - .expect("first range value"); - let range_second = values[1][1] - .as_str() - .and_then(|value| value.parse::().ok()) - .expect("second range value"); - assert_eq!( - range_first, - first_value(&first_instant, "value").expect("first instant value"), - "range value differs from an independent instant evaluation at first step for {query}" - ); - assert_eq!( - range_second, - first_value(&second_instant, "value").expect("second instant value"), - "range value differs from an independent instant evaluation at second step for {query}" - ); } // Readiness polling may briefly reach the exact fallback before a newly