Skip to content

Commit

Permalink
Add tests for examplars
Browse files Browse the repository at this point in the history
Signed-off-by: beorn7 <beorn@grafana.com>
  • Loading branch information
beorn7 committed Jan 24, 2020
1 parent 57d4125 commit c32ffd1
Show file tree
Hide file tree
Showing 4 changed files with 144 additions and 6 deletions.
6 changes: 4 additions & 2 deletions prometheus/counter.go
Expand Up @@ -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
}
Expand All @@ -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 {
Expand Down Expand Up @@ -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)
}
Expand Down
62 changes: 62 additions & 0 deletions prometheus/counter_test.go
Expand Up @@ -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"
)
Expand Down Expand Up @@ -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")
}
}
5 changes: 4 additions & 1 deletion prometheus/histogram.go
Expand Up @@ -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 {
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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)
}
Expand Down
77 changes: 74 additions & 3 deletions prometheus/histogram_test.go
Expand Up @@ -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"
)
Expand Down Expand Up @@ -182,7 +186,11 @@ func TestHistogramConcurrency(t *testing.T) {
go func(vals []float64) {
start.Wait()
for _, v := range vals {
sum.Observe(v)
if n%2 == 0 {
sum.Observe(v)
} else {
sum.ObserveWithExemplar(v, Labels{"foo": "bar"})
}
}
end.Done()
}(vals)
Expand All @@ -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 {
Expand Down Expand Up @@ -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)
}
}
}

0 comments on commit c32ffd1

Please sign in to comment.