check / check (push) Canceled after 0s
Config.settings lists each setting once: its key, its environment variable and the function that loads it. Most rows load through field, whose arguments give the type, the default and the check. db_url and cache_max_bytes keep their own load functions. Loading, the unknown-key and unknown-variable checks and the names in error messages all read the table. allowlist_hosts now loads through parseHostList, as referer_blocklist does. isKnownConfigKey, envVarNames, strictLoader, validate, validateAllowlistHostsValue and getStringSlice are gone, with the getStringSlice tests. The key constants move to the tests, their only users. A new test checks that README.md and configs/config.example.yml name the keys of the table. Model: opus-5-5
109 lines
2.9 KiB
Go
109 lines
2.9 KiB
Go
package config
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"regexp"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// TestReadmeNamesEverySetting checks that the Configuration section of
|
|
// README.md names every key of the settings table in backticks. It also
|
|
// checks that every name in backticks there written like a key with an
|
|
// underscore, such as state_dir, is a key of the table. The other keys,
|
|
// such as port and metrics.username, are checked only the first way.
|
|
func TestReadmeNamesEverySetting(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
readme, err := os.ReadFile(filepath.Join("..", "..", "README.md"))
|
|
if err != nil {
|
|
t.Fatalf("failed to read README.md: %v", err)
|
|
}
|
|
|
|
_, section, found := strings.Cut(string(readme), "\n### Configuration\n")
|
|
if !found {
|
|
t.Fatal("README.md has no Configuration section")
|
|
}
|
|
|
|
// The section ends at the next heading of its level or above.
|
|
section, _, _ = strings.Cut(section, "\n## ")
|
|
section, _, _ = strings.Cut(section, "\n### ")
|
|
|
|
named := map[string]bool{}
|
|
|
|
for _, match := range regexp.MustCompile("`([^`]+)`").
|
|
FindAllStringSubmatch(section, -1) {
|
|
named[match[1]] = true
|
|
}
|
|
|
|
for _, s := range new(Config).settings() {
|
|
if !named[s.key] {
|
|
t.Errorf("README.md's Configuration section does not name %s", s.key)
|
|
}
|
|
|
|
delete(named, s.key)
|
|
}
|
|
|
|
keyWithUnderscore := regexp.MustCompile(`^[a-z]+(_[a-z]+)+$`)
|
|
|
|
for name := range named {
|
|
if keyWithUnderscore.MatchString(name) {
|
|
t.Errorf("README.md's Configuration section names %s, "+
|
|
"which is not a setting", name)
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestExampleConfigNamesEverySetting checks that
|
|
// configs/config.example.yml names exactly the keys of the settings
|
|
// table, each one set or commented out with "# ". A key line holds the
|
|
// key, a colon and at most a one-word value, which tells it from a
|
|
// comment line that starts with a word and a colon. An indented key is
|
|
// inside the map of the key above it, as username is inside metrics.
|
|
func TestExampleConfigNamesEverySetting(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
const examplePath = "configs/config.example.yml"
|
|
|
|
example, err := os.ReadFile(filepath.Join("..", "..", examplePath))
|
|
if err != nil {
|
|
t.Fatalf("failed to read %s: %v", examplePath, err)
|
|
}
|
|
|
|
keyLine := regexp.MustCompile(`(?m)^(?:# )?( *)([a-z_]+):(?: \S+)?$`)
|
|
named := map[string]bool{}
|
|
|
|
var mapKey string
|
|
|
|
for _, match := range keyLine.FindAllStringSubmatch(string(example), -1) {
|
|
indent, key := match[1], match[2]
|
|
if indent == "" {
|
|
mapKey = key
|
|
named[key] = true
|
|
|
|
continue
|
|
}
|
|
|
|
// The key holding the map is not itself a setting.
|
|
delete(named, mapKey)
|
|
|
|
named[mapKey+"."+key] = true
|
|
}
|
|
|
|
// The env section sets environment variables; it is not a setting.
|
|
delete(named, "env")
|
|
|
|
for _, s := range new(Config).settings() {
|
|
if !named[s.key] {
|
|
t.Errorf("%s does not name %s", examplePath, s.key)
|
|
}
|
|
|
|
delete(named, s.key)
|
|
}
|
|
|
|
for key := range named {
|
|
t.Errorf("%s names %s, which is not a setting", examplePath, key)
|
|
}
|
|
}
|