mirror of
https://github.com/prometheus/prometheus.git
synced 2025-01-12 06:17:27 -08:00
refactor: extract almost.Equal() to new package
To avoid a circular reference between promql and promqltest. Signed-off-by: Bryan Boreham <bjboreham@gmail.com>
This commit is contained in:
parent
94c81bba41
commit
a1af3c27d4
|
@ -35,6 +35,7 @@ import (
|
||||||
"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/tsdb/tsdbutil"
|
"github.com/prometheus/prometheus/tsdb/tsdbutil"
|
||||||
|
"github.com/prometheus/prometheus/util/almost"
|
||||||
"github.com/prometheus/prometheus/util/annotations"
|
"github.com/prometheus/prometheus/util/annotations"
|
||||||
"github.com/prometheus/prometheus/util/stats"
|
"github.com/prometheus/prometheus/util/stats"
|
||||||
"github.com/prometheus/prometheus/util/teststorage"
|
"github.com/prometheus/prometheus/util/teststorage"
|
||||||
|
@ -3873,7 +3874,7 @@ func TestNativeHistogram_HistogramQuantile(t *testing.T) {
|
||||||
|
|
||||||
require.Len(t, vector, 1)
|
require.Len(t, vector, 1)
|
||||||
require.Nil(t, vector[0].H)
|
require.Nil(t, vector[0].H)
|
||||||
require.True(t, almostEqual(sc.value, vector[0].F, defaultEpsilon))
|
require.True(t, almost.Equal(sc.value, vector[0].F, defaultEpsilon))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
idx++
|
idx++
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -19,7 +19,6 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"math"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -36,13 +35,12 @@ import (
|
||||||
"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+(.+)$`)
|
||||||
|
@ -551,7 +549,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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -601,7 +599,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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -621,7 +619,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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -894,29 +892,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)
|
||||||
|
|
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
|
||||||
|
}
|
Loading…
Reference in a new issue