Add tests for examplars
Signed-off-by: beorn7 <beorn@grafana.com>
This commit is contained in:
parent
57d41259e1
commit
c32ffd121f
|
@ -70,7 +70,7 @@ func NewCounter(opts CounterOpts) Counter {
|
|||
nil,
|
||||
opts.ConstLabels,
|
||||
)
|
||||
result := &counter{desc: desc, labelPairs: desc.constLabelPairs}
|
||||
result := &counter{desc: desc, labelPairs: desc.constLabelPairs, now: time.Now}
|
||||
result.init(result) // Init self-collection.
|
||||
return result
|
||||
}
|
||||
|
@ -88,6 +88,8 @@ type counter struct {
|
|||
|
||||
labelPairs []*dto.LabelPair
|
||||
exemplar atomic.Value // Containing nil or a *dto.Exemplar.
|
||||
|
||||
now func() time.Time // To mock out time.Now() for testing.
|
||||
}
|
||||
|
||||
func (c *counter) Desc() *Desc {
|
||||
|
@ -140,7 +142,7 @@ func (c *counter) updateExemplar(v float64, l Labels) {
|
|||
if l == nil {
|
||||
return
|
||||
}
|
||||
e, err := newExemplar(v, time.Now(), l)
|
||||
e, err := newExemplar(v, c.now(), l)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
|
|
@ -17,6 +17,10 @@ import (
|
|||
"fmt"
|
||||
"math"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/golang/protobuf/ptypes"
|
||||
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
)
|
||||
|
@ -210,3 +214,61 @@ func TestCounterAddSmall(t *testing.T) {
|
|||
t.Errorf("expected %q, got %q", expected, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCounterExemplar(t *testing.T) {
|
||||
now := time.Now()
|
||||
|
||||
counter := NewCounter(CounterOpts{
|
||||
Name: "test",
|
||||
Help: "test help",
|
||||
}).(*counter)
|
||||
counter.now = func() time.Time { return now }
|
||||
|
||||
ts, err := ptypes.TimestampProto(now)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
expectedExemplar := &dto.Exemplar{
|
||||
Label: []*dto.LabelPair{
|
||||
&dto.LabelPair{Name: proto.String("foo"), Value: proto.String("bar")},
|
||||
},
|
||||
Value: proto.Float64(42),
|
||||
Timestamp: ts,
|
||||
}
|
||||
|
||||
counter.AddWithExemplar(42, Labels{"foo": "bar"})
|
||||
if expected, got := expectedExemplar.String(), counter.exemplar.Load().(*dto.Exemplar).String(); expected != got {
|
||||
t.Errorf("expected exemplar %s, got %s.", expected, got)
|
||||
}
|
||||
|
||||
addExemplarWithInvalidLabel := func() (err error) {
|
||||
defer func() {
|
||||
if e := recover(); e != nil {
|
||||
err = e.(error)
|
||||
}
|
||||
}()
|
||||
// Should panic because of invalid label name.
|
||||
counter.AddWithExemplar(42, Labels{":o)": "smile"})
|
||||
return nil
|
||||
}
|
||||
if addExemplarWithInvalidLabel() == nil {
|
||||
t.Error("adding exemplar with invalid label succeeded")
|
||||
}
|
||||
|
||||
addExemplarWithOversizedLabels := func() (err error) {
|
||||
defer func() {
|
||||
if e := recover(); e != nil {
|
||||
err = e.(error)
|
||||
}
|
||||
}()
|
||||
// Should panic because of 65 runes.
|
||||
counter.AddWithExemplar(42, Labels{
|
||||
"abcdefghijklmnopqrstuvwxyz": "26+16 characters",
|
||||
"x1234567": "8+15 characters",
|
||||
})
|
||||
return nil
|
||||
}
|
||||
if addExemplarWithOversizedLabels() == nil {
|
||||
t.Error("adding exemplar with oversized labels succeeded")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -198,6 +198,7 @@ func newHistogram(desc *Desc, opts HistogramOpts, labelValues ...string) Histogr
|
|||
upperBounds: opts.Buckets,
|
||||
labelPairs: makeLabelPairs(desc, labelValues),
|
||||
counts: [2]*histogramCounts{{}, {}},
|
||||
now: time.Now,
|
||||
}
|
||||
for i, upperBound := range h.upperBounds {
|
||||
if i < len(h.upperBounds)-1 {
|
||||
|
@ -266,6 +267,8 @@ type histogram struct {
|
|||
upperBounds []float64
|
||||
labelPairs []*dto.LabelPair
|
||||
exemplars []atomic.Value // One more than buckets (to include +Inf), each a *dto.Exemplar.
|
||||
|
||||
now func() time.Time // To mock out time.Now() for testing.
|
||||
}
|
||||
|
||||
func (h *histogram) Desc() *Desc {
|
||||
|
@ -397,7 +400,7 @@ func (h *histogram) updateExemplar(v float64, bucket int, l Labels) {
|
|||
if l == nil {
|
||||
return
|
||||
}
|
||||
e, err := newExemplar(v, time.Now(), l)
|
||||
e, err := newExemplar(v, h.now(), l)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
|
|
@ -22,6 +22,10 @@ import (
|
|||
"sync"
|
||||
"testing"
|
||||
"testing/quick"
|
||||
"time"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/golang/protobuf/ptypes"
|
||||
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
)
|
||||
|
@ -182,7 +186,11 @@ func TestHistogramConcurrency(t *testing.T) {
|
|||
go func(vals []float64) {
|
||||
start.Wait()
|
||||
for _, v := range vals {
|
||||
if n%2 == 0 {
|
||||
sum.Observe(v)
|
||||
} else {
|
||||
sum.ObserveWithExemplar(v, Labels{"foo": "bar"})
|
||||
}
|
||||
}
|
||||
end.Done()
|
||||
}(vals)
|
||||
|
@ -201,9 +209,13 @@ func TestHistogramConcurrency(t *testing.T) {
|
|||
}
|
||||
|
||||
wantCounts := getCumulativeCounts(allVars)
|
||||
wantBuckets := len(testBuckets)
|
||||
if !math.IsInf(m.Histogram.Bucket[len(m.Histogram.Bucket)-1].GetUpperBound(), +1) {
|
||||
wantBuckets--
|
||||
}
|
||||
|
||||
if got, want := len(m.Histogram.Bucket), len(testBuckets)-1; got != want {
|
||||
t.Errorf("got %d buckets in protobuf, want %d", got, want)
|
||||
if got := len(m.Histogram.Bucket); got != wantBuckets {
|
||||
t.Errorf("got %d buckets in protobuf, want %d", got, wantBuckets)
|
||||
}
|
||||
for i, wantBound := range testBuckets {
|
||||
if i == len(testBuckets)-1 {
|
||||
|
@ -384,3 +396,62 @@ func TestHistogramAtomicObserve(t *testing.T) {
|
|||
runtime.Gosched()
|
||||
}
|
||||
}
|
||||
|
||||
func TestHistogramExemplar(t *testing.T) {
|
||||
now := time.Now()
|
||||
|
||||
histogram := NewHistogram(HistogramOpts{
|
||||
Name: "test",
|
||||
Help: "test help",
|
||||
Buckets: []float64{1, 2, 3, 4},
|
||||
}).(*histogram)
|
||||
histogram.now = func() time.Time { return now }
|
||||
|
||||
ts, err := ptypes.TimestampProto(now)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
expectedExemplars := []*dto.Exemplar{
|
||||
nil,
|
||||
&dto.Exemplar{
|
||||
Label: []*dto.LabelPair{
|
||||
&dto.LabelPair{Name: proto.String("id"), Value: proto.String("2")},
|
||||
},
|
||||
Value: proto.Float64(1.6),
|
||||
Timestamp: ts,
|
||||
},
|
||||
nil,
|
||||
&dto.Exemplar{
|
||||
Label: []*dto.LabelPair{
|
||||
&dto.LabelPair{Name: proto.String("id"), Value: proto.String("3")},
|
||||
},
|
||||
Value: proto.Float64(4),
|
||||
Timestamp: ts,
|
||||
},
|
||||
&dto.Exemplar{
|
||||
Label: []*dto.LabelPair{
|
||||
&dto.LabelPair{Name: proto.String("id"), Value: proto.String("4")},
|
||||
},
|
||||
Value: proto.Float64(4.5),
|
||||
Timestamp: ts,
|
||||
},
|
||||
}
|
||||
|
||||
histogram.ObserveWithExemplar(1.5, Labels{"id": "1"})
|
||||
histogram.ObserveWithExemplar(1.6, Labels{"id": "2"}) // To replace exemplar in bucket 0.
|
||||
histogram.ObserveWithExemplar(4, Labels{"id": "3"})
|
||||
histogram.ObserveWithExemplar(4.5, Labels{"id": "4"}) // Should go to +Inf bucket.
|
||||
|
||||
for i, ex := range histogram.exemplars {
|
||||
var got, expected string
|
||||
if val := ex.Load(); val != nil {
|
||||
got = val.(*dto.Exemplar).String()
|
||||
}
|
||||
if expectedExemplars[i] != nil {
|
||||
expected = expectedExemplars[i].String()
|
||||
}
|
||||
if got != expected {
|
||||
t.Errorf("expected exemplar %s, got %s.", expected, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue