Skip to content

Commit

Permalink
improve query fuzzing tests with better promql result comparison (#5724)
Browse files Browse the repository at this point in the history
Signed-off-by: Ben Ye <[email protected]>
  • Loading branch information
yeya24 authored Jan 15, 2024
1 parent 6cf21b6 commit 1caa451
Showing 1 changed file with 83 additions and 32 deletions.
115 changes: 83 additions & 32 deletions integration/query_fuzz_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ func TestVerticalShardingFuzz(t *testing.T) {
t.Logf("case %d error mismatch.\n%s: %s\nerr1: %v\nerr2: %v\n", i, qt, tc.query, tc.err1, tc.err2)
failures++
}
} else if !sameModelValue(tc.res1, tc.res2) {
} else if !cmp.Equal(tc.res1, tc.res2, comparer) {
t.Logf("case %d results mismatch.\n%s: %s\nres1: %s\nres2: %s\n", i, qt, tc.query, tc.res1.String(), tc.res2.String())
failures++
}
Expand All @@ -196,37 +196,88 @@ func TestVerticalShardingFuzz(t *testing.T) {
}
}

func sameModelValue(a model.Value, b model.Value) bool {
if a.Type() != b.Type() {
// comparer should be used to compare promql results between engines.
var comparer = cmp.Comparer(func(x, y model.Value) bool {
if x.Type() != y.Type() {
return false
}
// We allow a margin for comparing floats.
opts := []cmp.Option{cmpopts.EquateNaNs(), cmpopts.EquateApprox(0, 1e-6)}
switch a.Type() {
case model.ValMatrix:
s1, _ := a.(model.Matrix)
s2, _ := b.(model.Matrix)
// Sort to make sure we are not affected by series order.
sort.Sort(s1)
sort.Sort(s2)
return cmp.Equal(s1, s2, opts...)
case model.ValVector:
s1, _ := a.(model.Vector)
s2, _ := b.(model.Vector)
// Sort to make sure we are not affected by series order.
sort.Sort(s1)
sort.Sort(s2)
return cmp.Equal(s1, s2, opts...)
case model.ValScalar:
s1, _ := a.(*model.Scalar)
s2, _ := b.(*model.Scalar)
return cmp.Equal(s1, s2, opts...)
case model.ValString:
s1, _ := a.(*model.String)
s2, _ := b.(*model.String)
return cmp.Equal(s1, s2, opts...)
default:
// model.ValNone is impossible.
return false
compareFloats := func(l, r float64) bool {
const epsilon = 1e-6
return cmp.Equal(l, r, cmpopts.EquateNaNs(), cmpopts.EquateApprox(0, epsilon))
}
}
compareMetrics := func(l, r model.Metric) bool {
return l.Equal(r)
}

vx, xvec := x.(model.Vector)
vy, yvec := y.(model.Vector)

if xvec && yvec {
if len(vx) != len(vy) {
return false
}

// Sort vector before comparing.
sort.Sort(vx)
sort.Sort(vy)

for i := 0; i < len(vx); i++ {
if !compareMetrics(vx[i].Metric, vy[i].Metric) {
return false
}
if vx[i].Timestamp != vy[i].Timestamp {
return false
}
if !compareFloats(float64(vx[i].Value), float64(vy[i].Value)) {
return false
}
}
return true
}

mx, xmat := x.(model.Matrix)
my, ymat := y.(model.Matrix)

if xmat && ymat {
if len(mx) != len(my) {
return false
}
// Sort matrix before comparing.
sort.Sort(mx)
sort.Sort(my)
for i := 0; i < len(mx); i++ {
mxs := mx[i]
mys := my[i]

if !compareMetrics(mxs.Metric, mys.Metric) {
return false
}

xps := mxs.Values
yps := mys.Values

if len(xps) != len(yps) {
return false
}
for j := 0; j < len(xps); j++ {
if xps[j].Timestamp != yps[j].Timestamp {
return false
}
if !compareFloats(float64(xps[j].Value), float64(yps[j].Value)) {
return false
}
}
}
return true
}

sx, xscalar := x.(*model.Scalar)
sy, yscalar := y.(*model.Scalar)
if xscalar && yscalar {
if sx.Timestamp != sy.Timestamp {
return false
}
return compareFloats(float64(sx.Value), float64(sy.Value))
}
return false
})

0 comments on commit 1caa451

Please sign in to comment.