2017-04-19 13:43:09 +01:00
// Copyright 2017 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.
2016-12-25 01:40:28 +01:00
package storage
import (
"math/rand"
"testing"
2020-10-29 10:43:23 +01:00
"github.com/stretchr/testify/require"
2016-12-25 01:40:28 +01:00
)
func TestSampleRing ( t * testing . T ) {
cases := [ ] struct {
input [ ] int64
delta int64
size int
} {
{
input : [ ] int64 { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 } ,
delta : 2 ,
size : 1 ,
} ,
{
input : [ ] int64 { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 } ,
delta : 2 ,
size : 2 ,
} ,
{
input : [ ] int64 { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 } ,
delta : 7 ,
size : 3 ,
} ,
{
input : [ ] int64 { 1 , 2 , 3 , 4 , 5 , 16 , 17 , 18 , 19 , 20 } ,
delta : 7 ,
size : 1 ,
} ,
2018-03-12 13:16:59 +00:00
{
input : [ ] int64 { 1 , 2 , 3 , 4 , 6 } ,
delta : 4 ,
size : 4 ,
} ,
2016-12-25 01:40:28 +01:00
}
for _ , c := range cases {
r := newSampleRing ( c . delta , c . size )
input := [ ] sample { }
for _ , t := range c . input {
input = append ( input , sample {
t : t ,
v : float64 ( rand . Intn ( 100 ) ) ,
} )
}
for i , s := range input {
r . add ( s . t , s . v )
buffered := r . samples ( )
for _ , sold := range input [ : i ] {
found := false
for _ , bs := range buffered {
if bs . t == sold . t && bs . v == sold . v {
found = true
break
}
}
2019-10-02 01:28:08 -04:00
if found {
2020-10-29 10:43:23 +01:00
require . GreaterOrEqual ( t , sold . t , s . t - c . delta , "%d: unexpected sample %d in buffer; buffer %v" , i , sold . t , buffered )
2019-10-02 01:28:08 -04:00
} else {
2020-10-29 10:43:23 +01:00
require . Less ( t , sold . t , s . t - c . delta , "%d: expected sample %d to be in buffer but was not; buffer %v" , i , sold . t , buffered )
2016-12-25 01:40:28 +01:00
}
}
}
}
}
func TestBufferedSeriesIterator ( t * testing . T ) {
var it * BufferedSeriesIterator
bufferEq := func ( exp [ ] sample ) {
var b [ ] sample
bit := it . Buffer ( )
for bit . Next ( ) {
2017-01-02 13:33:37 +01:00
t , v := bit . At ( )
2016-12-25 01:40:28 +01:00
b = append ( b , sample { t : t , v : v } )
}
2020-10-29 10:43:23 +01:00
require . Equal ( t , exp , b , "buffer mismatch" )
2016-12-25 01:40:28 +01:00
}
sampleEq := func ( ets int64 , ev float64 ) {
ts , v := it . Values ( )
2020-10-29 10:43:23 +01:00
require . Equal ( t , ets , ts , "timestamp mismatch" )
require . Equal ( t , ev , v , "value mismatch" )
2016-12-25 01:40:28 +01:00
}
2021-03-11 14:32:56 +01:00
prevSampleEq := func ( ets int64 , ev float64 , eok bool ) {
ts , v , ok := it . PeekBack ( 1 )
require . Equal ( t , eok , ok , "exist mismatch" )
require . Equal ( t , ets , ts , "timestamp mismatch" )
require . Equal ( t , ev , v , "value mismatch" )
}
2016-12-25 01:40:28 +01:00
2020-06-24 15:41:52 +02:00
it = NewBufferIterator ( NewListSeriesIterator ( samples {
2020-03-24 20:15:47 +00:00
sample { t : 1 , v : 2 } ,
sample { t : 2 , v : 3 } ,
sample { t : 3 , v : 4 } ,
sample { t : 4 , v : 5 } ,
sample { t : 5 , v : 6 } ,
sample { t : 99 , v : 8 } ,
sample { t : 100 , v : 9 } ,
sample { t : 101 , v : 10 } ,
2016-12-25 01:40:28 +01:00
} ) , 2 )
2020-10-29 10:43:23 +01:00
require . True ( t , it . Seek ( - 123 ) , "seek failed" )
2016-12-25 01:40:28 +01:00
sampleEq ( 1 , 2 )
2021-03-11 14:32:56 +01:00
prevSampleEq ( 0 , 0 , false )
2016-12-25 01:40:28 +01:00
bufferEq ( nil )
2020-10-29 10:43:23 +01:00
require . True ( t , it . Next ( ) , "next failed" )
2016-12-25 01:40:28 +01:00
sampleEq ( 2 , 3 )
2021-03-11 14:32:56 +01:00
prevSampleEq ( 1 , 2 , true )
2016-12-25 01:40:28 +01:00
bufferEq ( [ ] sample { { t : 1 , v : 2 } } )
2020-10-29 10:43:23 +01:00
require . True ( t , it . Next ( ) , "next failed" )
require . True ( t , it . Next ( ) , "next failed" )
require . True ( t , it . Next ( ) , "next failed" )
2016-12-25 01:40:28 +01:00
sampleEq ( 5 , 6 )
2021-03-11 14:32:56 +01:00
prevSampleEq ( 4 , 5 , true )
2016-12-25 01:40:28 +01:00
bufferEq ( [ ] sample { { t : 2 , v : 3 } , { t : 3 , v : 4 } , { t : 4 , v : 5 } } )
2020-10-29 10:43:23 +01:00
require . True ( t , it . Seek ( 5 ) , "seek failed" )
2016-12-25 01:40:28 +01:00
sampleEq ( 5 , 6 )
2021-03-11 14:32:56 +01:00
prevSampleEq ( 4 , 5 , true )
2016-12-25 01:40:28 +01:00
bufferEq ( [ ] sample { { t : 2 , v : 3 } , { t : 3 , v : 4 } , { t : 4 , v : 5 } } )
2020-10-29 10:43:23 +01:00
require . True ( t , it . Seek ( 101 ) , "seek failed" )
2016-12-25 01:40:28 +01:00
sampleEq ( 101 , 10 )
2021-03-11 14:32:56 +01:00
prevSampleEq ( 100 , 9 , true )
2016-12-25 01:40:28 +01:00
bufferEq ( [ ] sample { { t : 99 , v : 8 } , { t : 100 , v : 9 } } )
2020-10-29 10:43:23 +01:00
require . False ( t , it . Next ( ) , "next succeeded unexpectedly" )
2016-12-25 01:40:28 +01:00
}
2016-12-30 10:45:56 +01:00
2017-06-13 10:52:27 +05:30
// At() should not be called once Next() returns false.
func TestBufferedSeriesIteratorNoBadAt ( t * testing . T ) {
done := false
m := & mockSeriesIterator {
seek : func ( int64 ) bool { return false } ,
at : func ( ) ( int64 , float64 ) {
2020-10-29 10:43:23 +01:00
require . False ( t , done , "unexpectedly done" )
2017-06-13 10:52:27 +05:30
done = true
return 0 , 0
} ,
next : func ( ) bool { return ! done } ,
err : func ( ) error { return nil } ,
}
2018-07-18 06:10:28 +02:00
it := NewBufferIterator ( m , 60 )
2017-06-13 10:52:27 +05:30
it . Next ( )
it . Next ( )
}
2017-03-14 10:57:34 +01:00
func BenchmarkBufferedSeriesIterator ( b * testing . B ) {
// Simulate a 5 minute rate.
2018-12-18 12:22:33 +01:00
it := NewBufferIterator ( newFakeSeriesIterator ( int64 ( b . N ) , 30 ) , 5 * 60 )
2017-03-14 10:57:34 +01:00
b . SetBytes ( int64 ( b . N * 16 ) )
b . ReportAllocs ( )
b . ResetTimer ( )
for it . Next ( ) {
// scan everything
}
2020-10-29 10:43:23 +01:00
require . NoError ( b , it . Err ( ) )
2017-03-14 10:57:34 +01:00
}
2016-12-30 10:45:56 +01:00
type mockSeriesIterator struct {
2017-06-13 10:52:27 +05:30
seek func ( int64 ) bool
at func ( ) ( int64 , float64 )
next func ( ) bool
err func ( ) error
2016-12-30 10:45:56 +01:00
}
2017-06-13 10:52:27 +05:30
func ( m * mockSeriesIterator ) Seek ( t int64 ) bool { return m . seek ( t ) }
func ( m * mockSeriesIterator ) At ( ) ( int64 , float64 ) { return m . at ( ) }
func ( m * mockSeriesIterator ) Next ( ) bool { return m . next ( ) }
func ( m * mockSeriesIterator ) Err ( ) error { return m . err ( ) }
2016-12-30 10:45:56 +01:00
2018-12-18 12:22:33 +01:00
type fakeSeriesIterator struct {
nsamples int64
step int64
idx int64
}
func newFakeSeriesIterator ( nsamples , step int64 ) * fakeSeriesIterator {
return & fakeSeriesIterator { nsamples : nsamples , step : step , idx : - 1 }
}
func ( it * fakeSeriesIterator ) At ( ) ( int64 , float64 ) {
return it . idx * it . step , 123 // value doesn't matter
}
func ( it * fakeSeriesIterator ) Next ( ) bool {
it . idx ++
return it . idx < it . nsamples
}
func ( it * fakeSeriesIterator ) Seek ( t int64 ) bool {
it . idx = t / it . step
return it . idx < it . nsamples
}
2020-03-24 20:15:47 +00:00
func ( it * fakeSeriesIterator ) Err ( ) error { return nil }