Like Prometheus, but for logs.
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.
loki/pkg/logql/range_vector_test.go

141 lines
4.1 KiB

package logql
import (
"context"
"fmt"
"testing"
"time"
"github.com/prometheus/prometheus/promql"
"github.com/stretchr/testify/require"
"github.com/grafana/loki/pkg/iter"
"github.com/grafana/loki/pkg/logproto"
)
var entries = []logproto.Entry{
{Timestamp: time.Unix(2, 0)},
{Timestamp: time.Unix(5, 0)},
{Timestamp: time.Unix(6, 0)},
{Timestamp: time.Unix(10, 0)},
{Timestamp: time.Unix(10, 1)},
{Timestamp: time.Unix(11, 0)},
{Timestamp: time.Unix(35, 0)},
{Timestamp: time.Unix(35, 1)},
{Timestamp: time.Unix(40, 0)},
{Timestamp: time.Unix(100, 0)},
{Timestamp: time.Unix(100, 1)},
}
var labelFoo, _ = promql.ParseMetric("{app=\"foo\"}")
var labelBar, _ = promql.ParseMetric("{app=\"bar\"}")
func newEntryIterator() iter.EntryIterator {
return iter.NewHeapIterator(context.Background(), []iter.EntryIterator{
iter.NewStreamIterator(&logproto.Stream{
Labels: labelFoo.String(),
Entries: entries,
}),
iter.NewStreamIterator(&logproto.Stream{
Labels: labelBar.String(),
Entries: entries,
}),
}, logproto.FORWARD)
}
func newPoint(t time.Time, v float64) promql.Point {
return promql.Point{T: t.UnixNano() / 1e+6, V: v}
}
func Test_RangeVectorIterator(t *testing.T) {
tests := []struct {
selRange int64
step int64
expectedVectors []promql.Vector
expectedTs []time.Time
}{
{
(5 * time.Second).Nanoseconds(), // no overlap
(30 * time.Second).Nanoseconds(),
[]promql.Vector{
[]promql.Sample{
{Point: newPoint(time.Unix(10, 0), 2), Metric: labelBar},
{Point: newPoint(time.Unix(10, 0), 2), Metric: labelFoo},
},
[]promql.Sample{
{Point: newPoint(time.Unix(40, 0), 2), Metric: labelBar},
{Point: newPoint(time.Unix(40, 0), 2), Metric: labelFoo},
},
{},
[]promql.Sample{
{Point: newPoint(time.Unix(100, 0), 1), Metric: labelBar},
{Point: newPoint(time.Unix(100, 0), 1), Metric: labelFoo},
},
},
[]time.Time{time.Unix(10, 0), time.Unix(40, 0), time.Unix(70, 0), time.Unix(100, 0)},
},
{
(35 * time.Second).Nanoseconds(), // will overlap by 5 sec
(30 * time.Second).Nanoseconds(),
[]promql.Vector{
[]promql.Sample{
{Point: newPoint(time.Unix(10, 0), 4), Metric: labelBar},
{Point: newPoint(time.Unix(10, 0), 4), Metric: labelFoo},
},
[]promql.Sample{
{Point: newPoint(time.Unix(40, 0), 7), Metric: labelBar},
{Point: newPoint(time.Unix(40, 0), 7), Metric: labelFoo},
},
[]promql.Sample{
{Point: newPoint(time.Unix(70, 0), 2), Metric: labelBar},
{Point: newPoint(time.Unix(70, 0), 2), Metric: labelFoo},
},
[]promql.Sample{
{Point: newPoint(time.Unix(100, 0), 1), Metric: labelBar},
{Point: newPoint(time.Unix(100, 0), 1), Metric: labelFoo},
},
},
[]time.Time{time.Unix(10, 0), time.Unix(40, 0), time.Unix(70, 0), time.Unix(100, 0)},
},
{
(30 * time.Second).Nanoseconds(), // same range
(30 * time.Second).Nanoseconds(),
[]promql.Vector{
[]promql.Sample{
{Point: newPoint(time.Unix(10, 0), 4), Metric: labelBar},
{Point: newPoint(time.Unix(10, 0), 4), Metric: labelFoo},
},
[]promql.Sample{
{Point: newPoint(time.Unix(40, 0), 5), Metric: labelBar},
{Point: newPoint(time.Unix(40, 0), 5), Metric: labelFoo},
},
[]promql.Sample{},
[]promql.Sample{
{Point: newPoint(time.Unix(100, 0), 1), Metric: labelBar},
{Point: newPoint(time.Unix(100, 0), 1), Metric: labelFoo},
},
},
[]time.Time{time.Unix(10, 0), time.Unix(40, 0), time.Unix(70, 0), time.Unix(100, 0)},
},
}
for _, tt := range tests {
t.Run(
fmt.Sprintf("logs[%s] - step: %s", time.Duration(tt.selRange), time.Duration(tt.step)),
func(t *testing.T) {
it := newRangeVectorIterator(newEntryIterator(), tt.selRange,
tt.step, time.Unix(10, 0).UnixNano(), time.Unix(100, 0).UnixNano())
i := 0
for it.Next() {
ts, v := it.At(count)
require.ElementsMatch(t, tt.expectedVectors[i], v)
require.Equal(t, tt.expectedTs[i].UnixNano()/1e+6, ts)
i++
}
require.Equal(t, len(tt.expectedTs), i)
require.Equal(t, len(tt.expectedVectors), i)
})
}
}