240 lines
8.4 KiB
Go
240 lines
8.4 KiB
Go
package consumers_test
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
"testing"
|
|
|
|
configkit "gitea.maximumdirect.net/eric/ConfigKit"
|
|
"gitea.maximumdirect.net/eric/ConfigKit/examples/consumers"
|
|
)
|
|
|
|
func Example_sequenceCatalog() {
|
|
const oldSecret = "CONFIGKIT_SEQUENCE_CATALOG_OLD_SECRET"
|
|
const newSecret = "CONFIGKIT_SEQUENCE_CATALOG_NEW_SECRET"
|
|
restoreOld, restoreNew := preserveEnvironment(oldSecret), preserveEnvironment(newSecret)
|
|
defer restoreOld()
|
|
defer restoreNew()
|
|
_ = os.Setenv(oldSecret, "disposable-old-example-credential")
|
|
_ = os.Setenv(newSecret, "disposable-new-example-credential")
|
|
|
|
result, err := consumers.LoadSequenceCatalog(fixture("sequence-catalog", "config.yml"), "upsert", "preview")
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
return
|
|
}
|
|
ids := make([]string, 0, len(result.Config.Prompts))
|
|
for _, prompt := range result.Config.Prompts {
|
|
ids = append(ids, prompt.ID)
|
|
}
|
|
shared := configkit.Keys("prompts").Index(1).Key("name")
|
|
info, _ := result.Metadata().Lookup(shared)
|
|
resource, resourceErr := consumers.ReadSequenceCatalogResource(result, "concise")
|
|
fmt.Println(ids, result.Config.ResolvedLabel, info.Explicit, len(result.Metadata().History(shared)), resource, resourceErr == nil, err)
|
|
// Output: [foundation shared welcome concise extra] for:preview true 2 Foundation resource text.
|
|
// true <nil>
|
|
}
|
|
|
|
func TestSequenceCatalogSelectedOverlayOperations(t *testing.T) {
|
|
const oldSecret = "CONFIGKIT_SEQUENCE_CATALOG_OLD_SECRET"
|
|
const newSecret = "CONFIGKIT_SEQUENCE_CATALOG_NEW_SECRET"
|
|
t.Setenv(oldSecret, "sequence-catalog-old-canary")
|
|
t.Setenv(newSecret, "sequence-catalog-new-canary")
|
|
|
|
tests := []struct {
|
|
name string
|
|
wantIDs []string
|
|
shared *consumers.SequenceCatalogEntry
|
|
}{
|
|
{name: "append", wantIDs: []string{"foundation", "shared", "welcome", "concise", "extra"}},
|
|
{name: "upsert", wantIDs: []string{"foundation", "shared", "welcome", "concise", "extra"}, shared: &consumers.SequenceCatalogEntry{ID: "shared", Name: "Shared replacement", Messages: []string{"Replacement message"}, Credential: configkit.SecretEnv(newSecret)}},
|
|
{name: "replace", wantIDs: []string{"replacement", "last"}},
|
|
}
|
|
for _, test := range tests {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
result, err := consumers.LoadSequenceCatalog(fixture("sequence-catalog", "config.yml"), test.name, "test")
|
|
if err != nil {
|
|
var loadError *configkit.LoadError
|
|
if errors.As(err, &loadError) {
|
|
t.Fatalf("load selected overlay: %v (%#v)", err, loadError.Diagnostics())
|
|
}
|
|
t.Fatal(err)
|
|
}
|
|
gotIDs := make([]string, 0, len(result.Config.Prompts))
|
|
for _, prompt := range result.Config.Prompts {
|
|
gotIDs = append(gotIDs, prompt.ID)
|
|
}
|
|
if strings.Join(gotIDs, ",") != strings.Join(test.wantIDs, ",") {
|
|
t.Fatalf("prompt order = %v, want %v", gotIDs, test.wantIDs)
|
|
}
|
|
if test.shared == nil {
|
|
return
|
|
}
|
|
shared := result.Config.Prompts[1]
|
|
if shared.ID != test.shared.ID || shared.Name != test.shared.Name || len(shared.Messages) != 1 ||
|
|
shared.Messages[0] != test.shared.Messages[0] || shared.Description != "" || shared.Resource != "" || shared.Credential.EnvName() != newSecret {
|
|
t.Fatalf("upsert did not replace the complete matched record: %#v", shared)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestSequenceCatalogInspectionTracksResourcesAndSecretHistory(t *testing.T) {
|
|
const oldSecret = "CONFIGKIT_SEQUENCE_CATALOG_OLD_SECRET"
|
|
const newSecret = "CONFIGKIT_SEQUENCE_CATALOG_NEW_SECRET"
|
|
const oldCanary = "sequence-catalog-old-canary"
|
|
const newCanary = "sequence-catalog-new-canary"
|
|
t.Setenv(oldSecret, oldCanary)
|
|
t.Setenv(newSecret, newCanary)
|
|
|
|
result, err := consumers.LoadSequenceCatalog(fixture("sequence-catalog", "config.yml"), "upsert", "history")
|
|
if err != nil {
|
|
var loadError *configkit.LoadError
|
|
if errors.As(err, &loadError) {
|
|
t.Fatalf("load sequence catalog: %v (%#v)", err, loadError.Diagnostics())
|
|
}
|
|
t.Fatal(err)
|
|
}
|
|
resourcePath := configkit.Keys("prompts").Index(3).Key("resource")
|
|
resourceInfo, found := result.Metadata().Lookup(resourcePath)
|
|
if !found || len(resourceInfo.Origin.Locations) != 1 || len(resourceInfo.Origin.Inheritance) != 1 {
|
|
t.Fatalf("inherited resource inspection = %#v, %v", resourceInfo, found)
|
|
}
|
|
resource, err := consumers.ReadSequenceCatalogResource(result, "concise")
|
|
if err != nil || resource != "Foundation resource text.\n" {
|
|
t.Fatalf("resource from inherited source context = %q, %v", resource, err)
|
|
}
|
|
if len(result.Metadata().History(configkit.Keys("resolved_label"))) == 0 {
|
|
t.Fatal("recorded CLI-driven resolution was absent from final inspection")
|
|
}
|
|
credentialPath := configkit.Keys("prompts").Index(1).Key("credential")
|
|
credentialHistory := result.Metadata().History(credentialPath)
|
|
if len(credentialHistory) == 0 {
|
|
t.Fatal("upsert did not retain the replaced secret reference in history")
|
|
}
|
|
var explanation bytes.Buffer
|
|
if err := result.WriteExplanation(&explanation, credentialPath); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if strings.Contains(explanation.String(), oldCanary) || strings.Contains(explanation.String(), newCanary) {
|
|
t.Fatalf("secret explanation exposed a credential value: %s", explanation.String())
|
|
}
|
|
}
|
|
|
|
func TestNamespacedTypedMapIdentityScopesAreIndependent(t *testing.T) {
|
|
source := configkit.Bytes("namespaced maps", []byte(`
|
|
prompts:
|
|
- id: shared
|
|
text: root prompt
|
|
collections:
|
|
team:
|
|
prompts:
|
|
- id: shared
|
|
text: team prompt
|
|
operations:
|
|
prompts:
|
|
- id: shared
|
|
text: operations prompt
|
|
`))
|
|
result, err := consumers.LoadNamespacedMapCatalog(source)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if result.Config.Prompts[0]["text"] != "root prompt" ||
|
|
result.Config.Collections["team"]["prompts"].([]any)[0].(map[string]any)["text"] != "team prompt" ||
|
|
result.Config.Collections["operations"]["prompts"].([]any)[0].(map[string]any)["text"] != "operations prompt" {
|
|
t.Fatalf("typed map collections = %#v", result.Config)
|
|
}
|
|
}
|
|
|
|
func TestNamespacedTypedMapIdentityFindsCollectionsIntroducedByInheritance(t *testing.T) {
|
|
result, err := consumers.LoadNamespacedMapCatalog(configkit.Bytes("inherited namespace", []byte(`
|
|
collections:
|
|
source:
|
|
prompts:
|
|
- id: shared
|
|
text: inherited prompt
|
|
copied:
|
|
extends: source
|
|
`)))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
copied := result.Config.Collections["copied"]["prompts"].([]any)
|
|
if len(copied) != 1 || copied[0].(map[string]any)["text"] != "inherited prompt" {
|
|
t.Fatalf("inherited typed-map collection = %#v", result.Config.Collections["copied"])
|
|
}
|
|
}
|
|
|
|
func Example_yamlDeclaredIdentityOnly() {
|
|
result, err := configkit.Load(configkit.Bytes("YAML identity only", []byte(`
|
|
configkit:
|
|
sequences:
|
|
- destination: [prompts]
|
|
key: id
|
|
prompts:
|
|
- id: initial
|
|
`)), configkit.Options[map[string]any]{
|
|
Overrides: []configkit.Override{{
|
|
Path: configkit.Keys("prompts"),
|
|
Value: []any{
|
|
map[string]any{"id": "same"},
|
|
map[string]any{"id": "same"},
|
|
},
|
|
Flag: "--prompts",
|
|
}},
|
|
})
|
|
fmt.Println(len(result.Config["prompts"].([]any)), err)
|
|
// Output: 2 <nil>
|
|
}
|
|
|
|
func TestYAMLDeclaredIdentityDoesNotRegisterFinalTypedConstraint(t *testing.T) {
|
|
result, err := configkit.Load(configkit.Bytes("YAML identity only", []byte(`
|
|
configkit:
|
|
sequences:
|
|
- destination: [prompts]
|
|
key: id
|
|
prompts:
|
|
- id: initial
|
|
`)), configkit.Options[map[string]any]{
|
|
Overrides: []configkit.Override{{
|
|
Path: configkit.Keys("prompts"),
|
|
Value: []any{
|
|
map[string]any{"id": "same"},
|
|
map[string]any{"id": "same"},
|
|
},
|
|
Flag: "--prompts",
|
|
}},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("YAML-only identity incorrectly became an application constraint: %v", err)
|
|
}
|
|
prompts := result.Config["prompts"].([]any)
|
|
if len(prompts) != 2 || prompts[0].(map[string]any)["id"] != prompts[1].(map[string]any)["id"] {
|
|
t.Fatalf("CLI result = %#v", result.Config)
|
|
}
|
|
}
|
|
|
|
func TestNamespacedTypedMapRejectsDuplicatesWithinOneCollection(t *testing.T) {
|
|
_, err := consumers.LoadNamespacedMapCatalog(configkit.Bytes("duplicate namespace", []byte(`
|
|
collections:
|
|
team:
|
|
prompts:
|
|
- id: duplicate
|
|
- id: duplicate
|
|
`)))
|
|
var loadError *configkit.LoadError
|
|
if !errors.As(err, &loadError) || len(loadError.Diagnostics()) != 1 ||
|
|
loadError.Diagnostics()[0].Code != configkit.CodeComposeConflict ||
|
|
loadError.Diagnostics()[0].Path.String() != "/collections/team/prompts" {
|
|
diagnostics := []configkit.Diagnostic(nil)
|
|
if loadError != nil {
|
|
diagnostics = loadError.Diagnostics()
|
|
}
|
|
t.Fatalf("duplicate namespaced identity error = %v (%#v)", err, diagnostics)
|
|
}
|
|
}
|