github.com/thanos-io/thanos@v0.32.5/internal/cortex/querier/series/series_set_test.go (about)

     1  // Copyright (c) The Cortex Authors.
     2  // Licensed under the Apache License 2.0.
     3  
     4  package series
     5  
     6  import (
     7  	"math/rand"
     8  	"testing"
     9  
    10  	"github.com/prometheus/common/model"
    11  	"github.com/prometheus/prometheus/model/labels"
    12  	"github.com/prometheus/prometheus/storage"
    13  	"github.com/prometheus/prometheus/tsdb/chunkenc"
    14  	"github.com/stretchr/testify/require"
    15  )
    16  
    17  func TestConcreteSeriesSet(t *testing.T) {
    18  	series1 := &ConcreteSeries{
    19  		labels:  labels.FromStrings("foo", "bar"),
    20  		samples: []model.SamplePair{{Value: 1, Timestamp: 2}},
    21  	}
    22  	series2 := &ConcreteSeries{
    23  		labels:  labels.FromStrings("foo", "baz"),
    24  		samples: []model.SamplePair{{Value: 3, Timestamp: 4}},
    25  	}
    26  	c := NewConcreteSeriesSet([]storage.Series{series2, series1})
    27  	require.True(t, c.Next())
    28  	require.Equal(t, series1, c.At())
    29  	require.True(t, c.Next())
    30  	require.Equal(t, series2, c.At())
    31  	require.False(t, c.Next())
    32  }
    33  
    34  func TestMatrixToSeriesSetSortsMetricLabels(t *testing.T) {
    35  	matrix := model.Matrix{
    36  		{
    37  			Metric: model.Metric{
    38  				model.MetricNameLabel: "testmetric",
    39  				"e":                   "f",
    40  				"a":                   "b",
    41  				"g":                   "h",
    42  				"c":                   "d",
    43  			},
    44  			Values: []model.SamplePair{{Timestamp: 0, Value: 0}},
    45  		},
    46  	}
    47  	ss := MatrixToSeriesSet(matrix)
    48  	require.True(t, ss.Next())
    49  	require.NoError(t, ss.Err())
    50  
    51  	l := ss.At().Labels()
    52  	require.Equal(t, labels.Labels{
    53  		{Name: string(model.MetricNameLabel), Value: "testmetric"},
    54  		{Name: "a", Value: "b"},
    55  		{Name: "c", Value: "d"},
    56  		{Name: "e", Value: "f"},
    57  		{Name: "g", Value: "h"},
    58  	}, l)
    59  }
    60  
    61  func TestDeletedSeriesIterator(t *testing.T) {
    62  	cs := ConcreteSeries{labels: labels.FromStrings("foo", "bar")}
    63  	// Insert random stuff from (0, 1000).
    64  	for i := 0; i < 1000; i++ {
    65  		cs.samples = append(cs.samples, model.SamplePair{Timestamp: model.Time(i), Value: model.SampleValue(rand.Float64())})
    66  	}
    67  
    68  	cases := []struct {
    69  		r []model.Interval
    70  	}{
    71  		{r: []model.Interval{{Start: 1, End: 20}}},
    72  		{r: []model.Interval{{Start: 1, End: 10}, {Start: 12, End: 20}, {Start: 21, End: 23}, {Start: 25, End: 30}}},
    73  		{r: []model.Interval{{Start: 1, End: 10}, {Start: 12, End: 20}, {Start: 20, End: 30}}},
    74  		{r: []model.Interval{{Start: 1, End: 10}, {Start: 12, End: 23}, {Start: 25, End: 30}}},
    75  		{r: []model.Interval{{Start: 1, End: 23}, {Start: 12, End: 20}, {Start: 25, End: 30}}},
    76  		{r: []model.Interval{{Start: 1, End: 23}, {Start: 12, End: 20}, {Start: 25, End: 3000}}},
    77  		{r: []model.Interval{{Start: 0, End: 2000}}},
    78  		{r: []model.Interval{{Start: 500, End: 2000}}},
    79  		{r: []model.Interval{{Start: 0, End: 200}}},
    80  		{r: []model.Interval{{Start: 1000, End: 20000}}},
    81  	}
    82  
    83  	for _, c := range cases {
    84  		i := int64(-1)
    85  		it := NewDeletedSeriesIterator(NewConcreteSeriesIterator(&cs), c.r)
    86  		ranges := c.r[:]
    87  
    88  		for it.Next() != chunkenc.ValNone {
    89  			i++
    90  			for _, tr := range ranges {
    91  				if inbound(model.Time(i), tr) {
    92  					i = int64(tr.End + 1)
    93  					ranges = ranges[1:]
    94  				}
    95  			}
    96  
    97  			require.Equal(t, true, i < 1000)
    98  
    99  			ts, v := it.At()
   100  			require.Equal(t, int64(cs.samples[i].Timestamp), ts)
   101  			require.Equal(t, float64(cs.samples[i].Value), v)
   102  		}
   103  
   104  		// There has been an extra call to Next().
   105  		i++
   106  		for _, tr := range ranges {
   107  			if inbound(model.Time(i), tr) {
   108  				i = int64(tr.End + 1)
   109  				ranges = ranges[1:]
   110  			}
   111  		}
   112  
   113  		require.Equal(t, true, i >= 1000)
   114  		require.NoError(t, it.Err())
   115  	}
   116  }
   117  
   118  func TestDeletedIterator_WithSeek(t *testing.T) {
   119  	cs := ConcreteSeries{labels: labels.FromStrings("foo", "bar")}
   120  	// Insert random stuff from (0, 1000).
   121  	for i := 0; i < 1000; i++ {
   122  		cs.samples = append(cs.samples, model.SamplePair{Timestamp: model.Time(i), Value: model.SampleValue(rand.Float64())})
   123  	}
   124  
   125  	cases := []struct {
   126  		r         []model.Interval
   127  		seek      int64
   128  		valueType chunkenc.ValueType
   129  		seekedTs  int64
   130  	}{
   131  		{r: []model.Interval{{Start: 1, End: 20}}, seek: 1, valueType: chunkenc.ValFloat, seekedTs: 21},
   132  		{r: []model.Interval{{Start: 1, End: 20}}, seek: 20, valueType: chunkenc.ValFloat, seekedTs: 21},
   133  		{r: []model.Interval{{Start: 1, End: 20}}, seek: 10, valueType: chunkenc.ValFloat, seekedTs: 21},
   134  		{r: []model.Interval{{Start: 1, End: 20}}, seek: 999, valueType: chunkenc.ValFloat, seekedTs: 999},
   135  		{r: []model.Interval{{Start: 1, End: 20}}, seek: 1000, valueType: chunkenc.ValNone},
   136  		{r: []model.Interval{{Start: 1, End: 23}, {Start: 24, End: 40}, {Start: 45, End: 3000}}, seek: 1, valueType: chunkenc.ValFloat, seekedTs: 41},
   137  		{r: []model.Interval{{Start: 5, End: 23}, {Start: 24, End: 40}, {Start: 41, End: 3000}}, seek: 5, valueType: chunkenc.ValNone},
   138  		{r: []model.Interval{{Start: 0, End: 2000}}, seek: 10, valueType: chunkenc.ValNone},
   139  		{r: []model.Interval{{Start: 500, End: 2000}}, seek: 10, valueType: chunkenc.ValFloat, seekedTs: 10},
   140  		{r: []model.Interval{{Start: 500, End: 2000}}, seek: 501, valueType: chunkenc.ValNone},
   141  	}
   142  
   143  	for _, c := range cases {
   144  		it := NewDeletedSeriesIterator(NewConcreteSeriesIterator(&cs), c.r)
   145  
   146  		require.Equal(t, c.valueType, it.Seek(c.seek))
   147  		if c.valueType != chunkenc.ValNone {
   148  			ts, _ := it.At()
   149  			require.Equal(t, c.seekedTs, ts)
   150  		}
   151  	}
   152  }
   153  
   154  func inbound(t model.Time, interval model.Interval) bool {
   155  	return interval.Start <= t && t <= interval.End
   156  }