mirror of
https://github.com/tailscale/tailscale.git
synced 2025-04-23 09:21:41 +00:00

I added yet another one in 6d117d64a256234 but that new one is at the best place int he dependency graph and has the best name, so let's use that one for everything possible. types/lazy can't use it for circular dependency reasons, so unexport that copy at least. Updates #cleanup Change-Id: I25db6b6a0d81dbb8e89a0a9080c7f15cbf7aa770 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
90 lines
2.4 KiB
Go
90 lines
2.4 KiB
Go
// Copyright (c) Tailscale Inc & AUTHORS
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
package metrics
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"tailscale.com/util/clientmetric"
|
|
"tailscale.com/util/set"
|
|
"tailscale.com/util/syspolicy/internal"
|
|
"tailscale.com/util/testenv"
|
|
)
|
|
|
|
// TestState represents a metric name and its expected value.
|
|
type TestState struct {
|
|
Name string // `$os` in the name will be replaced by the actual operating system name.
|
|
Value int64
|
|
}
|
|
|
|
// TestHandler facilitates testing of the code that uses metrics.
|
|
type TestHandler struct {
|
|
t testenv.TB
|
|
|
|
m map[string]int64
|
|
}
|
|
|
|
// NewTestHandler returns a new TestHandler.
|
|
func NewTestHandler(t testenv.TB) *TestHandler {
|
|
return &TestHandler{t, make(map[string]int64)}
|
|
}
|
|
|
|
// AddMetric increments the metric with the specified name and type by delta d.
|
|
func (h *TestHandler) AddMetric(name string, typ clientmetric.Type, d int64) {
|
|
h.t.Helper()
|
|
if typ == clientmetric.TypeCounter && d < 0 {
|
|
h.t.Fatalf("an attempt was made to decrement a counter metric %q", name)
|
|
}
|
|
if v, ok := h.m[name]; ok || d != 0 {
|
|
h.m[name] = v + d
|
|
}
|
|
}
|
|
|
|
// SetMetric sets the metric with the specified name and type to the value v.
|
|
func (h *TestHandler) SetMetric(name string, typ clientmetric.Type, v int64) {
|
|
h.t.Helper()
|
|
if typ == clientmetric.TypeCounter {
|
|
h.t.Fatalf("an attempt was made to set a counter metric %q", name)
|
|
}
|
|
if _, ok := h.m[name]; ok || v != 0 {
|
|
h.m[name] = v
|
|
}
|
|
}
|
|
|
|
// MustEqual fails the test if the actual metric state differs from the specified state.
|
|
func (h *TestHandler) MustEqual(metrics ...TestState) {
|
|
h.t.Helper()
|
|
h.MustContain(metrics...)
|
|
h.mustNoExtra(metrics...)
|
|
}
|
|
|
|
// MustContain fails the test if the specified metrics are not set or have
|
|
// different values than specified. It permits other metrics to be set in
|
|
// addition to the ones being tested.
|
|
func (h *TestHandler) MustContain(metrics ...TestState) {
|
|
h.t.Helper()
|
|
for _, m := range metrics {
|
|
name := strings.ReplaceAll(m.Name, "$os", internal.OS())
|
|
v, ok := h.m[name]
|
|
if !ok {
|
|
h.t.Errorf("%q: got (none), want %v", name, m.Value)
|
|
} else if v != m.Value {
|
|
h.t.Fatalf("%q: got %v, want %v", name, v, m.Value)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (h *TestHandler) mustNoExtra(metrics ...TestState) {
|
|
h.t.Helper()
|
|
s := make(set.Set[string])
|
|
for i := range metrics {
|
|
s.Add(strings.ReplaceAll(metrics[i].Name, "$os", internal.OS()))
|
|
}
|
|
for n, v := range h.m {
|
|
if !s.Contains(n) {
|
|
h.t.Errorf("%q: got %v, want (none)", n, v)
|
|
}
|
|
}
|
|
}
|