Skip to content

Commit 719f3e9

Browse files
committed
Add tests for examplars
Signed-off-by: beorn7 <[email protected]>
1 parent 67bdff8 commit 719f3e9

File tree

4 files changed

+142
-6
lines changed

4 files changed

+142
-6
lines changed

prometheus/counter.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ func NewCounter(opts CounterOpts) Counter {
7272
nil,
7373
opts.ConstLabels,
7474
)
75-
result := &counter{desc: desc, labelPairs: desc.constLabelPairs}
75+
result := &counter{desc: desc, labelPairs: desc.constLabelPairs, now: time.Now}
7676
result.init(result) // Init self-collection.
7777
return result
7878
}
@@ -90,6 +90,8 @@ type counter struct {
9090

9191
labelPairs []*dto.LabelPair
9292
exemplar atomic.Value // *dto.Exemplar
93+
94+
now func() time.Time // To mock out time.Now() for testing.
9395
}
9496

9597
func (c *counter) Desc() *Desc {
@@ -142,7 +144,7 @@ func (c *counter) updateExemplar(v float64, l Labels) {
142144
if l == nil {
143145
return
144146
}
145-
e, err := newExemplar(v, time.Now(), l)
147+
e, err := newExemplar(v, c.now(), l)
146148
if err != nil {
147149
panic(err)
148150
}

prometheus/counter_test.go

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@ import (
1717
"fmt"
1818
"math"
1919
"testing"
20+
"time"
2021

22+
"github.com/golang/protobuf/proto"
23+
"github.com/golang/protobuf/ptypes"
2124
dto "github.com/prometheus/client_model/go"
2225
)
2326

@@ -210,3 +213,61 @@ func TestCounterAddSmall(t *testing.T) {
210213
t.Errorf("expected %q, got %q", expected, got)
211214
}
212215
}
216+
217+
func TestCounterExemplar(t *testing.T) {
218+
now := time.Now()
219+
220+
counter := NewCounter(CounterOpts{
221+
Name: "test",
222+
Help: "test help",
223+
}).(*counter)
224+
counter.now = func() time.Time { return now }
225+
226+
ts, err := ptypes.TimestampProto(now)
227+
if err != nil {
228+
t.Fatal(err)
229+
}
230+
expectedExemplar := &dto.Exemplar{
231+
Label: []*dto.LabelPair{
232+
&dto.LabelPair{Name: proto.String("foo"), Value: proto.String("bar")},
233+
},
234+
Value: proto.Float64(42),
235+
Timestamp: ts,
236+
}
237+
238+
counter.AddWithExemplar(42, Labels{"foo": "bar"})
239+
if expected, got := expectedExemplar.String(), counter.exemplar.Load().(*dto.Exemplar).String(); expected != got {
240+
t.Errorf("expected exemplar %s, got %s.", expected, got)
241+
}
242+
243+
addExemplarWithInvalidLabel := func() (err error) {
244+
defer func() {
245+
if e := recover(); e != nil {
246+
err = e.(error)
247+
}
248+
}()
249+
// Should panic because of invalid label name.
250+
counter.AddWithExemplar(42, Labels{":o)": "smile"})
251+
return nil
252+
}
253+
if addExemplarWithInvalidLabel() == nil {
254+
t.Error("adding exemplar with invalid label succeeded")
255+
}
256+
257+
addExemplarWithOversizedLabels := func() (err error) {
258+
defer func() {
259+
if e := recover(); e != nil {
260+
err = e.(error)
261+
}
262+
}()
263+
// Should panic because of 65 runes.
264+
counter.AddWithExemplar(42, Labels{
265+
"abcdefghijklmnopqrstuvwxyz": "26+16 characters",
266+
"x1234567": "8+15 characters",
267+
})
268+
return nil
269+
}
270+
if addExemplarWithOversizedLabels() == nil {
271+
t.Error("adding exemplar with oversized labels succeeded")
272+
}
273+
}

prometheus/histogram.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ func newHistogram(desc *Desc, opts HistogramOpts, labelValues ...string) Histogr
199199
upperBounds: opts.Buckets,
200200
labelPairs: makeLabelPairs(desc, labelValues),
201201
counts: [2]*histogramCounts{{}, {}},
202+
now: time.Now,
202203
}
203204
for i, upperBound := range h.upperBounds {
204205
if i < len(h.upperBounds)-1 {
@@ -267,6 +268,8 @@ type histogram struct {
267268
upperBounds []float64
268269
labelPairs []*dto.LabelPair
269270
exemplars []atomic.Value // One more than buckets (to include +Inf), each a *dto.Exemplar.
271+
272+
now func() time.Time // To mock out time.Now() for testing.
270273
}
271274

272275
func (h *histogram) Desc() *Desc {
@@ -398,7 +401,7 @@ func (h *histogram) updateExemplar(v float64, bucket int, l Labels) {
398401
if l == nil {
399402
return
400403
}
401-
e, err := newExemplar(v, time.Now(), l)
404+
e, err := newExemplar(v, h.now(), l)
402405
if err != nil {
403406
panic(err)
404407
}

prometheus/histogram_test.go

Lines changed: 73 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@ import (
2222
"sync"
2323
"testing"
2424
"testing/quick"
25+
"time"
2526

27+
"github.com/golang/protobuf/proto"
28+
"github.com/golang/protobuf/ptypes"
2629
dto "github.com/prometheus/client_model/go"
2730
)
2831

@@ -182,7 +185,11 @@ func TestHistogramConcurrency(t *testing.T) {
182185
go func(vals []float64) {
183186
start.Wait()
184187
for _, v := range vals {
185-
sum.Observe(v)
188+
if n%2 == 0 {
189+
sum.Observe(v)
190+
} else {
191+
sum.ObserveWithExemplar(v, Labels{"foo": "bar"})
192+
}
186193
}
187194
end.Done()
188195
}(vals)
@@ -201,9 +208,13 @@ func TestHistogramConcurrency(t *testing.T) {
201208
}
202209

203210
wantCounts := getCumulativeCounts(allVars)
211+
wantBuckets := len(testBuckets)
212+
if !math.IsInf(m.Histogram.Bucket[len(m.Histogram.Bucket)-1].GetUpperBound(), +1) {
213+
wantBuckets--
214+
}
204215

205-
if got, want := len(m.Histogram.Bucket), len(testBuckets)-1; got != want {
206-
t.Errorf("got %d buckets in protobuf, want %d", got, want)
216+
if got := len(m.Histogram.Bucket); got != wantBuckets {
217+
t.Errorf("got %d buckets in protobuf, want %d", got, wantBuckets)
207218
}
208219
for i, wantBound := range testBuckets {
209220
if i == len(testBuckets)-1 {
@@ -384,3 +395,62 @@ func TestHistogramAtomicObserve(t *testing.T) {
384395
runtime.Gosched()
385396
}
386397
}
398+
399+
func TestHistogramExemplar(t *testing.T) {
400+
now := time.Now()
401+
402+
histogram := NewHistogram(HistogramOpts{
403+
Name: "test",
404+
Help: "test help",
405+
Buckets: []float64{1, 2, 3, 4},
406+
}).(*histogram)
407+
histogram.now = func() time.Time { return now }
408+
409+
ts, err := ptypes.TimestampProto(now)
410+
if err != nil {
411+
t.Fatal(err)
412+
}
413+
expectedExemplars := []*dto.Exemplar{
414+
nil,
415+
&dto.Exemplar{
416+
Label: []*dto.LabelPair{
417+
&dto.LabelPair{Name: proto.String("id"), Value: proto.String("2")},
418+
},
419+
Value: proto.Float64(1.6),
420+
Timestamp: ts,
421+
},
422+
nil,
423+
&dto.Exemplar{
424+
Label: []*dto.LabelPair{
425+
&dto.LabelPair{Name: proto.String("id"), Value: proto.String("3")},
426+
},
427+
Value: proto.Float64(4),
428+
Timestamp: ts,
429+
},
430+
&dto.Exemplar{
431+
Label: []*dto.LabelPair{
432+
&dto.LabelPair{Name: proto.String("id"), Value: proto.String("4")},
433+
},
434+
Value: proto.Float64(4.5),
435+
Timestamp: ts,
436+
},
437+
}
438+
439+
histogram.ObserveWithExemplar(1.5, Labels{"id": "1"})
440+
histogram.ObserveWithExemplar(1.6, Labels{"id": "2"}) // To replace exemplar in bucket 0.
441+
histogram.ObserveWithExemplar(4, Labels{"id": "3"})
442+
histogram.ObserveWithExemplar(4.5, Labels{"id": "4"}) // Should go to +Inf bucket.
443+
444+
for i, ex := range histogram.exemplars {
445+
var got, expected string
446+
if val := ex.Load(); val != nil {
447+
got = val.(*dto.Exemplar).String()
448+
}
449+
if expectedExemplars[i] != nil {
450+
expected = expectedExemplars[i].String()
451+
}
452+
if got != expected {
453+
t.Errorf("expected exemplar %s, got %s.", expected, got)
454+
}
455+
}
456+
}

0 commit comments

Comments
 (0)