Files
ConfigKit/internal/engine/destination_load_test.go

211 lines
7.1 KiB
Go

package engine
import (
"bytes"
"testing"
)
type destinationLoadConfig struct {
Main map[string]string `yaml:"main"`
Defaults map[string]string `yaml:"defaults"`
Collections map[string]map[string]string `yaml:"collections"`
Value string `yaml:"value"`
}
type destinationItemConfig struct {
Catalog struct {
Entries []map[string]string `yaml:"entries"`
} `yaml:"catalog"`
}
func TestLayeredLoadPlacesCompletedMappingAsOneItem(t *testing.T) {
t.Parallel()
loaded, err := LoadLayered[destinationItemConfig](
Input{Source: NoSource(), Destination: Keys("catalog", "entries"), placementMode: placementModeSequenceItem},
testSecretBinding(),
LayeredOptions[destinationItemConfig]{Underlays: []Underlay{{Inputs: []Input{{
Source: Mapping("empty-item", map[string]any{}), Destination: Keys("catalog", "entries"),
placementMode: placementModeSequenceItem,
}}}}},
)
if err != nil {
t.Fatalf("LoadLayered: %v", err)
}
result := testLoaded(loaded)
if len(result.Config.Catalog.Entries) != 1 || result.Config.Catalog.Entries[0] == nil || len(result.Config.Catalog.Entries[0]) != 0 {
t.Fatalf("empty mapping item = %#v", result.Config.Catalog.Entries)
}
if _, ok := result.Metadata().Lookup(Keys("catalog", "entries", "0")); ok {
t.Fatal("sequence index was treated as a literal mapping key during metadata lookup")
}
sources := result.Sources()
if len(sources) != 1 || sources[0].placementMode != placementModeSequenceItem || sources[0].destinationUnresolved {
t.Fatalf("source placement evidence = %#v", sources)
}
if got := sources[0].Destination.String(); got != "/catalog/entries" {
t.Fatalf("source destination = %q", got)
}
absent, err := LoadLayered[destinationItemConfig](
Input{Source: NoSource(), Destination: Keys("catalog", "entries"), placementMode: placementModeSequenceItem},
testSecretBinding(),
)
if err != nil {
t.Fatalf("NoSource item load: %v", err)
}
if got := len(testLoaded(absent).Config.Catalog.Entries); got != 0 {
t.Fatalf("absent item created %d entries", got)
}
}
func TestLayeredItemPlacementPreflightsModeAndDestination(t *testing.T) {
t.Parallel()
for _, test := range []struct {
name string
mode placementMode
path Path
}{
{name: "root item", mode: placementModeSequenceItem},
{name: "unknown mode", mode: placementMode(255), path: Keys("catalog")},
} {
t.Run(test.name, func(t *testing.T) {
t.Parallel()
reader := bytes.NewBufferString("value: unused\n")
_, err := LoadLayered[destinationItemConfig](
Input{Source: Reader("reader", reader), Destination: test.path, placementMode: test.mode},
testSecretBinding(),
)
if err == nil || reader.Len() == 0 {
t.Fatalf("preflight err %v, unread bytes %d", err, reader.Len())
}
loadError, ok := err.(*LoadError)
if !ok || len(loadError.Diagnostics()) == 0 || loadError.Diagnostics()[0].Code != CodeOptionsInvalid {
t.Fatalf("preflight error = %#v", err)
}
})
}
}
func TestLoadOptionsPlaceOneMappingItem(t *testing.T) {
t.Parallel()
loaded, err := Load[destinationItemConfig](
Mapping("ordinary", map[string]any{}), testSecretBinding(),
Options[destinationItemConfig]{destination: Keys("catalog", "entries"), placementMode: placementModeSequenceItem},
)
if err != nil {
t.Fatalf("Load: %v", err)
}
result := testLoaded(loaded)
if len(result.Config.Catalog.Entries) != 1 || result.Config.Catalog.Entries[0] == nil {
t.Fatalf("ordinary item placement = %#v", result.Config.Catalog.Entries)
}
}
func TestLayeredLoadPlacesNonImportMainAndUnderlayInputs(t *testing.T) {
t.Parallel()
destination := Keys("main")
main := Input{Source: Bytes("main", []byte("value: primary\n")), Destination: destination}
underlay := Input{Source: Bytes("defaults", []byte("value: fallback\n")), Destination: Keys("defaults")}
loaded, err := LoadLayered(main, testSecretBinding(), LayeredOptions[destinationLoadConfig]{
Underlays: []Underlay{{Inputs: []Input{underlay}}},
})
if err != nil {
t.Fatalf("LoadLayered: %v", err)
}
result := testLoaded(loaded)
if result.Config.Main["value"] != "primary" || result.Config.Defaults["value"] != "fallback" {
t.Fatalf("mounted configuration = %#v", result.Config)
}
sources := result.Sources()
if len(sources) != 2 || sources[0].Destination.String() != "/main" || sources[1].Destination.String() != "/defaults" {
t.Fatalf("source destinations = %#v", sources)
}
destination.segments[0].key = "caller mutation"
sources[0].Destination.segments[0].key = "record mutation"
if got := result.Sources()[0].Destination.String(); got != "/main" {
t.Fatalf("source destination was not independently owned: %q", got)
}
}
func TestLayeredLoadOmittedAndEmptyDestinationsKeepRootPlacement(t *testing.T) {
t.Parallel()
inputs := []Input{
{Source: Bytes("omitted", []byte("value: same\n"))},
{Source: Bytes("empty", []byte("value: same\n")), Destination: Keys()},
}
for _, input := range inputs {
loaded, err := LoadLayered(input, testSecretBinding(), LayeredOptions[destinationLoadConfig]{})
if err != nil {
t.Fatalf("LoadLayered: %v", err)
}
result := testLoaded(loaded)
if result.Config.Value != "same" {
t.Fatalf("root value = %q", result.Config.Value)
}
sources := result.Sources()
if len(sources) != 1 || sources[0].Destination.String() != "" {
t.Fatalf("root source destination = %#v", sources)
}
}
}
func TestLayeredLoadDistinguishesEmptyBodyFromNoSource(t *testing.T) {
t.Parallel()
loaded, err := LoadLayered(
Input{Source: NoSource(), Destination: Keys("absent")},
testSecretBinding(),
LayeredOptions[destinationLoadConfig]{Underlays: []Underlay{{Inputs: []Input{{
Source: Bytes("empty", []byte("{}\n")), Destination: Keys("collections", "one"),
}}}}},
)
if err != nil {
t.Fatalf("LoadLayered: %v", err)
}
result := testLoaded(loaded)
info, ok := result.Metadata().Lookup(Keys("collections", "one"))
if !ok || !info.Explicit || info.Origin.Layer != LayerUnderlay {
t.Fatalf("empty mounted mapping = %#v, %v", info, ok)
}
if _, ok := result.Metadata().Lookup(Keys("absent")); ok {
t.Fatal("NoSource materialized its destination")
}
sources := result.Sources()
if len(sources) != 1 || sources[0].Label != "empty" || sources[0].Destination.String() != "/collections/one" {
t.Fatalf("sources = %#v", sources)
}
}
func TestLayeredLoadPreflightsDestinationsBeforeReadingSources(t *testing.T) {
t.Parallel()
reader := bytes.NewBufferString("value: unused\n")
_, err := LoadLayered(
Input{Source: NoSource()},
testSecretBinding(),
LayeredOptions[destinationLoadConfig]{Underlays: []Underlay{{Inputs: []Input{{
Source: Reader("reader", reader), Destination: Keys("configkit"),
}}}}},
)
if err == nil {
t.Fatal("reserved destination was accepted")
}
if reader.Len() == 0 {
t.Fatal("source reader was consumed before destination preflight")
}
loadError, ok := err.(*LoadError)
if !ok || len(loadError.Diagnostics()) != 1 {
t.Fatalf("error = %#v", err)
}
diagnostic := loadError.Diagnostics()[0]
if diagnostic.Code != CodeOptionsInvalid || diagnostic.Path.String() != "/configkit" || diagnostic.Primary != nil {
t.Fatalf("destination diagnostic = %#v", diagnostic)
}
}