Files
audita/internal/core/config/config_test.go

200 lines
6.6 KiB
Go

package config
import (
"io/fs"
"os"
"path"
"path/filepath"
"testing"
ck "go.maximumdirect.net/configkit"
)
func TestDefaultsAndVersion(t *testing.T) {
result, err := Load(ck.Input{Source: ck.NoSource()}, "")
if err != nil {
t.Fatal(err)
}
if result.Config.Version != 3 || len(result.Config.Pipeline.Stages) != 5 {
t.Fatalf("defaults: %+v", result.Config)
}
path := filepath.Join(t.TempDir(), "config.yml")
for _, text := range []string{"version: 2\n", "version: null\n", "version: invalid\n"} {
if err := os.WriteFile(path, []byte(text), 0644); err != nil {
t.Fatal(err)
}
if _, err := Load(ck.Input{Source: ck.File(path)}, ""); err == nil {
t.Fatalf("accepted %q", text)
}
}
if err := os.WriteFile(path, []byte("pipeline:\n stages: []\n"), 0644); err != nil {
t.Fatal(err)
}
empty, err := Load(ck.Input{Source: ck.File(path)}, "")
if err != nil {
t.Fatal(err)
}
if len(empty.Config.Pipeline.Stages) != 0 {
t.Fatal("empty pipeline was not preserved")
}
}
func TestMainContextImportsAndOverlay(t *testing.T) {
dir := t.TempDir()
if err := os.Mkdir(filepath.Join(dir, "overlays"), 0755); err != nil {
t.Fatal(err)
}
for name, contents := range map[string]string{
"main.yml": "version: 3\nconfig:\n imports:\n - path: fragment.yml\noutput:\n schema: bare-segments\n",
"fragment.yml": "context:\n description: imported\n",
"overlays/selected.yml": "context:\n description: overlay\n",
} {
if err := os.WriteFile(filepath.Join(dir, name), []byte(contents), 0644); err != nil {
t.Fatal(err)
}
}
result, err := Load(ck.Input{Source: ck.File(filepath.Join(dir, "main.yml"))}, "selected", ck.Override{Path: ck.Keys("context", "description"), Value: "override", Flag: "--description"})
if err != nil {
t.Fatal(err)
}
if info, ok := result.Metadata().Lookup(ck.Keys("context", "description")); !ok || info.Origin.Layer != ck.LayerCLI {
t.Fatalf("override origin = %+v", info)
}
if result.Config.Context.Description != "override" {
t.Fatalf("description = %q", result.Config.Context.Description)
}
found := false
for _, source := range result.Sources() {
if source.Layer == ck.LayerMain && source.ImportedFrom == nil {
context, ok := result.SourceContext(source.ID)
if !ok {
t.Fatal("main context missing")
}
data, err := fs.ReadFile(context.FS, path.Join(context.BaseDir, "fragment.yml"))
if err != nil || len(data) == 0 {
t.Fatalf("main context cannot access companion: %v", err)
}
found = true
}
}
if !found {
t.Fatal("main source missing")
}
if _, err := Load(ck.Input{Source: ck.File(filepath.Join(dir, "main.yml"))}, "missing"); err == nil {
t.Fatal("missing overlay accepted")
}
if _, err := Load(ck.Input{Source: ck.NoSource()}, "selected"); err == nil {
t.Fatal("overlay without context accepted")
}
}
func TestDiscoveryAndSelectedFailure(t *testing.T) {
first, second := t.TempDir(), t.TempDir()
search := ck.Searches(ck.SearchDirectory(first), ck.SearchDirectory(second))
load := func() (*ck.Result[Config], error) {
return Load(ck.Input{Source: ck.SearchConfig("audita", search)}, "")
}
result, err := load()
if err != nil {
t.Fatal(err)
}
for _, source := range result.Sources() {
if source.Layer == ck.LayerMain {
t.Fatalf("unexpected main source: %+v", source)
}
}
if err := os.WriteFile(filepath.Join(second, "config.yml"), []byte("context:\n description: selected\n"), 0644); err != nil {
t.Fatal(err)
}
result, err = load()
if err != nil {
t.Fatal(err)
}
if result.Config.Context.Description != "selected" {
t.Fatalf("description = %q", result.Config.Context.Description)
}
if err := os.WriteFile(filepath.Join(first, "config.yml"), []byte("version: 2\n"), 0644); err != nil {
t.Fatal(err)
}
if _, err := load(); err == nil {
t.Fatal("invalid selected file fell through")
}
}
func TestOverlayUsesMainDirectoryWithinWiderRoot(t *testing.T) {
root := t.TempDir()
dir := filepath.Join(root, "project")
if err := os.MkdirAll(filepath.Join(dir, "overlays"), 0755); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(dir, "config.yml"), []byte("version: 3\n"), 0644); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(dir, "overlays", "local.yml"), []byte("context:\n description: project\n"), 0644); err != nil {
t.Fatal(err)
}
result, err := Load(ck.Input{Source: ck.File(filepath.Join(dir, "config.yml")), Filesystem: &ck.FilesystemContext{Root: root}}, "local")
if err != nil {
t.Fatal(err)
}
if result.Config.Context.Description != "project" {
t.Fatalf("description = %q", result.Config.Context.Description)
}
}
func TestSchemaConstraintsAndExplicitValues(t *testing.T) {
path := filepath.Join(t.TempDir(), "config.yml")
for _, tc := range []struct {
name, text string
valid bool
}{
{"nullable selections", "glossaries: null\nprotected_terms: []\nllm:\n validation_profile: null\n", true},
{"repeated modules", "pipeline:\n stages:\n - module: grammar\n - module: grammar\n", true},
{"removed backends", "backends: {}\n", false},
{"removed debug", "diagnostics:\n debug: true\n", false},
{"unknown module", "pipeline:\n stages:\n - module: unknown\n", false},
{"invalid chunk limit", "chunking:\n target_sections: 0\n", false},
{"invalid threshold", "thresholds:\n grammar: 1.1\n", false},
{"null group", "llm: null\n", false},
{"zero budgets", "llm:\n transient_retries: 0\n repair_attempts: 0\n", true},
} {
t.Run(tc.name, func(t *testing.T) {
if err := os.WriteFile(path, []byte(tc.text), 0644); err != nil {
t.Fatal(err)
}
_, err := Load(ck.Input{Source: ck.File(path)}, "")
if (err == nil) != tc.valid {
t.Fatalf("load error: %v", err)
}
})
}
}
func TestOverridesFollowInheritance(t *testing.T) {
dir := t.TempDir()
path := filepath.Join(dir, "config.yml")
data := `glossary_collections:
common:
entries:
- id: a
name: First
category: character
derived:
extends: common
`
if err := os.WriteFile(path, []byte(data), 0644); err != nil {
t.Fatal(err)
}
result, err := Load(ck.Input{Source: ck.File(path)}, "", ck.Override{Path: ck.Keys("glossary_collections", "common", "entries"), Value: []any{map[string]any{"id": "a", "name": "Changed", "category": "character"}}, Flag: "--set"})
if err != nil {
t.Fatalf("%v: %+v", err, err.(*ck.LoadError).Diagnostics())
}
if got := result.Config.GlossaryCollections["derived"].Entries[0].Name; got != "First" {
t.Fatalf("inherited name = %q", got)
}
if got := result.Config.GlossaryCollections["common"].Entries[0].Name; got != "Changed" {
t.Fatalf("overridden name = %q", got)
}
}