internal/telemetry/expose_test.go
Rama main · réplica de lectura del repositorio original.
package telemetry
import (
"math"
"strings"
"testing"
)
func rendered(t *testing.T, reg *Registry) string {
t.Helper()
page := &strings.Builder{}
err := reg.Write(page)
if err != nil {
t.Fatalf("write the registry: %v", err)
}
return page.String()
}
func smallRegistry(t *testing.T) *Registry {
t.Helper()
reg := New()
build := reg.Gauge("spinoza_build_info", "the build of spinoza that is running", "version")
build.Set(1, "v1.2.3")
calls := reg.Counter("spinoza_apiserver_calls_total", "calls spinoza has made to an apiserver", "outcome")
calls.Add(3, "ok")
calls.Inc("refused")
took := reg.Histogram("spinoza_check_run_duration_seconds", "how long a run of the checks took", []float64{0.5, 1, 2})
took.Observe(0.25)
took.Observe(1.5)
took.Observe(4)
return reg
}
func TestASmallRegistryRendersExactlyThisPage(t *testing.T) {
want := `# HELP spinoza_apiserver_calls_total calls spinoza has made to an apiserver
# TYPE spinoza_apiserver_calls_total counter
spinoza_apiserver_calls_total{outcome="ok"} 3
spinoza_apiserver_calls_total{outcome="refused"} 1
# HELP spinoza_build_info the build of spinoza that is running
# TYPE spinoza_build_info gauge
spinoza_build_info{version="v1.2.3"} 1
# HELP spinoza_check_run_duration_seconds how long a run of the checks took
# TYPE spinoza_check_run_duration_seconds histogram
spinoza_check_run_duration_seconds_bucket{le="0.5"} 1
spinoza_check_run_duration_seconds_bucket{le="1"} 1
spinoza_check_run_duration_seconds_bucket{le="2"} 2
spinoza_check_run_duration_seconds_bucket{le="+Inf"} 3
spinoza_check_run_duration_seconds_sum 5.75
spinoza_check_run_duration_seconds_count 3
`
got := rendered(t, smallRegistry(t))
if got != want {
t.Fatalf("the exposition page reads\n%s\nand should read\n%s", got, want)
}
}
func TestTheSameRegistryRendersTheSamePageEveryTime(t *testing.T) {
reg := New()
calls := reg.Counter("spinoza_apiserver_calls_total", "calls spinoza has made to an apiserver", "outcome")
sessions := reg.Gauge("spinoza_sessions", "signed-in sessions right now", "role")
for _, outcome := range []string{"ok", "refused", "timeout", "unreachable", "conflict"} {
calls.Inc(outcome)
}
for _, role := range []string{"admin", "editor", "viewer", "auditor"} {
sessions.Set(2, role)
}
first := rendered(t, reg)
for range 40 {
if rendered(t, reg) != first {
t.Fatal("two renders of one registry disagreed, so the order is not settled")
}
}
}
func TestAMetricNamePrecedesTheOneAfterItAlphabetically(t *testing.T) {
reg := New()
reg.Counter("spinoza_zulu_total", "last", "kind")
reg.Counter("spinoza_alpha_total", "first", "kind")
reg.Counter("spinoza_mike_total", "middle", "kind")
for _, name := range []string{"spinoza_zulu_total", "spinoza_alpha_total", "spinoza_mike_total"} {
reg.vectors[name].at([]string{"one"})
}
page := rendered(t, reg)
order := []int{
strings.Index(page, "spinoza_alpha_total{"),
strings.Index(page, "spinoza_mike_total{"),
strings.Index(page, "spinoza_zulu_total{"),
}
for at := range len(order) - 1 {
if order[at] < 0 || order[at] > order[at+1] {
t.Fatalf("the metrics came out in the order %v, which is not alphabetical", order)
}
}
}
func TestALabelValueThatWouldBreakTheFormatIsEscaped(t *testing.T) {
cases := []struct {
name string
value string
want string
}{
{name: "a double quote", value: `say "no"`, want: `spinoza_auth_failures_total{reason="say \"no\""} 1`},
{name: "a backslash", value: `back\slash`, want: `spinoza_auth_failures_total{reason="back\\slash"} 1`},
{name: "a newline", value: "two\nlines", want: `spinoza_auth_failures_total{reason="two\nlines"} 1`},
{name: "all three at once", value: "a\"b\\c\nd", want: `spinoza_auth_failures_total{reason="a\"b\\c\nd"} 1`},
{name: "nothing that needs it", value: "expired", want: `spinoza_auth_failures_total{reason="expired"} 1`},
}
for _, one := range cases {
t.Run(one.name, func(t *testing.T) {
reg := New()
failures := reg.Counter("spinoza_auth_failures_total", "sign-ins spinoza refused", "reason")
failures.Inc(one.value)
page := rendered(t, reg)
if !strings.Contains(page, one.want) {
t.Fatalf("the page reads\n%s\nand should carry the line\n%s", page, one.want)
}
})
}
}
func TestHelpTextThatWouldBreakTheFormatIsEscaped(t *testing.T) {
reg := New()
reg.Counter("spinoza_odd_help_total", "one\ntwo\\three")
page := rendered(t, reg)
if !strings.Contains(page, `# HELP spinoza_odd_help_total one\ntwo\\three`+"\n") {
t.Fatalf("the help line was not escaped:\n%s", page)
}
}
func TestAMetricWithNoSeriesYetIsLeftOffThePage(t *testing.T) {
reg := New()
reg.Counter("spinoza_auth_failures_total", "sign-ins spinoza refused", "reason")
page := rendered(t, reg)
if strings.Contains(page, "spinoza_auth_failures_total") {
t.Fatalf("a metric nothing has written to was announced anyway:\n%s", page)
}
}
func TestAMetricWithNoLabelsReportsZeroBeforeAnythingWritesToIt(t *testing.T) {
reg := New()
reg.Counter("spinoza_audit_write_failures_total", "audit rows spinoza could not write")
page := rendered(t, reg)
if !strings.Contains(page, "spinoza_audit_write_failures_total 0\n") {
t.Fatalf("an unwritten counter did not report zero:\n%s", page)
}
}
func TestAValueTooLargeForAnIntegerStillRendersAsANumber(t *testing.T) {
cases := []struct {
name string
value float64
want string
}{
{name: "a whole number", value: 42, want: "spinoza_sessions{role=\"admin\"} 42"},
{name: "a fraction", value: 0.5, want: "spinoza_sessions{role=\"admin\"} 0.5"},
{name: "a million", value: 1e6, want: "spinoza_sessions{role=\"admin\"} 1e+06"},
{name: "a tiny fraction", value: 1e-9, want: "spinoza_sessions{role=\"admin\"} 1e-09"},
}
for _, one := range cases {
t.Run(one.name, func(t *testing.T) {
reg := New()
sessions := reg.Gauge("spinoza_sessions", "signed-in sessions right now", "role")
sessions.Set(one.value, "admin")
page := rendered(t, reg)
if !strings.Contains(page, one.want) {
t.Fatalf("the page reads\n%s\nand should carry\n%s", page, one.want)
}
})
}
}
func TestTheContentTypeNamesTheExpositionVersionTheBodyIsWrittenIn(t *testing.T) {
if ContentType() != "text/plain; version=0.0.4; charset=utf-8" {
t.Fatalf("ContentType() = %q", ContentType())
}
}
func TestAGaugeThatIsNotAFiniteNumberStillRendersAsTheFormatSpellsIt(t *testing.T) {
cases := []struct {
name string
value float64
want string
}{
{name: "no reading at all", value: math.NaN(), want: "NaN"},
{name: "past anything measurable", value: math.Inf(1), want: "+Inf"},
{name: "below anything measurable", value: math.Inf(-1), want: "-Inf"},
}
for _, one := range cases {
t.Run(one.name, func(t *testing.T) {
reg := New()
sessions := reg.Gauge("spinoza_sessions", "signed-in sessions right now", "role")
sessions.Set(one.value, "admin")
page := rendered(t, reg)
if !strings.Contains(page, `spinoza_sessions{role="admin"} `+one.want+"\n") {
t.Fatalf("the page reads\n%s\nand should carry %s", page, one.want)
}
})
}
}