mirror of
https://github.com/prometheus/prometheus.git
synced 2024-11-16 10:34: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/notifier"
|
||||
_ "github.com/prometheus/prometheus/plugins" // Register plugins.
|
||||
"github.com/prometheus/prometheus/promql"
|
||||
"github.com/prometheus/prometheus/promql/parser"
|
||||
"github.com/prometheus/prometheus/promql/promqltest"
|
||||
"github.com/prometheus/prometheus/scrape"
|
||||
"github.com/prometheus/prometheus/util/documentcli"
|
||||
)
|
||||
|
@ -377,7 +377,7 @@ func main() {
|
|||
|
||||
case testRulesCmd.FullCommand():
|
||||
os.Exit(RulesUnitTest(
|
||||
promql.LazyLoaderOpts{
|
||||
promqltest.LazyLoaderOpts{
|
||||
EnableAtModifier: true,
|
||||
EnableNegativeOffset: true,
|
||||
},
|
||||
|
|
|
@ -26,7 +26,7 @@ import (
|
|||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/prometheus/prometheus/promql"
|
||||
"github.com/prometheus/prometheus/promql/promqltest"
|
||||
"github.com/prometheus/prometheus/tsdb"
|
||||
)
|
||||
|
||||
|
@ -88,7 +88,7 @@ func normalizeNewLine(b []byte) []byte {
|
|||
}
|
||||
|
||||
func TestTSDBDump(t *testing.T) {
|
||||
storage := promql.LoadedStorage(t, `
|
||||
storage := promqltest.LoadedStorage(t, `
|
||||
load 1m
|
||||
metric{foo="bar", baz="abc"} 1 2 3 4 5
|
||||
heavy_metric{foo="bar"} 5 4 3 2 1
|
||||
|
@ -158,7 +158,7 @@ func TestTSDBDump(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestTSDBDumpOpenMetrics(t *testing.T) {
|
||||
storage := promql.LoadedStorage(t, `
|
||||
storage := promqltest.LoadedStorage(t, `
|
||||
load 1m
|
||||
my_counter{foo="bar", baz="abc"} 1 2 3 4 5
|
||||
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/promql"
|
||||
"github.com/prometheus/prometheus/promql/parser"
|
||||
"github.com/prometheus/prometheus/promql/promqltest"
|
||||
"github.com/prometheus/prometheus/rules"
|
||||
"github.com/prometheus/prometheus/storage"
|
||||
)
|
||||
|
||||
// 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.
|
||||
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
|
||||
|
||||
var run *regexp.Regexp
|
||||
|
@ -69,7 +70,7 @@ func RulesUnitTest(queryOpts promql.LazyLoaderOpts, runStrings []string, diffFla
|
|||
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)
|
||||
|
||||
b, err := os.ReadFile(filename)
|
||||
|
@ -175,9 +176,9 @@ type testGroup struct {
|
|||
}
|
||||
|
||||
// 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.
|
||||
suite, err := promql.NewLazyLoader(tg.seriesLoadingString(), queryOpts)
|
||||
suite, err := promqltest.NewLazyLoader(tg.seriesLoadingString(), queryOpts)
|
||||
if err != nil {
|
||||
return []error{err}
|
||||
}
|
||||
|
@ -413,7 +414,7 @@ Outer:
|
|||
gotSamples = append(gotSamples, parsedSample{
|
||||
Labels: s.Metric.Copy(),
|
||||
Value: s.F,
|
||||
Histogram: promql.HistogramTestExpression(s.H),
|
||||
Histogram: promqltest.HistogramTestExpression(s.H),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -443,7 +444,7 @@ Outer:
|
|||
expSamples = append(expSamples, parsedSample{
|
||||
Labels: lb,
|
||||
Value: s.Value,
|
||||
Histogram: promql.HistogramTestExpression(hist),
|
||||
Histogram: promqltest.HistogramTestExpression(hist),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ import (
|
|||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/prometheus/prometheus/promql"
|
||||
"github.com/prometheus/prometheus/promql/promqltest"
|
||||
)
|
||||
|
||||
func TestRulesUnitTest(t *testing.T) {
|
||||
|
@ -28,7 +28,7 @@ func TestRulesUnitTest(t *testing.T) {
|
|||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
queryOpts promql.LazyLoaderOpts
|
||||
queryOpts promqltest.LazyLoaderOpts
|
||||
want int
|
||||
}{
|
||||
{
|
||||
|
@ -92,7 +92,7 @@ func TestRulesUnitTest(t *testing.T) {
|
|||
args: args{
|
||||
files: []string{"./testdata/at-modifier-test.yml"},
|
||||
},
|
||||
queryOpts: promql.LazyLoaderOpts{
|
||||
queryOpts: promqltest.LazyLoaderOpts{
|
||||
EnableAtModifier: true,
|
||||
},
|
||||
want: 0,
|
||||
|
@ -109,7 +109,7 @@ func TestRulesUnitTest(t *testing.T) {
|
|||
args: args{
|
||||
files: []string{"./testdata/negative-offset-test.yml"},
|
||||
},
|
||||
queryOpts: promql.LazyLoaderOpts{
|
||||
queryOpts: promqltest.LazyLoaderOpts{
|
||||
EnableNegativeOffset: true,
|
||||
},
|
||||
want: 0,
|
||||
|
@ -119,7 +119,7 @@ func TestRulesUnitTest(t *testing.T) {
|
|||
args: args{
|
||||
files: []string{"./testdata/no-test-group-interval.yml"},
|
||||
},
|
||||
queryOpts: promql.LazyLoaderOpts{
|
||||
queryOpts: promqltest.LazyLoaderOpts{
|
||||
EnableNegativeOffset: true,
|
||||
},
|
||||
want: 0,
|
||||
|
@ -142,7 +142,7 @@ func TestRulesUnitTestRun(t *testing.T) {
|
|||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
queryOpts promql.LazyLoaderOpts
|
||||
queryOpts promqltest.LazyLoaderOpts
|
||||
want int
|
||||
}{
|
||||
{
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package promql
|
||||
package promql_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
@ -23,13 +23,14 @@ import (
|
|||
|
||||
"github.com/prometheus/prometheus/model/histogram"
|
||||
"github.com/prometheus/prometheus/model/labels"
|
||||
"github.com/prometheus/prometheus/promql"
|
||||
"github.com/prometheus/prometheus/promql/parser"
|
||||
"github.com/prometheus/prometheus/storage"
|
||||
"github.com/prometheus/prometheus/tsdb/tsdbutil"
|
||||
"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()
|
||||
|
||||
metrics := []labels.Labels{}
|
||||
|
@ -249,13 +250,13 @@ func BenchmarkRangeQuery(b *testing.B) {
|
|||
stor := teststorage.New(b)
|
||||
stor.DB.DisableCompactions() // Don't want auto-compaction disrupting timings.
|
||||
defer stor.Close()
|
||||
opts := EngineOpts{
|
||||
opts := promql.EngineOpts{
|
||||
Logger: nil,
|
||||
Reg: nil,
|
||||
MaxSamples: 50000000,
|
||||
Timeout: 100 * time.Second,
|
||||
}
|
||||
engine := NewEngine(opts)
|
||||
engine := promql.NewEngine(opts)
|
||||
|
||||
const interval = 10000 // 10s interval.
|
||||
// A day of data plus 10k steps.
|
||||
|
@ -324,7 +325,7 @@ func BenchmarkNativeHistograms(b *testing.B) {
|
|||
},
|
||||
}
|
||||
|
||||
opts := EngineOpts{
|
||||
opts := promql.EngineOpts{
|
||||
Logger: nil,
|
||||
Reg: nil,
|
||||
MaxSamples: 50000000,
|
||||
|
@ -338,7 +339,7 @@ func BenchmarkNativeHistograms(b *testing.B) {
|
|||
|
||||
for _, tc := range cases {
|
||||
b.Run(tc.name, func(b *testing.B) {
|
||||
ng := NewEngine(opts)
|
||||
ng := promql.NewEngine(opts)
|
||||
for i := 0; i < b.N; i++ {
|
||||
qry, err := ng.NewRangeQuery(context.Background(), testStorage, nil, tc.query, start, end, step)
|
||||
if err != nil {
|
||||
|
|
|
@ -573,7 +573,8 @@ func (ng *Engine) validateOpts(expr parser.Expr) error {
|
|||
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{
|
||||
q: "test statement",
|
||||
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
|
||||
}
|
||||
|
||||
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) {
|
||||
t := sum + inc
|
||||
// Using Neumaier improvement, swap if next term larger than sum.
|
||||
|
|
|
@ -11,11 +11,10 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package promql
|
||||
package promql_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
|
@ -23,6 +22,7 @@ import (
|
|||
|
||||
"github.com/prometheus/prometheus/model/labels"
|
||||
"github.com/prometheus/prometheus/model/timestamp"
|
||||
"github.com/prometheus/prometheus/promql"
|
||||
"github.com/prometheus/prometheus/promql/parser"
|
||||
"github.com/prometheus/prometheus/util/teststorage"
|
||||
)
|
||||
|
@ -33,13 +33,13 @@ func TestDeriv(t *testing.T) {
|
|||
// so we test it by hand.
|
||||
storage := teststorage.New(t)
|
||||
defer storage.Close()
|
||||
opts := EngineOpts{
|
||||
opts := promql.EngineOpts{
|
||||
Logger: nil,
|
||||
Reg: nil,
|
||||
MaxSamples: 10000,
|
||||
Timeout: 10 * time.Second,
|
||||
}
|
||||
engine := NewEngine(opts)
|
||||
engine := promql.NewEngine(opts)
|
||||
|
||||
a := storage.Appender(context.Background())
|
||||
|
||||
|
@ -70,19 +70,13 @@ func TestDeriv(t *testing.T) {
|
|||
|
||||
func TestFunctionList(t *testing.T) {
|
||||
// Test that Functions and parser.Functions list the same functions.
|
||||
for i := range FunctionCalls {
|
||||
for i := range promql.FunctionCalls {
|
||||
_, ok := parser.Functions[i]
|
||||
require.True(t, ok, "function %s exists in promql package, but not in parser package", i)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
// limitations under the License.
|
||||
|
||||
package promql
|
||||
package promql_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
@ -22,37 +22,30 @@ import (
|
|||
"github.com/stretchr/testify/require"
|
||||
"golang.org/x/sync/errgroup"
|
||||
|
||||
"github.com/prometheus/prometheus/promql"
|
||||
"github.com/prometheus/prometheus/promql/promqltest"
|
||||
"github.com/prometheus/prometheus/util/teststorage"
|
||||
)
|
||||
|
||||
func newTestEngine() *Engine {
|
||||
return NewEngine(EngineOpts{
|
||||
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 newTestEngine() *promql.Engine {
|
||||
return promqltest.NewTestEngine(false, 0, promqltest.DefaultMaxSamplesPerQuery)
|
||||
}
|
||||
|
||||
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.
|
||||
func TestConcurrentRangeQueries(t *testing.T) {
|
||||
stor := teststorage.New(t)
|
||||
defer stor.Close()
|
||||
opts := EngineOpts{
|
||||
opts := promql.EngineOpts{
|
||||
Logger: nil,
|
||||
Reg: nil,
|
||||
MaxSamples: 50000000,
|
||||
Timeout: 100 * time.Second,
|
||||
}
|
||||
engine := NewEngine(opts)
|
||||
engine := promql.NewEngine(opts)
|
||||
|
||||
const interval = 10000 // 10s interval.
|
||||
// A day of data plus 10k steps.
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package promql
|
||||
package promqltest
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
@ -19,7 +19,6 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
|
@ -33,16 +32,16 @@ import (
|
|||
"github.com/prometheus/prometheus/model/histogram"
|
||||
"github.com/prometheus/prometheus/model/labels"
|
||||
"github.com/prometheus/prometheus/model/timestamp"
|
||||
"github.com/prometheus/prometheus/promql"
|
||||
"github.com/prometheus/prometheus/promql/parser"
|
||||
"github.com/prometheus/prometheus/promql/parser/posrange"
|
||||
"github.com/prometheus/prometheus/storage"
|
||||
"github.com/prometheus/prometheus/util/almost"
|
||||
"github.com/prometheus/prometheus/util/teststorage"
|
||||
"github.com/prometheus/prometheus/util/testutil"
|
||||
)
|
||||
|
||||
var (
|
||||
minNormal = math.Float64frombits(0x0010000000000000) // The smallest positive normal value of type float64.
|
||||
|
||||
patSpace = regexp.MustCompile("[\t ]+")
|
||||
patLoad = regexp.MustCompile(`^load\s+(.+?)$`)
|
||||
patEvalInstant = regexp.MustCompile(`^eval(?:_(fail|ordered))?\s+instant\s+(?:at\s+(.+?))?\s+(.+)$`)
|
||||
|
@ -50,7 +49,8 @@ var (
|
|||
)
|
||||
|
||||
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()
|
||||
|
@ -72,8 +72,22 @@ func LoadedStorage(t testutil.T, input string) *teststorage.TestStorage {
|
|||
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.
|
||||
func RunBuiltinTests(t *testing.T, engine QueryEngine) {
|
||||
func RunBuiltinTests(t *testing.T, engine promql.QueryEngine) {
|
||||
t.Cleanup(func() { parser.EnableExperimentalFunctions = false })
|
||||
parser.EnableExperimentalFunctions = true
|
||||
|
||||
|
@ -90,11 +104,11 @@ func RunBuiltinTests(t *testing.T, engine QueryEngine) {
|
|||
}
|
||||
|
||||
// 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))
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
// 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 {
|
||||
gap time.Duration
|
||||
metrics map[uint64]labels.Labels
|
||||
defs map[uint64][]Sample
|
||||
defs map[uint64][]promql.Sample
|
||||
exemplars map[uint64][]exemplar.Exemplar
|
||||
}
|
||||
|
||||
|
@ -376,7 +390,7 @@ func newLoadCmd(gap time.Duration) *loadCmd {
|
|||
return &loadCmd{
|
||||
gap: gap,
|
||||
metrics: map[uint64]labels.Labels{},
|
||||
defs: map[uint64][]Sample{},
|
||||
defs: map[uint64][]promql.Sample{},
|
||||
exemplars: map[uint64][]exemplar.Exemplar{},
|
||||
}
|
||||
}
|
||||
|
@ -389,11 +403,11 @@ func (cmd loadCmd) String() string {
|
|||
func (cmd *loadCmd) set(m labels.Labels, vals ...parser.SequenceValue) {
|
||||
h := m.Hash()
|
||||
|
||||
samples := make([]Sample, 0, len(vals))
|
||||
samples := make([]promql.Sample, 0, len(vals))
|
||||
ts := testStartTime
|
||||
for _, v := range vals {
|
||||
if !v.Omitted {
|
||||
samples = append(samples, Sample{
|
||||
samples = append(samples, promql.Sample{
|
||||
T: ts.UnixNano() / int64(time.Millisecond/time.Nanosecond),
|
||||
F: v.Value,
|
||||
H: v.Histogram,
|
||||
|
@ -419,7 +433,7 @@ func (cmd *loadCmd) append(a storage.Appender) error {
|
|||
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 _, err := a.AppendHistogram(0, m, s.T, nil, s.H); err != nil {
|
||||
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.
|
||||
func (ev *evalCmd) compareResult(result parser.Value) error {
|
||||
switch val := result.(type) {
|
||||
case Matrix:
|
||||
case promql.Matrix:
|
||||
if ev.ordered {
|
||||
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
|
||||
exp := ev.expected[hash]
|
||||
|
||||
var expectedFloats []FPoint
|
||||
var expectedHistograms []HPoint
|
||||
var expectedFloats []promql.FPoint
|
||||
var expectedHistograms []promql.HPoint
|
||||
|
||||
for i, e := range exp.vals {
|
||||
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)
|
||||
|
||||
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 {
|
||||
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))
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
@ -575,7 +589,7 @@ func (ev *evalCmd) compareResult(result parser.Value) error {
|
|||
}
|
||||
}
|
||||
|
||||
case Vector:
|
||||
case promql.Vector:
|
||||
seen := map[uint64]bool{}
|
||||
for pos, v := range val {
|
||||
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) {
|
||||
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)
|
||||
}
|
||||
|
||||
|
@ -613,7 +627,7 @@ func (ev *evalCmd) compareResult(result parser.Value) error {
|
|||
}
|
||||
}
|
||||
|
||||
case Scalar:
|
||||
case promql.Scalar:
|
||||
if len(ev.expected) != 1 {
|
||||
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 {
|
||||
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)
|
||||
}
|
||||
|
||||
|
@ -631,7 +645,7 @@ func (ev *evalCmd) compareResult(result parser.Value) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func formatSeriesResult(s Series) string {
|
||||
func formatSeriesResult(s promql.Series) string {
|
||||
floatPlural := "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 any selector already has the @ timestamp set, then it is untouched.
|
||||
parser.Inspect(expr, func(node parser.Node, path []parser.Node) error {
|
||||
_, _, subqTs := subqueryTimes(path)
|
||||
if subqTs != nil {
|
||||
if hasAtModifier(path) {
|
||||
// There is a subquery with timestamp in the path,
|
||||
// hence don't change any timestamps further.
|
||||
return nil
|
||||
|
@ -701,7 +714,7 @@ func atModifierTestCases(exprStr string, evalTime time.Time) ([]atModifierTestCa
|
|||
}
|
||||
|
||||
case *parser.Call:
|
||||
_, ok := AtModifierUnsafeFunctions[n.Func.Name]
|
||||
_, ok := promql.AtModifierUnsafeFunctions[n.Func.Name]
|
||||
containsNonStepInvariant = containsNonStepInvariant || ok
|
||||
}
|
||||
return nil
|
||||
|
@ -729,8 +742,19 @@ func atModifierTestCases(exprStr string, evalTime time.Time) ([]atModifierTestCa
|
|||
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.
|
||||
func (t *test) exec(tc testCommand, engine QueryEngine) error {
|
||||
func (t *test) exec(tc testCommand, engine promql.QueryEngine) error {
|
||||
switch cmd := tc.(type) {
|
||||
case *clearCmd:
|
||||
t.clear()
|
||||
|
@ -755,7 +779,7 @@ func (t *test) exec(tc testCommand, engine QueryEngine) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (t *test) execEval(cmd *evalCmd, engine QueryEngine) error {
|
||||
func (t *test) execEval(cmd *evalCmd, engine promql.QueryEngine) error {
|
||||
if cmd.isRange {
|
||||
return t.execRangeEval(cmd, engine)
|
||||
}
|
||||
|
@ -763,7 +787,7 @@ func (t *test) execEval(cmd *evalCmd, engine QueryEngine) error {
|
|||
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)
|
||||
if err != nil {
|
||||
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
|
||||
}
|
||||
|
||||
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)
|
||||
if err != nil {
|
||||
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.
|
||||
continue
|
||||
}
|
||||
mat := rangeRes.Value.(Matrix)
|
||||
mat := rangeRes.Value.(promql.Matrix)
|
||||
if err := assertMatrixSorted(mat); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
vec := make(Vector, 0, len(mat))
|
||||
vec := make(promql.Vector, 0, len(mat))
|
||||
for _, series := range mat {
|
||||
// We expect either Floats or Histograms.
|
||||
for _, point := range series.Floats {
|
||||
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
|
||||
}
|
||||
}
|
||||
for _, point := range series.Histograms {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
if _, ok := res.Value.(Scalar); ok {
|
||||
err = cmd.compareResult(Scalar{V: vec[0].F})
|
||||
if _, ok := res.Value.(promql.Scalar); ok {
|
||||
err = cmd.compareResult(promql.Scalar{V: vec[0].F})
|
||||
} else {
|
||||
err = cmd.compareResult(vec)
|
||||
}
|
||||
|
@ -864,7 +888,7 @@ func (t *test) execInstantEval(cmd *evalCmd, engine QueryEngine) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func assertMatrixSorted(m Matrix) error {
|
||||
func assertMatrixSorted(m promql.Matrix) error {
|
||||
if len(m) <= 1 {
|
||||
return nil
|
||||
}
|
||||
|
@ -894,29 +918,6 @@ func (t *test) clear() {
|
|||
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) {
|
||||
n, err := strconv.ParseInt(s, 0, 64)
|
||||
f := float64(n)
|
||||
|
@ -937,7 +938,7 @@ type LazyLoader struct {
|
|||
storage storage.Storage
|
||||
SubqueryInterval time.Duration
|
||||
|
||||
queryEngine *Engine
|
||||
queryEngine *promql.Engine
|
||||
context context.Context
|
||||
cancelCtx context.CancelFunc
|
||||
|
||||
|
@ -1004,7 +1005,7 @@ func (ll *LazyLoader) clear() error {
|
|||
return err
|
||||
}
|
||||
|
||||
opts := EngineOpts{
|
||||
opts := promql.EngineOpts{
|
||||
Logger: nil,
|
||||
Reg: nil,
|
||||
MaxSamples: 10000,
|
||||
|
@ -1014,7 +1015,7 @@ func (ll *LazyLoader) clear() error {
|
|||
EnableNegativeOffset: ll.opts.EnableNegativeOffset,
|
||||
}
|
||||
|
||||
ll.queryEngine = NewEngine(opts)
|
||||
ll.queryEngine = promql.NewEngine(opts)
|
||||
ll.context, ll.cancelCtx = context.WithCancel(context.Background())
|
||||
return nil
|
||||
}
|
||||
|
@ -1048,7 +1049,7 @@ func (ll *LazyLoader) WithSamplesTill(ts time.Time, fn func(error)) {
|
|||
}
|
||||
|
||||
// QueryEngine returns the LazyLoader's query engine.
|
||||
func (ll *LazyLoader) QueryEngine() *Engine {
|
||||
func (ll *LazyLoader) QueryEngine() *promql.Engine {
|
||||
return ll.queryEngine
|
||||
}
|
||||
|
||||
|
@ -1074,3 +1075,17 @@ func (ll *LazyLoader) Close() error {
|
|||
ll.cancelCtx()
|
||||
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
|
||||
// limitations under the License.
|
||||
|
||||
package promql
|
||||
package promqltest
|
||||
|
||||
import (
|
||||
"math"
|
||||
|
@ -21,14 +21,15 @@ import (
|
|||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/prometheus/prometheus/model/labels"
|
||||
"github.com/prometheus/prometheus/promql"
|
||||
"github.com/prometheus/prometheus/tsdb/chunkenc"
|
||||
)
|
||||
|
||||
func TestLazyLoader_WithSamplesTill(t *testing.T) {
|
||||
type testCase struct {
|
||||
ts time.Time
|
||||
series []Series // Each series is checked separately. Need not mention all series here.
|
||||
checkOnlyError bool // If this is true, series is not checked.
|
||||
series []promql.Series // Each series is checked separately. Need not mention all series here.
|
||||
checkOnlyError bool // If this is true, series is not checked.
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
|
@ -44,33 +45,33 @@ func TestLazyLoader_WithSamplesTill(t *testing.T) {
|
|||
testCases: []testCase{
|
||||
{
|
||||
ts: time.Unix(40, 0),
|
||||
series: []Series{
|
||||
series: []promql.Series{
|
||||
{
|
||||
Metric: labels.FromStrings("__name__", "metric1"),
|
||||
Floats: []FPoint{
|
||||
{0, 1}, {10000, 2}, {20000, 3}, {30000, 4}, {40000, 5},
|
||||
Floats: []promql.FPoint{
|
||||
{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),
|
||||
series: []Series{
|
||||
series: []promql.Series{
|
||||
{
|
||||
Metric: labels.FromStrings("__name__", "metric1"),
|
||||
Floats: []FPoint{
|
||||
{0, 1}, {10000, 2}, {20000, 3}, {30000, 4}, {40000, 5},
|
||||
Floats: []promql.FPoint{
|
||||
{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),
|
||||
series: []Series{
|
||||
series: []promql.Series{
|
||||
{
|
||||
Metric: labels.FromStrings("__name__", "metric1"),
|
||||
Floats: []FPoint{
|
||||
{0, 1}, {10000, 2}, {20000, 3}, {30000, 4}, {40000, 5}, {50000, 6}, {60000, 7},
|
||||
Floats: []promql.FPoint{
|
||||
{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{
|
||||
{ // Adds all samples of metric1.
|
||||
ts: time.Unix(70, 0),
|
||||
series: []Series{
|
||||
series: []promql.Series{
|
||||
{
|
||||
Metric: labels.FromStrings("__name__", "metric1"),
|
||||
Floats: []FPoint{
|
||||
{0, 1}, {10000, 1}, {20000, 1}, {30000, 1}, {40000, 1}, {50000, 1},
|
||||
Floats: []promql.FPoint{
|
||||
{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"),
|
||||
Floats: []FPoint{
|
||||
{0, 1}, {10000, 2}, {20000, 3}, {30000, 4}, {40000, 5}, {50000, 6}, {60000, 7}, {70000, 8},
|
||||
Floats: []promql.FPoint{
|
||||
{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")
|
||||
|
||||
// Convert `storage.Series` to `promql.Series`.
|
||||
got := Series{
|
||||
got := promql.Series{
|
||||
Metric: storageSeries.Labels(),
|
||||
}
|
||||
it := storageSeries.Iterator(nil)
|
||||
for it.Next() == chunkenc.ValFloat {
|
||||
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())
|
||||
|
||||
|
@ -450,7 +451,7 @@ eval range from 0 to 5m step 5m testmetric
|
|||
|
||||
for name, testCase := range testCases {
|
||||
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 == "" {
|
||||
require.NoError(t, err)
|
||||
|
@ -463,42 +464,42 @@ eval range from 0 to 5m step 5m testmetric
|
|||
|
||||
func TestAssertMatrixSorted(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
matrix Matrix
|
||||
matrix promql.Matrix
|
||||
expectedError string
|
||||
}{
|
||||
"empty matrix": {
|
||||
matrix: Matrix{},
|
||||
matrix: promql.Matrix{},
|
||||
},
|
||||
"matrix with one series": {
|
||||
matrix: Matrix{
|
||||
Series{Metric: labels.FromStrings("the_label", "value_1")},
|
||||
matrix: promql.Matrix{
|
||||
promql.Series{Metric: labels.FromStrings("the_label", "value_1")},
|
||||
},
|
||||
},
|
||||
"matrix with two series, series in sorted order": {
|
||||
matrix: Matrix{
|
||||
Series{Metric: labels.FromStrings("the_label", "value_1")},
|
||||
Series{Metric: labels.FromStrings("the_label", "value_2")},
|
||||
matrix: promql.Matrix{
|
||||
promql.Series{Metric: labels.FromStrings("the_label", "value_1")},
|
||||
promql.Series{Metric: labels.FromStrings("the_label", "value_2")},
|
||||
},
|
||||
},
|
||||
"matrix with two series, series in reverse order": {
|
||||
matrix: Matrix{
|
||||
Series{Metric: labels.FromStrings("the_label", "value_2")},
|
||||
Series{Metric: labels.FromStrings("the_label", "value_1")},
|
||||
matrix: promql.Matrix{
|
||||
promql.Series{Metric: labels.FromStrings("the_label", "value_2")},
|
||||
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"}`,
|
||||
},
|
||||
"matrix with three series, series in sorted order": {
|
||||
matrix: Matrix{
|
||||
Series{Metric: labels.FromStrings("the_label", "value_1")},
|
||||
Series{Metric: labels.FromStrings("the_label", "value_2")},
|
||||
Series{Metric: labels.FromStrings("the_label", "value_3")},
|
||||
matrix: promql.Matrix{
|
||||
promql.Series{Metric: labels.FromStrings("the_label", "value_1")},
|
||||
promql.Series{Metric: labels.FromStrings("the_label", "value_2")},
|
||||
promql.Series{Metric: labels.FromStrings("the_label", "value_3")},
|
||||
},
|
||||
},
|
||||
"matrix with three series, series not in sorted order": {
|
||||
matrix: Matrix{
|
||||
Series{Metric: labels.FromStrings("the_label", "value_1")},
|
||||
Series{Metric: labels.FromStrings("the_label", "value_3")},
|
||||
Series{Metric: labels.FromStrings("the_label", "value_2")},
|
||||
matrix: promql.Matrix{
|
||||
promql.Series{Metric: labels.FromStrings("the_label", "value_1")},
|
||||
promql.Series{Metric: labels.FromStrings("the_label", "value_3")},
|
||||
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"}`,
|
||||
},
|
|
@ -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])
|
||||
{} 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.
|
||||
clear
|
||||
load 10s
|
|
@ -20,6 +20,7 @@ import (
|
|||
|
||||
"github.com/prometheus/prometheus/model/histogram"
|
||||
"github.com/prometheus/prometheus/model/labels"
|
||||
"github.com/prometheus/prometheus/util/almost"
|
||||
)
|
||||
|
||||
// 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.
|
||||
continue
|
||||
}
|
||||
if almostEqual(prev, curr, tolerance) {
|
||||
if almost.Equal(prev, curr, tolerance) {
|
||||
// Silently correct numerically insignificant differences from floating
|
||||
// point precision errors, regardless of direction.
|
||||
// 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
|
||||
// limitations under the License.
|
||||
|
||||
package promql
|
||||
package promql_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
@ -19,39 +19,40 @@ import (
|
|||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/prometheus/prometheus/model/labels"
|
||||
"github.com/prometheus/prometheus/promql"
|
||||
)
|
||||
|
||||
func TestVector_ContainsSameLabelset(t *testing.T) {
|
||||
for name, tc := range map[string]struct {
|
||||
vector Vector
|
||||
vector promql.Vector
|
||||
expected bool
|
||||
}{
|
||||
"empty vector": {
|
||||
vector: Vector{},
|
||||
vector: promql.Vector{},
|
||||
expected: false,
|
||||
},
|
||||
"vector with one series": {
|
||||
vector: Vector{
|
||||
vector: promql.Vector{
|
||||
{Metric: labels.FromStrings("lbl", "a")},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
"vector with two different series": {
|
||||
vector: Vector{
|
||||
vector: promql.Vector{
|
||||
{Metric: labels.FromStrings("lbl", "a")},
|
||||
{Metric: labels.FromStrings("lbl", "b")},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
"vector with two equal series": {
|
||||
vector: Vector{
|
||||
vector: promql.Vector{
|
||||
{Metric: labels.FromStrings("lbl", "a")},
|
||||
{Metric: labels.FromStrings("lbl", "a")},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
"vector with three series, two equal": {
|
||||
vector: Vector{
|
||||
vector: promql.Vector{
|
||||
{Metric: labels.FromStrings("lbl", "a")},
|
||||
{Metric: labels.FromStrings("lbl", "b")},
|
||||
{Metric: labels.FromStrings("lbl", "a")},
|
||||
|
@ -67,35 +68,35 @@ func TestVector_ContainsSameLabelset(t *testing.T) {
|
|||
|
||||
func TestMatrix_ContainsSameLabelset(t *testing.T) {
|
||||
for name, tc := range map[string]struct {
|
||||
matrix Matrix
|
||||
matrix promql.Matrix
|
||||
expected bool
|
||||
}{
|
||||
"empty matrix": {
|
||||
matrix: Matrix{},
|
||||
matrix: promql.Matrix{},
|
||||
expected: false,
|
||||
},
|
||||
"matrix with one series": {
|
||||
matrix: Matrix{
|
||||
matrix: promql.Matrix{
|
||||
{Metric: labels.FromStrings("lbl", "a")},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
"matrix with two different series": {
|
||||
matrix: Matrix{
|
||||
matrix: promql.Matrix{
|
||||
{Metric: labels.FromStrings("lbl", "a")},
|
||||
{Metric: labels.FromStrings("lbl", "b")},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
"matrix with two equal series": {
|
||||
matrix: Matrix{
|
||||
matrix: promql.Matrix{
|
||||
{Metric: labels.FromStrings("lbl", "a")},
|
||||
{Metric: labels.FromStrings("lbl", "a")},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
"matrix with three series, two equal": {
|
||||
matrix: Matrix{
|
||||
matrix: promql.Matrix{
|
||||
{Metric: labels.FromStrings("lbl", "a")},
|
||||
{Metric: labels.FromStrings("lbl", "b")},
|
||||
{Metric: labels.FromStrings("lbl", "a")},
|
||||
|
|
|
@ -30,6 +30,7 @@ import (
|
|||
"github.com/prometheus/prometheus/notifier"
|
||||
"github.com/prometheus/prometheus/promql"
|
||||
"github.com/prometheus/prometheus/promql/parser"
|
||||
"github.com/prometheus/prometheus/promql/promqltest"
|
||||
"github.com/prometheus/prometheus/storage"
|
||||
"github.com/prometheus/prometheus/util/teststorage"
|
||||
"github.com/prometheus/prometheus/util/testutil"
|
||||
|
@ -148,7 +149,7 @@ func TestAlertingRuleTemplateWithHistogram(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestAlertingRuleLabelsUpdate(t *testing.T) {
|
||||
storage := promql.LoadedStorage(t, `
|
||||
storage := promqltest.LoadedStorage(t, `
|
||||
load 1m
|
||||
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) {
|
||||
storage := promql.LoadedStorage(t, `
|
||||
storage := promqltest.LoadedStorage(t, `
|
||||
load 1m
|
||||
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) {
|
||||
storage := promql.LoadedStorage(t, `
|
||||
storage := promqltest.LoadedStorage(t, `
|
||||
load 1m
|
||||
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) {
|
||||
storage := promql.LoadedStorage(t, `
|
||||
storage := promqltest.LoadedStorage(t, `
|
||||
load 1m
|
||||
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) {
|
||||
storage := promql.LoadedStorage(t, `
|
||||
storage := promqltest.LoadedStorage(t, `
|
||||
load 1m
|
||||
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) {
|
||||
storage := promql.LoadedStorage(t, `
|
||||
storage := promqltest.LoadedStorage(t, `
|
||||
load 1m
|
||||
metric{label="1"} 1
|
||||
metric{label="2"} 1
|
||||
|
@ -783,7 +784,7 @@ func TestSendAlertsDontAffectActiveAlerts(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestKeepFiringFor(t *testing.T) {
|
||||
storage := promql.LoadedStorage(t, `
|
||||
storage := promqltest.LoadedStorage(t, `
|
||||
load 1m
|
||||
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) {
|
||||
storage := promql.LoadedStorage(t, `
|
||||
storage := promqltest.LoadedStorage(t, `
|
||||
load 1m
|
||||
http_requests{job="app-server", instance="0"} 75 10x10
|
||||
`)
|
||||
|
|
|
@ -38,6 +38,7 @@ import (
|
|||
"github.com/prometheus/prometheus/model/value"
|
||||
"github.com/prometheus/prometheus/promql"
|
||||
"github.com/prometheus/prometheus/promql/parser"
|
||||
"github.com/prometheus/prometheus/promql/promqltest"
|
||||
"github.com/prometheus/prometheus/storage"
|
||||
"github.com/prometheus/prometheus/tsdb/chunkenc"
|
||||
"github.com/prometheus/prometheus/tsdb/tsdbutil"
|
||||
|
@ -50,7 +51,7 @@ func TestMain(m *testing.M) {
|
|||
}
|
||||
|
||||
func TestAlertingRule(t *testing.T) {
|
||||
storage := promql.LoadedStorage(t, `
|
||||
storage := promqltest.LoadedStorage(t, `
|
||||
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="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) {
|
||||
storage := promql.LoadedStorage(t, `
|
||||
storage := promqltest.LoadedStorage(t, `
|
||||
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="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) {
|
||||
storage := promql.LoadedStorage(t, `
|
||||
storage := promqltest.LoadedStorage(t, `
|
||||
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="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) {
|
||||
storage := promql.LoadedStorage(t, `
|
||||
storage := promqltest.LoadedStorage(t, `
|
||||
load 5m
|
||||
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/promql"
|
||||
"github.com/prometheus/prometheus/promql/parser"
|
||||
"github.com/prometheus/prometheus/promql/promqltest"
|
||||
"github.com/prometheus/prometheus/util/teststorage"
|
||||
"github.com/prometheus/prometheus/util/testutil"
|
||||
)
|
||||
|
@ -111,7 +112,7 @@ var ruleEvalTestScenarios = []struct {
|
|||
}
|
||||
|
||||
func setUpRuleEvalTest(t require.TestingT) *teststorage.TestStorage {
|
||||
return promql.LoadedStorage(t, `
|
||||
return promqltest.LoadedStorage(t, `
|
||||
load 1m
|
||||
metric{label_a="1",label_b="3"} 1
|
||||
metric{label_a="2",label_b="4"} 10
|
||||
|
@ -178,7 +179,7 @@ func TestRuleEvalDuplicate(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestRecordingRuleLimit(t *testing.T) {
|
||||
storage := promql.LoadedStorage(t, `
|
||||
storage := promqltest.LoadedStorage(t, `
|
||||
load 1m
|
||||
metric{label="1"} 1
|
||||
metric{label="2"} 1
|
||||
|
|
|
@ -30,14 +30,14 @@ import (
|
|||
"github.com/prometheus/prometheus/config"
|
||||
"github.com/prometheus/prometheus/model/labels"
|
||||
"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/tsdb/tsdbutil"
|
||||
"github.com/prometheus/prometheus/util/teststorage"
|
||||
)
|
||||
|
||||
func TestSampledReadEndpoint(t *testing.T) {
|
||||
store := promql.LoadedStorage(t, `
|
||||
store := promqltest.LoadedStorage(t, `
|
||||
load 1m
|
||||
test_metric1{foo="bar",baz="qux"} 1
|
||||
`)
|
||||
|
@ -132,7 +132,7 @@ func TestSampledReadEndpoint(t *testing.T) {
|
|||
}
|
||||
|
||||
func BenchmarkStreamReadEndpoint(b *testing.B) {
|
||||
store := promql.LoadedStorage(b, `
|
||||
store := promqltest.LoadedStorage(b, `
|
||||
load 1m
|
||||
test_metric1{foo="bar1",baz="qux"} 0+100x119
|
||||
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.
|
||||
// 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.
|
||||
store := promql.LoadedStorage(t, `
|
||||
store := promqltest.LoadedStorage(t, `
|
||||
load 1m
|
||||
test_metric1{foo="bar1",baz="qux"} 0+100x119
|
||||
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/promql"
|
||||
"github.com/prometheus/prometheus/promql/parser"
|
||||
"github.com/prometheus/prometheus/promql/promqltest"
|
||||
"github.com/prometheus/prometheus/rules"
|
||||
"github.com/prometheus/prometheus/scrape"
|
||||
"github.com/prometheus/prometheus/storage"
|
||||
|
@ -338,7 +339,7 @@ var sampleFlagMap = map[string]string{
|
|||
}
|
||||
|
||||
func TestEndpoints(t *testing.T) {
|
||||
storage := promql.LoadedStorage(t, `
|
||||
storage := promqltest.LoadedStorage(t, `
|
||||
load 1m
|
||||
test_metric1{foo="bar"} 0+100x100
|
||||
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) {
|
||||
// TestEndpoints doesn't have enough label names to test api.labelNames
|
||||
// endpoint properly. Hence we test it separately.
|
||||
storage := promql.LoadedStorage(t, `
|
||||
storage := promqltest.LoadedStorage(t, `
|
||||
load 1m
|
||||
test_metric1{foo1="bar", baz="abc"} 0+100x100
|
||||
test_metric1{foo2="boo"} 1+0x100
|
||||
|
@ -606,7 +607,7 @@ func TestGetSeries(t *testing.T) {
|
|||
|
||||
func TestQueryExemplars(t *testing.T) {
|
||||
start := time.Unix(0, 0)
|
||||
storage := promql.LoadedStorage(t, `
|
||||
storage := promqltest.LoadedStorage(t, `
|
||||
load 1m
|
||||
test_metric1{foo="bar"} 0+100x100
|
||||
test_metric1{foo="boo"} 1+0x100
|
||||
|
@ -725,7 +726,7 @@ func TestQueryExemplars(t *testing.T) {
|
|||
func TestLabelNames(t *testing.T) {
|
||||
// TestEndpoints doesn't have enough label names to test api.labelNames
|
||||
// endpoint properly. Hence we test it separately.
|
||||
storage := promql.LoadedStorage(t, `
|
||||
storage := promqltest.LoadedStorage(t, `
|
||||
load 1m
|
||||
test_metric1{foo1="bar", baz="abc"} 0+100x100
|
||||
test_metric1{foo2="boo"} 1+0x100
|
||||
|
@ -3835,7 +3836,7 @@ func TestExtractQueryOpts(t *testing.T) {
|
|||
|
||||
// Test query timeout parameter.
|
||||
func TestQueryTimeout(t *testing.T) {
|
||||
storage := promql.LoadedStorage(t, `
|
||||
storage := promqltest.LoadedStorage(t, `
|
||||
load 1m
|
||||
test_metric1{foo="bar"} 0+100x100
|
||||
`)
|
||||
|
|
|
@ -34,6 +34,7 @@ import (
|
|||
"github.com/prometheus/prometheus/model/labels"
|
||||
"github.com/prometheus/prometheus/model/textparse"
|
||||
"github.com/prometheus/prometheus/promql"
|
||||
"github.com/prometheus/prometheus/promql/promqltest"
|
||||
"github.com/prometheus/prometheus/storage"
|
||||
"github.com/prometheus/prometheus/tsdb"
|
||||
"github.com/prometheus/prometheus/util/teststorage"
|
||||
|
@ -201,7 +202,7 @@ test_metric_without_labels{instance="baz"} 1001 6000000
|
|||
}
|
||||
|
||||
func TestFederation(t *testing.T) {
|
||||
storage := promql.LoadedStorage(t, `
|
||||
storage := promqltest.LoadedStorage(t, `
|
||||
load 1m
|
||||
test_metric1{foo="bar",instance="i"} 0+100x100
|
||||
test_metric1{foo="boo",instance="i"} 1+0x100
|
||||
|
|
Loading…
Reference in a new issue