series_counters_seeded_test.go
Rama main · réplica de lectura del repositorio original.
package main
import (
"os"
"path/filepath"
"regexp"
"runtime"
"sort"
"strings"
"testing"
)
// TestSeriesCountersAreSeededAndExported guards the two lists that have to move
// together whenever the chart-aggregate cache learns a new outcome, and which
// nothing else checks: seedKnownCounters in this file's package (main.go) and
// the named-family table in writeNamedStats (internal/web/web.go).
//
// The failure this exists to catch has already happened twice. A state is added
// to Store.Series, the store's own tests pass because they read the counter
// directly, and the two lists are left behind - so the new counter is absent
// from a scrape until its first increment (unseeded counters spring into
// existence at 1, which rate() and increase() cannot see across that boundary)
// and, if it is also missing from writeNamedStats, has no named family at all.
// The visible symptom is a scrape whose numbers do not reconcile: main.go's
// seeding comment states the relation the families are read against each other
// with, queries = outcomes - hits, and a missing member silently breaks it.
//
// Scanning the store's source rather than hardcoding the names is the point.
// A fixed list here would need the same manual update as the two lists it
// guards, and would therefore go stale in exactly the case the test exists for.
func TestSeriesCountersAreSeededAndExported(t *testing.T) {
_, thisFile, ok := callerFile()
if !ok {
t.Fatal("runtime.Caller failed; cannot locate the module root")
}
root := filepath.Dir(thisFile) // this file lives at the module root
read := func(rel string) string {
b, err := os.ReadFile(filepath.Join(root, rel))
if err != nil {
t.Fatalf("read %s: %v", rel, err)
}
return string(b)
}
// Every stats.Inc("series...") the store records. The store is the only
// producer: these counters describe its cache, and a counter incremented
// anywhere else would not be part of the queries = outcomes - hits relation.
storeSrc := read(filepath.Join("internal", "store", "store.go"))
recorded := regexp.MustCompile(`stats\.Inc\("(series\.[a-z.]+)"\)`).FindAllStringSubmatch(storeSrc, -1)
if len(recorded) == 0 {
t.Fatal("no stats.Inc(\"series.*\") calls found in internal/store/store.go: " +
"either the counters were removed, or the call shape changed and this guard now " +
"scans for something that no longer exists, which would let it pass vacuously")
}
seen := map[string]bool{}
var keys []string
for _, m := range recorded {
if !seen[m[1]] {
seen[m[1]] = true
keys = append(keys, m[1])
}
}
sort.Strings(keys)
mainSrc := read("main.go")
webSrc := read(filepath.Join("internal", "web", "web.go"))
for _, k := range keys {
quoted := `"` + k + `"`
if !strings.Contains(mainSrc, quoted) {
t.Errorf("internal/store records %s but main.go never names it: an unseeded counter is "+
"absent from /metrics until its first increment, so its family appears mid-series and "+
"rate() cannot see the step. Add it to seedKnownCounters.", k)
}
if !strings.Contains(webSrc, quoted) {
t.Errorf("internal/store records %s but internal/web/web.go never names it: with no entry "+
"in writeNamedStats it has no pingularity_series_* family, so a scrape carries a query "+
"count its outcome counters cannot account for. Add it to the named-family table.", k)
}
}
}
// callerFile isolates the runtime.Caller call so the test body reads plainly.
func callerFile() (uintptr, string, bool) {
pc, file, _, ok := runtime.Caller(1)
return pc, file, ok
}