Skip to content

Commit b430755

Browse files
zzylolclaude
andcommitted
test(query-engine): DDSketch e2e with two instances per job and zeros
Each job now has two instances feeding one DDSketch, sent in time order since the watermark is per group, plus ten zeros per instance. The zeros move the true p90 from 90·scale to 88·scale, outside the alpha bound, so the test fails if zeros are dropped. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 3302e14 commit b430755

1 file changed

Lines changed: 34 additions & 23 deletions

File tree

‎asap-query-engine/tests/e2e_precompute_equivalence.rs‎

Lines changed: 34 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1701,9 +1701,11 @@ async fn e2e_grouped_quantile_preserves_output_label_shape() {
17011701
);
17021702
}
17031703

1704-
/// A grouped quantile served by a DDSketch aggregation: samples flow through
1705-
/// remote write and precompute into one DDSketch per group, and each returned
1706-
/// quantile stays within the sketch's relative-accuracy bound.
1704+
/// A grouped quantile served by a DDSketch aggregation: samples from two
1705+
/// instances per job flow through remote write and precompute into one
1706+
/// DDSketch per group, and each returned quantile stays within the sketch's
1707+
/// relative-accuracy bound. Zeros are part of the population, so a sketch
1708+
/// that dropped them would answer outside the bound.
17071709
#[tokio::test]
17081710
async fn e2e_grouped_quantile_over_ddsketch_is_within_alpha() {
17091711
let port = 19421u16;
@@ -1721,30 +1723,38 @@ async fn e2e_grouped_quantile_over_ddsketch_is_within_alpha() {
17211723
);
17221724
config.parameters.insert("alpha".to_string(), json!(alpha));
17231725

1724-
// Each group gets 1..=100 (scaled per group) inside the (1s, 2s] window,
1725-
// plus one later sample to close the window.
1726+
// Inside the (1s, 2s] window, instance "a" sends scale * 1..=50 and "b"
1727+
// sends scale * 51..=100, and each sends ten zeros. Samples go in time
1728+
// order across instances, since the watermark is per group, and one later
1729+
// sample per series closes the window.
17261730
let groups = [("frontend", 1.0), ("backend", 10.0)];
1727-
let samples = groups
1728-
.iter()
1729-
.flat_map(|&(job, scale)| {
1730-
(1..=100)
1731-
.map(move |i| {
1732-
make_timeseries(metric, vec![("job", job)], 1_000 + 5 * i, scale * i as f64)
1733-
})
1734-
.chain(std::iter::once(make_timeseries(
1735-
metric,
1736-
vec![("job", job)],
1737-
3_500,
1738-
scale,
1739-
)))
1740-
})
1741-
.collect();
1731+
let instances = [("a", 1), ("b", 51)];
1732+
let mut samples = Vec::new();
1733+
for (job, scale) in groups {
1734+
for i in 0..50 {
1735+
for (instance, first) in instances {
1736+
let value = scale * (first + i) as f64;
1737+
let labels = vec![("job", job), ("instance", instance)];
1738+
samples.push(make_timeseries(metric, labels, 1_005 + 5 * i, value));
1739+
}
1740+
}
1741+
for j in 0..10 {
1742+
for (instance, _) in instances {
1743+
let labels = vec![("job", job), ("instance", instance)];
1744+
samples.push(make_timeseries(metric, labels, 1_600 + j, 0.0));
1745+
}
1746+
}
1747+
for (instance, _) in instances {
1748+
let labels = vec![("job", job), ("instance", instance)];
1749+
samples.push(make_timeseries(metric, labels, 3_500, scale));
1750+
}
1751+
}
17421752
let (engine, query) = NativeDagScenario {
17431753
port,
17441754
metric,
17451755
query,
17461756
aggregation_configs: vec![config],
1747-
schema_labels: vec!["job".to_string()],
1757+
schema_labels: vec!["instance".to_string(), "job".to_string()],
17481758
samples,
17491759
evaluation_time_seconds: 2.0,
17501760
base_interval_ms: 1_000,
@@ -1763,8 +1773,9 @@ async fn e2e_grouped_quantile_over_ddsketch_is_within_alpha() {
17631773
for element in vector.values {
17641774
let job = element.labels.labels[0].as_str();
17651775
let scale = groups.iter().find(|(g, _)| *g == job).unwrap().1;
1766-
// The 0.9 quantile of scale * {1..=100} is scale * 90.
1767-
let truth = scale * 90.0;
1776+
// 120 values: 20 zeros, then scale * 1..=100. Rank ceil(0.9 * 120) = 108
1777+
// is scale * 88; without the zeros it would be scale * 90.
1778+
let truth = scale * 88.0;
17681779
assert!(
17691780
(element.value - truth).abs() / truth <= alpha,
17701781
"{job}: estimate {} vs truth {truth}",

0 commit comments

Comments
 (0)