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.
295 lines
6.5 KiB
295 lines
6.5 KiB
// Copyright 2021 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.
|
|
|
|
// The code in this file was largely written by Damian Gryski as part of
|
|
// https://github.com/dgryski/go-tsz and published under the license below.
|
|
// It was modified to accommodate reading from byte slices without modifying
|
|
// the underlying bytes, which would panic when reading from mmap'd
|
|
// read-only byte slices.
|
|
package chunkenc
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/prometheus/prometheus/pkg/histogram"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// example of a span layout and resulting bucket indices (_idx_ is used in this histogram, others are shown just for context)
|
|
// spans : [offset: 0, length: 2] [offset 1, length 1]
|
|
// bucket idx : _0_ _1_ 2 [3] 4 ...
|
|
|
|
func TestBucketIterator(t *testing.T) {
|
|
type test struct {
|
|
spans []histogram.Span
|
|
idxs []int
|
|
}
|
|
tests := []test{
|
|
{
|
|
spans: []histogram.Span{
|
|
{
|
|
Offset: 0,
|
|
Length: 1,
|
|
},
|
|
},
|
|
idxs: []int{0},
|
|
},
|
|
{
|
|
spans: []histogram.Span{
|
|
{
|
|
Offset: 0,
|
|
Length: 2,
|
|
},
|
|
{
|
|
Offset: 1,
|
|
Length: 1,
|
|
},
|
|
},
|
|
idxs: []int{0, 1, 3},
|
|
},
|
|
{
|
|
spans: []histogram.Span{
|
|
{
|
|
Offset: 100,
|
|
Length: 4,
|
|
},
|
|
{
|
|
Offset: 8,
|
|
Length: 7,
|
|
},
|
|
{
|
|
Offset: 0,
|
|
Length: 1,
|
|
},
|
|
},
|
|
idxs: []int{100, 101, 102, 103, 112, 113, 114, 115, 116, 117, 118, 119},
|
|
},
|
|
// the below 2 sets ore the ones described in compareSpans's comments
|
|
{
|
|
spans: []histogram.Span{
|
|
{Offset: 0, Length: 2},
|
|
{Offset: 2, Length: 1},
|
|
{Offset: 3, Length: 2},
|
|
{Offset: 3, Length: 1},
|
|
{Offset: 1, Length: 1},
|
|
},
|
|
idxs: []int{0, 1, 4, 8, 9, 13, 15},
|
|
},
|
|
{
|
|
spans: []histogram.Span{
|
|
{Offset: 0, Length: 3},
|
|
{Offset: 1, Length: 1},
|
|
{Offset: 1, Length: 4},
|
|
{Offset: 3, Length: 3},
|
|
},
|
|
idxs: []int{0, 1, 2, 4, 6, 7, 8, 9, 13, 14, 15},
|
|
},
|
|
}
|
|
for _, test := range tests {
|
|
b := newBucketIterator(test.spans)
|
|
var got []int
|
|
v, ok := b.Next()
|
|
for ok {
|
|
got = append(got, v)
|
|
v, ok = b.Next()
|
|
}
|
|
require.Equal(t, test.idxs, got)
|
|
}
|
|
}
|
|
|
|
func TestInterjection(t *testing.T) {
|
|
scenarios := []struct {
|
|
description string
|
|
spansA, spansB []histogram.Span
|
|
valid bool
|
|
interjections []Interjection
|
|
bucketsIn, bucketsOut []int64
|
|
}{
|
|
{
|
|
description: "single prepend at the beginning",
|
|
spansA: []histogram.Span{
|
|
{Offset: -10, Length: 3},
|
|
},
|
|
spansB: []histogram.Span{
|
|
{Offset: -11, Length: 4},
|
|
},
|
|
valid: true,
|
|
interjections: []Interjection{
|
|
{
|
|
pos: 0,
|
|
num: 1,
|
|
},
|
|
},
|
|
bucketsIn: []int64{6, -3, 0},
|
|
bucketsOut: []int64{0, 6, -3, 0},
|
|
},
|
|
{
|
|
description: "single append at the end",
|
|
spansA: []histogram.Span{
|
|
{Offset: -10, Length: 3},
|
|
},
|
|
spansB: []histogram.Span{
|
|
{Offset: -10, Length: 4},
|
|
},
|
|
valid: true,
|
|
interjections: []Interjection{
|
|
{
|
|
pos: 3,
|
|
num: 1,
|
|
},
|
|
},
|
|
bucketsIn: []int64{6, -3, 0},
|
|
bucketsOut: []int64{6, -3, 0, -3},
|
|
},
|
|
{
|
|
description: "double prepend at the beginning",
|
|
spansA: []histogram.Span{
|
|
{Offset: -10, Length: 3},
|
|
},
|
|
spansB: []histogram.Span{
|
|
{Offset: -12, Length: 5},
|
|
},
|
|
valid: true,
|
|
interjections: []Interjection{
|
|
{
|
|
pos: 0,
|
|
num: 2,
|
|
},
|
|
},
|
|
bucketsIn: []int64{6, -3, 0},
|
|
bucketsOut: []int64{0, 0, 6, -3, 0},
|
|
},
|
|
{
|
|
description: "double append at the end",
|
|
spansA: []histogram.Span{
|
|
{Offset: -10, Length: 3},
|
|
},
|
|
spansB: []histogram.Span{
|
|
{Offset: -10, Length: 5},
|
|
},
|
|
valid: true,
|
|
interjections: []Interjection{
|
|
{
|
|
pos: 3,
|
|
num: 2,
|
|
},
|
|
},
|
|
bucketsIn: []int64{6, -3, 0},
|
|
bucketsOut: []int64{6, -3, 0, -3, 0},
|
|
},
|
|
{
|
|
description: "double prepond at the beginning and double append at the end",
|
|
spansA: []histogram.Span{
|
|
{Offset: -10, Length: 3},
|
|
},
|
|
spansB: []histogram.Span{
|
|
{Offset: -12, Length: 7},
|
|
},
|
|
valid: true,
|
|
interjections: []Interjection{
|
|
{
|
|
pos: 0,
|
|
num: 2,
|
|
},
|
|
{
|
|
pos: 3,
|
|
num: 2,
|
|
},
|
|
},
|
|
bucketsIn: []int64{6, -3, 0},
|
|
bucketsOut: []int64{0, 0, 6, -3, 0, -3, 0},
|
|
},
|
|
{
|
|
description: "single removal of bucket at the start",
|
|
spansA: []histogram.Span{
|
|
{Offset: -10, Length: 4},
|
|
},
|
|
spansB: []histogram.Span{
|
|
{Offset: -9, Length: 3},
|
|
},
|
|
valid: false,
|
|
},
|
|
{
|
|
description: "single removal of bucket in the middle",
|
|
spansA: []histogram.Span{
|
|
{Offset: -10, Length: 4},
|
|
},
|
|
spansB: []histogram.Span{
|
|
{Offset: -10, Length: 2},
|
|
{Offset: 1, Length: 1},
|
|
},
|
|
valid: false,
|
|
},
|
|
{
|
|
description: "single removal of bucket at the end",
|
|
spansA: []histogram.Span{
|
|
{Offset: -10, Length: 4},
|
|
},
|
|
spansB: []histogram.Span{
|
|
{Offset: -10, Length: 3},
|
|
},
|
|
valid: false,
|
|
},
|
|
{
|
|
description: "as described in doc comment",
|
|
spansA: []histogram.Span{
|
|
{Offset: 0, Length: 2},
|
|
{Offset: 2, Length: 1},
|
|
{Offset: 3, Length: 2},
|
|
{Offset: 3, Length: 1},
|
|
{Offset: 1, Length: 1},
|
|
},
|
|
spansB: []histogram.Span{
|
|
{Offset: 0, Length: 3},
|
|
{Offset: 1, Length: 1},
|
|
{Offset: 1, Length: 4},
|
|
{Offset: 3, Length: 3},
|
|
},
|
|
valid: true,
|
|
interjections: []Interjection{
|
|
{
|
|
pos: 2,
|
|
num: 1,
|
|
},
|
|
{
|
|
pos: 3,
|
|
num: 2,
|
|
},
|
|
{
|
|
pos: 6,
|
|
num: 1,
|
|
},
|
|
},
|
|
bucketsIn: []int64{6, -3, 0, -1, 2, 1, -4},
|
|
bucketsOut: []int64{6, -3, -3, 3, -3, 0, 2, 2, 1, -5, 1},
|
|
},
|
|
}
|
|
|
|
for _, s := range scenarios {
|
|
t.Run(s.description, func(t *testing.T) {
|
|
interjections, valid := compareSpans(s.spansA, s.spansB)
|
|
if !s.valid {
|
|
require.False(t, valid, "compareScan unexpectedly returned true")
|
|
return
|
|
}
|
|
require.True(t, valid, "compareScan unexpectedly returned false")
|
|
require.Equal(t, s.interjections, interjections)
|
|
|
|
gotBuckets := make([]int64, len(s.bucketsOut))
|
|
interject(s.bucketsIn, gotBuckets, interjections)
|
|
require.Equal(t, s.bucketsOut, gotBuckets)
|
|
|
|
})
|
|
}
|
|
}
|