2019-04-11 12:59:53 +03:00
|
|
|
package metrics
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"fmt"
|
2024-01-16 00:06:40 +02:00
|
|
|
"io"
|
2022-08-08 17:13:46 +03:00
|
|
|
"strings"
|
2019-04-11 12:59:53 +03:00
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
2023-12-19 01:36:54 +01:00
|
|
|
func TestWriteMetrics(t *testing.T) {
|
|
|
|
t.Run("gauge_uint64", func(t *testing.T) {
|
|
|
|
var bb bytes.Buffer
|
|
|
|
|
|
|
|
WriteGaugeUint64(&bb, "foo", 123)
|
|
|
|
sExpected := "foo 123\n"
|
|
|
|
if s := bb.String(); s != sExpected {
|
|
|
|
t.Fatalf("unexpected value; got\n%s\nwant\n%s", s, sExpected)
|
|
|
|
}
|
|
|
|
|
|
|
|
ExposeMetadata(true)
|
|
|
|
bb.Reset()
|
|
|
|
WriteGaugeUint64(&bb, "foo", 123)
|
|
|
|
sExpected = "# HELP foo\n# TYPE foo gauge\nfoo 123\n"
|
|
|
|
ExposeMetadata(false)
|
|
|
|
if s := bb.String(); s != sExpected {
|
|
|
|
t.Fatalf("unexpected value; got\n%s\nwant\n%s", s, sExpected)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
t.Run("gauge_float64", func(t *testing.T) {
|
|
|
|
var bb bytes.Buffer
|
|
|
|
|
|
|
|
WriteGaugeFloat64(&bb, "foo", 1.23)
|
|
|
|
sExpected := "foo 1.23\n"
|
|
|
|
if s := bb.String(); s != sExpected {
|
|
|
|
t.Fatalf("unexpected value; got\n%s\nwant\n%s", s, sExpected)
|
|
|
|
}
|
|
|
|
|
|
|
|
ExposeMetadata(true)
|
|
|
|
bb.Reset()
|
|
|
|
WriteGaugeFloat64(&bb, "foo", 1.23)
|
|
|
|
sExpected = "# HELP foo\n# TYPE foo gauge\nfoo 1.23\n"
|
|
|
|
ExposeMetadata(false)
|
|
|
|
if s := bb.String(); s != sExpected {
|
|
|
|
t.Fatalf("unexpected value; got\n%s\nwant\n%s", s, sExpected)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
t.Run("counter_uint64", func(t *testing.T) {
|
|
|
|
var bb bytes.Buffer
|
|
|
|
|
|
|
|
WriteCounterUint64(&bb, "foo_total", 123)
|
|
|
|
sExpected := "foo_total 123\n"
|
|
|
|
if s := bb.String(); s != sExpected {
|
|
|
|
t.Fatalf("unexpected value; got\n%s\nwant\n%s", s, sExpected)
|
|
|
|
}
|
|
|
|
|
|
|
|
ExposeMetadata(true)
|
|
|
|
bb.Reset()
|
|
|
|
WriteCounterUint64(&bb, "foo_total", 123)
|
|
|
|
sExpected = "# HELP foo_total\n# TYPE foo_total counter\nfoo_total 123\n"
|
|
|
|
ExposeMetadata(false)
|
|
|
|
if s := bb.String(); s != sExpected {
|
|
|
|
t.Fatalf("unexpected value; got\n%s\nwant\n%s", s, sExpected)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
t.Run("counter_float64", func(t *testing.T) {
|
|
|
|
var bb bytes.Buffer
|
|
|
|
|
|
|
|
WriteCounterFloat64(&bb, "foo_total", 1.23)
|
|
|
|
sExpected := "foo_total 1.23\n"
|
|
|
|
if s := bb.String(); s != sExpected {
|
|
|
|
t.Fatalf("unexpected value; got\n%s\nwant\n%s", s, sExpected)
|
|
|
|
}
|
|
|
|
|
|
|
|
ExposeMetadata(true)
|
|
|
|
bb.Reset()
|
|
|
|
WriteCounterFloat64(&bb, "foo_total", 1.23)
|
|
|
|
sExpected = "# HELP foo_total\n# TYPE foo_total counter\nfoo_total 1.23\n"
|
|
|
|
ExposeMetadata(false)
|
|
|
|
if s := bb.String(); s != sExpected {
|
|
|
|
t.Fatalf("unexpected value; got\n%s\nwant\n%s", s, sExpected)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2022-10-25 10:53:32 +03:00
|
|
|
func TestGetDefaultSet(t *testing.T) {
|
|
|
|
s := GetDefaultSet()
|
|
|
|
if s != defaultSet {
|
|
|
|
t.Fatalf("GetDefaultSet must return defaultSet=%p, but returned %p", defaultSet, s)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestUnregisterAllMetrics(t *testing.T) {
|
|
|
|
for j := 0; j < 3; j++ {
|
|
|
|
for i := 0; i < 10; i++ {
|
|
|
|
_ = NewCounter(fmt.Sprintf("counter_%d", i))
|
|
|
|
_ = NewSummary(fmt.Sprintf("summary_%d", i))
|
|
|
|
_ = NewHistogram(fmt.Sprintf("histogram_%d", i))
|
|
|
|
_ = NewGauge(fmt.Sprintf("gauge_%d", i), func() float64 { return 0 })
|
|
|
|
}
|
|
|
|
if mns := ListMetricNames(); len(mns) == 0 {
|
|
|
|
t.Fatalf("unexpected empty list of metrics on iteration %d", j)
|
|
|
|
}
|
|
|
|
UnregisterAllMetrics()
|
|
|
|
if mns := ListMetricNames(); len(mns) != 0 {
|
|
|
|
t.Fatalf("unexpected metric names after UnregisterAllMetrics call on iteration %d: %q", j, mns)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-16 00:06:40 +02:00
|
|
|
func TestRegisterMetricsWriter(t *testing.T) {
|
|
|
|
RegisterMetricsWriter(func(w io.Writer) {
|
|
|
|
WriteCounterUint64(w, `counter{label="abc"}`, 1234)
|
|
|
|
WriteGaugeFloat64(w, `gauge{a="b",c="d"}`, -34.43)
|
|
|
|
})
|
|
|
|
|
|
|
|
var bb bytes.Buffer
|
|
|
|
WritePrometheus(&bb, false)
|
|
|
|
data := bb.String()
|
|
|
|
|
|
|
|
UnregisterAllMetrics()
|
|
|
|
|
|
|
|
expectedLine := fmt.Sprintf(`counter{label="abc"} 1234` + "\n")
|
|
|
|
if !strings.Contains(data, expectedLine) {
|
|
|
|
t.Fatalf("missing %q in\n%s", expectedLine, data)
|
|
|
|
}
|
|
|
|
|
|
|
|
expectedLine = fmt.Sprintf(`gauge{a="b",c="d"} -34.43` + "\n")
|
|
|
|
if !strings.Contains(data, expectedLine) {
|
|
|
|
t.Fatalf("missing %q in\n%s", expectedLine, data)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-08 17:13:46 +03:00
|
|
|
func TestRegisterUnregisterSet(t *testing.T) {
|
|
|
|
const metricName = "metric_from_set"
|
|
|
|
const metricValue = 123
|
|
|
|
s := NewSet()
|
|
|
|
c := s.NewCounter(metricName)
|
|
|
|
c.Set(metricValue)
|
|
|
|
|
|
|
|
RegisterSet(s)
|
|
|
|
var bb bytes.Buffer
|
|
|
|
WritePrometheus(&bb, false)
|
|
|
|
data := bb.String()
|
|
|
|
expectedLine := fmt.Sprintf("%s %d\n", metricName, metricValue)
|
|
|
|
if !strings.Contains(data, expectedLine) {
|
|
|
|
t.Fatalf("missing %q in\n%s", expectedLine, data)
|
|
|
|
}
|
|
|
|
|
2024-07-15 10:29:56 +02:00
|
|
|
UnregisterSet(s, true)
|
2022-08-08 17:13:46 +03:00
|
|
|
bb.Reset()
|
|
|
|
WritePrometheus(&bb, false)
|
|
|
|
data = bb.String()
|
|
|
|
if strings.Contains(data, expectedLine) {
|
|
|
|
t.Fatalf("unepected %q in\n%s", expectedLine, data)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-11 12:59:53 +03:00
|
|
|
func TestInvalidName(t *testing.T) {
|
|
|
|
f := func(name string) {
|
|
|
|
t.Helper()
|
|
|
|
expectPanic(t, fmt.Sprintf("NewCounter(%q)", name), func() { NewCounter(name) })
|
|
|
|
expectPanic(t, fmt.Sprintf("NewGauge(%q)", name), func() { NewGauge(name, func() float64 { return 0 }) })
|
|
|
|
expectPanic(t, fmt.Sprintf("NewSummary(%q)", name), func() { NewSummary(name) })
|
2019-04-11 14:03:30 +03:00
|
|
|
expectPanic(t, fmt.Sprintf("GetOrCreateCounter(%q)", name), func() { GetOrCreateCounter(name) })
|
2019-04-15 15:34:02 +03:00
|
|
|
expectPanic(t, fmt.Sprintf("GetOrCreateGauge(%q)", name), func() { GetOrCreateGauge(name, func() float64 { return 0 }) })
|
2019-04-11 14:03:30 +03:00
|
|
|
expectPanic(t, fmt.Sprintf("GetOrCreateSummary(%q)", name), func() { GetOrCreateSummary(name) })
|
2019-11-23 00:16:17 +02:00
|
|
|
expectPanic(t, fmt.Sprintf("GetOrCreateHistogram(%q)", name), func() { GetOrCreateHistogram(name) })
|
2019-04-11 12:59:53 +03:00
|
|
|
}
|
|
|
|
f("")
|
|
|
|
f("foo{")
|
|
|
|
f("foo}")
|
|
|
|
f("foo{bar")
|
|
|
|
f("foo{bar=")
|
|
|
|
f(`foo{bar="`)
|
|
|
|
f(`foo{bar="baz`)
|
|
|
|
f(`foo{bar="baz"`)
|
|
|
|
f(`foo{bar="baz",`)
|
|
|
|
f(`foo{bar="baz",}`)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestDoubleRegister(t *testing.T) {
|
|
|
|
t.Run("NewCounter", func(t *testing.T) {
|
|
|
|
name := "NewCounterDoubleRegister"
|
|
|
|
NewCounter(name)
|
|
|
|
expectPanic(t, name, func() { NewCounter(name) })
|
|
|
|
})
|
|
|
|
t.Run("NewGauge", func(t *testing.T) {
|
|
|
|
name := "NewGaugeDoubleRegister"
|
|
|
|
NewGauge(name, func() float64 { return 0 })
|
|
|
|
expectPanic(t, name, func() { NewGauge(name, func() float64 { return 0 }) })
|
|
|
|
})
|
|
|
|
t.Run("NewSummary", func(t *testing.T) {
|
|
|
|
name := "NewSummaryDoubleRegister"
|
|
|
|
NewSummary(name)
|
|
|
|
expectPanic(t, name, func() { NewSummary(name) })
|
|
|
|
})
|
2019-11-23 00:16:17 +02:00
|
|
|
t.Run("NewHistogram", func(t *testing.T) {
|
|
|
|
name := "NewHistogramDoubleRegister"
|
|
|
|
NewHistogram(name)
|
|
|
|
expectPanic(t, name, func() { NewSummary(name) })
|
|
|
|
})
|
2019-04-11 12:59:53 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestGetOrCreateNotCounter(t *testing.T) {
|
|
|
|
name := "GetOrCreateNotCounter"
|
|
|
|
NewSummary(name)
|
|
|
|
expectPanic(t, name, func() { GetOrCreateCounter(name) })
|
|
|
|
}
|
|
|
|
|
2019-04-15 15:34:02 +03:00
|
|
|
func TestGetOrCreateNotGauge(t *testing.T) {
|
|
|
|
name := "GetOrCreateNotGauge"
|
|
|
|
NewCounter(name)
|
|
|
|
expectPanic(t, name, func() { GetOrCreateGauge(name, func() float64 { return 0 }) })
|
|
|
|
}
|
|
|
|
|
2019-04-11 14:03:30 +03:00
|
|
|
func TestGetOrCreateNotSummary(t *testing.T) {
|
|
|
|
name := "GetOrCreateNotSummary"
|
|
|
|
NewCounter(name)
|
|
|
|
expectPanic(t, name, func() { GetOrCreateSummary(name) })
|
|
|
|
}
|
|
|
|
|
2019-11-23 00:16:17 +02:00
|
|
|
func TestGetOrCreateNotHistogram(t *testing.T) {
|
|
|
|
name := "GetOrCreateNotHistogram"
|
|
|
|
NewCounter(name)
|
|
|
|
expectPanic(t, name, func() { GetOrCreateHistogram(name) })
|
|
|
|
}
|
|
|
|
|
2019-04-11 12:59:53 +03:00
|
|
|
func TestWritePrometheusSerial(t *testing.T) {
|
|
|
|
if err := testWritePrometheus(); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestWritePrometheusConcurrent(t *testing.T) {
|
|
|
|
if err := testConcurrent(testWritePrometheus); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func testWritePrometheus() error {
|
|
|
|
var bb bytes.Buffer
|
|
|
|
WritePrometheus(&bb, false)
|
|
|
|
resultWithoutProcessMetrics := bb.String()
|
|
|
|
bb.Reset()
|
|
|
|
WritePrometheus(&bb, true)
|
|
|
|
resultWithProcessMetrics := bb.String()
|
|
|
|
if len(resultWithProcessMetrics) <= len(resultWithoutProcessMetrics) {
|
|
|
|
return fmt.Errorf("result with process metrics must contain more data than the result without process metrics; got\n%q\nvs\n%q",
|
|
|
|
resultWithProcessMetrics, resultWithoutProcessMetrics)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func expectPanic(t *testing.T, context string, f func()) {
|
|
|
|
t.Helper()
|
|
|
|
defer func() {
|
2019-11-23 23:58:18 +02:00
|
|
|
t.Helper()
|
2019-04-11 12:59:53 +03:00
|
|
|
if r := recover(); r == nil {
|
|
|
|
t.Fatalf("expecting panic in %s", context)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
f()
|
|
|
|
}
|
|
|
|
|
|
|
|
func testConcurrent(f func() error) error {
|
|
|
|
const concurrency = 5
|
|
|
|
resultsCh := make(chan error, concurrency)
|
|
|
|
for i := 0; i < concurrency; i++ {
|
|
|
|
go func() {
|
|
|
|
resultsCh <- f()
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
for i := 0; i < concurrency; i++ {
|
|
|
|
select {
|
|
|
|
case err := <-resultsCh:
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("unexpected error: %s", err)
|
|
|
|
}
|
|
|
|
case <-time.After(time.Second * 5):
|
|
|
|
return fmt.Errorf("timeout")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func testMarshalTo(t *testing.T, m metric, prefix, resultExpected string) {
|
|
|
|
t.Helper()
|
|
|
|
var bb bytes.Buffer
|
|
|
|
m.marshalTo(prefix, &bb)
|
|
|
|
result := bb.String()
|
|
|
|
if result != resultExpected {
|
2019-11-25 13:03:26 +02:00
|
|
|
t.Fatalf("unexpected marshaled metric;\ngot\n%q\nwant\n%q", result, resultExpected)
|
2019-04-11 12:59:53 +03:00
|
|
|
}
|
|
|
|
}
|