Files
member-console/internal/config/config_reference_test.go
T
cgalo5758 88db730fcc Add dual licensing and SPDX headers
Introduce a commercial license option alongside AGPL-3.0-only, require a
CLA for contributors, and document the terms in COMMERCIAL.md and
NOTICE. Add a script to stamp SPDX headers on Go files and apply it
across the tree.
2026-09-06 02:29:42 -05:00

187 lines
6.6 KiB
Go

// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Commercial
// SPDX-FileCopyrightText: 2025-2026 Christian Galo
package config
import (
"os"
"path/filepath"
"regexp"
"runtime"
"sort"
"strconv"
"strings"
"testing"
)
// configKeyCallRE matches viper accessor call sites whose first argument is
// a string literal: viper.GetString("db-dsn"), viper.Set("port", v),
// viper.SetDefault("env", "development"), viper.IsSet("x"),
// viper.BindEnv("x"), and so on. It intentionally also matches a few Viper
// bootstrap calls (SetConfigType, SetConfigName, SetEnvPrefix) that are not
// application configuration keys at all — those are excluded below via
// excludedLiterals, one entry per call site, each commented with why.
//
// This is a lightweight regex scan, not a Go parser: it does not understand
// multi-line string concatenation or build tags, and a call site whose key
// argument is a variable or struct field (e.g. viper.GetString(pair.Name))
// is invisible to it by design — those keys are declared data-driven
// (internal/config.ConfigKey) and validated by other means
// (RequiredKeysUnresolved, ApplyOverlay), not by this literal scan.
var configKeyCallRE = regexp.MustCompile(`viper\.(?:Get\w*|Set\w*|IsSet|BindEnv|RegisterAlias)\(\s*"([^"]*)"`)
// excludedLiterals lists string literals configKeyCallRE matches that are
// not application configuration keys, with the reason each is not one.
// Keep this list small — a real new config key belongs in
// docs/environment-reference.md, not here.
var excludedLiterals = map[string]string{
"yaml": "viper.SetConfigType(\"yaml\") in cmd/root.go — the config file format, not a config key",
"mc-config": "viper.SetConfigName(\"mc-config\") in cmd/root.go — the config file's base name, not a config key",
"MC": "viper.SetEnvPrefix(\"MC\") in cmd/root.go — the env var prefix itself, not a config key",
}
// repoRootFromCaller locates the repository root from this test file's own
// path, so the test works regardless of the working directory it runs
// under (`go test ./...` from the repo root, `go test .` from this
// package's directory, an IDE runner, etc).
func repoRootFromCaller(t *testing.T) string {
t.Helper()
_, thisFile, _, ok := runtime.Caller(0)
if !ok {
t.Fatal("runtime.Caller(0) failed; cannot locate repo root")
}
// This file lives at <repoRoot>/internal/config/config_reference_test.go.
root := filepath.Clean(filepath.Join(filepath.Dir(thisFile), "..", ".."))
return root
}
// extractConfigKeys walks dir (skipping _test.go files and non-.go files)
// and returns the sorted, de-duplicated set of string-literal keys found at
// viper accessor call sites, along with the first file:line each was found
// at (for failure messages).
func extractConfigKeys(t *testing.T, dir string) (keys []string, firstSeenAt map[string]string) {
t.Helper()
firstSeenAt = make(map[string]string)
seen := make(map[string]bool)
err := filepath.WalkDir(dir, func(path string, d os.DirEntry, err error) error {
if err != nil {
return err
}
if d.IsDir() {
return nil
}
if !strings.HasSuffix(path, ".go") || strings.HasSuffix(path, "_test.go") {
return nil
}
content, err := os.ReadFile(path)
if err != nil {
return err
}
for i, line := range strings.Split(string(content), "\n") {
trimmed := strings.TrimSpace(line)
// Skip whole-line comments; this is a line-based scan (the
// codebase's viper call sites are all single-line), so a
// commented-out call on its own line never produces a false
// positive.
if strings.HasPrefix(trimmed, "//") {
continue
}
for _, m := range configKeyCallRE.FindAllStringSubmatch(line, -1) {
key := m[1]
if !seen[key] {
seen[key] = true
rel, relErr := filepath.Rel(dir, path)
if relErr != nil {
rel = path
}
firstSeenAt[key] = rel + ":" + strconv.Itoa(i+1)
}
}
}
return nil
})
if err != nil {
t.Fatalf("walking %s: %v", dir, err)
}
for k := range seen {
keys = append(keys, k)
}
sort.Strings(keys)
return keys, firstSeenAt
}
// TestEnvironmentReferenceDocumentsEveryConfigKey scans cmd/ and internal/
// for every string-literal key read or written through Viper and asserts
// each one (other than the deliberately excluded bootstrap literals) is
// documented in docs/environment-reference.md. It is a completeness check,
// not a correctness check: it does not verify the documented purpose,
// default, or required/optional call is accurate, only that the key is not
// silently undocumented.
func TestEnvironmentReferenceDocumentsEveryConfigKey(t *testing.T) {
root := repoRootFromCaller(t)
docPath := filepath.Join(root, "docs", "environment-reference.md")
docBytes, err := os.ReadFile(docPath)
if err != nil {
t.Fatalf("reading %s: %v", docPath, err)
}
doc := string(docBytes)
var allKeys []string
allFirstSeen := make(map[string]string)
for _, sub := range []string{"cmd", "internal"} {
dir := filepath.Join(root, sub)
keys, firstSeen := extractConfigKeys(t, dir)
allKeys = append(allKeys, keys...)
for k, v := range firstSeen {
// Keep the first location found across both directories.
if _, ok := allFirstSeen[k]; !ok {
allFirstSeen[k] = filepath.Join(sub, v)
}
}
}
sort.Strings(allKeys)
var missing []string
for _, key := range allKeys {
if _, excluded := excludedLiterals[key]; excluded {
continue
}
if !strings.Contains(doc, key) {
missing = append(missing, key)
}
}
if len(missing) > 0 {
var b strings.Builder
b.WriteString("the following config keys are read via viper but not documented in docs/environment-reference.md:\n")
for _, key := range missing {
b.WriteString(" - " + key + " (first seen at " + allFirstSeen[key] + ")\n")
}
b.WriteString("add each to docs/environment-reference.md (or, if it is deliberately not an application config key, to excludedLiterals in internal/config/config_reference_test.go with a reason)")
t.Error(b.String())
}
}
// TestExcludedLiteralsStillMatchesRealCallSites guards against a stale
// allowlist entry: if a bootstrap call site is ever rewritten to no longer
// use one of these literals, the entry should be removed rather than left
// silently unused.
func TestExcludedLiteralsStillMatchesRealCallSites(t *testing.T) {
root := repoRootFromCaller(t)
var found = make(map[string]bool)
for _, sub := range []string{"cmd", "internal"} {
keys, _ := extractConfigKeys(t, filepath.Join(root, sub))
for _, k := range keys {
found[k] = true
}
}
for literal := range excludedLiterals {
if !found[literal] {
t.Errorf("excludedLiterals entry %q no longer matches any viper call site; remove it from internal/config/config_reference_test.go", literal)
}
}
}