histograms: Add missing float histograms tests for PromQL (#11780)

* test: TestSparseHistogramRate

* test: TestSparseHistogram_HistogramQuantile

* test: TestSparseHistogram_HistogramFraction

* test: TestSparseHistogram_HistogramFraction

* test: TestSparseHistogram_Sum_Count_AddOperator

* test: TestSparseHistogram_HistogramCountAndSum

* tests: fix TestSparseHistogram_HistogramCountAndSum

* linter

* refactor TestSparseHistogram_HistogramCountAndSum

* wrap TestSparseHistogram_HistogramCountAndSum

Signed-off-by: Marc Tuduri <marctc@protonmail.com>
This commit is contained in:
Marc Tudurí 2022-12-28 14:45:47 +01:00 committed by GitHub
parent 9474610baf
commit 49f775d8a0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -3128,7 +3128,6 @@ func TestRangeQuery(t *testing.T) {
func TestSparseHistogramRate(t *testing.T) { func TestSparseHistogramRate(t *testing.T) {
// TODO(beorn7): Integrate histograms into the PromQL testing framework // TODO(beorn7): Integrate histograms into the PromQL testing framework
// and write more tests there. // and write more tests there.
// TODO(marctc): Add similar test for float histograms
test, err := NewTest(t, "") test, err := NewTest(t, "")
require.NoError(t, err) require.NoError(t, err)
defer test.Close() defer test.Close()
@ -3167,10 +3166,50 @@ func TestSparseHistogramRate(t *testing.T) {
require.Equal(t, expectedHistogram, actualHistogram) require.Equal(t, expectedHistogram, actualHistogram)
} }
func TestSparseFloatHistogramRate(t *testing.T) {
// TODO(beorn7): Integrate histograms into the PromQL testing framework
// and write more tests there.
test, err := NewTest(t, "")
require.NoError(t, err)
defer test.Close()
seriesName := "sparse_histogram_series"
lbls := labels.FromStrings("__name__", seriesName)
app := test.Storage().Appender(context.TODO())
for i, fh := range tsdb.GenerateTestFloatHistograms(100) {
_, err := app.AppendHistogram(0, lbls, int64(i)*int64(15*time.Second/time.Millisecond), nil, fh)
require.NoError(t, err)
}
require.NoError(t, app.Commit())
require.NoError(t, test.Run())
engine := test.QueryEngine()
queryString := fmt.Sprintf("rate(%s[1m])", seriesName)
qry, err := engine.NewInstantQuery(test.Queryable(), nil, queryString, timestamp.Time(int64(5*time.Minute/time.Millisecond)))
require.NoError(t, err)
res := qry.Exec(test.Context())
require.NoError(t, res.Err)
vector, err := res.Vector()
require.NoError(t, err)
require.Len(t, vector, 1)
actualHistogram := vector[0].H
expectedHistogram := &histogram.FloatHistogram{
Schema: 1,
ZeroThreshold: 0.001,
ZeroCount: 1. / 15.,
Count: 4. / 15.,
Sum: 1.226666666666667,
PositiveSpans: []histogram.Span{{Offset: 0, Length: 2}, {Offset: 1, Length: 2}},
PositiveBuckets: []float64{1. / 15., 1. / 15., 1. / 15., 1. / 15.},
}
require.Equal(t, expectedHistogram, actualHistogram)
}
func TestSparseHistogram_HistogramCountAndSum(t *testing.T) { func TestSparseHistogram_HistogramCountAndSum(t *testing.T) {
// TODO(codesome): Integrate histograms into the PromQL testing framework // TODO(codesome): Integrate histograms into the PromQL testing framework
// and write more tests there. // and write more tests there.
// TODO(marctc): Add similar test for float histograms
h := &histogram.Histogram{ h := &histogram.Histogram{
Count: 24, Count: 24,
ZeroCount: 4, ZeroCount: 4,
@ -3188,54 +3227,68 @@ func TestSparseHistogram_HistogramCountAndSum(t *testing.T) {
}, },
NegativeBuckets: []int64{2, 1, -2, 3}, NegativeBuckets: []int64{2, 1, -2, 3},
} }
for _, floatHisto := range []bool{true, false} {
t.Run(fmt.Sprintf("floatHistogram=%t", floatHisto), func(t *testing.T) {
test, err := NewTest(t, "")
require.NoError(t, err)
t.Cleanup(test.Close)
test, err := NewTest(t, "") seriesName := "sparse_histogram_series"
require.NoError(t, err) lbls := labels.FromStrings("__name__", seriesName)
t.Cleanup(test.Close) engine := test.QueryEngine()
seriesName := "sparse_histogram_series" ts := int64(10 * time.Minute / time.Millisecond)
lbls := labels.FromStrings("__name__", seriesName) app := test.Storage().Appender(context.TODO())
engine := test.QueryEngine() if floatHisto {
_, err = app.AppendHistogram(0, lbls, ts, nil, h.ToFloat())
} else {
_, err = app.AppendHistogram(0, lbls, ts, h, nil)
}
require.NoError(t, err)
require.NoError(t, app.Commit())
ts := int64(10 * time.Minute / time.Millisecond) queryString := fmt.Sprintf("histogram_count(%s)", seriesName)
app := test.Storage().Appender(context.TODO()) qry, err := engine.NewInstantQuery(test.Queryable(), nil, queryString, timestamp.Time(ts))
_, err = app.AppendHistogram(0, lbls, ts, h, nil) require.NoError(t, err)
require.NoError(t, err)
require.NoError(t, app.Commit())
queryString := fmt.Sprintf("histogram_count(%s)", seriesName) res := qry.Exec(test.Context())
qry, err := engine.NewInstantQuery(test.Queryable(), nil, queryString, timestamp.Time(ts)) require.NoError(t, res.Err)
require.NoError(t, err)
res := qry.Exec(test.Context()) vector, err := res.Vector()
require.NoError(t, res.Err) require.NoError(t, err)
vector, err := res.Vector() require.Len(t, vector, 1)
require.NoError(t, err) require.Nil(t, vector[0].H)
if floatHisto {
require.Equal(t, float64(h.ToFloat().Count), vector[0].V)
} else {
require.Equal(t, float64(h.Count), vector[0].V)
}
require.Len(t, vector, 1) queryString = fmt.Sprintf("histogram_sum(%s)", seriesName)
require.Nil(t, vector[0].H) qry, err = engine.NewInstantQuery(test.Queryable(), nil, queryString, timestamp.Time(ts))
require.Equal(t, float64(h.Count), vector[0].V) require.NoError(t, err)
queryString = fmt.Sprintf("histogram_sum(%s)", seriesName) res = qry.Exec(test.Context())
qry, err = engine.NewInstantQuery(test.Queryable(), nil, queryString, timestamp.Time(ts)) require.NoError(t, res.Err)
require.NoError(t, err)
res = qry.Exec(test.Context()) vector, err = res.Vector()
require.NoError(t, res.Err) require.NoError(t, err)
vector, err = res.Vector() require.Len(t, vector, 1)
require.NoError(t, err) require.Nil(t, vector[0].H)
if floatHisto {
require.Len(t, vector, 1) require.Equal(t, h.ToFloat().Sum, vector[0].V)
require.Nil(t, vector[0].H) } else {
require.Equal(t, h.Sum, vector[0].V) require.Equal(t, h.Sum, vector[0].V)
}
})
}
} }
func TestSparseHistogram_HistogramQuantile(t *testing.T) { func TestSparseHistogram_HistogramQuantile(t *testing.T) {
// TODO(codesome): Integrate histograms into the PromQL testing framework // TODO(codesome): Integrate histograms into the PromQL testing framework
// and write more tests there. // and write more tests there.
// TODO(marctc): Add similar test for float histograms
type subCase struct { type subCase struct {
quantile string quantile string
value float64 value float64
@ -3429,43 +3482,49 @@ func TestSparseHistogram_HistogramQuantile(t *testing.T) {
test, err := NewTest(t, "") test, err := NewTest(t, "")
require.NoError(t, err) require.NoError(t, err)
t.Cleanup(test.Close) t.Cleanup(test.Close)
for i, c := range cases { idx := int64(0)
t.Run(c.text, func(t *testing.T) { for _, floatHisto := range []bool{true, false} {
seriesName := "sparse_histogram_series" for _, c := range cases {
lbls := labels.FromStrings("__name__", seriesName) t.Run(fmt.Sprintf("%s floatHistogram=%t", c.text, floatHisto), func(t *testing.T) {
engine := test.QueryEngine() seriesName := "sparse_histogram_series"
lbls := labels.FromStrings("__name__", seriesName)
engine := test.QueryEngine()
ts := idx * int64(10*time.Minute/time.Millisecond)
app := test.Storage().Appender(context.TODO())
if floatHisto {
_, err = app.AppendHistogram(0, lbls, ts, nil, c.h.ToFloat())
} else {
_, err = app.AppendHistogram(0, lbls, ts, c.h, nil)
}
require.NoError(t, err)
require.NoError(t, app.Commit())
ts := int64(i+1) * int64(10*time.Minute/time.Millisecond) for j, sc := range c.subCases {
app := test.Storage().Appender(context.TODO()) t.Run(fmt.Sprintf("%d %s", j, sc.quantile), func(t *testing.T) {
_, err = app.AppendHistogram(0, lbls, ts, c.h, nil) queryString := fmt.Sprintf("histogram_quantile(%s, %s)", sc.quantile, seriesName)
require.NoError(t, err) qry, err := engine.NewInstantQuery(test.Queryable(), nil, queryString, timestamp.Time(ts))
require.NoError(t, app.Commit()) require.NoError(t, err)
for j, sc := range c.subCases { res := qry.Exec(test.Context())
t.Run(fmt.Sprintf("%d %s", j, sc.quantile), func(t *testing.T) { require.NoError(t, res.Err)
queryString := fmt.Sprintf("histogram_quantile(%s, %s)", sc.quantile, seriesName)
qry, err := engine.NewInstantQuery(test.Queryable(), nil, queryString, timestamp.Time(ts))
require.NoError(t, err)
res := qry.Exec(test.Context()) vector, err := res.Vector()
require.NoError(t, res.Err) require.NoError(t, err)
vector, err := res.Vector() require.Len(t, vector, 1)
require.NoError(t, err) require.Nil(t, vector[0].H)
require.True(t, almostEqual(sc.value, vector[0].V))
require.Len(t, vector, 1) })
require.Nil(t, vector[0].H) }
require.True(t, almostEqual(sc.value, vector[0].V)) idx++
}) })
} }
})
} }
} }
func TestSparseHistogram_HistogramFraction(t *testing.T) { func TestSparseHistogram_HistogramFraction(t *testing.T) {
// TODO(codesome): Integrate histograms into the PromQL testing framework // TODO(codesome): Integrate histograms into the PromQL testing framework
// and write more tests there. // and write more tests there.
// TODO(marctc): Add similar test for float histograms
type subCase struct { type subCase struct {
lower, upper string lower, upper string
value float64 value float64
@ -3849,52 +3908,58 @@ func TestSparseHistogram_HistogramFraction(t *testing.T) {
}, invariantCases...), }, invariantCases...),
}, },
} }
idx := int64(0)
for _, floatHisto := range []bool{true, false} {
for _, c := range cases {
t.Run(fmt.Sprintf("%s floatHistogram=%t", c.text, floatHisto), func(t *testing.T) {
test, err := NewTest(t, "")
require.NoError(t, err)
t.Cleanup(test.Close)
for i, c := range cases { seriesName := "sparse_histogram_series"
t.Run(c.text, func(t *testing.T) { lbls := labels.FromStrings("__name__", seriesName)
test, err := NewTest(t, "") engine := test.QueryEngine()
require.NoError(t, err)
t.Cleanup(test.Close)
seriesName := "sparse_histogram_series" ts := idx * int64(10*time.Minute/time.Millisecond)
lbls := labels.FromStrings("__name__", seriesName) app := test.Storage().Appender(context.TODO())
engine := test.QueryEngine() if floatHisto {
_, err = app.AppendHistogram(0, lbls, ts, nil, c.h.ToFloat())
} else {
_, err = app.AppendHistogram(0, lbls, ts, c.h, nil)
}
require.NoError(t, err)
require.NoError(t, app.Commit())
ts := int64(i+1) * int64(10*time.Minute/time.Millisecond) for j, sc := range c.subCases {
app := test.Storage().Appender(context.TODO()) t.Run(fmt.Sprintf("%d %s %s", j, sc.lower, sc.upper), func(t *testing.T) {
_, err = app.AppendHistogram(0, lbls, ts, c.h, nil) queryString := fmt.Sprintf("histogram_fraction(%s, %s, %s)", sc.lower, sc.upper, seriesName)
require.NoError(t, err) qry, err := engine.NewInstantQuery(test.Queryable(), nil, queryString, timestamp.Time(ts))
require.NoError(t, app.Commit()) require.NoError(t, err)
for j, sc := range c.subCases { res := qry.Exec(test.Context())
t.Run(fmt.Sprintf("%d %s %s", j, sc.lower, sc.upper), func(t *testing.T) { require.NoError(t, res.Err)
queryString := fmt.Sprintf("histogram_fraction(%s, %s, %s)", sc.lower, sc.upper, seriesName)
qry, err := engine.NewInstantQuery(test.Queryable(), nil, queryString, timestamp.Time(ts))
require.NoError(t, err)
res := qry.Exec(test.Context()) vector, err := res.Vector()
require.NoError(t, res.Err) require.NoError(t, err)
vector, err := res.Vector() require.Len(t, vector, 1)
require.NoError(t, err) require.Nil(t, vector[0].H)
if math.IsNaN(sc.value) {
require.Len(t, vector, 1) require.True(t, math.IsNaN(vector[0].V))
require.Nil(t, vector[0].H) return
if math.IsNaN(sc.value) { }
require.True(t, math.IsNaN(vector[0].V)) require.Equal(t, sc.value, vector[0].V)
return })
} }
require.Equal(t, sc.value, vector[0].V) idx++
}) })
} }
})
} }
} }
func TestSparseHistogram_Sum_Count_AddOperator(t *testing.T) { func TestSparseHistogram_Sum_Count_AddOperator(t *testing.T) {
// TODO(codesome): Integrate histograms into the PromQL testing framework // TODO(codesome): Integrate histograms into the PromQL testing framework
// and write more tests there. // and write more tests there.
// TODO(marctc): Add similar test for float histograms
cases := []struct { cases := []struct {
histograms []histogram.Histogram histograms []histogram.Histogram
expected histogram.FloatHistogram expected histogram.FloatHistogram
@ -3978,60 +4043,68 @@ func TestSparseHistogram_Sum_Count_AddOperator(t *testing.T) {
}, },
} }
for i, c := range cases { idx0 := int64(0)
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { for _, c := range cases {
test, err := NewTest(t, "") for _, floatHisto := range []bool{true, false} {
require.NoError(t, err) t.Run(fmt.Sprintf("floatHistogram=%t %d", floatHisto, idx0), func(t *testing.T) {
t.Cleanup(test.Close) test, err := NewTest(t, "")
seriesName := "sparse_histogram_series"
engine := test.QueryEngine()
ts := int64(i+1) * int64(10*time.Minute/time.Millisecond)
app := test.Storage().Appender(context.TODO())
for idx, h := range c.histograms {
lbls := labels.FromStrings("__name__", seriesName, "idx", fmt.Sprintf("%d", idx))
// Since we mutate h later, we need to create a copy here.
_, err = app.AppendHistogram(0, lbls, ts, h.Copy(), nil)
require.NoError(t, err) require.NoError(t, err)
} t.Cleanup(test.Close)
require.NoError(t, app.Commit())
queryAndCheck := func(queryString string, exp Vector) { seriesName := "sparse_histogram_series"
qry, err := engine.NewInstantQuery(test.Queryable(), nil, queryString, timestamp.Time(ts))
require.NoError(t, err)
res := qry.Exec(test.Context()) engine := test.QueryEngine()
require.NoError(t, res.Err)
vector, err := res.Vector() ts := idx0 * int64(10*time.Minute/time.Millisecond)
require.NoError(t, err) app := test.Storage().Appender(context.TODO())
for idx1, h := range c.histograms {
lbls := labels.FromStrings("__name__", seriesName, "idx", fmt.Sprintf("%d", idx1))
// Since we mutate h later, we need to create a copy here.
if floatHisto {
_, err = app.AppendHistogram(0, lbls, ts, nil, h.Copy().ToFloat())
} else {
_, err = app.AppendHistogram(0, lbls, ts, h.Copy(), nil)
}
require.NoError(t, err)
}
require.NoError(t, app.Commit())
require.Equal(t, exp, vector) queryAndCheck := func(queryString string, exp Vector) {
} qry, err := engine.NewInstantQuery(test.Queryable(), nil, queryString, timestamp.Time(ts))
require.NoError(t, err)
// sum(). res := qry.Exec(test.Context())
queryString := fmt.Sprintf("sum(%s)", seriesName) require.NoError(t, res.Err)
queryAndCheck(queryString, []Sample{
{Point{T: ts, H: &c.expected}, labels.EmptyLabels()}, vector, err := res.Vector()
require.NoError(t, err)
require.Equal(t, exp, vector)
}
// sum().
queryString := fmt.Sprintf("sum(%s)", seriesName)
queryAndCheck(queryString, []Sample{
{Point{T: ts, H: &c.expected}, labels.EmptyLabels()},
})
// + operator.
queryString = fmt.Sprintf(`%s{idx="0"}`, seriesName)
for idx := 1; idx < len(c.histograms); idx++ {
queryString += fmt.Sprintf(` + ignoring(idx) %s{idx="%d"}`, seriesName, idx)
}
queryAndCheck(queryString, []Sample{
{Point{T: ts, H: &c.expected}, labels.EmptyLabels()},
})
// count().
queryString = fmt.Sprintf("count(%s)", seriesName)
queryAndCheck(queryString, []Sample{
{Point{T: ts, V: 3}, labels.EmptyLabels()},
})
}) })
idx0++
// + operator. }
queryString = fmt.Sprintf(`%s{idx="0"}`, seriesName)
for idx := 1; idx < len(c.histograms); idx++ {
queryString += fmt.Sprintf(` + ignoring(idx) %s{idx="%d"}`, seriesName, idx)
}
queryAndCheck(queryString, []Sample{
{Point{T: ts, H: &c.expected}, labels.EmptyLabels()},
})
// count().
queryString = fmt.Sprintf("count(%s)", seriesName)
queryAndCheck(queryString, []Sample{
{Point{T: ts, V: 3}, labels.EmptyLabels()},
})
})
} }
} }