164 lines
5.8 KiB
Go
164 lines
5.8 KiB
Go
package config
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"reflect"
|
|
"strings"
|
|
"testing"
|
|
|
|
configkit "gitea.maximumdirect.net/eric/ConfigKit"
|
|
)
|
|
|
|
func loadDocumentBytes(content string) (*configkit.Result[Document], error) {
|
|
return configkit.Load(configkit.Bytes("application.yml", []byte(content)), configkit.Options[Document]{
|
|
Definition: documentDefinition(),
|
|
})
|
|
}
|
|
|
|
func TestDocumentDefaultsAndExplicitValues(t *testing.T) {
|
|
defaultsOnly, err := configkit.Load(configkit.NoSource(), configkit.Options[Document]{Definition: documentDefinition()})
|
|
if err != nil {
|
|
t.Fatalf("defaults-only load: %v", err)
|
|
}
|
|
if !reflect.DeepEqual(defaultsOnly.Config, documentDefaults()) || len(defaultsOnly.Sources()) != 0 {
|
|
t.Fatalf("unexpected defaults-only result: %+v sources=%+v", defaultsOnly.Config, defaultsOnly.Sources())
|
|
}
|
|
|
|
result, err := loadDocumentBytes(`prompt_dir: ""
|
|
profile_dir: ""
|
|
schema_dir: ""
|
|
transient_retries: 0
|
|
server:
|
|
addr: ""
|
|
artifact_root: ""
|
|
max_request_bytes: 0
|
|
max_artifact_bytes: 0
|
|
max_response_bytes: 0
|
|
defaults:
|
|
render_format: " JSON "
|
|
backends:
|
|
local:
|
|
endpoint: "http://fixture.invalid/v1"
|
|
queue_capacity: 0
|
|
extra_params:
|
|
sample_count: 23
|
|
`)
|
|
if err != nil {
|
|
t.Fatalf("explicit-value load: %v", err)
|
|
}
|
|
config := result.Config
|
|
if config.SchemaDir != "" || config.Server.Addr != "" || config.Server.MaxRequestBytes != 0 || config.Server.MaxArtifactBytes != 0 || config.Server.MaxResponseBytes != 0 {
|
|
t.Fatalf("explicit empty and zero values did not replace defaults: %+v", config)
|
|
}
|
|
if config.TransientRetries == nil || *config.TransientRetries != 0 {
|
|
t.Fatalf("explicit zero retry budget lost: %+v", config.TransientRetries)
|
|
}
|
|
if backend := config.Backends["local"]; backend.QueueCapacity == nil || *backend.QueueCapacity != 0 || backend.ExtraParams["sample_count"] != int64(23) {
|
|
t.Fatalf("backend presence or dynamic integer changed: %+v", backend)
|
|
}
|
|
if config.Defaults.RenderFormat != "json" {
|
|
t.Fatalf("render format normalization failed: %q", config.Defaults.RenderFormat)
|
|
}
|
|
|
|
nullable, err := loadDocumentBytes("transient_retries: null\nbackends:\n local:\n queue_capacity: null\n")
|
|
if err != nil {
|
|
t.Fatalf("nullable-value load: %v", err)
|
|
}
|
|
if nullable.Config.TransientRetries != nil || nullable.Config.Backends["local"].QueueCapacity != nil {
|
|
t.Fatalf("nullable fields did not remain nil: %+v", nullable.Config)
|
|
}
|
|
|
|
nullBackends, err := loadDocumentBytes("backends: null\n")
|
|
if err != nil || nullBackends.Config.Backends != nil {
|
|
t.Fatalf("nullable backend map did not remain nil: %+v error=%v", nullBackends, err)
|
|
}
|
|
}
|
|
|
|
func TestDocumentRecordsEffectiveNormalization(t *testing.T) {
|
|
result, err := loadDocumentBytes(`prompt_dir: " ./one/../two "
|
|
profile_dir: " "
|
|
server:
|
|
artifact_root: " ./data/../artifacts "
|
|
addr: " :9000 "
|
|
defaults:
|
|
render_format: " JSON "
|
|
`)
|
|
if err != nil {
|
|
t.Fatalf("load normalized document: %v", err)
|
|
}
|
|
if result.Config.PromptDir != "two" || result.Config.ProfileDir != "" || result.Config.Server.ArtifactRoot != "artifacts" || result.Config.Server.Addr != ":9000" {
|
|
t.Fatalf("unexpected normalized values: %+v", result.Config)
|
|
}
|
|
var effective bytes.Buffer
|
|
if err := result.WriteEffective(&effective); err != nil {
|
|
t.Fatalf("write effective configuration: %v", err)
|
|
}
|
|
for _, fragment := range []string{"prompt_dir: two", "profile_dir: ''", "artifact_root: artifacts", "addr: :9000", "render_format: json"} {
|
|
if !strings.Contains(effective.String(), fragment) {
|
|
t.Fatalf("effective output omitted %q: %s", fragment, effective.String())
|
|
}
|
|
}
|
|
explanation, known := result.Explain(configkit.Keys("prompt_dir"))
|
|
if !known || explanation.Effective.YAML != "two\n" {
|
|
t.Fatalf("explanation does not agree with effective value: %+v known=%t", explanation, known)
|
|
}
|
|
found := false
|
|
for _, change := range explanation.History {
|
|
if change.Origin.Operation == configkit.ChangeNormalization {
|
|
found = true
|
|
}
|
|
}
|
|
if !found {
|
|
t.Fatalf("normalization was not recorded: %+v", explanation.History)
|
|
}
|
|
}
|
|
|
|
func TestDocumentValidationIsSafeAndPathSpecific(t *testing.T) {
|
|
for _, tc := range []struct{ name, content, path string }{
|
|
{"negative retry", "transient_retries: -9173\n", "/transient_retries"},
|
|
{"negative request limit", "server:\n max_request_bytes: -9173\n", "/server/max_request_bytes"},
|
|
{"negative artifact limit", "server:\n max_artifact_bytes: -9173\n", "/server/max_artifact_bytes"},
|
|
{"negative response limit", "server:\n max_response_bytes: -9173\n", "/server/max_response_bytes"},
|
|
{"empty format", "defaults:\n render_format: \"\"\n", "/defaults/render_format"},
|
|
{"unknown format", "defaults:\n render_format: private-invalid-value\n", "/defaults/render_format"},
|
|
} {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
_, err := loadDocumentBytes(tc.content)
|
|
var loadError *configkit.LoadError
|
|
if !errors.As(err, &loadError) {
|
|
t.Fatalf("expected typed validation error, got %v", err)
|
|
}
|
|
found := false
|
|
for _, diagnostic := range loadError.Diagnostics() {
|
|
if diagnostic.Code == configkit.CodeValidateError && diagnostic.Path.String() == tc.path {
|
|
found = true
|
|
}
|
|
if strings.Contains(diagnostic.Message, "9173") || strings.Contains(diagnostic.Message, "private-invalid-value") {
|
|
t.Fatalf("diagnostic disclosed rejected value: %+v", diagnostic)
|
|
}
|
|
}
|
|
if !found {
|
|
t.Fatalf("expected validation at %s, got %+v", tc.path, loadError.Diagnostics())
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDocumentRejectsNativeShapeErrors(t *testing.T) {
|
|
for _, content := range []string{
|
|
"server: null\n",
|
|
"defaults: null\n",
|
|
"server:\n addr: null\n",
|
|
"server:\n max_request_bytes: null\n",
|
|
"defaults:\n render_format: null\n",
|
|
"server:\n unknown_field: 1\n",
|
|
"backends:\n local:\n unknown_field: 1\n",
|
|
} {
|
|
_, err := loadDocumentBytes(content)
|
|
if err == nil {
|
|
t.Fatalf("unexpected acceptance of %q", content)
|
|
}
|
|
}
|
|
}
|