From ce26370eeb2e19bdfac68c40a1f21913a046fddd Mon Sep 17 00:00:00 2001 From: Julius Volz Date: Wed, 10 Dec 2025 20:07:43 +0100 Subject: [PATCH] Add PromLens binop matching explain view tests Signed-off-by: Julius Volz --- web/ui/mantine-ui/src/promql/binOp.test.ts | 431 +++++++++++++++++++++ web/ui/mantine-ui/src/promql/binOp.ts | 4 +- 2 files changed, 433 insertions(+), 2 deletions(-) diff --git a/web/ui/mantine-ui/src/promql/binOp.test.ts b/web/ui/mantine-ui/src/promql/binOp.test.ts index 9c5d59a94c..76dd24fa79 100644 --- a/web/ui/mantine-ui/src/promql/binOp.test.ts +++ b/web/ui/mantine-ui/src/promql/binOp.test.ts @@ -2163,6 +2163,437 @@ const testCases: TestCase[] = [ numGroups: 2, }, }, + { + // metric_a - fill(0) metric_b + desc: "subtraction with fill(0) but no missing series", + op: binaryOperatorType.sub, + matching: { + card: vectorMatchCardinality.oneToOne, + on: false, + include: [], + labels: [], + fillValues: { lhs: 0, rhs: 0 }, + }, + lhs: testMetricA, + rhs: testMetricB, + result: { + groups: { + [fnv1a(["a", "x", "same"])]: { + groupLabels: { label1: "a", label2: "x", same: "same" }, + lhs: [ + { + metric: { + __name__: "metric_a", + label1: "a", + label2: "x", + same: "same", + }, + value: [0, "1"], + }, + ], + lhsCount: 1, + rhs: [ + { + metric: { + __name__: "metric_b", + label1: "a", + label2: "x", + same: "same", + }, + value: [0, "10"], + }, + ], + rhsCount: 1, + result: [ + { + sample: { + metric: { label1: "a", label2: "x", same: "same" }, + value: [0, "-9"], + }, + manySideIdx: 0, + }, + ], + error: null, + }, + [fnv1a(["a", "y", "same"])]: { + groupLabels: { label1: "a", label2: "y", same: "same" }, + lhs: [ + { + metric: { + __name__: "metric_a", + label1: "a", + label2: "y", + same: "same", + }, + value: [0, "2"], + }, + ], + lhsCount: 1, + rhs: [ + { + metric: { + __name__: "metric_b", + label1: "a", + label2: "y", + same: "same", + }, + value: [0, "20"], + }, + ], + rhsCount: 1, + result: [ + { + sample: { + metric: { label1: "a", label2: "y", same: "same" }, + value: [0, "-18"], + }, + manySideIdx: 0, + }, + ], + error: null, + }, + [fnv1a(["b", "x", "same"])]: { + groupLabels: { label1: "b", label2: "x", same: "same" }, + lhs: [ + { + metric: { + __name__: "metric_a", + label1: "b", + label2: "x", + same: "same", + }, + value: [0, "3"], + }, + ], + lhsCount: 1, + rhs: [ + { + metric: { + __name__: "metric_b", + label1: "b", + label2: "x", + same: "same", + }, + value: [0, "30"], + }, + ], + rhsCount: 1, + result: [ + { + sample: { + metric: { label1: "b", label2: "x", same: "same" }, + value: [0, "-27"], + }, + manySideIdx: 0, + }, + ], + error: null, + }, + [fnv1a(["b", "y", "same"])]: { + groupLabels: { label1: "b", label2: "y", same: "same" }, + lhs: [ + { + metric: { + __name__: "metric_a", + label1: "b", + label2: "y", + same: "same", + }, + value: [0, "4"], + }, + ], + lhsCount: 1, + rhs: [ + { + metric: { + __name__: "metric_b", + label1: "b", + label2: "y", + same: "same", + }, + value: [0, "40"], + }, + ], + rhsCount: 1, + result: [ + { + sample: { + metric: { label1: "b", label2: "y", same: "same" }, + value: [0, "-36"], + }, + manySideIdx: 0, + }, + ], + error: null, + }, + }, + numGroups: 4, + }, + }, + { + // metric_a[0..2] - fill_left(23) fill_right(42) metric_b[1...3] + desc: "subtraction with different fill values and missing series on each side", + op: binaryOperatorType.sub, + matching: { + card: vectorMatchCardinality.oneToOne, + on: false, + include: [], + labels: [], + fillValues: { lhs: 23, rhs: 42 }, + }, + lhs: testMetricA.slice(0, 3), + rhs: testMetricB.slice(1, 4), + result: { + groups: { + [fnv1a(["a", "x", "same"])]: { + groupLabels: { label1: "a", label2: "x", same: "same" }, + lhs: [ + { + metric: { + __name__: "metric_a", + label1: "a", + label2: "x", + same: "same", + }, + value: [0, "1"], + }, + ], + lhsCount: 1, + rhs: [ + { + metric: { + label1: "a", + label2: "x", + same: "same", + }, + value: [0, "42"], + filled: true, + }, + ], + rhsCount: 1, + result: [ + { + sample: { + metric: { label1: "a", label2: "x", same: "same" }, + value: [0, "-41"], + }, + manySideIdx: 0, + }, + ], + error: null, + }, + [fnv1a(["a", "y", "same"])]: { + groupLabels: { label1: "a", label2: "y", same: "same" }, + lhs: [ + { + metric: { + __name__: "metric_a", + label1: "a", + label2: "y", + same: "same", + }, + value: [0, "2"], + }, + ], + lhsCount: 1, + rhs: [ + { + metric: { + __name__: "metric_b", + label1: "a", + label2: "y", + same: "same", + }, + value: [0, "20"], + }, + ], + rhsCount: 1, + result: [ + { + sample: { + metric: { label1: "a", label2: "y", same: "same" }, + value: [0, "-18"], + }, + manySideIdx: 0, + }, + ], + error: null, + }, + [fnv1a(["b", "x", "same"])]: { + groupLabels: { label1: "b", label2: "x", same: "same" }, + lhs: [ + { + metric: { + __name__: "metric_a", + label1: "b", + label2: "x", + same: "same", + }, + value: [0, "3"], + }, + ], + lhsCount: 1, + rhs: [ + { + metric: { + __name__: "metric_b", + label1: "b", + label2: "x", + same: "same", + }, + value: [0, "30"], + }, + ], + rhsCount: 1, + result: [ + { + sample: { + metric: { label1: "b", label2: "x", same: "same" }, + value: [0, "-27"], + }, + manySideIdx: 0, + }, + ], + error: null, + }, + [fnv1a(["b", "y", "same"])]: { + groupLabels: { label1: "b", label2: "y", same: "same" }, + lhs: [ + { + metric: { + label1: "b", + label2: "y", + same: "same", + }, + filled: true, + value: [0, "23"], + }, + ], + lhsCount: 1, + rhs: [ + { + metric: { + __name__: "metric_b", + label1: "b", + label2: "y", + same: "same", + }, + value: [0, "40"], + }, + ], + rhsCount: 1, + result: [ + { + sample: { + metric: { label1: "b", label2: "y", same: "same" }, + value: [0, "-17"], + }, + manySideIdx: 0, + }, + ], + error: null, + }, + }, + numGroups: 4, + }, + }, + { + // metric_b[0...1] - on(label1) group_left fill(0) metric_c + desc: "many-to-one matching with matching labels specified, group_left, and fill specified", + op: binaryOperatorType.sub, + matching: { + card: vectorMatchCardinality.manyToOne, + on: true, + include: [], + labels: ["label1"], + fillValues: { lhs: 0, rhs: 0 }, + }, + lhs: testMetricB.slice(0, 2), + rhs: testMetricC, + result: { + groups: { + [fnv1a(["a"])]: { + groupLabels: { label1: "a" }, + lhs: [ + { + metric: { + __name__: "metric_b", + label1: "a", + label2: "x", + same: "same", + }, + value: [0, "10"], + }, + { + metric: { + __name__: "metric_b", + label1: "a", + label2: "y", + same: "same", + }, + value: [0, "20"], + }, + ], + lhsCount: 2, + rhs: [ + { + metric: { __name__: "metric_c", label1: "a" }, + value: [0, "100"], + }, + ], + rhsCount: 1, + result: [ + { + sample: { + metric: { label1: "a", label2: "x", same: "same" }, + value: [0, "-90"], + }, + manySideIdx: 0, + }, + { + sample: { + metric: { label1: "a", label2: "y", same: "same" }, + value: [0, "-80"], + }, + manySideIdx: 1, + }, + ], + error: null, + }, + [fnv1a(["b"])]: { + groupLabels: { label1: "b" }, + lhs: [ + { + metric: { + label1: "b", + }, + filled: true, + value: [0, "0"], + }, + ], + lhsCount: 1, + rhs: [ + { + metric: { __name__: "metric_c", label1: "b" }, + value: [0, "200"], + }, + ], + rhsCount: 1, + result: [ + { + sample: { + metric: { label1: "b" }, + value: [0, "-200"], + }, + manySideIdx: 0, + }, + ], + error: null, + }, + }, + numGroups: 2, + }, + }, { // metric_a and metric b desc: "and operator with no matching labels and matching groups", diff --git a/web/ui/mantine-ui/src/promql/binOp.ts b/web/ui/mantine-ui/src/promql/binOp.ts index f583bf81bb..9ebee90f64 100644 --- a/web/ui/mantine-ui/src/promql/binOp.ts +++ b/web/ui/mantine-ui/src/promql/binOp.ts @@ -347,7 +347,7 @@ export const computeVectorVectorBinOp = ( Object.values(groups).forEach((mg) => { if (mg.lhs.length === 0 && matching.fillValues.lhs !== null) { mg.lhs.push({ - metric: {}, + metric: mg.groupLabels, value: [0, formatPrometheusFloat(matching.fillValues.lhs as number)], filled: true, }); @@ -355,7 +355,7 @@ export const computeVectorVectorBinOp = ( } if (mg.rhs.length === 0 && matching.fillValues.rhs !== null) { mg.rhs.push({ - metric: {}, + metric: mg.groupLabels, value: [0, formatPrometheusFloat(matching.fillValues.rhs as number)], filled: true, });