189 lines
7.3 KiB
Go
189 lines
7.3 KiB
Go
package config
|
|
|
|
import (
|
|
"errors"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
configkit "gitea.maximumdirect.net/eric/ConfigKit"
|
|
)
|
|
|
|
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)
|
|
}
|