Files
notarius/internal/core/config/operational_document_test.go

229 lines
8.7 KiB
Go

package config
import (
"bytes"
"errors"
"os"
"path/filepath"
"strings"
"testing"
configkit "gitea.maximumdirect.net/eric/ConfigKit"
)
func TestWorkerKeyNormalizationPreservesExplicitCount(t *testing.T) {
t.Parallel()
for _, test := range []struct {
name, workers string
want int
errorPath string
}{
{name: "omitted", workers: "{}", want: 4},
{name: "padded", workers: "{' extract ': 2}", want: 2},
{name: "explicit invalid", workers: "{' extract ': 0}", errorPath: "/concurrency/stage_workers/extract"},
{name: "collision", workers: "{' extract ': 2, extract: 3}", errorPath: "/concurrency/stage_workers/extract"},
} {
t.Run(test.name, func(t *testing.T) {
loaded, err := loadConfigSource(configkit.Bytes("workers.yml", []byte(
"version: 5\nconcurrency:\n total_llm: 4\n stage_workers: "+test.workers+"\n")), LoadOptions{})
if test.errorPath != "" {
assertDocumentDiagnosticAt(t, err, test.errorPath)
return
}
if err != nil {
t.Fatal(err)
}
if got := loaded.Config.Concurrency.StageWorkers["extract"]; got != test.want {
t.Fatalf("workers = %d, want %d", got, test.want)
}
var explanation bytes.Buffer
if err := loaded.WriteExplanation(&explanation, "/concurrency/stage_workers"); err != nil {
t.Fatal(err)
}
if test.name == "padded" && (!strings.Contains(explanation.String(), "normalization") ||
!strings.Contains(explanation.String(), " extract ") ||
strings.Contains(explanation.String(), "derived extraction workers")) {
t.Fatalf("explicit worker provenance = %s", explanation.String())
}
})
}
}
func TestDocumentLoadAppliesOperationalDefaultsAndNormalization(t *testing.T) {
t.Parallel()
loaded, err := loadDocumentSource(configkit.Bytes("document.yml", []byte(`version: 5
concurrency:
total_llm: 4
promptkit:
profile_dir: " ./profiles "
local_backend:
endpoint: " https://localhost:8080/v1 "
output:
directory: " ./output "
cache:
chunk_plans:
mode: " refresh "
directory: " "
checkpoints:
directory: " "
debug:
directory: " ./debug "
`)), LoadOptions{})
if err != nil {
t.Fatal(err)
}
if loaded.Config.Concurrency.TotalLLM == nil || *loaded.Config.Concurrency.TotalLLM != 4 || loaded.Config.Concurrency.StageWorkers["extract"] != 4 {
t.Fatalf("concurrency = %#v", loaded.Config.Concurrency)
}
workingDirectory, err := os.Getwd()
if err != nil {
t.Fatal(err)
}
if loaded.Config.PromptKit.ProfileDir == nil || *loaded.Config.PromptKit.ProfileDir != filepath.Join(workingDirectory, "profiles") ||
loaded.Config.PromptKit.LocalBackend == nil || loaded.Config.PromptKit.LocalBackend.Endpoint == nil || *loaded.Config.PromptKit.LocalBackend.Endpoint != "https://localhost:8080/v1" ||
loaded.Config.PromptKit.LocalBackend.ConcurrencyLimit == nil || *loaded.Config.PromptKit.LocalBackend.ConcurrencyLimit != 0 {
t.Fatalf("promptkit = %#v", loaded.Config.PromptKit)
}
if loaded.Config.Output.Directory == nil || *loaded.Config.Output.Directory != filepath.Join(workingDirectory, "output") ||
loaded.Config.Cache.ChunkPlans.Mode == nil || *loaded.Config.Cache.ChunkPlans.Mode != "refresh" ||
loaded.Config.Cache.ChunkPlans.Directory == nil || *loaded.Config.Cache.ChunkPlans.Directory != "" ||
loaded.Config.Cache.Checkpoints.Directory == nil || *loaded.Config.Cache.Checkpoints.Directory != "" ||
loaded.Config.Debug.Directory == nil || *loaded.Config.Debug.Directory != filepath.Join(workingDirectory, "debug") {
t.Fatalf("state = %#v, %#v, %#v", loaded.Config.Output, loaded.Config.Cache, loaded.Config.Debug)
}
if diagnostics := loaded.Diagnostics(); len(diagnostics) != 0 {
t.Fatalf("diagnostics = %#v", diagnostics)
}
extractHistory := loaded.Metadata().History(configkit.Keys("concurrency", "stage_workers", "extract"))
if len(extractHistory) == 0 || extractHistory[len(extractHistory)-1].Origin.Operation != configkit.ChangeDerivedDefault {
t.Fatalf("extract history = %#v", extractHistory)
}
outputHistory := loaded.Metadata().History(configkit.Keys("output", "directory"))
if len(outputHistory) == 0 || outputHistory[len(outputHistory)-1].Origin.Operation != configkit.ChangeNormalization {
t.Fatalf("output history = %#v", outputHistory)
}
}
func TestDocumentLoadDerivesWorkersAfterProfileAndCLIOverrides(t *testing.T) {
t.Parallel()
directory := t.TempDir()
main := filepath.Join(directory, "config.yml")
profiles := filepath.Join(directory, "profiles")
if err := os.Mkdir(profiles, 0o755); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(main, []byte("version: 5\nconcurrency:\n total_llm: 4\n"), 0o600); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(profiles, "development.yml"), []byte("concurrency:\n total_llm: 3\n"), 0o600); err != nil {
t.Fatal(err)
}
profiled, err := loadDocument(main, LoadOptions{Profile: "development"})
if err != nil {
t.Fatal(err)
}
if profiled.Config.Concurrency.TotalLLM == nil || *profiled.Config.Concurrency.TotalLLM != 3 || profiled.Config.Concurrency.StageWorkers["extract"] != 3 {
t.Fatalf("profiled concurrency = %#v", profiled.Config.Concurrency)
}
overridden, err := loadDocument(main, LoadOptions{Overrides: []configkit.Override{{
Path: configkit.Keys("concurrency", "total_llm"), Value: 2, Flag: "--total-llm",
}}})
if err != nil {
t.Fatal(err)
}
if overridden.Config.Concurrency.TotalLLM == nil || *overridden.Config.Concurrency.TotalLLM != 2 || overridden.Config.Concurrency.StageWorkers["extract"] != 2 {
t.Fatalf("overridden concurrency = %#v", overridden.Config.Concurrency)
}
}
func TestDocumentLoadRetainsExplicitWorkerAndRejectsInvalidOperationalValues(t *testing.T) {
t.Parallel()
loaded, err := loadDocumentSource(configkit.Bytes("explicit.yml", []byte(`version: 5
concurrency:
total_llm: 4
stage_workers:
extract: 0
`)), LoadOptions{})
if loaded != nil {
t.Fatalf("loaded = %#v, want validation failure", loaded.Config)
}
assertDocumentDiagnostic(t, err, configkit.CodeValidateError, "/concurrency/stage_workers/extract")
_, err = loadDocumentSource(configkit.Bytes("invalid.yml", []byte(`version: 5
concurrency:
total_llm: 0
output:
directory: ""
promptkit:
local_backend:
endpoint: "ftp://localhost"
concurrency_limit: -1
`)), LoadOptions{})
var loadError *configkit.LoadError
if !errors.As(err, &loadError) {
t.Fatalf("error = %v, want ConfigKit load error", err)
}
seen := make(map[string]bool)
for _, diagnostic := range loadError.Diagnostics() {
if diagnostic.Code != configkit.CodeValidateError || diagnostic.Primary == nil {
t.Fatalf("diagnostic = %#v", diagnostic)
}
seen[diagnostic.Path.String()] = true
}
for _, path := range []string{"/concurrency/total_llm", "/output/directory", "/promptkit/local_backend/endpoint", "/promptkit/local_backend/concurrency_limit"} {
if !seen[path] {
t.Fatalf("diagnostics missing %s: %#v", path, loadError.Diagnostics())
}
}
}
func TestDocumentLoadDistinguishesRequiredAndOptionalPathValues(t *testing.T) {
t.Parallel()
loaded, err := loadDocumentSource(configkit.Bytes("cache.yml", []byte(`version: 5
cache:
chunk_plans:
directory: " "
checkpoints:
directory: " "
`)), LoadOptions{})
if err != nil {
t.Fatal(err)
}
if loaded.Config.Cache.ChunkPlans.Directory == nil || *loaded.Config.Cache.ChunkPlans.Directory != "" ||
loaded.Config.Cache.Checkpoints.Directory == nil || *loaded.Config.Cache.Checkpoints.Directory != "" {
t.Fatalf("cache directories = %#v", loaded.Config.Cache)
}
_, err = loadDocumentSource(configkit.Bytes("output.yml", []byte("version: 5\noutput:\n directory: ' '\n")), LoadOptions{})
assertDocumentDiagnostic(t, err, configkit.CodeValidateError, "/output/directory")
_, err = loadDocumentSource(configkit.Bytes("promptkit.yml", []byte("version: 5\npromptkit:\n profile_file: null\n local_backend: {}\n")), LoadOptions{})
assertDocumentDiagnostic(t, err, configkit.CodeResolveError, "/promptkit/profile_file")
_, err = loadDocumentSource(configkit.Bytes("empty-source.yml", []byte("version: 5\npromptkit:\n profile_dir: ' '\n")), LoadOptions{})
assertDocumentDiagnostic(t, err, configkit.CodeValidateError, "/promptkit/profile_dir")
_, err = loadDocumentSource(configkit.Bytes("missing-endpoint.yml", []byte("version: 5\npromptkit:\n local_backend: {}\n")), LoadOptions{})
assertDocumentDiagnostic(t, err, configkit.CodeValidateError, "/promptkit/local_backend/endpoint")
}
func assertDocumentDiagnostic(t *testing.T, err error, code configkit.Code, path string) {
t.Helper()
var loadError *configkit.LoadError
if !errors.As(err, &loadError) {
t.Fatalf("error = %v, want ConfigKit load error", err)
}
for _, diagnostic := range loadError.Diagnostics() {
if diagnostic.Code == code && diagnostic.Path.String() == path {
return
}
}
t.Fatalf("diagnostics = %#v, want %s at %s", loadError.Diagnostics(), code, path)
}