327 lines
13 KiB
Go
327 lines
13 KiB
Go
package configuration
|
|
|
|
import (
|
|
"errors"
|
|
"testing"
|
|
|
|
"gitea.maximumdirect.net/eric/ConfigKit"
|
|
)
|
|
|
|
func mapping(label string, values map[string]any) configkit.Input {
|
|
return configkit.Input{Source: configkit.Mapping(label, values)}
|
|
}
|
|
|
|
func TestLoadComposesLiteralKeysAndEffectivePresence(t *testing.T) {
|
|
base := mapping("defaults", map[string]any{
|
|
"backends": map[string]any{
|
|
"local.v1": map[string]any{"endpoint": "http://localhost:8080/v1", "concurrency_limit": 2},
|
|
},
|
|
"profiles": map[string]any{
|
|
"base/one": map[string]any{"backend": "local.v1", "temperature": 0.8, "top_p": 0.9, "api_key_required": true,
|
|
"extra_params": map[string]any{"provider": map[string]any{"first": 1, "second": 2}}},
|
|
"child.v1": map[string]any{"extends": "base/one"},
|
|
},
|
|
"prompts": map[string]any{"invoice/summary": map[string]any{
|
|
"version": "v1.0",
|
|
"messages": []any{map[string]any{"role": "user", "content": "Summarize."}},
|
|
"output": map[string]any{"format": "text", "validation_mode": "basic"},
|
|
}},
|
|
})
|
|
overlay := mapping("operator", map[string]any{
|
|
"backends": map[string]any{"local.v1": map[string]any{"queue_capacity": 0}},
|
|
"profiles": map[string]any{"child.v1": map[string]any{
|
|
"temperature": 0, "top_p": nil, "api_key_required": false,
|
|
"extra_params": map[string]any{"provider": map[string]any{"second": 3}},
|
|
}},
|
|
})
|
|
loaded, err := load(configkit.Input{Source: configkit.NoSource()}, []configkit.Underlay{
|
|
{Inputs: []configkit.Input{base}}, {Inputs: []configkit.Input{overlay}},
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
profile := loaded.result.Config.Profiles["child.v1"]
|
|
if profile.Temperature == nil || *profile.Temperature != 0 || profile.TopP != nil || profile.APIKeyRequired == nil || *profile.APIKeyRequired {
|
|
t.Fatalf("effective values were not retained: %+v", profile)
|
|
}
|
|
if loaded.profiles["child.v1"]["temperature"] != fieldValue || loaded.profiles["child.v1"]["top_p"] != fieldNull || loaded.profiles["child.v1"]["api_key_required"] != fieldValue {
|
|
t.Fatalf("effective presence was lost: %+v", loaded.profiles["child.v1"])
|
|
}
|
|
provider := profile.ExtraParams["provider"].(map[string]any)
|
|
if provider["first"] != int64(1) || provider["second"] != int64(3) {
|
|
t.Fatalf("recursive overlay failed: %+v", provider)
|
|
}
|
|
backend := loaded.result.Config.Backends["local.v1"]
|
|
if backend.QueueCapacity == nil || *backend.QueueCapacity != 0 || loaded.backends["local.v1"]["queue_capacity"] != fieldValue {
|
|
t.Fatalf("explicit zero queue capacity was lost: %+v", backend)
|
|
}
|
|
if loaded.result.Config.Prompts["invoice/summary"].Messages[0].Content == nil || loaded.result.Config.Prompts["invoice/summary"].Version == nil || *loaded.result.Config.Prompts["invoice/summary"].Version != "v1.0" {
|
|
t.Fatal("literal prompt ID and version were not decoded")
|
|
}
|
|
}
|
|
|
|
func TestLoadRecordsBackendNormalizationAndNullDefault(t *testing.T) {
|
|
loaded, err := load(mapping("backend", map[string]any{"backends": map[string]any{
|
|
"local": map[string]any{"endpoint": " HTTP://localhost:8080/v1 ", "api_key_env": " TOKEN_NAME ",
|
|
"concurrency_limit": 2, "queue_capacity": nil},
|
|
}}), nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
backend := loaded.result.Config.Backends["local"]
|
|
if backend.Endpoint == nil || *backend.Endpoint != "http://localhost:8080/v1" ||
|
|
backend.APIKeyEnv == nil || *backend.APIKeyEnv != "TOKEN_NAME" ||
|
|
backend.QueueCapacity == nil || *backend.QueueCapacity != 1024 {
|
|
t.Fatalf("backend normalization/default was not applied: %+v", backend)
|
|
}
|
|
if loaded.backends["local"]["queue_capacity"] != fieldNull {
|
|
t.Fatalf("explicit null was not retained: %+v", loaded.backends["local"])
|
|
}
|
|
}
|
|
|
|
func TestLoadBackendSmokeTestsOmissionAndNull(t *testing.T) {
|
|
for _, test := range []struct {
|
|
name string
|
|
smokeTests any
|
|
include bool
|
|
inherited bool
|
|
}{
|
|
{name: "omitted"},
|
|
{name: "null", smokeTests: nil, include: true, inherited: true},
|
|
} {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
backend := map[string]any{"endpoint": "https://backend.example/v1"}
|
|
if test.include {
|
|
backend["smoke_tests"] = test.smokeTests
|
|
}
|
|
main := mapping("backend", map[string]any{
|
|
"backends": map[string]any{"local": backend},
|
|
})
|
|
var underlays []configkit.Underlay
|
|
if test.inherited {
|
|
underlays = []configkit.Underlay{{Inputs: []configkit.Input{mapping("defaults", map[string]any{
|
|
"backends": map[string]any{"local": map[string]any{
|
|
"endpoint": "https://backend.example/v1",
|
|
"smoke_tests": map[string]any{"default_profile": "inherited-profile"},
|
|
}},
|
|
})}}}
|
|
}
|
|
loaded, err := load(main, underlays)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got := loaded.result.Config.Backends["local"].SmokeTests; got != nil {
|
|
t.Fatalf("smoke_tests = %+v, want nil", got)
|
|
}
|
|
selected, err := loaded.registry.GetBackend("local")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if selected.SmokeTests != nil {
|
|
t.Fatalf("indexed smoke_tests = %+v, want nil", selected.SmokeTests)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestLoadMergesBackendSmokeTestsAndRetainsFallbacks(t *testing.T) {
|
|
base := mapping("defaults", map[string]any{
|
|
"backends": map[string]any{"local": map[string]any{
|
|
"endpoint": "https://backend.example/v1",
|
|
"smoke_tests": map[string]any{
|
|
"default_profile": "catalog-profile",
|
|
"reachability": map[string]any{"endpoint": " https://probe.example/ready?check=1 "},
|
|
"authentication": map[string]any{
|
|
"kind": " OPENROUTER_KEY ",
|
|
"endpoint": "https://probe.example/key?scope=current",
|
|
},
|
|
},
|
|
}},
|
|
})
|
|
overlay := mapping("operator", map[string]any{
|
|
"backends": map[string]any{"local": map[string]any{
|
|
"smoke_tests": map[string]any{
|
|
"default_profile": "not-yet-listed",
|
|
"authentication": map[string]any{"kind": " NONE ", "endpoint": nil},
|
|
},
|
|
}},
|
|
})
|
|
loaded, err := load(configkit.Input{Source: configkit.NoSource()}, []configkit.Underlay{
|
|
{Inputs: []configkit.Input{base}},
|
|
{Inputs: []configkit.Input{overlay}},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("load effective diagnostic metadata: %v", err)
|
|
}
|
|
selected, err := loaded.registry.GetBackend("local")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
metadata := selected.SmokeTests
|
|
if selected.Endpoint != "https://backend.example/v1" {
|
|
t.Fatalf("effective backend endpoint = %q", selected.Endpoint)
|
|
}
|
|
if metadata == nil || metadata.DefaultProfile == nil || *metadata.DefaultProfile != "not-yet-listed" {
|
|
t.Fatalf("default profile overlay was not retained: %+v", metadata)
|
|
}
|
|
if metadata.Reachability == nil || metadata.Reachability.Endpoint == nil ||
|
|
*metadata.Reachability.Endpoint != "https://probe.example/ready?check=1" {
|
|
t.Fatalf("full reachability destination was not normalized: %+v", metadata.Reachability)
|
|
}
|
|
if metadata.Authentication == nil || metadata.Authentication.Kind == nil || *metadata.Authentication.Kind != "none" ||
|
|
metadata.Authentication.Endpoint != nil {
|
|
t.Fatalf("authentication overlay or null fallback was not retained: %+v", metadata.Authentication)
|
|
}
|
|
}
|
|
|
|
func TestLoadRejectsInvalidFinalBackendSmokeTests(t *testing.T) {
|
|
for _, test := range []struct {
|
|
name string
|
|
data map[string]any
|
|
path string
|
|
}{
|
|
{
|
|
name: "blank default profile",
|
|
data: map[string]any{"default_profile": " \t "},
|
|
path: "/backends/local/smoke_tests/default_profile",
|
|
},
|
|
{
|
|
name: "authentication kind required",
|
|
data: map[string]any{"authentication": map[string]any{}},
|
|
path: "/backends/local/smoke_tests/authentication/kind",
|
|
},
|
|
{
|
|
name: "unknown authentication kind",
|
|
data: map[string]any{"authentication": map[string]any{"kind": "bearer"}},
|
|
path: "/backends/local/smoke_tests/authentication/kind",
|
|
},
|
|
{
|
|
name: "non-http reachability URL",
|
|
data: map[string]any{"reachability": map[string]any{"endpoint": "ftp://probe.example/ready"}},
|
|
path: "/backends/local/smoke_tests/reachability/endpoint",
|
|
},
|
|
{
|
|
name: "blank authentication URL",
|
|
data: map[string]any{"authentication": map[string]any{"kind": "none", "endpoint": " "}},
|
|
path: "/backends/local/smoke_tests/authentication/endpoint",
|
|
},
|
|
{
|
|
name: "relative authentication URL",
|
|
data: map[string]any{"authentication": map[string]any{"kind": "none", "endpoint": "/key"}},
|
|
path: "/backends/local/smoke_tests/authentication/endpoint",
|
|
},
|
|
} {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
_, err := load(mapping("backend", map[string]any{
|
|
"backends": map[string]any{"local": map[string]any{
|
|
"endpoint": "https://backend.example/v1",
|
|
"smoke_tests": test.data,
|
|
}},
|
|
}), nil)
|
|
var loadError *configkit.LoadError
|
|
if !errors.As(err, &loadError) {
|
|
t.Fatalf("expected final-value validation error, got %v", err)
|
|
}
|
|
for _, diagnostic := range loadError.Diagnostics() {
|
|
if diagnostic.Path.String() == test.path {
|
|
return
|
|
}
|
|
}
|
|
t.Fatalf("expected diagnostic at %s, got %+v", test.path, loadError.Diagnostics())
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestLoadDefaultsAbsentQueueCapacity(t *testing.T) {
|
|
loaded, err := load(mapping("backend", map[string]any{"backends": map[string]any{
|
|
"local": map[string]any{"endpoint": "http://localhost:8080/v1", "concurrency_limit": 1},
|
|
}}), nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
backend := loaded.result.Config.Backends["local"]
|
|
if backend.QueueCapacity == nil || *backend.QueueCapacity != 1024 || loaded.backends["local"]["queue_capacity"] != fieldAbsent {
|
|
t.Fatalf("absent queue capacity did not receive its default: %+v", backend)
|
|
}
|
|
}
|
|
|
|
func TestLoadRejectsStrictGroupConflict(t *testing.T) {
|
|
_, err := load(configkit.Input{Source: configkit.NoSource()}, []configkit.Underlay{{Inputs: []configkit.Input{
|
|
mapping("first", map[string]any{"profiles": map[string]any{"shared": map[string]any{"model": "one"}}}),
|
|
mapping("second", map[string]any{"profiles": map[string]any{"shared": map[string]any{"model": "one"}}}),
|
|
}}})
|
|
var loadError *configkit.LoadError
|
|
if !errors.As(err, &loadError) {
|
|
t.Fatalf("expected ConfigKit load error, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestLoadValidatesOnlyFinalDomainValues(t *testing.T) {
|
|
underlay := mapping("defaults", map[string]any{
|
|
"backends": map[string]any{"local": map[string]any{"endpoint": "not a URL"}},
|
|
"profiles": map[string]any{"partial": map[string]any{"backend": "local"}},
|
|
})
|
|
main := mapping("operator", map[string]any{"backends": map[string]any{"local": map[string]any{"endpoint": "http://localhost:8080/v1"}}})
|
|
loaded, err := load(main, []configkit.Underlay{{Inputs: []configkit.Input{underlay}}})
|
|
if err != nil {
|
|
t.Fatalf("replaced lower-layer domain value should not fail: %v", err)
|
|
}
|
|
if loaded.result.Config.Profiles["partial"].Model != nil {
|
|
t.Fatal("unused partial profile unexpectedly gained a model")
|
|
}
|
|
|
|
_, err = load(configkit.Input{Source: configkit.NoSource()}, []configkit.Underlay{{Inputs: []configkit.Input{
|
|
mapping("invalid", map[string]any{"backends": map[string]any{"unused": map[string]any{"endpoint": "not a URL"}}}),
|
|
}}})
|
|
var loadError *configkit.LoadError
|
|
if !errors.As(err, &loadError) {
|
|
t.Fatalf("expected path-aware effective backend failure, got %v", err)
|
|
}
|
|
if diagnostics := loadError.Diagnostics(); len(diagnostics) != 1 || diagnostics[0].Path.String() != "/backends/unused/endpoint" {
|
|
t.Fatalf("expected endpoint diagnostic, got %+v", diagnostics)
|
|
}
|
|
}
|
|
|
|
func TestLoadValidatesOnlyFinalBackendSmokeTestValues(t *testing.T) {
|
|
underlay := mapping("defaults", map[string]any{
|
|
"backends": map[string]any{"local": map[string]any{
|
|
"endpoint": "https://backend.example/v1",
|
|
"smoke_tests": map[string]any{
|
|
"default_profile": " ",
|
|
"reachability": map[string]any{"endpoint": "ftp://invalid.example/"},
|
|
"authentication": map[string]any{"kind": "unsupported"},
|
|
},
|
|
}},
|
|
})
|
|
main := mapping("operator", map[string]any{
|
|
"backends": map[string]any{"local": map[string]any{
|
|
"smoke_tests": map[string]any{
|
|
"default_profile": "dangling-profile",
|
|
"reachability": map[string]any{"endpoint": nil},
|
|
"authentication": map[string]any{"kind": "none"},
|
|
},
|
|
}},
|
|
})
|
|
loaded, err := load(main, []configkit.Underlay{{Inputs: []configkit.Input{underlay}}})
|
|
if err != nil {
|
|
t.Fatalf("replaced lower metadata should not fail: %v", err)
|
|
}
|
|
selected, err := loaded.registry.GetBackend("local")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if selected.SmokeTests == nil || selected.SmokeTests.DefaultProfile == nil ||
|
|
*selected.SmokeTests.DefaultProfile != "dangling-profile" {
|
|
t.Fatalf("final dangling default profile was not retained: %+v", selected.SmokeTests)
|
|
}
|
|
}
|
|
|
|
func TestLoadKeepsSyntaxErrorsFromLowerTiers(t *testing.T) {
|
|
_, err := load(mapping("operator", map[string]any{"backends": map[string]any{"local": map[string]any{"endpoint": "http://localhost:8080"}}}),
|
|
[]configkit.Underlay{{Inputs: []configkit.Input{{Source: configkit.Bytes("broken", []byte("backends: ["))}}}})
|
|
var loadError *configkit.LoadError
|
|
if !errors.As(err, &loadError) {
|
|
t.Fatalf("expected lower-tier parsing error, got %v", err)
|
|
}
|
|
}
|