Ctrl K
ComunidadGuías…

internal/telemetry/expose_test.go

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
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)
			}
		})
	}
}