prometheus/scrape/st_synthesis_test.go
bwplotka 3ade1a7f94 add todo && gofumpt
Signed-off-by: bwplotka <bwplotka@gmail.com>
2026-05-14 11:05:26 +01:00

368 lines
9.6 KiB
Go

// Copyright 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 scrape
import (
"testing"
"github.com/stretchr/testify/require"
"github.com/prometheus/prometheus/model/histogram"
)
func TestSynthesizeFloat_ValidCounter(t *testing.T) {
st := &stCache{}
// Scrape loop anchors first sample.
v, ct, skip := st.synthesizeFloat(10.0, 1000)
require.Equal(t, 10.0, v)
require.Equal(t, int64(1000), ct)
require.True(t, skip)
require.Equal(t, 10.0, st.f.prev)
require.Equal(t, 10.0, st.f.starting)
// Second scrape, no reset.
v, ct, skip = st.synthesizeFloat(15.0, 2000)
require.Equal(t, 5.0, v)
require.Equal(t, 15.0, st.f.prev)
require.Equal(t, int64(1000), ct)
require.False(t, skip)
// Third scrape, no reset.
v, ct, skip = st.synthesizeFloat(20.0, 3000)
require.Equal(t, 10.0, v)
require.Equal(t, 20.0, st.f.prev)
require.Equal(t, int64(1000), ct)
require.False(t, skip)
}
func TestSynthesizeFloat_CounterReset(t *testing.T) {
st := &stCache{}
// Scrape loop anchors first sample.
v, ct, skip := st.synthesizeFloat(100.0, 1000)
require.Equal(t, 100.0, v)
require.Equal(t, int64(1000), ct)
require.True(t, skip)
require.Equal(t, 100.0, st.f.prev)
require.Equal(t, 100.0, st.f.starting)
// First reset (value goes down).
v, ct, skip = st.synthesizeFloat(5.0, 2000)
require.Equal(t, 5.0, v)
require.Equal(t, int64(1999), ct)
require.False(t, skip)
require.Equal(t, 5.0, st.f.prev)
require.Equal(t, 0.0, st.f.starting)
// Increment.
v, ct, skip = st.synthesizeFloat(15.0, 3000)
require.Equal(t, 15.0, v)
require.Equal(t, int64(1999), ct)
require.False(t, skip)
}
func TestSynthesizeFloatHistogram_ValidAndReset(t *testing.T) {
st := &stCache{}
fh1 := &histogram.FloatHistogram{
Count: 10,
Sum: 50.5,
ZeroCount: 2,
}
// Scrape loop anchors first sample.
v, ct, skip := st.synthesizeFloatHistogram(fh1, 1000)
require.Equal(t, fh1, v)
require.Equal(t, int64(1000), ct)
require.True(t, skip)
require.NotNil(t, st.h)
require.NotNil(t, st.h.prev)
require.NotNil(t, st.h.starting)
// Next scrape.
fh2 := &histogram.FloatHistogram{
Count: 25,
Sum: 120.0,
ZeroCount: 5,
}
v, ct, skip = st.synthesizeFloatHistogram(fh2, 2000)
require.Equal(t, 15.0, v.Count)
require.Equal(t, 69.5, v.Sum)
require.Equal(t, 3.0, v.ZeroCount)
require.Equal(t, int64(1000), ct)
require.False(t, skip)
// Reset scrape (values go down).
fh3 := &histogram.FloatHistogram{
Count: 5,
Sum: 12.0,
ZeroCount: 1,
}
v, ct, skip = st.synthesizeFloatHistogram(fh3, 3000)
require.Equal(t, 5.0, v.Count)
require.Equal(t, 12.0, v.Sum)
require.Equal(t, 1.0, v.ZeroCount)
require.Equal(t, int64(2999), ct)
require.False(t, skip)
require.Nil(t, st.h.starting)
// Next scrape.
fh4 := &histogram.FloatHistogram{
Count: 25,
Sum: 120.0,
ZeroCount: 5,
}
v, ct, skip = st.synthesizeFloatHistogram(fh4, 4000)
require.Equal(t, 25.0, v.Count)
require.Equal(t, 120.0, v.Sum)
require.Equal(t, 5.0, v.ZeroCount)
require.Equal(t, int64(2999), ct)
require.False(t, skip)
}
func TestSynthesizeHistogram_ValidAndReset(t *testing.T) {
st := &stCache{}
h1 := &histogram.Histogram{
Count: 10,
Sum: 50.5,
ZeroCount: 2,
}
// Scrape loop anchors first sample.
v, ct, skip := st.synthesizeHistogram(h1, 1000)
require.Equal(t, h1, v)
require.Equal(t, int64(1000), ct)
require.True(t, skip)
require.NotNil(t, st.h)
// Next scrape.
h2 := &histogram.Histogram{
Count: 25,
Sum: 120.0,
ZeroCount: 5,
}
v, ct, skip = st.synthesizeHistogram(h2, 2000)
require.Equal(t, uint64(15), v.Count)
require.Equal(t, 69.5, v.Sum)
require.Equal(t, uint64(3), v.ZeroCount)
require.Equal(t, int64(1000), ct)
require.False(t, skip)
// Reset scrape (values go down).
h3 := &histogram.Histogram{
Count: 5,
Sum: 12.0,
ZeroCount: 1,
}
v, ct, skip = st.synthesizeHistogram(h3, 3000)
require.Equal(t, uint64(5), v.Count)
require.Equal(t, 12.0, v.Sum)
require.Equal(t, uint64(1), v.ZeroCount)
require.Equal(t, int64(2999), ct)
require.False(t, skip)
require.Nil(t, st.h.starting)
// Next scrape.
h4 := &histogram.Histogram{
Count: 25,
Sum: 120.0,
ZeroCount: 5,
}
v, ct, skip = st.synthesizeHistogram(h4, 4000)
require.Equal(t, uint64(25), v.Count)
require.Equal(t, 120.0, v.Sum)
require.Equal(t, uint64(5), v.ZeroCount)
require.Equal(t, int64(2999), ct)
require.False(t, skip)
}
func TestSynthesizeFloatHistogram_SubtractionMapping(t *testing.T) {
st := &stCache{}
// Create an anchor.
fh1 := &histogram.FloatHistogram{
Count: 10,
Sum: 50.5,
ZeroCount: 2,
PositiveSpans: []histogram.Span{
{Offset: 0, Length: 2}, // Buckets at index 0, 1
},
PositiveBuckets: []float64{3.0, 5.0}, // total 8
}
// Scrape loop anchors first sample.
v, ct, skip := st.synthesizeFloatHistogram(fh1, 1000)
require.Equal(t, fh1, v)
require.Equal(t, int64(1000), ct)
require.True(t, skip)
// Next scrape has a NEW span layout because a previous 0 bucket got populated
// We expect NO reset, just proper subtraction.
fh2 := &histogram.FloatHistogram{
Count: 25,
Sum: 120.0,
ZeroCount: 3,
PositiveSpans: []histogram.Span{
{Offset: 0, Length: 3}, // Buckets at index 0, 1, 2
},
PositiveBuckets: []float64{4.0, 7.0, 6.0}, // The previous 0 bucket is now index 2 with 6.0 counts!
}
// Expect subtraction:
// fh1 buckets [0, 1]: 3.0, 5.0
// fh2 buckets [0, 1, 2]: 4.0, 7.0, 6.0
// Result: [4-3, 7-5, 6-0] -> [1.0, 2.0, 6.0]
// Count: 25 - 10 = 15
// Sum: 120 - 50.5 = 69.5
// ZeroCount: 3 - 2 = 1.0
v, ct, skip = st.synthesizeFloatHistogram(fh2, 2000)
require.False(t, skip)
require.Equal(t, int64(1000), ct)
require.Equal(t, 15.0, v.Count)
require.Equal(t, 69.5, v.Sum)
require.Equal(t, 1.0, v.ZeroCount)
require.Len(t, v.PositiveSpans, 1)
require.Equal(t, uint32(3), v.PositiveSpans[0].Length)
require.Equal(t, []float64{1.0, 2.0, 6.0}, v.PositiveBuckets)
}
func TestSynthesizeHistogram_SubtractionMapping(t *testing.T) {
st := &stCache{}
// Create an anchor
h1 := &histogram.Histogram{
Count: 10,
Sum: 50.5,
ZeroCount: 2,
PositiveSpans: []histogram.Span{
{Offset: 0, Length: 2}, // Buckets at index 0, 1
},
PositiveBuckets: []int64{3, 2}, // Absolute: 3, 5
}
// Scrape loop anchors first sample
v, ct, skip := st.synthesizeHistogram(h1, 1000)
require.Equal(t, h1, v)
require.Equal(t, int64(1000), ct)
require.True(t, skip)
// Next scrape has a NEW span layout because a previous 0 bucket got populated
h2 := &histogram.Histogram{
Count: 25,
Sum: 120.0,
ZeroCount: 3,
PositiveSpans: []histogram.Span{
{Offset: 0, Length: 3}, // Buckets at index 0, 1, 2
},
PositiveBuckets: []int64{4, 3, -1}, // Absolute: 4, 7, 6
}
// Expect absolute subtraction result:
// fh1 buckets absolute: 3, 5
// fh2 buckets absolute: 4, 7, 6
// Result absolute: 1, 2, 6
// Back to Delta -> [1, 1, 4]
v, ct, skip = st.synthesizeHistogram(h2, 2000)
require.False(t, skip)
require.Equal(t, int64(1000), ct)
require.Equal(t, uint64(15), v.Count)
require.Equal(t, 69.5, v.Sum)
require.Equal(t, uint64(1), v.ZeroCount)
require.Len(t, v.PositiveSpans, 1)
}
func TestSynthesizeFloatHistogram_BucketReset(t *testing.T) {
st := &stCache{}
fh1 := &histogram.FloatHistogram{
Count: 10,
Sum: 50.5,
ZeroCount: 2,
PositiveSpans: []histogram.Span{
{Offset: 0, Length: 2}, // Buckets at index 0, 1
},
PositiveBuckets: []float64{3.0, 5.0}, // total 8
}
v, ct, skip := st.synthesizeFloatHistogram(fh1, 1000)
_ = v
_ = ct
require.True(t, skip)
// Next scrape: total count up to 12. Sum up to 60.0. Zero count stable.
// BUT Bucket 0 goes from 3.0 down to 2.0. Bucket 1 goes from 5.0 to 8.0.
fh2 := &histogram.FloatHistogram{
Count: 12,
Sum: 60.0,
ZeroCount: 2,
PositiveSpans: []histogram.Span{
{Offset: 0, Length: 2},
},
PositiveBuckets: []float64{2.0, 8.0},
}
v, ct, skip = st.synthesizeFloatHistogram(fh2, 2000)
require.False(t, skip)
// Since it resets, ct should be 1999.
require.Equal(t, int64(1999), ct)
// v should equal fh2 exactly since it resets
require.Equal(t, 12.0, v.Count)
require.Equal(t, 60.0, v.Sum)
require.Equal(t, 2.0, v.ZeroCount)
require.Equal(t, []float64{2.0, 8.0}, v.PositiveBuckets)
require.Nil(t, st.h.starting)
}
func TestSynthesizeHistogram_BucketReset(t *testing.T) {
st := &stCache{}
h1 := &histogram.Histogram{
Count: 10,
Sum: 50.5,
ZeroCount: 2,
PositiveSpans: []histogram.Span{
{Offset: 0, Length: 2}, // Buckets at index 0, 1
},
PositiveBuckets: []int64{3, 2}, // Absolute: 3, 5
}
v, ct, skip := st.synthesizeHistogram(h1, 1000)
_ = v
_ = ct
require.True(t, skip)
h2 := &histogram.Histogram{
Count: 12,
Sum: 60.0,
ZeroCount: 2,
PositiveSpans: []histogram.Span{
{Offset: 0, Length: 2},
},
PositiveBuckets: []int64{2, 6}, // Absolute: 2, 8. Bucket 0 went from 3 to 2 -> Reset!
}
v, ct, skip = st.synthesizeHistogram(h2, 2000)
require.False(t, skip)
require.Equal(t, int64(1999), ct)
require.Equal(t, uint64(12), v.Count)
require.Equal(t, 60.0, v.Sum)
require.Equal(t, []int64{2, 6}, v.PositiveBuckets)
require.Nil(t, st.h.starting)
}