mirror of https://github.com/prometheus/prometheus
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
190 lines
6.2 KiB
190 lines
6.2 KiB
// Copyright 2015 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 ( |
|
"math" |
|
"testing" |
|
|
|
"github.com/stretchr/testify/require" |
|
|
|
"github.com/prometheus/prometheus/model/histogram" |
|
"github.com/prometheus/prometheus/model/labels" |
|
"github.com/prometheus/prometheus/model/value" |
|
"github.com/prometheus/prometheus/tsdb/chunkenc" |
|
"github.com/prometheus/prometheus/tsdb/tsdbutil" |
|
) |
|
|
|
func TestHistogramStatsDecoding(t *testing.T) { |
|
cases := []struct { |
|
name string |
|
histograms []*histogram.Histogram |
|
expectedHints []histogram.CounterResetHint |
|
}{ |
|
{ |
|
name: "unknown counter reset triggers detection", |
|
histograms: []*histogram.Histogram{ |
|
tsdbutil.GenerateTestHistogramWithHint(0, histogram.NotCounterReset), |
|
tsdbutil.GenerateTestHistogramWithHint(1, histogram.UnknownCounterReset), |
|
tsdbutil.GenerateTestHistogramWithHint(2, histogram.CounterReset), |
|
tsdbutil.GenerateTestHistogramWithHint(2, histogram.UnknownCounterReset), |
|
}, |
|
expectedHints: []histogram.CounterResetHint{ |
|
histogram.NotCounterReset, |
|
histogram.NotCounterReset, |
|
histogram.CounterReset, |
|
histogram.NotCounterReset, |
|
}, |
|
}, |
|
{ |
|
name: "stale sample before unknown reset hint", |
|
histograms: []*histogram.Histogram{ |
|
tsdbutil.GenerateTestHistogramWithHint(0, histogram.NotCounterReset), |
|
tsdbutil.GenerateTestHistogramWithHint(1, histogram.UnknownCounterReset), |
|
{Sum: math.Float64frombits(value.StaleNaN)}, |
|
tsdbutil.GenerateTestHistogramWithHint(1, histogram.UnknownCounterReset), |
|
}, |
|
expectedHints: []histogram.CounterResetHint{ |
|
histogram.NotCounterReset, |
|
histogram.NotCounterReset, |
|
histogram.UnknownCounterReset, |
|
histogram.NotCounterReset, |
|
}, |
|
}, |
|
{ |
|
name: "unknown counter reset at the beginning", |
|
histograms: []*histogram.Histogram{ |
|
tsdbutil.GenerateTestHistogramWithHint(1, histogram.UnknownCounterReset), |
|
}, |
|
expectedHints: []histogram.CounterResetHint{ |
|
histogram.NotCounterReset, |
|
}, |
|
}, |
|
{ |
|
name: "detect real counter reset", |
|
histograms: []*histogram.Histogram{ |
|
tsdbutil.GenerateTestHistogramWithHint(2, histogram.UnknownCounterReset), |
|
tsdbutil.GenerateTestHistogramWithHint(1, histogram.UnknownCounterReset), |
|
}, |
|
expectedHints: []histogram.CounterResetHint{ |
|
histogram.NotCounterReset, |
|
histogram.CounterReset, |
|
}, |
|
}, |
|
{ |
|
name: "detect real counter reset after stale NaN", |
|
histograms: []*histogram.Histogram{ |
|
tsdbutil.GenerateTestHistogramWithHint(2, histogram.UnknownCounterReset), |
|
{Sum: math.Float64frombits(value.StaleNaN)}, |
|
tsdbutil.GenerateTestHistogramWithHint(1, histogram.UnknownCounterReset), |
|
}, |
|
expectedHints: []histogram.CounterResetHint{ |
|
histogram.NotCounterReset, |
|
histogram.UnknownCounterReset, |
|
histogram.CounterReset, |
|
}, |
|
}, |
|
} |
|
|
|
for _, tc := range cases { |
|
t.Run(tc.name, func(t *testing.T) { |
|
t.Run("histogram_stats", func(t *testing.T) { |
|
decodedStats := make([]*histogram.Histogram, 0) |
|
statsIterator := NewHistogramStatsIterator(newHistogramSeries(tc.histograms).Iterator(nil)) |
|
for statsIterator.Next() != chunkenc.ValNone { |
|
_, h := statsIterator.AtHistogram(nil) |
|
decodedStats = append(decodedStats, h) |
|
} |
|
for i := 0; i < len(tc.histograms); i++ { |
|
require.Equalf(t, tc.expectedHints[i], decodedStats[i].CounterResetHint, "mismatch in counter reset hint for histogram %d", i) |
|
h := tc.histograms[i] |
|
if value.IsStaleNaN(h.Sum) { |
|
require.True(t, value.IsStaleNaN(decodedStats[i].Sum)) |
|
require.Equal(t, uint64(0), decodedStats[i].Count) |
|
} else { |
|
require.Equal(t, tc.histograms[i].Count, decodedStats[i].Count) |
|
require.Equal(t, tc.histograms[i].Sum, decodedStats[i].Sum) |
|
} |
|
} |
|
}) |
|
t.Run("float_histogram_stats", func(t *testing.T) { |
|
decodedStats := make([]*histogram.FloatHistogram, 0) |
|
statsIterator := NewHistogramStatsIterator(newHistogramSeries(tc.histograms).Iterator(nil)) |
|
for statsIterator.Next() != chunkenc.ValNone { |
|
_, h := statsIterator.AtFloatHistogram(nil) |
|
decodedStats = append(decodedStats, h) |
|
} |
|
for i := 0; i < len(tc.histograms); i++ { |
|
require.Equal(t, tc.expectedHints[i], decodedStats[i].CounterResetHint) |
|
fh := tc.histograms[i].ToFloat(nil) |
|
if value.IsStaleNaN(fh.Sum) { |
|
require.True(t, value.IsStaleNaN(decodedStats[i].Sum)) |
|
require.Equal(t, float64(0), decodedStats[i].Count) |
|
} else { |
|
require.Equal(t, fh.Count, decodedStats[i].Count) |
|
require.Equal(t, fh.Sum, decodedStats[i].Sum) |
|
} |
|
} |
|
}) |
|
}) |
|
} |
|
} |
|
|
|
type histogramSeries struct { |
|
histograms []*histogram.Histogram |
|
} |
|
|
|
func newHistogramSeries(histograms []*histogram.Histogram) *histogramSeries { |
|
return &histogramSeries{ |
|
histograms: histograms, |
|
} |
|
} |
|
|
|
func (m histogramSeries) Labels() labels.Labels { return labels.EmptyLabels() } |
|
|
|
func (m histogramSeries) Iterator(_ chunkenc.Iterator) chunkenc.Iterator { |
|
return &histogramIterator{ |
|
i: -1, |
|
histograms: m.histograms, |
|
} |
|
} |
|
|
|
type histogramIterator struct { |
|
i int |
|
histograms []*histogram.Histogram |
|
} |
|
|
|
func (h *histogramIterator) Next() chunkenc.ValueType { |
|
h.i++ |
|
if h.i < len(h.histograms) { |
|
return chunkenc.ValHistogram |
|
} |
|
return chunkenc.ValNone |
|
} |
|
|
|
func (h *histogramIterator) Seek(t int64) chunkenc.ValueType { panic("not implemented") } |
|
|
|
func (h *histogramIterator) At() (int64, float64) { panic("not implemented") } |
|
|
|
func (h *histogramIterator) AtHistogram(_ *histogram.Histogram) (int64, *histogram.Histogram) { |
|
return 0, h.histograms[h.i] |
|
} |
|
|
|
func (h *histogramIterator) AtFloatHistogram(_ *histogram.FloatHistogram) (int64, *histogram.FloatHistogram) { |
|
return 0, h.histograms[h.i].ToFloat(nil) |
|
} |
|
|
|
func (h *histogramIterator) AtT() int64 { return 0 } |
|
|
|
func (h *histogramIterator) Err() error { return nil }
|
|
|