Test bundled configuration composition
This commit is contained in:
115
bundled_composition_contract_test.go
Normal file
115
bundled_composition_contract_test.go
Normal file
@@ -0,0 +1,115 @@
|
||||
package promptkit_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"go.maximumdirect.net/configkit"
|
||||
"go.maximumdirect.net/promptkit"
|
||||
)
|
||||
|
||||
func TestBundledCompositionReplacementAndInheritance(t *testing.T) {
|
||||
underlay := configkit.Input{Source: configkit.Mapping("caller underlay", map[string]any{
|
||||
"profiles": []any{map[string]any{"id": "gpt-sol-latest", "model": "underlay-model"}},
|
||||
})}
|
||||
underlayEngine, err := promptkit.NewEngine(promptkit.Config{Sources: promptkit.ConfigurationSources{Underlays: []configkit.Underlay{{Inputs: []configkit.Input{underlay}}}}})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
underlayProfile, err := underlayEngine.InspectProfile(context.Background(), "gpt-sol-latest")
|
||||
if err != nil || underlayProfile.EffectiveModelParams.Model != "underlay-model" || underlayProfile.EffectiveModelParams.BackendID != "" {
|
||||
t.Fatalf("underlay replacement = %+v, %v", underlayProfile, err)
|
||||
}
|
||||
main := configkit.Input{Source: configkit.Mapping("caller main", map[string]any{
|
||||
"backends": []any{map[string]any{"id": "openrouter", "endpoint": "https://local.invalid/v1"}, map[string]any{"id": "other", "endpoint": "https://other.invalid/v1"}},
|
||||
"profiles": []any{
|
||||
map[string]any{"id": "gpt-sol-latest", "model": "main-model"},
|
||||
map[string]any{"id": "custom", "extends": map[string]any{"id": "gpt-luna-latest"}, "model": "custom-model"},
|
||||
map[string]any{"id": "auto", "backend": "other", "model": "other-model"},
|
||||
},
|
||||
"collections": map[string]any{"openrouter": map[string]any{
|
||||
"backends": []any{map[string]any{"id": "local", "endpoint": "https://collection.invalid/v1"}},
|
||||
"profiles": []any{map[string]any{"id": "profile", "backend": "openrouter/local", "model": "collection-model"}},
|
||||
}},
|
||||
})}
|
||||
engine, err := promptkit.NewEngine(promptkit.Config{Sources: promptkit.ConfigurationSources{Underlays: []configkit.Underlay{{Inputs: []configkit.Input{underlay}}}, Main: &main}})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
inspect := func(id string) promptkit.ExecutionTarget {
|
||||
t.Helper()
|
||||
profile, err := engine.InspectProfile(context.Background(), id)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return profile.EffectiveModelParams
|
||||
}
|
||||
if target := inspect("gpt-sol-latest"); target.Model != "main-model" || target.BackendID != "" {
|
||||
t.Fatalf("replacement = %+v", target)
|
||||
}
|
||||
if target := inspect("custom"); target.Model != "custom-model" || target.BackendID != "openrouter" || target.Endpoint != "https://local.invalid/v1" {
|
||||
t.Fatalf("inherited = %+v", target)
|
||||
}
|
||||
if target := inspect("gpt-luna-latest"); target.Endpoint != "https://local.invalid/v1" || target.APIKeyEnv != "" {
|
||||
t.Fatalf("backend replacement = %+v", target)
|
||||
}
|
||||
if target := inspect("openrouter/profile"); target.BackendID != "openrouter/local" || target.Model != "collection-model" {
|
||||
t.Fatalf("collection = %+v", target)
|
||||
}
|
||||
for _, tier := range []string{"low", "medium", "high", "xhigh", "max"} {
|
||||
target := inspect("auto-" + tier)
|
||||
if target.BackendID != "other" || target.Model != "other-model" || !strings.Contains(fmt.Sprint(target.ExtraParams), "cost_tier:"+tier) || !strings.Contains(fmt.Sprint(target.ExtraParams), "id:auto-router") {
|
||||
t.Errorf("tier %s = %+v", tier, target)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBundledCompositionSequenceModes(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
name, mode, id string
|
||||
wantErr bool
|
||||
count int
|
||||
}{
|
||||
{"duplicate append", "append", "auto", true, 0},
|
||||
{"distinct append", "append", "custom", false, 18},
|
||||
{"replace", "replace", "custom", false, 1},
|
||||
} {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
input := configkit.Input{Source: configkit.Mapping("sequence", map[string]any{
|
||||
"config": map[string]any{"sequences": []any{map[string]any{"destination": []any{"profiles"}, "mode": test.mode}}},
|
||||
"profiles": []any{map[string]any{"id": test.id, "model": "custom-model"}},
|
||||
})}
|
||||
engine, err := promptkit.NewEngine(promptkit.Config{Sources: promptkit.ConfigurationSources{Main: &input}})
|
||||
if test.wantErr {
|
||||
if err == nil {
|
||||
t.Fatal("expected duplicate rejection")
|
||||
}
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
profiles, err := engine.ListProfiles(context.Background())
|
||||
if err != nil || len(profiles) != test.count {
|
||||
t.Fatalf("profiles = %v, %v", profiles, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestBundledCompositionRejectsStrictConflictsAndMissingBackends(t *testing.T) {
|
||||
profile := configkit.Input{Source: configkit.Mapping("profile", map[string]any{"profiles": []any{map[string]any{"id": "auto", "model": "caller"}}})}
|
||||
_, err := promptkit.NewEngine(promptkit.Config{Sources: promptkit.ConfigurationSources{Underlays: []configkit.Underlay{{Inputs: []configkit.Input{profile, profile}}}}})
|
||||
if err == nil {
|
||||
t.Fatal("strict group accepted duplicate records")
|
||||
}
|
||||
input := configkit.Input{Source: configkit.Mapping("replace backends", map[string]any{
|
||||
"config": map[string]any{"sequences": []any{map[string]any{"destination": []any{"backends"}, "mode": "replace"}}},
|
||||
"backends": []any{map[string]any{"id": "other", "endpoint": "https://other.invalid/v1"}},
|
||||
})}
|
||||
if _, err := promptkit.NewEngine(promptkit.Config{Sources: promptkit.ConfigurationSources{Main: &input}}); err == nil {
|
||||
t.Fatal("missing bundled backend was accepted")
|
||||
}
|
||||
}
|
||||
@@ -183,6 +183,10 @@ Validation: targeted new composition tests plus existing source, inheritance,
|
||||
namespace, and profile-completion tests. Avoid reproducing ConfigKit's generic
|
||||
sequence implementation suite.
|
||||
|
||||
Completion: facade integration tests cover caller precedence, whole-record
|
||||
replacement, inheritance, scoped resources, sequence modes, strict conflicts,
|
||||
and missing backend rejection. Targeted tests pass on Go 1.27.0.
|
||||
|
||||
## Stage 4: Verify Preparation And HTTP Request Construction
|
||||
|
||||
Scope: bundled-profile execution integration with existing runner/client paths.
|
||||
|
||||
Reference in New Issue
Block a user