1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package metric
16
17 import (
18 "fmt"
19 "sort"
20 "testing"
21 "time"
22
23 "github.com/google/go-cmp/cmp"
24
25 "go.opencensus.io/metric/metricdata"
26 )
27
28 func TestGauge(t *testing.T) {
29 r := NewRegistry()
30
31 f, _ := r.AddFloat64Gauge("TestGauge",
32 WithLabelKeys("k1", "k2"))
33 e, _ := f.GetEntry(metricdata.LabelValue{}, metricdata.LabelValue{})
34 e.Set(5)
35 e, _ = f.GetEntry(metricdata.NewLabelValue("k1v1"), metricdata.LabelValue{})
36 e.Add(1)
37 e, _ = f.GetEntry(metricdata.NewLabelValue("k1v1"), metricdata.LabelValue{})
38 e.Add(1)
39 e, _ = f.GetEntry(metricdata.NewLabelValue("k1v2"), metricdata.NewLabelValue("k2v2"))
40 e.Add(1)
41 m := r.Read()
42 want := []*metricdata.Metric{
43 {
44 Descriptor: metricdata.Descriptor{
45 Name: "TestGauge",
46 LabelKeys: []metricdata.LabelKey{
47 {Key: "k1"},
48 {Key: "k2"},
49 },
50 Type: metricdata.TypeGaugeFloat64,
51 },
52 TimeSeries: []*metricdata.TimeSeries{
53 {
54 LabelValues: []metricdata.LabelValue{
55 {}, {},
56 },
57 Points: []metricdata.Point{
58 metricdata.NewFloat64Point(time.Time{}, 5),
59 },
60 },
61 {
62 LabelValues: []metricdata.LabelValue{
63 metricdata.NewLabelValue("k1v1"),
64 {},
65 },
66 Points: []metricdata.Point{
67 metricdata.NewFloat64Point(time.Time{}, 2),
68 },
69 },
70 {
71 LabelValues: []metricdata.LabelValue{
72 metricdata.NewLabelValue("k1v2"),
73 metricdata.NewLabelValue("k2v2"),
74 },
75 Points: []metricdata.Point{
76 metricdata.NewFloat64Point(time.Time{}, 1),
77 },
78 },
79 },
80 },
81 }
82 canonicalize(m)
83 canonicalize(want)
84 if diff := cmp.Diff(m, want, cmp.Comparer(ignoreTimes)); diff != "" {
85 t.Errorf("-got +want: %s", diff)
86 }
87 }
88
89 func TestGaugeConstLabel(t *testing.T) {
90 r := NewRegistry()
91
92 f, _ := r.AddFloat64Gauge("TestGaugeWithConstLabel",
93 WithLabelKeys("k1"),
94 WithConstLabel(map[metricdata.LabelKey]metricdata.LabelValue{
95 {Key: "const"}: metricdata.NewLabelValue("same"),
96 {Key: "const2"}: metricdata.NewLabelValue("same2"),
97 }))
98
99 e, _ := f.GetEntry(metricdata.LabelValue{})
100 e.Set(5)
101 e, _ = f.GetEntry(metricdata.NewLabelValue("k1v1"))
102 e.Add(1)
103 m := r.Read()
104 want := []*metricdata.Metric{
105 {
106 Descriptor: metricdata.Descriptor{
107 Name: "TestGaugeWithConstLabel",
108 LabelKeys: []metricdata.LabelKey{
109 {Key: "const"},
110 {Key: "const2"},
111 {Key: "k1"}},
112 Type: metricdata.TypeGaugeFloat64,
113 },
114 TimeSeries: []*metricdata.TimeSeries{
115 {
116 LabelValues: []metricdata.LabelValue{
117 metricdata.NewLabelValue("same"),
118 metricdata.NewLabelValue("same2"),
119 {},
120 },
121 Points: []metricdata.Point{
122 metricdata.NewFloat64Point(time.Time{}, 5),
123 },
124 },
125 {
126 LabelValues: []metricdata.LabelValue{
127 metricdata.NewLabelValue("same"),
128 metricdata.NewLabelValue("same2"),
129 metricdata.NewLabelValue("k1v1"),
130 },
131 Points: []metricdata.Point{
132 metricdata.NewFloat64Point(time.Time{}, 1),
133 },
134 },
135 },
136 },
137 }
138 canonicalize(m)
139 canonicalize(want)
140 if diff := cmp.Diff(m, want, cmp.Comparer(ignoreTimes)); diff != "" {
141 t.Errorf("-got +want: %s", diff)
142 }
143 }
144
145 func TestGaugeMetricDescriptor(t *testing.T) {
146 r := NewRegistry()
147
148 gf, _ := r.AddFloat64Gauge("float64_gauge")
149 compareType(gf.bm.desc.Type, metricdata.TypeGaugeFloat64, t)
150 gi, _ := r.AddInt64Gauge("int64_gauge")
151 compareType(gi.bm.desc.Type, metricdata.TypeGaugeInt64, t)
152 dgf, _ := r.AddFloat64DerivedGauge("derived_float64_gauge")
153 compareType(dgf.bm.desc.Type, metricdata.TypeGaugeFloat64, t)
154 dgi, _ := r.AddInt64DerivedGauge("derived_int64_gauge")
155 compareType(dgi.bm.desc.Type, metricdata.TypeGaugeInt64, t)
156 }
157
158 func compareType(got, want metricdata.Type, t *testing.T) {
159 if got != want {
160 t.Errorf("metricdata type: got %v, want %v\n", got, want)
161 }
162 }
163
164 func TestGaugeMetricOptionDesc(t *testing.T) {
165 r := NewRegistry()
166 name := "testOptDesc"
167 gf, _ := r.AddFloat64Gauge(name, WithDescription("test"))
168 want := metricdata.Descriptor{
169 Name: name,
170 Description: "test",
171 Type: metricdata.TypeGaugeFloat64,
172 }
173 got := gf.bm.desc
174 if !cmp.Equal(got, want) {
175 t.Errorf("metric option description: got %v, want %v\n", got, want)
176 }
177 }
178
179 func TestGaugeMetricOptionUnit(t *testing.T) {
180 r := NewRegistry()
181 name := "testOptUnit"
182 gf, _ := r.AddFloat64Gauge(name, WithUnit(metricdata.UnitMilliseconds))
183 want := metricdata.Descriptor{
184 Name: name,
185 Unit: metricdata.UnitMilliseconds,
186 Type: metricdata.TypeGaugeFloat64,
187 }
188 got := gf.bm.desc
189 if !cmp.Equal(got, want) {
190 t.Errorf("metric descriptor: got %v, want %v\n", got, want)
191 }
192 }
193
194 func TestGaugeMetricOptionLabelKeys(t *testing.T) {
195 r := NewRegistry()
196 name := "testOptUnit"
197 gf, _ := r.AddFloat64Gauge(name, WithLabelKeys("k1", "k3"))
198 want := metricdata.Descriptor{
199 Name: name,
200 LabelKeys: []metricdata.LabelKey{
201 {Key: "k1"},
202 {Key: "k3"},
203 },
204 Type: metricdata.TypeGaugeFloat64,
205 }
206 got := gf.bm.desc
207 if !cmp.Equal(got, want) {
208 t.Errorf("metric descriptor: got %v, want %v\n", got, want)
209 }
210 }
211
212 func TestGaugeMetricOptionLabelKeysAndDesc(t *testing.T) {
213 r := NewRegistry()
214 name := "testOptUnit"
215 lks := []metricdata.LabelKey{}
216 lks = append(lks, metricdata.LabelKey{Key: "k1", Description: "desc k1"},
217 metricdata.LabelKey{Key: "k3", Description: "desc k3"})
218 gf, _ := r.AddFloat64Gauge(name, WithLabelKeysAndDescription(lks...))
219 want := metricdata.Descriptor{
220 Name: name,
221 LabelKeys: []metricdata.LabelKey{
222 {Key: "k1", Description: "desc k1"},
223 {Key: "k3", Description: "desc k3"},
224 },
225 Type: metricdata.TypeGaugeFloat64,
226 }
227 got := gf.bm.desc
228 if !cmp.Equal(got, want) {
229 t.Errorf("metric descriptor: got %v, want %v\n", got, want)
230 }
231 }
232
233 func TestGaugeMetricOptionDefault(t *testing.T) {
234 r := NewRegistry()
235 name := "testOptUnit"
236 gf, _ := r.AddFloat64Gauge(name)
237 want := metricdata.Descriptor{
238 Name: name,
239 Type: metricdata.TypeGaugeFloat64,
240 }
241 got := gf.bm.desc
242 if !cmp.Equal(got, want) {
243 t.Errorf("metric descriptor: got %v, want %v\n", got, want)
244 }
245 }
246
247 func TestFloat64Entry_Add(t *testing.T) {
248 r := NewRegistry()
249 g, _ := r.AddFloat64Gauge("g")
250 e, _ := g.GetEntry()
251 e.Add(0)
252 ms := r.Read()
253 if got, want := ms[0].TimeSeries[0].Points[0].Value.(float64), 0.0; got != want {
254 t.Errorf("value = %v, want %v", got, want)
255 }
256 e, _ = g.GetEntry()
257 e.Add(1)
258 ms = r.Read()
259 if got, want := ms[0].TimeSeries[0].Points[0].Value.(float64), 1.0; got != want {
260 t.Errorf("value = %v, want %v", got, want)
261 }
262 e, _ = g.GetEntry()
263 e.Add(-1)
264 ms = r.Read()
265 if got, want := ms[0].TimeSeries[0].Points[0].Value.(float64), 0.0; got != want {
266 t.Errorf("value = %v, want %v", got, want)
267 }
268 }
269
270 func TestFloat64Gauge_Add_NegativeTotals(t *testing.T) {
271 r := NewRegistry()
272 g, _ := r.AddFloat64Gauge("g")
273 e, _ := g.GetEntry()
274 e.Add(-1.0)
275 ms := r.Read()
276 if got, want := ms[0].TimeSeries[0].Points[0].Value.(float64), float64(0); got != want {
277 t.Errorf("value = %v, want %v", got, want)
278 }
279 }
280
281 func TestInt64GaugeEntry_Add(t *testing.T) {
282 r := NewRegistry()
283 g, _ := r.AddInt64Gauge("g")
284 e, _ := g.GetEntry()
285 e.Add(0)
286 ms := r.Read()
287 if got, want := ms[0].TimeSeries[0].Points[0].Value.(int64), int64(0); got != want {
288 t.Errorf("value = %v, want %v", got, want)
289 }
290 e, _ = g.GetEntry()
291 e.Add(1)
292 ms = r.Read()
293 if got, want := ms[0].TimeSeries[0].Points[0].Value.(int64), int64(1); got != want {
294 t.Errorf("value = %v, want %v", got, want)
295 }
296 }
297
298 func TestInt64Gauge_Add_NegativeTotals(t *testing.T) {
299 r := NewRegistry()
300 g, _ := r.AddInt64Gauge("g")
301 e, _ := g.GetEntry()
302 e.Add(-1)
303 ms := r.Read()
304 if got, want := ms[0].TimeSeries[0].Points[0].Value.(int64), int64(0); got != want {
305 t.Errorf("value = %v, want %v", got, want)
306 }
307 }
308
309 func TestGaugeWithSameNameDiffType(t *testing.T) {
310 r := NewRegistry()
311 r.AddInt64Gauge("g")
312 _, gotErr := r.AddFloat64Gauge("g")
313 if gotErr == nil {
314 t.Errorf("got: nil, want error: %v", errMetricExistsWithDiffType)
315 }
316 _, gotErr = r.AddInt64DerivedGauge("g")
317 if gotErr == nil {
318 t.Errorf("got: nil, want error: %v", errMetricExistsWithDiffType)
319 }
320 _, gotErr = r.AddFloat64DerivedGauge("g")
321 if gotErr == nil {
322 t.Errorf("got: nil, want error: %v", errMetricExistsWithDiffType)
323 }
324 }
325
326 func TestGaugeWithLabelMismatch(t *testing.T) {
327 r := NewRegistry()
328 g, _ := r.AddInt64Gauge("g", WithLabelKeys("k1"))
329 _, gotErr := g.GetEntry(metricdata.NewLabelValue("k1v2"), metricdata.NewLabelValue("k2v2"))
330 if gotErr == nil {
331 t.Errorf("got: nil, want error: %v", errKeyValueMismatch)
332 }
333 }
334
335 func TestMapKey(t *testing.T) {
336 cases := [][]metricdata.LabelValue{
337 {},
338 {metricdata.LabelValue{}},
339 {metricdata.NewLabelValue("")},
340 {metricdata.NewLabelValue("-")},
341 {metricdata.NewLabelValue(",")},
342 {metricdata.NewLabelValue("v1"), metricdata.NewLabelValue("v2")},
343 {metricdata.NewLabelValue("v1"), metricdata.LabelValue{}},
344 {metricdata.NewLabelValue("v1"), metricdata.LabelValue{}, metricdata.NewLabelValue(string([]byte{0}))},
345 {metricdata.LabelValue{}, metricdata.LabelValue{}},
346 }
347 for i, tc := range cases {
348 t.Run(fmt.Sprintf("case %d", i), func(t *testing.T) {
349 g := &baseMetric{
350 keys: make([]metricdata.LabelKey, len(tc)),
351 }
352 mk := g.encodeLabelVals(tc)
353 vals := g.decodeLabelVals(mk)
354 if diff := cmp.Diff(vals, tc); diff != "" {
355 t.Errorf("values differ after serialization -got +want: %s", diff)
356 }
357 })
358 }
359 }
360
361 func TestRaceCondition(t *testing.T) {
362 r := NewRegistry()
363
364
365 var ms = []*metricdata.Metric{}
366 for i := 0; i < 5; i++ {
367 go func(k int) {
368 for j := 0; j < 5; j++ {
369 g, _ := r.AddInt64Gauge(fmt.Sprintf("g%d%d", k, j))
370 e, _ := g.GetEntry()
371 e.Add(1)
372 }
373 }(i)
374 }
375 time.Sleep(1 * time.Second)
376 ms = r.Read()
377 if got, want := ms[0].TimeSeries[0].Points[0].Value.(int64), int64(1); got != want {
378 t.Errorf("value = %v, want %v", got, want)
379 }
380 }
381
382 func ignoreTimes(_, _ time.Time) bool {
383 return true
384 }
385
386 func canonicalize(ms []*metricdata.Metric) {
387 for _, m := range ms {
388 sort.Slice(m.TimeSeries, func(i, j int) bool {
389
390 iStr := ""
391
392 for _, label := range m.TimeSeries[i].LabelValues {
393 iStr += fmt.Sprintf("%+v", label)
394 }
395
396 jStr := ""
397 for _, label := range m.TimeSeries[j].LabelValues {
398 jStr += fmt.Sprintf("%+v", label)
399 }
400
401 return iStr < jStr
402 })
403 }
404 }
405
406 type queueInt64 struct {
407 size int64
408 }
409
410 func (q *queueInt64) ToInt64() int64 {
411 return q.size
412 }
413
414 func TestInt64DerivedGaugeEntry_Add(t *testing.T) {
415 r := NewRegistry()
416 q := &queueInt64{3}
417 g, _ := r.AddInt64DerivedGauge("g", WithLabelKeys("k1", "k2"))
418 err := g.UpsertEntry(q.ToInt64, metricdata.NewLabelValue("k1v1"), metricdata.LabelValue{})
419 if err != nil {
420 t.Errorf("want: nil, got: %v", err)
421 }
422 ms := r.Read()
423 if got, want := ms[0].TimeSeries[0].Points[0].Value.(int64), int64(3); got != want {
424 t.Errorf("value = %v, want %v", got, want)
425 }
426 q.size = 5
427 ms = r.Read()
428 if got, want := ms[0].TimeSeries[0].Points[0].Value.(int64), int64(5); got != want {
429 t.Errorf("value = %v, want %v", got, want)
430 }
431 }
432
433 func TestInt64DerivedGaugeEntry_AddWithNilObj(t *testing.T) {
434 r := NewRegistry()
435 g, _ := r.AddInt64DerivedGauge("g", WithLabelKeys("k1", "k2"))
436 gotErr := g.UpsertEntry(nil, metricdata.NewLabelValue("k1v1"), metricdata.LabelValue{})
437 if gotErr == nil {
438 t.Errorf("expected error but got nil")
439 }
440 }
441
442 func TestInt64DerivedGaugeEntry_AddWithInvalidLabels(t *testing.T) {
443 r := NewRegistry()
444 q := &queueInt64{3}
445 g, _ := r.AddInt64DerivedGauge("g", WithLabelKeys("k1", "k2"))
446 gotErr := g.UpsertEntry(q.ToInt64, metricdata.NewLabelValue("k1v1"))
447 if gotErr == nil {
448 t.Errorf("expected error but got nil")
449 }
450 }
451
452 func TestInt64DerivedGaugeEntry_Update(t *testing.T) {
453 r := NewRegistry()
454 q := &queueInt64{3}
455 q2 := &queueInt64{5}
456 g, _ := r.AddInt64DerivedGauge("g", WithLabelKeys("k1", "k2"))
457 g.UpsertEntry(q.ToInt64, metricdata.NewLabelValue("k1v1"), metricdata.LabelValue{})
458 gotErr := g.UpsertEntry(q2.ToInt64, metricdata.NewLabelValue("k1v1"), metricdata.LabelValue{})
459 if gotErr != nil {
460 t.Errorf("got: %v, want: nil", gotErr)
461 }
462 ms := r.Read()
463 if got, want := ms[0].TimeSeries[0].Points[0].Value.(int64), int64(5); got != want {
464 t.Errorf("value = %v, want %v", got, want)
465 }
466 }
467
468 func TestInt64DerivedGaugeEntry_UpsertConstLabels(t *testing.T) {
469 r := NewRegistry()
470 q := &queueInt64{3}
471 g, _ := r.AddInt64DerivedGauge("g",
472 WithConstLabel(map[metricdata.LabelKey]metricdata.LabelValue{
473 {Key: "const"}: metricdata.NewLabelValue("same"),
474 }))
475 err := g.UpsertEntry(q.ToInt64)
476 if err != nil {
477 t.Errorf("want: nil, got: %v", err)
478 }
479 ms := r.Read()
480 if got, want := ms[0].TimeSeries[0].Points[0].Value.(int64), int64(3); got != want {
481 t.Errorf("value = %v, want %v", got, want)
482 }
483 if got, want := ms[0].Descriptor.LabelKeys[0].Key, "const"; got != want {
484 t.Errorf("label key = %v, want %v", got, want)
485 }
486 if got, want := ms[0].TimeSeries[0].LabelValues[0].Value, "same"; got != want {
487 t.Errorf("label value = %v, want %v", got, want)
488 }
489 }
490
491 type queueFloat64 struct {
492 size float64
493 }
494
495 func (q *queueFloat64) ToFloat64() float64 {
496 return q.size
497 }
498
499 func TestFloat64DerivedGaugeEntry_Add(t *testing.T) {
500 r := NewRegistry()
501 q := &queueFloat64{5.0}
502 g, _ := r.AddFloat64DerivedGauge("g", WithLabelKeys("k1", "k2"))
503 err := g.UpsertEntry(q.ToFloat64, metricdata.NewLabelValue("k1v1"), metricdata.LabelValue{})
504 if err != nil {
505 t.Errorf("want: nil, got: %v", err)
506 }
507 ms := r.Read()
508 if got, want := ms[0].TimeSeries[0].Points[0].Value.(float64), float64(5.0); got != want {
509 t.Errorf("value = %v, want %v", got, want)
510 }
511 q.size = 5
512 ms = r.Read()
513 if got, want := ms[0].TimeSeries[0].Points[0].Value.(float64), float64(5.0); got != want {
514 t.Errorf("value = %v, want %v", got, want)
515 }
516 }
517
518 func TestFloat64DerivedGaugeEntry_AddWithNilObj(t *testing.T) {
519 r := NewRegistry()
520 g, _ := r.AddFloat64DerivedGauge("g", WithLabelKeys("k1", "k2"))
521 gotErr := g.UpsertEntry(nil, metricdata.NewLabelValue("k1v1"), metricdata.LabelValue{})
522 if gotErr == nil {
523 t.Errorf("expected error but got nil")
524 }
525 }
526
527 func TestFloat64DerivedGaugeEntry_AddWithInvalidLabels(t *testing.T) {
528 r := NewRegistry()
529 q := &queueFloat64{3}
530 g, _ := r.AddFloat64DerivedGauge("g", WithLabelKeys("k1", "k2"))
531 gotErr := g.UpsertEntry(q.ToFloat64, metricdata.NewLabelValue("k1v1"))
532 if gotErr == nil {
533 t.Errorf("expected error but got nil")
534 }
535 }
536
537 func TestFloat64DerivedGaugeEntry_Update(t *testing.T) {
538 r := NewRegistry()
539 q := &queueFloat64{3.0}
540 q2 := &queueFloat64{5.0}
541 g, _ := r.AddFloat64DerivedGauge("g", WithLabelKeys("k1", "k2"))
542 g.UpsertEntry(q.ToFloat64, metricdata.NewLabelValue("k1v1"), metricdata.LabelValue{})
543 gotErr := g.UpsertEntry(q2.ToFloat64, metricdata.NewLabelValue("k1v1"), metricdata.LabelValue{})
544 if gotErr != nil {
545 t.Errorf("got: %v, want: nil", gotErr)
546 }
547 ms := r.Read()
548 if got, want := ms[0].TimeSeries[0].Points[0].Value.(float64), float64(5.0); got != want {
549 t.Errorf("value = %v, want %v", got, want)
550 }
551 }
552
View as plain text