mirror of
https://github.com/prometheus/prometheus.git
synced 2024-11-16 02:24:06 -08:00
Merge remote-tracking branch 'prometheus/main' into arve/wlog-histograms
This commit is contained in:
commit
38b971ed20
|
@ -56,8 +56,8 @@ import (
|
||||||
"github.com/prometheus/prometheus/model/rulefmt"
|
"github.com/prometheus/prometheus/model/rulefmt"
|
||||||
"github.com/prometheus/prometheus/notifier"
|
"github.com/prometheus/prometheus/notifier"
|
||||||
_ "github.com/prometheus/prometheus/plugins" // Register plugins.
|
_ "github.com/prometheus/prometheus/plugins" // Register plugins.
|
||||||
"github.com/prometheus/prometheus/promql"
|
|
||||||
"github.com/prometheus/prometheus/promql/parser"
|
"github.com/prometheus/prometheus/promql/parser"
|
||||||
|
"github.com/prometheus/prometheus/promql/promqltest"
|
||||||
"github.com/prometheus/prometheus/scrape"
|
"github.com/prometheus/prometheus/scrape"
|
||||||
"github.com/prometheus/prometheus/util/documentcli"
|
"github.com/prometheus/prometheus/util/documentcli"
|
||||||
)
|
)
|
||||||
|
@ -377,7 +377,7 @@ func main() {
|
||||||
|
|
||||||
case testRulesCmd.FullCommand():
|
case testRulesCmd.FullCommand():
|
||||||
os.Exit(RulesUnitTest(
|
os.Exit(RulesUnitTest(
|
||||||
promql.LazyLoaderOpts{
|
promqltest.LazyLoaderOpts{
|
||||||
EnableAtModifier: true,
|
EnableAtModifier: true,
|
||||||
EnableNegativeOffset: true,
|
EnableNegativeOffset: true,
|
||||||
},
|
},
|
||||||
|
|
|
@ -26,7 +26,7 @@ import (
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/prometheus/prometheus/promql"
|
"github.com/prometheus/prometheus/promql/promqltest"
|
||||||
"github.com/prometheus/prometheus/tsdb"
|
"github.com/prometheus/prometheus/tsdb"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -88,7 +88,7 @@ func normalizeNewLine(b []byte) []byte {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTSDBDump(t *testing.T) {
|
func TestTSDBDump(t *testing.T) {
|
||||||
storage := promql.LoadedStorage(t, `
|
storage := promqltest.LoadedStorage(t, `
|
||||||
load 1m
|
load 1m
|
||||||
metric{foo="bar", baz="abc"} 1 2 3 4 5
|
metric{foo="bar", baz="abc"} 1 2 3 4 5
|
||||||
heavy_metric{foo="bar"} 5 4 3 2 1
|
heavy_metric{foo="bar"} 5 4 3 2 1
|
||||||
|
@ -158,7 +158,7 @@ func TestTSDBDump(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTSDBDumpOpenMetrics(t *testing.T) {
|
func TestTSDBDumpOpenMetrics(t *testing.T) {
|
||||||
storage := promql.LoadedStorage(t, `
|
storage := promqltest.LoadedStorage(t, `
|
||||||
load 1m
|
load 1m
|
||||||
my_counter{foo="bar", baz="abc"} 1 2 3 4 5
|
my_counter{foo="bar", baz="abc"} 1 2 3 4 5
|
||||||
my_gauge{bar="foo", abc="baz"} 9 8 0 4 7
|
my_gauge{bar="foo", abc="baz"} 9 8 0 4 7
|
||||||
|
|
|
@ -36,13 +36,14 @@ import (
|
||||||
"github.com/prometheus/prometheus/model/labels"
|
"github.com/prometheus/prometheus/model/labels"
|
||||||
"github.com/prometheus/prometheus/promql"
|
"github.com/prometheus/prometheus/promql"
|
||||||
"github.com/prometheus/prometheus/promql/parser"
|
"github.com/prometheus/prometheus/promql/parser"
|
||||||
|
"github.com/prometheus/prometheus/promql/promqltest"
|
||||||
"github.com/prometheus/prometheus/rules"
|
"github.com/prometheus/prometheus/rules"
|
||||||
"github.com/prometheus/prometheus/storage"
|
"github.com/prometheus/prometheus/storage"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RulesUnitTest does unit testing of rules based on the unit testing files provided.
|
// RulesUnitTest does unit testing of rules based on the unit testing files provided.
|
||||||
// More info about the file format can be found in the docs.
|
// More info about the file format can be found in the docs.
|
||||||
func RulesUnitTest(queryOpts promql.LazyLoaderOpts, runStrings []string, diffFlag bool, files ...string) int {
|
func RulesUnitTest(queryOpts promqltest.LazyLoaderOpts, runStrings []string, diffFlag bool, files ...string) int {
|
||||||
failed := false
|
failed := false
|
||||||
|
|
||||||
var run *regexp.Regexp
|
var run *regexp.Regexp
|
||||||
|
@ -69,7 +70,7 @@ func RulesUnitTest(queryOpts promql.LazyLoaderOpts, runStrings []string, diffFla
|
||||||
return successExitCode
|
return successExitCode
|
||||||
}
|
}
|
||||||
|
|
||||||
func ruleUnitTest(filename string, queryOpts promql.LazyLoaderOpts, run *regexp.Regexp, diffFlag bool) []error {
|
func ruleUnitTest(filename string, queryOpts promqltest.LazyLoaderOpts, run *regexp.Regexp, diffFlag bool) []error {
|
||||||
fmt.Println("Unit Testing: ", filename)
|
fmt.Println("Unit Testing: ", filename)
|
||||||
|
|
||||||
b, err := os.ReadFile(filename)
|
b, err := os.ReadFile(filename)
|
||||||
|
@ -175,9 +176,9 @@ type testGroup struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// test performs the unit tests.
|
// test performs the unit tests.
|
||||||
func (tg *testGroup) test(evalInterval time.Duration, groupOrderMap map[string]int, queryOpts promql.LazyLoaderOpts, diffFlag bool, ruleFiles ...string) (outErr []error) {
|
func (tg *testGroup) test(evalInterval time.Duration, groupOrderMap map[string]int, queryOpts promqltest.LazyLoaderOpts, diffFlag bool, ruleFiles ...string) (outErr []error) {
|
||||||
// Setup testing suite.
|
// Setup testing suite.
|
||||||
suite, err := promql.NewLazyLoader(tg.seriesLoadingString(), queryOpts)
|
suite, err := promqltest.NewLazyLoader(tg.seriesLoadingString(), queryOpts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []error{err}
|
return []error{err}
|
||||||
}
|
}
|
||||||
|
@ -413,7 +414,7 @@ Outer:
|
||||||
gotSamples = append(gotSamples, parsedSample{
|
gotSamples = append(gotSamples, parsedSample{
|
||||||
Labels: s.Metric.Copy(),
|
Labels: s.Metric.Copy(),
|
||||||
Value: s.F,
|
Value: s.F,
|
||||||
Histogram: promql.HistogramTestExpression(s.H),
|
Histogram: promqltest.HistogramTestExpression(s.H),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -443,7 +444,7 @@ Outer:
|
||||||
expSamples = append(expSamples, parsedSample{
|
expSamples = append(expSamples, parsedSample{
|
||||||
Labels: lb,
|
Labels: lb,
|
||||||
Value: s.Value,
|
Value: s.Value,
|
||||||
Histogram: promql.HistogramTestExpression(hist),
|
Histogram: promqltest.HistogramTestExpression(hist),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ import (
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/prometheus/prometheus/promql"
|
"github.com/prometheus/prometheus/promql/promqltest"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestRulesUnitTest(t *testing.T) {
|
func TestRulesUnitTest(t *testing.T) {
|
||||||
|
@ -28,7 +28,7 @@ func TestRulesUnitTest(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
args args
|
args args
|
||||||
queryOpts promql.LazyLoaderOpts
|
queryOpts promqltest.LazyLoaderOpts
|
||||||
want int
|
want int
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
|
@ -92,7 +92,7 @@ func TestRulesUnitTest(t *testing.T) {
|
||||||
args: args{
|
args: args{
|
||||||
files: []string{"./testdata/at-modifier-test.yml"},
|
files: []string{"./testdata/at-modifier-test.yml"},
|
||||||
},
|
},
|
||||||
queryOpts: promql.LazyLoaderOpts{
|
queryOpts: promqltest.LazyLoaderOpts{
|
||||||
EnableAtModifier: true,
|
EnableAtModifier: true,
|
||||||
},
|
},
|
||||||
want: 0,
|
want: 0,
|
||||||
|
@ -109,7 +109,7 @@ func TestRulesUnitTest(t *testing.T) {
|
||||||
args: args{
|
args: args{
|
||||||
files: []string{"./testdata/negative-offset-test.yml"},
|
files: []string{"./testdata/negative-offset-test.yml"},
|
||||||
},
|
},
|
||||||
queryOpts: promql.LazyLoaderOpts{
|
queryOpts: promqltest.LazyLoaderOpts{
|
||||||
EnableNegativeOffset: true,
|
EnableNegativeOffset: true,
|
||||||
},
|
},
|
||||||
want: 0,
|
want: 0,
|
||||||
|
@ -119,7 +119,7 @@ func TestRulesUnitTest(t *testing.T) {
|
||||||
args: args{
|
args: args{
|
||||||
files: []string{"./testdata/no-test-group-interval.yml"},
|
files: []string{"./testdata/no-test-group-interval.yml"},
|
||||||
},
|
},
|
||||||
queryOpts: promql.LazyLoaderOpts{
|
queryOpts: promqltest.LazyLoaderOpts{
|
||||||
EnableNegativeOffset: true,
|
EnableNegativeOffset: true,
|
||||||
},
|
},
|
||||||
want: 0,
|
want: 0,
|
||||||
|
@ -142,7 +142,7 @@ func TestRulesUnitTestRun(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
args args
|
args args
|
||||||
queryOpts promql.LazyLoaderOpts
|
queryOpts promqltest.LazyLoaderOpts
|
||||||
want int
|
want int
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
package promql
|
package promql_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
@ -23,13 +23,14 @@ import (
|
||||||
|
|
||||||
"github.com/prometheus/prometheus/model/histogram"
|
"github.com/prometheus/prometheus/model/histogram"
|
||||||
"github.com/prometheus/prometheus/model/labels"
|
"github.com/prometheus/prometheus/model/labels"
|
||||||
|
"github.com/prometheus/prometheus/promql"
|
||||||
"github.com/prometheus/prometheus/promql/parser"
|
"github.com/prometheus/prometheus/promql/parser"
|
||||||
"github.com/prometheus/prometheus/storage"
|
"github.com/prometheus/prometheus/storage"
|
||||||
"github.com/prometheus/prometheus/tsdb/tsdbutil"
|
"github.com/prometheus/prometheus/tsdb/tsdbutil"
|
||||||
"github.com/prometheus/prometheus/util/teststorage"
|
"github.com/prometheus/prometheus/util/teststorage"
|
||||||
)
|
)
|
||||||
|
|
||||||
func setupRangeQueryTestData(stor *teststorage.TestStorage, _ *Engine, interval, numIntervals int) error {
|
func setupRangeQueryTestData(stor *teststorage.TestStorage, _ *promql.Engine, interval, numIntervals int) error {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
metrics := []labels.Labels{}
|
metrics := []labels.Labels{}
|
||||||
|
@ -249,13 +250,13 @@ func BenchmarkRangeQuery(b *testing.B) {
|
||||||
stor := teststorage.New(b)
|
stor := teststorage.New(b)
|
||||||
stor.DB.DisableCompactions() // Don't want auto-compaction disrupting timings.
|
stor.DB.DisableCompactions() // Don't want auto-compaction disrupting timings.
|
||||||
defer stor.Close()
|
defer stor.Close()
|
||||||
opts := EngineOpts{
|
opts := promql.EngineOpts{
|
||||||
Logger: nil,
|
Logger: nil,
|
||||||
Reg: nil,
|
Reg: nil,
|
||||||
MaxSamples: 50000000,
|
MaxSamples: 50000000,
|
||||||
Timeout: 100 * time.Second,
|
Timeout: 100 * time.Second,
|
||||||
}
|
}
|
||||||
engine := NewEngine(opts)
|
engine := promql.NewEngine(opts)
|
||||||
|
|
||||||
const interval = 10000 // 10s interval.
|
const interval = 10000 // 10s interval.
|
||||||
// A day of data plus 10k steps.
|
// A day of data plus 10k steps.
|
||||||
|
@ -324,7 +325,7 @@ func BenchmarkNativeHistograms(b *testing.B) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
opts := EngineOpts{
|
opts := promql.EngineOpts{
|
||||||
Logger: nil,
|
Logger: nil,
|
||||||
Reg: nil,
|
Reg: nil,
|
||||||
MaxSamples: 50000000,
|
MaxSamples: 50000000,
|
||||||
|
@ -338,7 +339,7 @@ func BenchmarkNativeHistograms(b *testing.B) {
|
||||||
|
|
||||||
for _, tc := range cases {
|
for _, tc := range cases {
|
||||||
b.Run(tc.name, func(b *testing.B) {
|
b.Run(tc.name, func(b *testing.B) {
|
||||||
ng := NewEngine(opts)
|
ng := promql.NewEngine(opts)
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
qry, err := ng.NewRangeQuery(context.Background(), testStorage, nil, tc.query, start, end, step)
|
qry, err := ng.NewRangeQuery(context.Background(), testStorage, nil, tc.query, start, end, step)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -573,7 +573,8 @@ func (ng *Engine) validateOpts(expr parser.Expr) error {
|
||||||
return validationErr
|
return validationErr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ng *Engine) newTestQuery(f func(context.Context) error) Query {
|
// NewTestQuery: inject special behaviour into Query for testing.
|
||||||
|
func (ng *Engine) NewTestQuery(f func(context.Context) error) Query {
|
||||||
qry := &query{
|
qry := &query{
|
||||||
q: "test statement",
|
q: "test statement",
|
||||||
stmt: parser.TestStmt(f),
|
stmt: parser.TestStmt(f),
|
||||||
|
|
82
promql/engine_internal_test.go
Normal file
82
promql/engine_internal_test.go
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
// Copyright 2024 The Prometheus Authors
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package promql
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/go-kit/log"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/prometheus/prometheus/promql/parser"
|
||||||
|
"github.com/prometheus/prometheus/util/annotations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRecoverEvaluatorRuntime(t *testing.T) {
|
||||||
|
var output []interface{}
|
||||||
|
logger := log.Logger(log.LoggerFunc(func(keyvals ...interface{}) error {
|
||||||
|
output = append(output, keyvals...)
|
||||||
|
return nil
|
||||||
|
}))
|
||||||
|
ev := &evaluator{logger: logger}
|
||||||
|
|
||||||
|
expr, _ := parser.ParseExpr("sum(up)")
|
||||||
|
|
||||||
|
var err error
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
require.EqualError(t, err, "unexpected error: runtime error: index out of range [123] with length 0")
|
||||||
|
require.Contains(t, output, "sum(up)")
|
||||||
|
}()
|
||||||
|
defer ev.recover(expr, nil, &err)
|
||||||
|
|
||||||
|
// Cause a runtime panic.
|
||||||
|
var a []int
|
||||||
|
a[123] = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRecoverEvaluatorError(t *testing.T) {
|
||||||
|
ev := &evaluator{logger: log.NewNopLogger()}
|
||||||
|
var err error
|
||||||
|
|
||||||
|
e := errors.New("custom error")
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
require.EqualError(t, err, e.Error())
|
||||||
|
}()
|
||||||
|
defer ev.recover(nil, nil, &err)
|
||||||
|
|
||||||
|
panic(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRecoverEvaluatorErrorWithWarnings(t *testing.T) {
|
||||||
|
ev := &evaluator{logger: log.NewNopLogger()}
|
||||||
|
var err error
|
||||||
|
var ws annotations.Annotations
|
||||||
|
|
||||||
|
warnings := annotations.New().Add(errors.New("custom warning"))
|
||||||
|
e := errWithWarnings{
|
||||||
|
err: errors.New("custom error"),
|
||||||
|
warnings: warnings,
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
require.EqualError(t, err, e.Error())
|
||||||
|
require.Equal(t, warnings, ws, "wrong warning message")
|
||||||
|
}()
|
||||||
|
defer ev.recover(nil, &ws, &err)
|
||||||
|
|
||||||
|
panic(e)
|
||||||
|
}
|
File diff suppressed because it is too large
Load diff
|
@ -948,15 +948,6 @@ func funcTimestamp(vals []parser.Value, args parser.Expressions, enh *EvalNodeHe
|
||||||
return enh.Out, nil
|
return enh.Out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func kahanSum(samples []float64) float64 {
|
|
||||||
var sum, c float64
|
|
||||||
|
|
||||||
for _, v := range samples {
|
|
||||||
sum, c = kahanSumInc(v, sum, c)
|
|
||||||
}
|
|
||||||
return sum + c
|
|
||||||
}
|
|
||||||
|
|
||||||
func kahanSumInc(inc, sum, c float64) (newSum, newC float64) {
|
func kahanSumInc(inc, sum, c float64) (newSum, newC float64) {
|
||||||
t := sum + inc
|
t := sum + inc
|
||||||
// Using Neumaier improvement, swap if next term larger than sum.
|
// Using Neumaier improvement, swap if next term larger than sum.
|
||||||
|
|
|
@ -11,11 +11,10 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
package promql
|
package promql_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"math"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -23,6 +22,7 @@ import (
|
||||||
|
|
||||||
"github.com/prometheus/prometheus/model/labels"
|
"github.com/prometheus/prometheus/model/labels"
|
||||||
"github.com/prometheus/prometheus/model/timestamp"
|
"github.com/prometheus/prometheus/model/timestamp"
|
||||||
|
"github.com/prometheus/prometheus/promql"
|
||||||
"github.com/prometheus/prometheus/promql/parser"
|
"github.com/prometheus/prometheus/promql/parser"
|
||||||
"github.com/prometheus/prometheus/util/teststorage"
|
"github.com/prometheus/prometheus/util/teststorage"
|
||||||
)
|
)
|
||||||
|
@ -33,13 +33,13 @@ func TestDeriv(t *testing.T) {
|
||||||
// so we test it by hand.
|
// so we test it by hand.
|
||||||
storage := teststorage.New(t)
|
storage := teststorage.New(t)
|
||||||
defer storage.Close()
|
defer storage.Close()
|
||||||
opts := EngineOpts{
|
opts := promql.EngineOpts{
|
||||||
Logger: nil,
|
Logger: nil,
|
||||||
Reg: nil,
|
Reg: nil,
|
||||||
MaxSamples: 10000,
|
MaxSamples: 10000,
|
||||||
Timeout: 10 * time.Second,
|
Timeout: 10 * time.Second,
|
||||||
}
|
}
|
||||||
engine := NewEngine(opts)
|
engine := promql.NewEngine(opts)
|
||||||
|
|
||||||
a := storage.Appender(context.Background())
|
a := storage.Appender(context.Background())
|
||||||
|
|
||||||
|
@ -70,19 +70,13 @@ func TestDeriv(t *testing.T) {
|
||||||
|
|
||||||
func TestFunctionList(t *testing.T) {
|
func TestFunctionList(t *testing.T) {
|
||||||
// Test that Functions and parser.Functions list the same functions.
|
// Test that Functions and parser.Functions list the same functions.
|
||||||
for i := range FunctionCalls {
|
for i := range promql.FunctionCalls {
|
||||||
_, ok := parser.Functions[i]
|
_, ok := parser.Functions[i]
|
||||||
require.True(t, ok, "function %s exists in promql package, but not in parser package", i)
|
require.True(t, ok, "function %s exists in promql package, but not in parser package", i)
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := range parser.Functions {
|
for i := range parser.Functions {
|
||||||
_, ok := FunctionCalls[i]
|
_, ok := promql.FunctionCalls[i]
|
||||||
require.True(t, ok, "function %s exists in parser package, but not in promql package", i)
|
require.True(t, ok, "function %s exists in parser package, but not in promql package", i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestKahanSum(t *testing.T) {
|
|
||||||
vals := []float64{1.0, math.Pow(10, 100), 1.0, -1 * math.Pow(10, 100)}
|
|
||||||
expected := 2.0
|
|
||||||
require.Equal(t, expected, kahanSum(vals))
|
|
||||||
}
|
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
package promql
|
package promql_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
@ -22,37 +22,30 @@ import (
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"golang.org/x/sync/errgroup"
|
"golang.org/x/sync/errgroup"
|
||||||
|
|
||||||
|
"github.com/prometheus/prometheus/promql"
|
||||||
|
"github.com/prometheus/prometheus/promql/promqltest"
|
||||||
"github.com/prometheus/prometheus/util/teststorage"
|
"github.com/prometheus/prometheus/util/teststorage"
|
||||||
)
|
)
|
||||||
|
|
||||||
func newTestEngine() *Engine {
|
func newTestEngine() *promql.Engine {
|
||||||
return NewEngine(EngineOpts{
|
return promqltest.NewTestEngine(false, 0, promqltest.DefaultMaxSamplesPerQuery)
|
||||||
Logger: nil,
|
|
||||||
Reg: nil,
|
|
||||||
MaxSamples: 10000,
|
|
||||||
Timeout: 100 * time.Second,
|
|
||||||
NoStepSubqueryIntervalFn: func(int64) int64 { return durationMilliseconds(1 * time.Minute) },
|
|
||||||
EnableAtModifier: true,
|
|
||||||
EnableNegativeOffset: true,
|
|
||||||
EnablePerStepStats: true,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEvaluations(t *testing.T) {
|
func TestEvaluations(t *testing.T) {
|
||||||
RunBuiltinTests(t, newTestEngine())
|
promqltest.RunBuiltinTests(t, newTestEngine())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run a lot of queries at the same time, to check for race conditions.
|
// Run a lot of queries at the same time, to check for race conditions.
|
||||||
func TestConcurrentRangeQueries(t *testing.T) {
|
func TestConcurrentRangeQueries(t *testing.T) {
|
||||||
stor := teststorage.New(t)
|
stor := teststorage.New(t)
|
||||||
defer stor.Close()
|
defer stor.Close()
|
||||||
opts := EngineOpts{
|
opts := promql.EngineOpts{
|
||||||
Logger: nil,
|
Logger: nil,
|
||||||
Reg: nil,
|
Reg: nil,
|
||||||
MaxSamples: 50000000,
|
MaxSamples: 50000000,
|
||||||
Timeout: 100 * time.Second,
|
Timeout: 100 * time.Second,
|
||||||
}
|
}
|
||||||
engine := NewEngine(opts)
|
engine := promql.NewEngine(opts)
|
||||||
|
|
||||||
const interval = 10000 // 10s interval.
|
const interval = 10000 // 10s interval.
|
||||||
// A day of data plus 10k steps.
|
// A day of data plus 10k steps.
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
package promql
|
package promqltest
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
@ -19,7 +19,6 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"math"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -33,16 +32,16 @@ import (
|
||||||
"github.com/prometheus/prometheus/model/histogram"
|
"github.com/prometheus/prometheus/model/histogram"
|
||||||
"github.com/prometheus/prometheus/model/labels"
|
"github.com/prometheus/prometheus/model/labels"
|
||||||
"github.com/prometheus/prometheus/model/timestamp"
|
"github.com/prometheus/prometheus/model/timestamp"
|
||||||
|
"github.com/prometheus/prometheus/promql"
|
||||||
"github.com/prometheus/prometheus/promql/parser"
|
"github.com/prometheus/prometheus/promql/parser"
|
||||||
"github.com/prometheus/prometheus/promql/parser/posrange"
|
"github.com/prometheus/prometheus/promql/parser/posrange"
|
||||||
"github.com/prometheus/prometheus/storage"
|
"github.com/prometheus/prometheus/storage"
|
||||||
|
"github.com/prometheus/prometheus/util/almost"
|
||||||
"github.com/prometheus/prometheus/util/teststorage"
|
"github.com/prometheus/prometheus/util/teststorage"
|
||||||
"github.com/prometheus/prometheus/util/testutil"
|
"github.com/prometheus/prometheus/util/testutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
minNormal = math.Float64frombits(0x0010000000000000) // The smallest positive normal value of type float64.
|
|
||||||
|
|
||||||
patSpace = regexp.MustCompile("[\t ]+")
|
patSpace = regexp.MustCompile("[\t ]+")
|
||||||
patLoad = regexp.MustCompile(`^load\s+(.+?)$`)
|
patLoad = regexp.MustCompile(`^load\s+(.+?)$`)
|
||||||
patEvalInstant = regexp.MustCompile(`^eval(?:_(fail|ordered))?\s+instant\s+(?:at\s+(.+?))?\s+(.+)$`)
|
patEvalInstant = regexp.MustCompile(`^eval(?:_(fail|ordered))?\s+instant\s+(?:at\s+(.+?))?\s+(.+)$`)
|
||||||
|
@ -50,7 +49,8 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
defaultEpsilon = 0.000001 // Relative error allowed for sample values.
|
defaultEpsilon = 0.000001 // Relative error allowed for sample values.
|
||||||
|
DefaultMaxSamplesPerQuery = 10000
|
||||||
)
|
)
|
||||||
|
|
||||||
var testStartTime = time.Unix(0, 0).UTC()
|
var testStartTime = time.Unix(0, 0).UTC()
|
||||||
|
@ -72,8 +72,22 @@ func LoadedStorage(t testutil.T, input string) *teststorage.TestStorage {
|
||||||
return test.storage
|
return test.storage
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewTestEngine(enablePerStepStats bool, lookbackDelta time.Duration, maxSamples int) *promql.Engine {
|
||||||
|
return promql.NewEngine(promql.EngineOpts{
|
||||||
|
Logger: nil,
|
||||||
|
Reg: nil,
|
||||||
|
MaxSamples: maxSamples,
|
||||||
|
Timeout: 100 * time.Second,
|
||||||
|
NoStepSubqueryIntervalFn: func(int64) int64 { return durationMilliseconds(1 * time.Minute) },
|
||||||
|
EnableAtModifier: true,
|
||||||
|
EnableNegativeOffset: true,
|
||||||
|
EnablePerStepStats: enablePerStepStats,
|
||||||
|
LookbackDelta: lookbackDelta,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// RunBuiltinTests runs an acceptance test suite against the provided engine.
|
// RunBuiltinTests runs an acceptance test suite against the provided engine.
|
||||||
func RunBuiltinTests(t *testing.T, engine QueryEngine) {
|
func RunBuiltinTests(t *testing.T, engine promql.QueryEngine) {
|
||||||
t.Cleanup(func() { parser.EnableExperimentalFunctions = false })
|
t.Cleanup(func() { parser.EnableExperimentalFunctions = false })
|
||||||
parser.EnableExperimentalFunctions = true
|
parser.EnableExperimentalFunctions = true
|
||||||
|
|
||||||
|
@ -90,11 +104,11 @@ func RunBuiltinTests(t *testing.T, engine QueryEngine) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// RunTest parses and runs the test against the provided engine.
|
// RunTest parses and runs the test against the provided engine.
|
||||||
func RunTest(t testutil.T, input string, engine QueryEngine) {
|
func RunTest(t testutil.T, input string, engine promql.QueryEngine) {
|
||||||
require.NoError(t, runTest(t, input, engine))
|
require.NoError(t, runTest(t, input, engine))
|
||||||
}
|
}
|
||||||
|
|
||||||
func runTest(t testutil.T, input string, engine QueryEngine) error {
|
func runTest(t testutil.T, input string, engine promql.QueryEngine) error {
|
||||||
test, err := newTest(t, input)
|
test, err := newTest(t, input)
|
||||||
|
|
||||||
// Why do this before checking err? newTest() can create the test storage and then return an error,
|
// Why do this before checking err? newTest() can create the test storage and then return an error,
|
||||||
|
@ -368,7 +382,7 @@ func (*evalCmd) testCmd() {}
|
||||||
type loadCmd struct {
|
type loadCmd struct {
|
||||||
gap time.Duration
|
gap time.Duration
|
||||||
metrics map[uint64]labels.Labels
|
metrics map[uint64]labels.Labels
|
||||||
defs map[uint64][]Sample
|
defs map[uint64][]promql.Sample
|
||||||
exemplars map[uint64][]exemplar.Exemplar
|
exemplars map[uint64][]exemplar.Exemplar
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -376,7 +390,7 @@ func newLoadCmd(gap time.Duration) *loadCmd {
|
||||||
return &loadCmd{
|
return &loadCmd{
|
||||||
gap: gap,
|
gap: gap,
|
||||||
metrics: map[uint64]labels.Labels{},
|
metrics: map[uint64]labels.Labels{},
|
||||||
defs: map[uint64][]Sample{},
|
defs: map[uint64][]promql.Sample{},
|
||||||
exemplars: map[uint64][]exemplar.Exemplar{},
|
exemplars: map[uint64][]exemplar.Exemplar{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -389,11 +403,11 @@ func (cmd loadCmd) String() string {
|
||||||
func (cmd *loadCmd) set(m labels.Labels, vals ...parser.SequenceValue) {
|
func (cmd *loadCmd) set(m labels.Labels, vals ...parser.SequenceValue) {
|
||||||
h := m.Hash()
|
h := m.Hash()
|
||||||
|
|
||||||
samples := make([]Sample, 0, len(vals))
|
samples := make([]promql.Sample, 0, len(vals))
|
||||||
ts := testStartTime
|
ts := testStartTime
|
||||||
for _, v := range vals {
|
for _, v := range vals {
|
||||||
if !v.Omitted {
|
if !v.Omitted {
|
||||||
samples = append(samples, Sample{
|
samples = append(samples, promql.Sample{
|
||||||
T: ts.UnixNano() / int64(time.Millisecond/time.Nanosecond),
|
T: ts.UnixNano() / int64(time.Millisecond/time.Nanosecond),
|
||||||
F: v.Value,
|
F: v.Value,
|
||||||
H: v.Histogram,
|
H: v.Histogram,
|
||||||
|
@ -419,7 +433,7 @@ func (cmd *loadCmd) append(a storage.Appender) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func appendSample(a storage.Appender, s Sample, m labels.Labels) error {
|
func appendSample(a storage.Appender, s promql.Sample, m labels.Labels) error {
|
||||||
if s.H != nil {
|
if s.H != nil {
|
||||||
if _, err := a.AppendHistogram(0, m, s.T, nil, s.H); err != nil {
|
if _, err := a.AppendHistogram(0, m, s.T, nil, s.H); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -503,7 +517,7 @@ func (ev *evalCmd) expectMetric(pos int, m labels.Labels, vals ...parser.Sequenc
|
||||||
// compareResult compares the result value with the defined expectation.
|
// compareResult compares the result value with the defined expectation.
|
||||||
func (ev *evalCmd) compareResult(result parser.Value) error {
|
func (ev *evalCmd) compareResult(result parser.Value) error {
|
||||||
switch val := result.(type) {
|
switch val := result.(type) {
|
||||||
case Matrix:
|
case promql.Matrix:
|
||||||
if ev.ordered {
|
if ev.ordered {
|
||||||
return fmt.Errorf("expected ordered result, but query returned a matrix")
|
return fmt.Errorf("expected ordered result, but query returned a matrix")
|
||||||
}
|
}
|
||||||
|
@ -521,8 +535,8 @@ func (ev *evalCmd) compareResult(result parser.Value) error {
|
||||||
seen[hash] = true
|
seen[hash] = true
|
||||||
exp := ev.expected[hash]
|
exp := ev.expected[hash]
|
||||||
|
|
||||||
var expectedFloats []FPoint
|
var expectedFloats []promql.FPoint
|
||||||
var expectedHistograms []HPoint
|
var expectedHistograms []promql.HPoint
|
||||||
|
|
||||||
for i, e := range exp.vals {
|
for i, e := range exp.vals {
|
||||||
ts := ev.start.Add(time.Duration(i) * ev.step)
|
ts := ev.start.Add(time.Duration(i) * ev.step)
|
||||||
|
@ -534,9 +548,9 @@ func (ev *evalCmd) compareResult(result parser.Value) error {
|
||||||
t := ts.UnixNano() / int64(time.Millisecond/time.Nanosecond)
|
t := ts.UnixNano() / int64(time.Millisecond/time.Nanosecond)
|
||||||
|
|
||||||
if e.Histogram != nil {
|
if e.Histogram != nil {
|
||||||
expectedHistograms = append(expectedHistograms, HPoint{T: t, H: e.Histogram})
|
expectedHistograms = append(expectedHistograms, promql.HPoint{T: t, H: e.Histogram})
|
||||||
} else if !e.Omitted {
|
} else if !e.Omitted {
|
||||||
expectedFloats = append(expectedFloats, FPoint{T: t, F: e.Value})
|
expectedFloats = append(expectedFloats, promql.FPoint{T: t, F: e.Value})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -551,7 +565,7 @@ func (ev *evalCmd) compareResult(result parser.Value) error {
|
||||||
return fmt.Errorf("expected float value at index %v for %s to have timestamp %v, but it had timestamp %v (result has %s)", i, ev.metrics[hash], expected.T, actual.T, formatSeriesResult(s))
|
return fmt.Errorf("expected float value at index %v for %s to have timestamp %v, but it had timestamp %v (result has %s)", i, ev.metrics[hash], expected.T, actual.T, formatSeriesResult(s))
|
||||||
}
|
}
|
||||||
|
|
||||||
if !almostEqual(actual.F, expected.F, defaultEpsilon) {
|
if !almost.Equal(actual.F, expected.F, defaultEpsilon) {
|
||||||
return fmt.Errorf("expected float value at index %v (t=%v) for %s to be %v, but got %v (result has %s)", i, actual.T, ev.metrics[hash], expected.F, actual.F, formatSeriesResult(s))
|
return fmt.Errorf("expected float value at index %v (t=%v) for %s to be %v, but got %v (result has %s)", i, actual.T, ev.metrics[hash], expected.F, actual.F, formatSeriesResult(s))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -575,7 +589,7 @@ func (ev *evalCmd) compareResult(result parser.Value) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case Vector:
|
case promql.Vector:
|
||||||
seen := map[uint64]bool{}
|
seen := map[uint64]bool{}
|
||||||
for pos, v := range val {
|
for pos, v := range val {
|
||||||
fp := v.Metric.Hash()
|
fp := v.Metric.Hash()
|
||||||
|
@ -601,7 +615,7 @@ func (ev *evalCmd) compareResult(result parser.Value) error {
|
||||||
if expH != nil && !expH.Compact(0).Equals(v.H) {
|
if expH != nil && !expH.Compact(0).Equals(v.H) {
|
||||||
return fmt.Errorf("expected %v for %s but got %s", HistogramTestExpression(expH), v.Metric, HistogramTestExpression(v.H))
|
return fmt.Errorf("expected %v for %s but got %s", HistogramTestExpression(expH), v.Metric, HistogramTestExpression(v.H))
|
||||||
}
|
}
|
||||||
if !almostEqual(exp0.Value, v.F, defaultEpsilon) {
|
if !almost.Equal(exp0.Value, v.F, defaultEpsilon) {
|
||||||
return fmt.Errorf("expected %v for %s but got %v", exp0.Value, v.Metric, v.F)
|
return fmt.Errorf("expected %v for %s but got %v", exp0.Value, v.Metric, v.F)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -613,7 +627,7 @@ func (ev *evalCmd) compareResult(result parser.Value) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case Scalar:
|
case promql.Scalar:
|
||||||
if len(ev.expected) != 1 {
|
if len(ev.expected) != 1 {
|
||||||
return fmt.Errorf("expected vector result, but got scalar %s", val.String())
|
return fmt.Errorf("expected vector result, but got scalar %s", val.String())
|
||||||
}
|
}
|
||||||
|
@ -621,7 +635,7 @@ func (ev *evalCmd) compareResult(result parser.Value) error {
|
||||||
if exp0.Histogram != nil {
|
if exp0.Histogram != nil {
|
||||||
return fmt.Errorf("expected Histogram %v but got scalar %s", exp0.Histogram.TestExpression(), val.String())
|
return fmt.Errorf("expected Histogram %v but got scalar %s", exp0.Histogram.TestExpression(), val.String())
|
||||||
}
|
}
|
||||||
if !almostEqual(exp0.Value, val.V, defaultEpsilon) {
|
if !almost.Equal(exp0.Value, val.V, defaultEpsilon) {
|
||||||
return fmt.Errorf("expected Scalar %v but got %v", val.V, exp0.Value)
|
return fmt.Errorf("expected Scalar %v but got %v", val.V, exp0.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -631,7 +645,7 @@ func (ev *evalCmd) compareResult(result parser.Value) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func formatSeriesResult(s Series) string {
|
func formatSeriesResult(s promql.Series) string {
|
||||||
floatPlural := "s"
|
floatPlural := "s"
|
||||||
histogramPlural := "s"
|
histogramPlural := "s"
|
||||||
|
|
||||||
|
@ -678,8 +692,7 @@ func atModifierTestCases(exprStr string, evalTime time.Time) ([]atModifierTestCa
|
||||||
// If there is a subquery, then the selectors inside it don't get the @ timestamp.
|
// If there is a subquery, then the selectors inside it don't get the @ timestamp.
|
||||||
// If any selector already has the @ timestamp set, then it is untouched.
|
// If any selector already has the @ timestamp set, then it is untouched.
|
||||||
parser.Inspect(expr, func(node parser.Node, path []parser.Node) error {
|
parser.Inspect(expr, func(node parser.Node, path []parser.Node) error {
|
||||||
_, _, subqTs := subqueryTimes(path)
|
if hasAtModifier(path) {
|
||||||
if subqTs != nil {
|
|
||||||
// There is a subquery with timestamp in the path,
|
// There is a subquery with timestamp in the path,
|
||||||
// hence don't change any timestamps further.
|
// hence don't change any timestamps further.
|
||||||
return nil
|
return nil
|
||||||
|
@ -701,7 +714,7 @@ func atModifierTestCases(exprStr string, evalTime time.Time) ([]atModifierTestCa
|
||||||
}
|
}
|
||||||
|
|
||||||
case *parser.Call:
|
case *parser.Call:
|
||||||
_, ok := AtModifierUnsafeFunctions[n.Func.Name]
|
_, ok := promql.AtModifierUnsafeFunctions[n.Func.Name]
|
||||||
containsNonStepInvariant = containsNonStepInvariant || ok
|
containsNonStepInvariant = containsNonStepInvariant || ok
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -729,8 +742,19 @@ func atModifierTestCases(exprStr string, evalTime time.Time) ([]atModifierTestCa
|
||||||
return testCases, nil
|
return testCases, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func hasAtModifier(path []parser.Node) bool {
|
||||||
|
for _, node := range path {
|
||||||
|
if n, ok := node.(*parser.SubqueryExpr); ok {
|
||||||
|
if n.Timestamp != nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// exec processes a single step of the test.
|
// exec processes a single step of the test.
|
||||||
func (t *test) exec(tc testCommand, engine QueryEngine) error {
|
func (t *test) exec(tc testCommand, engine promql.QueryEngine) error {
|
||||||
switch cmd := tc.(type) {
|
switch cmd := tc.(type) {
|
||||||
case *clearCmd:
|
case *clearCmd:
|
||||||
t.clear()
|
t.clear()
|
||||||
|
@ -755,7 +779,7 @@ func (t *test) exec(tc testCommand, engine QueryEngine) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *test) execEval(cmd *evalCmd, engine QueryEngine) error {
|
func (t *test) execEval(cmd *evalCmd, engine promql.QueryEngine) error {
|
||||||
if cmd.isRange {
|
if cmd.isRange {
|
||||||
return t.execRangeEval(cmd, engine)
|
return t.execRangeEval(cmd, engine)
|
||||||
}
|
}
|
||||||
|
@ -763,7 +787,7 @@ func (t *test) execEval(cmd *evalCmd, engine QueryEngine) error {
|
||||||
return t.execInstantEval(cmd, engine)
|
return t.execInstantEval(cmd, engine)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *test) execRangeEval(cmd *evalCmd, engine QueryEngine) error {
|
func (t *test) execRangeEval(cmd *evalCmd, engine promql.QueryEngine) error {
|
||||||
q, err := engine.NewRangeQuery(t.context, t.storage, nil, cmd.expr, cmd.start, cmd.end, cmd.step)
|
q, err := engine.NewRangeQuery(t.context, t.storage, nil, cmd.expr, cmd.start, cmd.end, cmd.step)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error creating range query for %q (line %d): %w", cmd.expr, cmd.line, err)
|
return fmt.Errorf("error creating range query for %q (line %d): %w", cmd.expr, cmd.line, err)
|
||||||
|
@ -788,7 +812,7 @@ func (t *test) execRangeEval(cmd *evalCmd, engine QueryEngine) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *test) execInstantEval(cmd *evalCmd, engine QueryEngine) error {
|
func (t *test) execInstantEval(cmd *evalCmd, engine promql.QueryEngine) error {
|
||||||
queries, err := atModifierTestCases(cmd.expr, cmd.start)
|
queries, err := atModifierTestCases(cmd.expr, cmd.start)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -830,29 +854,29 @@ func (t *test) execInstantEval(cmd *evalCmd, engine QueryEngine) error {
|
||||||
// Range queries are always sorted by labels, so skip this test case that expects results in a particular order.
|
// Range queries are always sorted by labels, so skip this test case that expects results in a particular order.
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
mat := rangeRes.Value.(Matrix)
|
mat := rangeRes.Value.(promql.Matrix)
|
||||||
if err := assertMatrixSorted(mat); err != nil {
|
if err := assertMatrixSorted(mat); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
vec := make(Vector, 0, len(mat))
|
vec := make(promql.Vector, 0, len(mat))
|
||||||
for _, series := range mat {
|
for _, series := range mat {
|
||||||
// We expect either Floats or Histograms.
|
// We expect either Floats or Histograms.
|
||||||
for _, point := range series.Floats {
|
for _, point := range series.Floats {
|
||||||
if point.T == timeMilliseconds(iq.evalTime) {
|
if point.T == timeMilliseconds(iq.evalTime) {
|
||||||
vec = append(vec, Sample{Metric: series.Metric, T: point.T, F: point.F})
|
vec = append(vec, promql.Sample{Metric: series.Metric, T: point.T, F: point.F})
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, point := range series.Histograms {
|
for _, point := range series.Histograms {
|
||||||
if point.T == timeMilliseconds(iq.evalTime) {
|
if point.T == timeMilliseconds(iq.evalTime) {
|
||||||
vec = append(vec, Sample{Metric: series.Metric, T: point.T, H: point.H})
|
vec = append(vec, promql.Sample{Metric: series.Metric, T: point.T, H: point.H})
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if _, ok := res.Value.(Scalar); ok {
|
if _, ok := res.Value.(promql.Scalar); ok {
|
||||||
err = cmd.compareResult(Scalar{V: vec[0].F})
|
err = cmd.compareResult(promql.Scalar{V: vec[0].F})
|
||||||
} else {
|
} else {
|
||||||
err = cmd.compareResult(vec)
|
err = cmd.compareResult(vec)
|
||||||
}
|
}
|
||||||
|
@ -864,7 +888,7 @@ func (t *test) execInstantEval(cmd *evalCmd, engine QueryEngine) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func assertMatrixSorted(m Matrix) error {
|
func assertMatrixSorted(m promql.Matrix) error {
|
||||||
if len(m) <= 1 {
|
if len(m) <= 1 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -894,29 +918,6 @@ func (t *test) clear() {
|
||||||
t.context, t.cancelCtx = context.WithCancel(context.Background())
|
t.context, t.cancelCtx = context.WithCancel(context.Background())
|
||||||
}
|
}
|
||||||
|
|
||||||
// almostEqual returns true if a and b differ by less than their sum
|
|
||||||
// multiplied by epsilon.
|
|
||||||
func almostEqual(a, b, epsilon float64) bool {
|
|
||||||
// NaN has no equality but for testing we still want to know whether both values
|
|
||||||
// are NaN.
|
|
||||||
if math.IsNaN(a) && math.IsNaN(b) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cf. http://floating-point-gui.de/errors/comparison/
|
|
||||||
if a == b {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
absSum := math.Abs(a) + math.Abs(b)
|
|
||||||
diff := math.Abs(a - b)
|
|
||||||
|
|
||||||
if a == 0 || b == 0 || absSum < minNormal {
|
|
||||||
return diff < epsilon*minNormal
|
|
||||||
}
|
|
||||||
return diff/math.Min(absSum, math.MaxFloat64) < epsilon
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseNumber(s string) (float64, error) {
|
func parseNumber(s string) (float64, error) {
|
||||||
n, err := strconv.ParseInt(s, 0, 64)
|
n, err := strconv.ParseInt(s, 0, 64)
|
||||||
f := float64(n)
|
f := float64(n)
|
||||||
|
@ -937,7 +938,7 @@ type LazyLoader struct {
|
||||||
storage storage.Storage
|
storage storage.Storage
|
||||||
SubqueryInterval time.Duration
|
SubqueryInterval time.Duration
|
||||||
|
|
||||||
queryEngine *Engine
|
queryEngine *promql.Engine
|
||||||
context context.Context
|
context context.Context
|
||||||
cancelCtx context.CancelFunc
|
cancelCtx context.CancelFunc
|
||||||
|
|
||||||
|
@ -1004,7 +1005,7 @@ func (ll *LazyLoader) clear() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
opts := EngineOpts{
|
opts := promql.EngineOpts{
|
||||||
Logger: nil,
|
Logger: nil,
|
||||||
Reg: nil,
|
Reg: nil,
|
||||||
MaxSamples: 10000,
|
MaxSamples: 10000,
|
||||||
|
@ -1014,7 +1015,7 @@ func (ll *LazyLoader) clear() error {
|
||||||
EnableNegativeOffset: ll.opts.EnableNegativeOffset,
|
EnableNegativeOffset: ll.opts.EnableNegativeOffset,
|
||||||
}
|
}
|
||||||
|
|
||||||
ll.queryEngine = NewEngine(opts)
|
ll.queryEngine = promql.NewEngine(opts)
|
||||||
ll.context, ll.cancelCtx = context.WithCancel(context.Background())
|
ll.context, ll.cancelCtx = context.WithCancel(context.Background())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -1048,7 +1049,7 @@ func (ll *LazyLoader) WithSamplesTill(ts time.Time, fn func(error)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// QueryEngine returns the LazyLoader's query engine.
|
// QueryEngine returns the LazyLoader's query engine.
|
||||||
func (ll *LazyLoader) QueryEngine() *Engine {
|
func (ll *LazyLoader) QueryEngine() *promql.Engine {
|
||||||
return ll.queryEngine
|
return ll.queryEngine
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1074,3 +1075,17 @@ func (ll *LazyLoader) Close() error {
|
||||||
ll.cancelCtx()
|
ll.cancelCtx()
|
||||||
return ll.storage.Close()
|
return ll.storage.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func makeInt64Pointer(val int64) *int64 {
|
||||||
|
valp := new(int64)
|
||||||
|
*valp = val
|
||||||
|
return valp
|
||||||
|
}
|
||||||
|
|
||||||
|
func timeMilliseconds(t time.Time) int64 {
|
||||||
|
return t.UnixNano() / int64(time.Millisecond/time.Nanosecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
func durationMilliseconds(d time.Duration) int64 {
|
||||||
|
return int64(d / (time.Millisecond / time.Nanosecond))
|
||||||
|
}
|
|
@ -11,7 +11,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
package promql
|
package promqltest
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math"
|
"math"
|
||||||
|
@ -21,14 +21,15 @@ import (
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/prometheus/prometheus/model/labels"
|
"github.com/prometheus/prometheus/model/labels"
|
||||||
|
"github.com/prometheus/prometheus/promql"
|
||||||
"github.com/prometheus/prometheus/tsdb/chunkenc"
|
"github.com/prometheus/prometheus/tsdb/chunkenc"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestLazyLoader_WithSamplesTill(t *testing.T) {
|
func TestLazyLoader_WithSamplesTill(t *testing.T) {
|
||||||
type testCase struct {
|
type testCase struct {
|
||||||
ts time.Time
|
ts time.Time
|
||||||
series []Series // Each series is checked separately. Need not mention all series here.
|
series []promql.Series // Each series is checked separately. Need not mention all series here.
|
||||||
checkOnlyError bool // If this is true, series is not checked.
|
checkOnlyError bool // If this is true, series is not checked.
|
||||||
}
|
}
|
||||||
|
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
|
@ -44,33 +45,33 @@ func TestLazyLoader_WithSamplesTill(t *testing.T) {
|
||||||
testCases: []testCase{
|
testCases: []testCase{
|
||||||
{
|
{
|
||||||
ts: time.Unix(40, 0),
|
ts: time.Unix(40, 0),
|
||||||
series: []Series{
|
series: []promql.Series{
|
||||||
{
|
{
|
||||||
Metric: labels.FromStrings("__name__", "metric1"),
|
Metric: labels.FromStrings("__name__", "metric1"),
|
||||||
Floats: []FPoint{
|
Floats: []promql.FPoint{
|
||||||
{0, 1}, {10000, 2}, {20000, 3}, {30000, 4}, {40000, 5},
|
{T: 0, F: 1}, {T: 10000, F: 2}, {T: 20000, F: 3}, {T: 30000, F: 4}, {T: 40000, F: 5},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ts: time.Unix(10, 0),
|
ts: time.Unix(10, 0),
|
||||||
series: []Series{
|
series: []promql.Series{
|
||||||
{
|
{
|
||||||
Metric: labels.FromStrings("__name__", "metric1"),
|
Metric: labels.FromStrings("__name__", "metric1"),
|
||||||
Floats: []FPoint{
|
Floats: []promql.FPoint{
|
||||||
{0, 1}, {10000, 2}, {20000, 3}, {30000, 4}, {40000, 5},
|
{T: 0, F: 1}, {T: 10000, F: 2}, {T: 20000, F: 3}, {T: 30000, F: 4}, {T: 40000, F: 5},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ts: time.Unix(60, 0),
|
ts: time.Unix(60, 0),
|
||||||
series: []Series{
|
series: []promql.Series{
|
||||||
{
|
{
|
||||||
Metric: labels.FromStrings("__name__", "metric1"),
|
Metric: labels.FromStrings("__name__", "metric1"),
|
||||||
Floats: []FPoint{
|
Floats: []promql.FPoint{
|
||||||
{0, 1}, {10000, 2}, {20000, 3}, {30000, 4}, {40000, 5}, {50000, 6}, {60000, 7},
|
{T: 0, F: 1}, {T: 10000, F: 2}, {T: 20000, F: 3}, {T: 30000, F: 4}, {T: 40000, F: 5}, {T: 50000, F: 6}, {T: 60000, F: 7},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -86,17 +87,17 @@ func TestLazyLoader_WithSamplesTill(t *testing.T) {
|
||||||
testCases: []testCase{
|
testCases: []testCase{
|
||||||
{ // Adds all samples of metric1.
|
{ // Adds all samples of metric1.
|
||||||
ts: time.Unix(70, 0),
|
ts: time.Unix(70, 0),
|
||||||
series: []Series{
|
series: []promql.Series{
|
||||||
{
|
{
|
||||||
Metric: labels.FromStrings("__name__", "metric1"),
|
Metric: labels.FromStrings("__name__", "metric1"),
|
||||||
Floats: []FPoint{
|
Floats: []promql.FPoint{
|
||||||
{0, 1}, {10000, 1}, {20000, 1}, {30000, 1}, {40000, 1}, {50000, 1},
|
{T: 0, F: 1}, {T: 10000, F: 1}, {T: 20000, F: 1}, {T: 30000, F: 1}, {T: 40000, F: 1}, {T: 50000, F: 1},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Metric: labels.FromStrings("__name__", "metric2"),
|
Metric: labels.FromStrings("__name__", "metric2"),
|
||||||
Floats: []FPoint{
|
Floats: []promql.FPoint{
|
||||||
{0, 1}, {10000, 2}, {20000, 3}, {30000, 4}, {40000, 5}, {50000, 6}, {60000, 7}, {70000, 8},
|
{T: 0, F: 1}, {T: 10000, F: 2}, {T: 20000, F: 3}, {T: 30000, F: 4}, {T: 40000, F: 5}, {T: 50000, F: 6}, {T: 60000, F: 7}, {T: 70000, F: 8},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -140,13 +141,13 @@ func TestLazyLoader_WithSamplesTill(t *testing.T) {
|
||||||
require.False(t, ss.Next(), "Expecting only 1 series")
|
require.False(t, ss.Next(), "Expecting only 1 series")
|
||||||
|
|
||||||
// Convert `storage.Series` to `promql.Series`.
|
// Convert `storage.Series` to `promql.Series`.
|
||||||
got := Series{
|
got := promql.Series{
|
||||||
Metric: storageSeries.Labels(),
|
Metric: storageSeries.Labels(),
|
||||||
}
|
}
|
||||||
it := storageSeries.Iterator(nil)
|
it := storageSeries.Iterator(nil)
|
||||||
for it.Next() == chunkenc.ValFloat {
|
for it.Next() == chunkenc.ValFloat {
|
||||||
t, v := it.At()
|
t, v := it.At()
|
||||||
got.Floats = append(got.Floats, FPoint{T: t, F: v})
|
got.Floats = append(got.Floats, promql.FPoint{T: t, F: v})
|
||||||
}
|
}
|
||||||
require.NoError(t, it.Err())
|
require.NoError(t, it.Err())
|
||||||
|
|
||||||
|
@ -450,7 +451,7 @@ eval range from 0 to 5m step 5m testmetric
|
||||||
|
|
||||||
for name, testCase := range testCases {
|
for name, testCase := range testCases {
|
||||||
t.Run(name, func(t *testing.T) {
|
t.Run(name, func(t *testing.T) {
|
||||||
err := runTest(t, testCase.input, newTestEngine())
|
err := runTest(t, testCase.input, NewTestEngine(false, 0, DefaultMaxSamplesPerQuery))
|
||||||
|
|
||||||
if testCase.expectedError == "" {
|
if testCase.expectedError == "" {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -463,42 +464,42 @@ eval range from 0 to 5m step 5m testmetric
|
||||||
|
|
||||||
func TestAssertMatrixSorted(t *testing.T) {
|
func TestAssertMatrixSorted(t *testing.T) {
|
||||||
testCases := map[string]struct {
|
testCases := map[string]struct {
|
||||||
matrix Matrix
|
matrix promql.Matrix
|
||||||
expectedError string
|
expectedError string
|
||||||
}{
|
}{
|
||||||
"empty matrix": {
|
"empty matrix": {
|
||||||
matrix: Matrix{},
|
matrix: promql.Matrix{},
|
||||||
},
|
},
|
||||||
"matrix with one series": {
|
"matrix with one series": {
|
||||||
matrix: Matrix{
|
matrix: promql.Matrix{
|
||||||
Series{Metric: labels.FromStrings("the_label", "value_1")},
|
promql.Series{Metric: labels.FromStrings("the_label", "value_1")},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"matrix with two series, series in sorted order": {
|
"matrix with two series, series in sorted order": {
|
||||||
matrix: Matrix{
|
matrix: promql.Matrix{
|
||||||
Series{Metric: labels.FromStrings("the_label", "value_1")},
|
promql.Series{Metric: labels.FromStrings("the_label", "value_1")},
|
||||||
Series{Metric: labels.FromStrings("the_label", "value_2")},
|
promql.Series{Metric: labels.FromStrings("the_label", "value_2")},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"matrix with two series, series in reverse order": {
|
"matrix with two series, series in reverse order": {
|
||||||
matrix: Matrix{
|
matrix: promql.Matrix{
|
||||||
Series{Metric: labels.FromStrings("the_label", "value_2")},
|
promql.Series{Metric: labels.FromStrings("the_label", "value_2")},
|
||||||
Series{Metric: labels.FromStrings("the_label", "value_1")},
|
promql.Series{Metric: labels.FromStrings("the_label", "value_1")},
|
||||||
},
|
},
|
||||||
expectedError: `matrix results should always be sorted by labels, but matrix is not sorted: series at index 1 with labels {the_label="value_1"} sorts before series at index 0 with labels {the_label="value_2"}`,
|
expectedError: `matrix results should always be sorted by labels, but matrix is not sorted: series at index 1 with labels {the_label="value_1"} sorts before series at index 0 with labels {the_label="value_2"}`,
|
||||||
},
|
},
|
||||||
"matrix with three series, series in sorted order": {
|
"matrix with three series, series in sorted order": {
|
||||||
matrix: Matrix{
|
matrix: promql.Matrix{
|
||||||
Series{Metric: labels.FromStrings("the_label", "value_1")},
|
promql.Series{Metric: labels.FromStrings("the_label", "value_1")},
|
||||||
Series{Metric: labels.FromStrings("the_label", "value_2")},
|
promql.Series{Metric: labels.FromStrings("the_label", "value_2")},
|
||||||
Series{Metric: labels.FromStrings("the_label", "value_3")},
|
promql.Series{Metric: labels.FromStrings("the_label", "value_3")},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"matrix with three series, series not in sorted order": {
|
"matrix with three series, series not in sorted order": {
|
||||||
matrix: Matrix{
|
matrix: promql.Matrix{
|
||||||
Series{Metric: labels.FromStrings("the_label", "value_1")},
|
promql.Series{Metric: labels.FromStrings("the_label", "value_1")},
|
||||||
Series{Metric: labels.FromStrings("the_label", "value_3")},
|
promql.Series{Metric: labels.FromStrings("the_label", "value_3")},
|
||||||
Series{Metric: labels.FromStrings("the_label", "value_2")},
|
promql.Series{Metric: labels.FromStrings("the_label", "value_2")},
|
||||||
},
|
},
|
||||||
expectedError: `matrix results should always be sorted by labels, but matrix is not sorted: series at index 2 with labels {the_label="value_2"} sorts before series at index 1 with labels {the_label="value_3"}`,
|
expectedError: `matrix results should always be sorted by labels, but matrix is not sorted: series at index 2 with labels {the_label="value_2"} sorts before series at index 1 with labels {the_label="value_3"}`,
|
||||||
},
|
},
|
|
@ -764,6 +764,14 @@ eval instant at 1m avg_over_time(metric10[1m])
|
||||||
eval instant at 1m sum_over_time(metric10[1m])/count_over_time(metric10[1m])
|
eval instant at 1m sum_over_time(metric10[1m])/count_over_time(metric10[1m])
|
||||||
{} 0
|
{} 0
|
||||||
|
|
||||||
|
# Test if very big intermediate values cause loss of detail.
|
||||||
|
clear
|
||||||
|
load 10s
|
||||||
|
metric 1 1e100 1 -1e100
|
||||||
|
|
||||||
|
eval instant at 1m sum_over_time(metric[1m])
|
||||||
|
{} 2
|
||||||
|
|
||||||
# Tests for stddev_over_time and stdvar_over_time.
|
# Tests for stddev_over_time and stdvar_over_time.
|
||||||
clear
|
clear
|
||||||
load 10s
|
load 10s
|
|
@ -20,6 +20,7 @@ import (
|
||||||
|
|
||||||
"github.com/prometheus/prometheus/model/histogram"
|
"github.com/prometheus/prometheus/model/histogram"
|
||||||
"github.com/prometheus/prometheus/model/labels"
|
"github.com/prometheus/prometheus/model/labels"
|
||||||
|
"github.com/prometheus/prometheus/util/almost"
|
||||||
)
|
)
|
||||||
|
|
||||||
// smallDeltaTolerance is the threshold for relative deltas between classic
|
// smallDeltaTolerance is the threshold for relative deltas between classic
|
||||||
|
@ -397,7 +398,7 @@ func ensureMonotonicAndIgnoreSmallDeltas(buckets buckets, tolerance float64) (bo
|
||||||
// No correction needed if the counts are identical between buckets.
|
// No correction needed if the counts are identical between buckets.
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if almostEqual(prev, curr, tolerance) {
|
if almost.Equal(prev, curr, tolerance) {
|
||||||
// Silently correct numerically insignificant differences from floating
|
// Silently correct numerically insignificant differences from floating
|
||||||
// point precision errors, regardless of direction.
|
// point precision errors, regardless of direction.
|
||||||
// Do not update the 'prev' value as we are ignoring the difference.
|
// Do not update the 'prev' value as we are ignoring the difference.
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
package promql
|
package promql_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -19,39 +19,40 @@ import (
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/prometheus/prometheus/model/labels"
|
"github.com/prometheus/prometheus/model/labels"
|
||||||
|
"github.com/prometheus/prometheus/promql"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestVector_ContainsSameLabelset(t *testing.T) {
|
func TestVector_ContainsSameLabelset(t *testing.T) {
|
||||||
for name, tc := range map[string]struct {
|
for name, tc := range map[string]struct {
|
||||||
vector Vector
|
vector promql.Vector
|
||||||
expected bool
|
expected bool
|
||||||
}{
|
}{
|
||||||
"empty vector": {
|
"empty vector": {
|
||||||
vector: Vector{},
|
vector: promql.Vector{},
|
||||||
expected: false,
|
expected: false,
|
||||||
},
|
},
|
||||||
"vector with one series": {
|
"vector with one series": {
|
||||||
vector: Vector{
|
vector: promql.Vector{
|
||||||
{Metric: labels.FromStrings("lbl", "a")},
|
{Metric: labels.FromStrings("lbl", "a")},
|
||||||
},
|
},
|
||||||
expected: false,
|
expected: false,
|
||||||
},
|
},
|
||||||
"vector with two different series": {
|
"vector with two different series": {
|
||||||
vector: Vector{
|
vector: promql.Vector{
|
||||||
{Metric: labels.FromStrings("lbl", "a")},
|
{Metric: labels.FromStrings("lbl", "a")},
|
||||||
{Metric: labels.FromStrings("lbl", "b")},
|
{Metric: labels.FromStrings("lbl", "b")},
|
||||||
},
|
},
|
||||||
expected: false,
|
expected: false,
|
||||||
},
|
},
|
||||||
"vector with two equal series": {
|
"vector with two equal series": {
|
||||||
vector: Vector{
|
vector: promql.Vector{
|
||||||
{Metric: labels.FromStrings("lbl", "a")},
|
{Metric: labels.FromStrings("lbl", "a")},
|
||||||
{Metric: labels.FromStrings("lbl", "a")},
|
{Metric: labels.FromStrings("lbl", "a")},
|
||||||
},
|
},
|
||||||
expected: true,
|
expected: true,
|
||||||
},
|
},
|
||||||
"vector with three series, two equal": {
|
"vector with three series, two equal": {
|
||||||
vector: Vector{
|
vector: promql.Vector{
|
||||||
{Metric: labels.FromStrings("lbl", "a")},
|
{Metric: labels.FromStrings("lbl", "a")},
|
||||||
{Metric: labels.FromStrings("lbl", "b")},
|
{Metric: labels.FromStrings("lbl", "b")},
|
||||||
{Metric: labels.FromStrings("lbl", "a")},
|
{Metric: labels.FromStrings("lbl", "a")},
|
||||||
|
@ -67,35 +68,35 @@ func TestVector_ContainsSameLabelset(t *testing.T) {
|
||||||
|
|
||||||
func TestMatrix_ContainsSameLabelset(t *testing.T) {
|
func TestMatrix_ContainsSameLabelset(t *testing.T) {
|
||||||
for name, tc := range map[string]struct {
|
for name, tc := range map[string]struct {
|
||||||
matrix Matrix
|
matrix promql.Matrix
|
||||||
expected bool
|
expected bool
|
||||||
}{
|
}{
|
||||||
"empty matrix": {
|
"empty matrix": {
|
||||||
matrix: Matrix{},
|
matrix: promql.Matrix{},
|
||||||
expected: false,
|
expected: false,
|
||||||
},
|
},
|
||||||
"matrix with one series": {
|
"matrix with one series": {
|
||||||
matrix: Matrix{
|
matrix: promql.Matrix{
|
||||||
{Metric: labels.FromStrings("lbl", "a")},
|
{Metric: labels.FromStrings("lbl", "a")},
|
||||||
},
|
},
|
||||||
expected: false,
|
expected: false,
|
||||||
},
|
},
|
||||||
"matrix with two different series": {
|
"matrix with two different series": {
|
||||||
matrix: Matrix{
|
matrix: promql.Matrix{
|
||||||
{Metric: labels.FromStrings("lbl", "a")},
|
{Metric: labels.FromStrings("lbl", "a")},
|
||||||
{Metric: labels.FromStrings("lbl", "b")},
|
{Metric: labels.FromStrings("lbl", "b")},
|
||||||
},
|
},
|
||||||
expected: false,
|
expected: false,
|
||||||
},
|
},
|
||||||
"matrix with two equal series": {
|
"matrix with two equal series": {
|
||||||
matrix: Matrix{
|
matrix: promql.Matrix{
|
||||||
{Metric: labels.FromStrings("lbl", "a")},
|
{Metric: labels.FromStrings("lbl", "a")},
|
||||||
{Metric: labels.FromStrings("lbl", "a")},
|
{Metric: labels.FromStrings("lbl", "a")},
|
||||||
},
|
},
|
||||||
expected: true,
|
expected: true,
|
||||||
},
|
},
|
||||||
"matrix with three series, two equal": {
|
"matrix with three series, two equal": {
|
||||||
matrix: Matrix{
|
matrix: promql.Matrix{
|
||||||
{Metric: labels.FromStrings("lbl", "a")},
|
{Metric: labels.FromStrings("lbl", "a")},
|
||||||
{Metric: labels.FromStrings("lbl", "b")},
|
{Metric: labels.FromStrings("lbl", "b")},
|
||||||
{Metric: labels.FromStrings("lbl", "a")},
|
{Metric: labels.FromStrings("lbl", "a")},
|
||||||
|
|
|
@ -30,6 +30,7 @@ import (
|
||||||
"github.com/prometheus/prometheus/notifier"
|
"github.com/prometheus/prometheus/notifier"
|
||||||
"github.com/prometheus/prometheus/promql"
|
"github.com/prometheus/prometheus/promql"
|
||||||
"github.com/prometheus/prometheus/promql/parser"
|
"github.com/prometheus/prometheus/promql/parser"
|
||||||
|
"github.com/prometheus/prometheus/promql/promqltest"
|
||||||
"github.com/prometheus/prometheus/storage"
|
"github.com/prometheus/prometheus/storage"
|
||||||
"github.com/prometheus/prometheus/util/teststorage"
|
"github.com/prometheus/prometheus/util/teststorage"
|
||||||
"github.com/prometheus/prometheus/util/testutil"
|
"github.com/prometheus/prometheus/util/testutil"
|
||||||
|
@ -148,7 +149,7 @@ func TestAlertingRuleTemplateWithHistogram(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAlertingRuleLabelsUpdate(t *testing.T) {
|
func TestAlertingRuleLabelsUpdate(t *testing.T) {
|
||||||
storage := promql.LoadedStorage(t, `
|
storage := promqltest.LoadedStorage(t, `
|
||||||
load 1m
|
load 1m
|
||||||
http_requests{job="app-server", instance="0"} 75 85 70 70 stale
|
http_requests{job="app-server", instance="0"} 75 85 70 70 stale
|
||||||
`)
|
`)
|
||||||
|
@ -252,7 +253,7 @@ func TestAlertingRuleLabelsUpdate(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAlertingRuleExternalLabelsInTemplate(t *testing.T) {
|
func TestAlertingRuleExternalLabelsInTemplate(t *testing.T) {
|
||||||
storage := promql.LoadedStorage(t, `
|
storage := promqltest.LoadedStorage(t, `
|
||||||
load 1m
|
load 1m
|
||||||
http_requests{job="app-server", instance="0"} 75 85 70 70
|
http_requests{job="app-server", instance="0"} 75 85 70 70
|
||||||
`)
|
`)
|
||||||
|
@ -345,7 +346,7 @@ func TestAlertingRuleExternalLabelsInTemplate(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAlertingRuleExternalURLInTemplate(t *testing.T) {
|
func TestAlertingRuleExternalURLInTemplate(t *testing.T) {
|
||||||
storage := promql.LoadedStorage(t, `
|
storage := promqltest.LoadedStorage(t, `
|
||||||
load 1m
|
load 1m
|
||||||
http_requests{job="app-server", instance="0"} 75 85 70 70
|
http_requests{job="app-server", instance="0"} 75 85 70 70
|
||||||
`)
|
`)
|
||||||
|
@ -438,7 +439,7 @@ func TestAlertingRuleExternalURLInTemplate(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAlertingRuleEmptyLabelFromTemplate(t *testing.T) {
|
func TestAlertingRuleEmptyLabelFromTemplate(t *testing.T) {
|
||||||
storage := promql.LoadedStorage(t, `
|
storage := promqltest.LoadedStorage(t, `
|
||||||
load 1m
|
load 1m
|
||||||
http_requests{job="app-server", instance="0"} 75 85 70 70
|
http_requests{job="app-server", instance="0"} 75 85 70 70
|
||||||
`)
|
`)
|
||||||
|
@ -492,7 +493,7 @@ func TestAlertingRuleEmptyLabelFromTemplate(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAlertingRuleQueryInTemplate(t *testing.T) {
|
func TestAlertingRuleQueryInTemplate(t *testing.T) {
|
||||||
storage := promql.LoadedStorage(t, `
|
storage := promqltest.LoadedStorage(t, `
|
||||||
load 1m
|
load 1m
|
||||||
http_requests{job="app-server", instance="0"} 70 85 70 70
|
http_requests{job="app-server", instance="0"} 70 85 70 70
|
||||||
`)
|
`)
|
||||||
|
@ -601,7 +602,7 @@ func TestAlertingRuleDuplicate(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAlertingRuleLimit(t *testing.T) {
|
func TestAlertingRuleLimit(t *testing.T) {
|
||||||
storage := promql.LoadedStorage(t, `
|
storage := promqltest.LoadedStorage(t, `
|
||||||
load 1m
|
load 1m
|
||||||
metric{label="1"} 1
|
metric{label="1"} 1
|
||||||
metric{label="2"} 1
|
metric{label="2"} 1
|
||||||
|
@ -783,7 +784,7 @@ func TestSendAlertsDontAffectActiveAlerts(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestKeepFiringFor(t *testing.T) {
|
func TestKeepFiringFor(t *testing.T) {
|
||||||
storage := promql.LoadedStorage(t, `
|
storage := promqltest.LoadedStorage(t, `
|
||||||
load 1m
|
load 1m
|
||||||
http_requests{job="app-server", instance="0"} 75 85 70 70 10x5
|
http_requests{job="app-server", instance="0"} 75 85 70 70 10x5
|
||||||
`)
|
`)
|
||||||
|
@ -893,7 +894,7 @@ func TestKeepFiringFor(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPendingAndKeepFiringFor(t *testing.T) {
|
func TestPendingAndKeepFiringFor(t *testing.T) {
|
||||||
storage := promql.LoadedStorage(t, `
|
storage := promqltest.LoadedStorage(t, `
|
||||||
load 1m
|
load 1m
|
||||||
http_requests{job="app-server", instance="0"} 75 10x10
|
http_requests{job="app-server", instance="0"} 75 10x10
|
||||||
`)
|
`)
|
||||||
|
|
|
@ -38,6 +38,7 @@ import (
|
||||||
"github.com/prometheus/prometheus/model/value"
|
"github.com/prometheus/prometheus/model/value"
|
||||||
"github.com/prometheus/prometheus/promql"
|
"github.com/prometheus/prometheus/promql"
|
||||||
"github.com/prometheus/prometheus/promql/parser"
|
"github.com/prometheus/prometheus/promql/parser"
|
||||||
|
"github.com/prometheus/prometheus/promql/promqltest"
|
||||||
"github.com/prometheus/prometheus/storage"
|
"github.com/prometheus/prometheus/storage"
|
||||||
"github.com/prometheus/prometheus/tsdb/chunkenc"
|
"github.com/prometheus/prometheus/tsdb/chunkenc"
|
||||||
"github.com/prometheus/prometheus/tsdb/tsdbutil"
|
"github.com/prometheus/prometheus/tsdb/tsdbutil"
|
||||||
|
@ -50,7 +51,7 @@ func TestMain(m *testing.M) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAlertingRule(t *testing.T) {
|
func TestAlertingRule(t *testing.T) {
|
||||||
storage := promql.LoadedStorage(t, `
|
storage := promqltest.LoadedStorage(t, `
|
||||||
load 5m
|
load 5m
|
||||||
http_requests{job="app-server", instance="0", group="canary", severity="overwrite-me"} 75 85 95 105 105 95 85
|
http_requests{job="app-server", instance="0", group="canary", severity="overwrite-me"} 75 85 95 105 105 95 85
|
||||||
http_requests{job="app-server", instance="1", group="canary", severity="overwrite-me"} 80 90 100 110 120 130 140
|
http_requests{job="app-server", instance="1", group="canary", severity="overwrite-me"} 80 90 100 110 120 130 140
|
||||||
|
@ -190,7 +191,7 @@ func TestAlertingRule(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestForStateAddSamples(t *testing.T) {
|
func TestForStateAddSamples(t *testing.T) {
|
||||||
storage := promql.LoadedStorage(t, `
|
storage := promqltest.LoadedStorage(t, `
|
||||||
load 5m
|
load 5m
|
||||||
http_requests{job="app-server", instance="0", group="canary", severity="overwrite-me"} 75 85 95 105 105 95 85
|
http_requests{job="app-server", instance="0", group="canary", severity="overwrite-me"} 75 85 95 105 105 95 85
|
||||||
http_requests{job="app-server", instance="1", group="canary", severity="overwrite-me"} 80 90 100 110 120 130 140
|
http_requests{job="app-server", instance="1", group="canary", severity="overwrite-me"} 80 90 100 110 120 130 140
|
||||||
|
@ -347,7 +348,7 @@ func sortAlerts(items []*Alert) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestForStateRestore(t *testing.T) {
|
func TestForStateRestore(t *testing.T) {
|
||||||
storage := promql.LoadedStorage(t, `
|
storage := promqltest.LoadedStorage(t, `
|
||||||
load 5m
|
load 5m
|
||||||
http_requests{job="app-server", instance="0", group="canary", severity="overwrite-me"} 75 85 50 0 0 25 0 0 40 0 120
|
http_requests{job="app-server", instance="0", group="canary", severity="overwrite-me"} 75 85 50 0 0 25 0 0 40 0 120
|
||||||
http_requests{job="app-server", instance="1", group="canary", severity="overwrite-me"} 125 90 60 0 0 25 0 0 40 0 130
|
http_requests{job="app-server", instance="1", group="canary", severity="overwrite-me"} 125 90 60 0 0 25 0 0 40 0 130
|
||||||
|
@ -1232,7 +1233,7 @@ func TestRuleHealthUpdates(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRuleGroupEvalIterationFunc(t *testing.T) {
|
func TestRuleGroupEvalIterationFunc(t *testing.T) {
|
||||||
storage := promql.LoadedStorage(t, `
|
storage := promqltest.LoadedStorage(t, `
|
||||||
load 5m
|
load 5m
|
||||||
http_requests{instance="0"} 75 85 50 0 0 25 0 0 40 0 120
|
http_requests{instance="0"} 75 85 50 0 0 25 0 0 40 0 120
|
||||||
`)
|
`)
|
||||||
|
|
|
@ -24,6 +24,7 @@ import (
|
||||||
"github.com/prometheus/prometheus/model/timestamp"
|
"github.com/prometheus/prometheus/model/timestamp"
|
||||||
"github.com/prometheus/prometheus/promql"
|
"github.com/prometheus/prometheus/promql"
|
||||||
"github.com/prometheus/prometheus/promql/parser"
|
"github.com/prometheus/prometheus/promql/parser"
|
||||||
|
"github.com/prometheus/prometheus/promql/promqltest"
|
||||||
"github.com/prometheus/prometheus/util/teststorage"
|
"github.com/prometheus/prometheus/util/teststorage"
|
||||||
"github.com/prometheus/prometheus/util/testutil"
|
"github.com/prometheus/prometheus/util/testutil"
|
||||||
)
|
)
|
||||||
|
@ -111,7 +112,7 @@ var ruleEvalTestScenarios = []struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func setUpRuleEvalTest(t require.TestingT) *teststorage.TestStorage {
|
func setUpRuleEvalTest(t require.TestingT) *teststorage.TestStorage {
|
||||||
return promql.LoadedStorage(t, `
|
return promqltest.LoadedStorage(t, `
|
||||||
load 1m
|
load 1m
|
||||||
metric{label_a="1",label_b="3"} 1
|
metric{label_a="1",label_b="3"} 1
|
||||||
metric{label_a="2",label_b="4"} 10
|
metric{label_a="2",label_b="4"} 10
|
||||||
|
@ -178,7 +179,7 @@ func TestRuleEvalDuplicate(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRecordingRuleLimit(t *testing.T) {
|
func TestRecordingRuleLimit(t *testing.T) {
|
||||||
storage := promql.LoadedStorage(t, `
|
storage := promqltest.LoadedStorage(t, `
|
||||||
load 1m
|
load 1m
|
||||||
metric{label="1"} 1
|
metric{label="1"} 1
|
||||||
metric{label="2"} 1
|
metric{label="2"} 1
|
||||||
|
|
|
@ -30,14 +30,14 @@ import (
|
||||||
"github.com/prometheus/prometheus/config"
|
"github.com/prometheus/prometheus/config"
|
||||||
"github.com/prometheus/prometheus/model/labels"
|
"github.com/prometheus/prometheus/model/labels"
|
||||||
"github.com/prometheus/prometheus/prompb"
|
"github.com/prometheus/prometheus/prompb"
|
||||||
"github.com/prometheus/prometheus/promql"
|
"github.com/prometheus/prometheus/promql/promqltest"
|
||||||
"github.com/prometheus/prometheus/storage"
|
"github.com/prometheus/prometheus/storage"
|
||||||
"github.com/prometheus/prometheus/tsdb/tsdbutil"
|
"github.com/prometheus/prometheus/tsdb/tsdbutil"
|
||||||
"github.com/prometheus/prometheus/util/teststorage"
|
"github.com/prometheus/prometheus/util/teststorage"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSampledReadEndpoint(t *testing.T) {
|
func TestSampledReadEndpoint(t *testing.T) {
|
||||||
store := promql.LoadedStorage(t, `
|
store := promqltest.LoadedStorage(t, `
|
||||||
load 1m
|
load 1m
|
||||||
test_metric1{foo="bar",baz="qux"} 1
|
test_metric1{foo="bar",baz="qux"} 1
|
||||||
`)
|
`)
|
||||||
|
@ -132,7 +132,7 @@ func TestSampledReadEndpoint(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkStreamReadEndpoint(b *testing.B) {
|
func BenchmarkStreamReadEndpoint(b *testing.B) {
|
||||||
store := promql.LoadedStorage(b, `
|
store := promqltest.LoadedStorage(b, `
|
||||||
load 1m
|
load 1m
|
||||||
test_metric1{foo="bar1",baz="qux"} 0+100x119
|
test_metric1{foo="bar1",baz="qux"} 0+100x119
|
||||||
test_metric1{foo="bar2",baz="qux"} 0+100x120
|
test_metric1{foo="bar2",baz="qux"} 0+100x120
|
||||||
|
@ -200,7 +200,7 @@ func TestStreamReadEndpoint(t *testing.T) {
|
||||||
// Second with 121 float samples, We expect 1 frame with 2 chunks.
|
// Second with 121 float samples, We expect 1 frame with 2 chunks.
|
||||||
// Third with 241 float samples. We expect 1 frame with 2 chunks, and 1 frame with 1 chunk for the same series due to bytes limit.
|
// Third with 241 float samples. We expect 1 frame with 2 chunks, and 1 frame with 1 chunk for the same series due to bytes limit.
|
||||||
// Fourth with 25 histogram samples. We expect 1 frame with 1 chunk.
|
// Fourth with 25 histogram samples. We expect 1 frame with 1 chunk.
|
||||||
store := promql.LoadedStorage(t, `
|
store := promqltest.LoadedStorage(t, `
|
||||||
load 1m
|
load 1m
|
||||||
test_metric1{foo="bar1",baz="qux"} 0+100x119
|
test_metric1{foo="bar1",baz="qux"} 0+100x119
|
||||||
test_metric1{foo="bar2",baz="qux"} 0+100x120
|
test_metric1{foo="bar2",baz="qux"} 0+100x120
|
||||||
|
|
41
util/almost/almost.go
Normal file
41
util/almost/almost.go
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
// Copyright 2024 The Prometheus Authors
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package almost
|
||||||
|
|
||||||
|
import "math"
|
||||||
|
|
||||||
|
var minNormal = math.Float64frombits(0x0010000000000000) // The smallest positive normal value of type float64.
|
||||||
|
|
||||||
|
// Equal returns true if a and b differ by less than their sum
|
||||||
|
// multiplied by epsilon.
|
||||||
|
func Equal(a, b, epsilon float64) bool {
|
||||||
|
// NaN has no equality but for testing we still want to know whether both values
|
||||||
|
// are NaN.
|
||||||
|
if math.IsNaN(a) && math.IsNaN(b) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cf. http://floating-point-gui.de/errors/comparison/
|
||||||
|
if a == b {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
absSum := math.Abs(a) + math.Abs(b)
|
||||||
|
diff := math.Abs(a - b)
|
||||||
|
|
||||||
|
if a == 0 || b == 0 || absSum < minNormal {
|
||||||
|
return diff < epsilon*minNormal
|
||||||
|
}
|
||||||
|
return diff/math.Min(absSum, math.MaxFloat64) < epsilon
|
||||||
|
}
|
|
@ -49,6 +49,7 @@ import (
|
||||||
"github.com/prometheus/prometheus/model/timestamp"
|
"github.com/prometheus/prometheus/model/timestamp"
|
||||||
"github.com/prometheus/prometheus/promql"
|
"github.com/prometheus/prometheus/promql"
|
||||||
"github.com/prometheus/prometheus/promql/parser"
|
"github.com/prometheus/prometheus/promql/parser"
|
||||||
|
"github.com/prometheus/prometheus/promql/promqltest"
|
||||||
"github.com/prometheus/prometheus/rules"
|
"github.com/prometheus/prometheus/rules"
|
||||||
"github.com/prometheus/prometheus/scrape"
|
"github.com/prometheus/prometheus/scrape"
|
||||||
"github.com/prometheus/prometheus/storage"
|
"github.com/prometheus/prometheus/storage"
|
||||||
|
@ -338,7 +339,7 @@ var sampleFlagMap = map[string]string{
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEndpoints(t *testing.T) {
|
func TestEndpoints(t *testing.T) {
|
||||||
storage := promql.LoadedStorage(t, `
|
storage := promqltest.LoadedStorage(t, `
|
||||||
load 1m
|
load 1m
|
||||||
test_metric1{foo="bar"} 0+100x100
|
test_metric1{foo="bar"} 0+100x100
|
||||||
test_metric1{foo="boo"} 1+0x100
|
test_metric1{foo="boo"} 1+0x100
|
||||||
|
@ -502,7 +503,7 @@ func (b byLabels) Less(i, j int) bool { return labels.Compare(b[i], b[j]) < 0 }
|
||||||
func TestGetSeries(t *testing.T) {
|
func TestGetSeries(t *testing.T) {
|
||||||
// TestEndpoints doesn't have enough label names to test api.labelNames
|
// TestEndpoints doesn't have enough label names to test api.labelNames
|
||||||
// endpoint properly. Hence we test it separately.
|
// endpoint properly. Hence we test it separately.
|
||||||
storage := promql.LoadedStorage(t, `
|
storage := promqltest.LoadedStorage(t, `
|
||||||
load 1m
|
load 1m
|
||||||
test_metric1{foo1="bar", baz="abc"} 0+100x100
|
test_metric1{foo1="bar", baz="abc"} 0+100x100
|
||||||
test_metric1{foo2="boo"} 1+0x100
|
test_metric1{foo2="boo"} 1+0x100
|
||||||
|
@ -606,7 +607,7 @@ func TestGetSeries(t *testing.T) {
|
||||||
|
|
||||||
func TestQueryExemplars(t *testing.T) {
|
func TestQueryExemplars(t *testing.T) {
|
||||||
start := time.Unix(0, 0)
|
start := time.Unix(0, 0)
|
||||||
storage := promql.LoadedStorage(t, `
|
storage := promqltest.LoadedStorage(t, `
|
||||||
load 1m
|
load 1m
|
||||||
test_metric1{foo="bar"} 0+100x100
|
test_metric1{foo="bar"} 0+100x100
|
||||||
test_metric1{foo="boo"} 1+0x100
|
test_metric1{foo="boo"} 1+0x100
|
||||||
|
@ -725,7 +726,7 @@ func TestQueryExemplars(t *testing.T) {
|
||||||
func TestLabelNames(t *testing.T) {
|
func TestLabelNames(t *testing.T) {
|
||||||
// TestEndpoints doesn't have enough label names to test api.labelNames
|
// TestEndpoints doesn't have enough label names to test api.labelNames
|
||||||
// endpoint properly. Hence we test it separately.
|
// endpoint properly. Hence we test it separately.
|
||||||
storage := promql.LoadedStorage(t, `
|
storage := promqltest.LoadedStorage(t, `
|
||||||
load 1m
|
load 1m
|
||||||
test_metric1{foo1="bar", baz="abc"} 0+100x100
|
test_metric1{foo1="bar", baz="abc"} 0+100x100
|
||||||
test_metric1{foo2="boo"} 1+0x100
|
test_metric1{foo2="boo"} 1+0x100
|
||||||
|
@ -3835,7 +3836,7 @@ func TestExtractQueryOpts(t *testing.T) {
|
||||||
|
|
||||||
// Test query timeout parameter.
|
// Test query timeout parameter.
|
||||||
func TestQueryTimeout(t *testing.T) {
|
func TestQueryTimeout(t *testing.T) {
|
||||||
storage := promql.LoadedStorage(t, `
|
storage := promqltest.LoadedStorage(t, `
|
||||||
load 1m
|
load 1m
|
||||||
test_metric1{foo="bar"} 0+100x100
|
test_metric1{foo="bar"} 0+100x100
|
||||||
`)
|
`)
|
||||||
|
|
|
@ -34,6 +34,7 @@ import (
|
||||||
"github.com/prometheus/prometheus/model/labels"
|
"github.com/prometheus/prometheus/model/labels"
|
||||||
"github.com/prometheus/prometheus/model/textparse"
|
"github.com/prometheus/prometheus/model/textparse"
|
||||||
"github.com/prometheus/prometheus/promql"
|
"github.com/prometheus/prometheus/promql"
|
||||||
|
"github.com/prometheus/prometheus/promql/promqltest"
|
||||||
"github.com/prometheus/prometheus/storage"
|
"github.com/prometheus/prometheus/storage"
|
||||||
"github.com/prometheus/prometheus/tsdb"
|
"github.com/prometheus/prometheus/tsdb"
|
||||||
"github.com/prometheus/prometheus/util/teststorage"
|
"github.com/prometheus/prometheus/util/teststorage"
|
||||||
|
@ -201,7 +202,7 @@ test_metric_without_labels{instance="baz"} 1001 6000000
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFederation(t *testing.T) {
|
func TestFederation(t *testing.T) {
|
||||||
storage := promql.LoadedStorage(t, `
|
storage := promqltest.LoadedStorage(t, `
|
||||||
load 1m
|
load 1m
|
||||||
test_metric1{foo="bar",instance="i"} 0+100x100
|
test_metric1{foo="bar",instance="i"} 0+100x100
|
||||||
test_metric1{foo="boo",instance="i"} 1+0x100
|
test_metric1{foo="boo",instance="i"} 1+0x100
|
||||||
|
|
Loading…
Reference in a new issue