Files
ConfigKit/internal/engine/destination_provenance_test.go

182 lines
7.8 KiB
Go

package engine
import (
"errors"
"io/fs"
"path"
"reflect"
"testing"
)
func TestLayeredDestinationsRetainOriginsHistoryAndDetachedRecords(t *testing.T) {
t.Parallel()
directory := t.TempDir()
sharedPath := writeImportFile(t, directory, "shared.yml", "section:\n shared: lower\n branch:\n child: old\n kept: retained\n")
shared := File(sharedPath)
load := func() (*Loaded[map[string]any], error) {
return LoadLayered(
Input{Source: NoSource()}, testSecretBinding(),
LayeredOptions[map[string]any]{Underlays: []Underlay{
{Inputs: []Input{
{Source: shared, Destination: Keys("catalog")},
{Source: Bytes("peer", []byte("section:\n peer: present\n")), Destination: Keys("catalog")},
}},
{Inputs: []Input{{Source: shared, Destination: Keys("backup")}}},
{Inputs: []Input{{Source: Bytes("replacement", []byte("section:\n branch: replaced\n")), Destination: Keys("catalog")}}},
}},
)
}
loaded, err := load()
if err != nil {
t.Fatalf("LoadLayered: %v, diagnostics %#v", err, err.(*LoadError).Diagnostics())
}
result := testLoaded(loaded)
metadata := result.Metadata()
container, ok := metadata.Lookup(Keys("catalog"))
if !ok || !container.Explicit || len(container.Origin.Locations) < 3 {
t.Fatalf("mounted container origin = %#v, %v", container, ok)
}
containerSources := make(map[string]bool)
for _, location := range container.Origin.Locations {
containerSources[location.SourceID] = true
if location.Line < 1 {
t.Fatalf("introduced container lacks its source-root fallback: %#v", location)
}
}
for _, sourceID := range []string{"source-1", "source-2", "source-4"} {
if !containerSources[sourceID] {
t.Fatalf("container contributors = %#v, missing %s", container.Origin.Locations, sourceID)
}
}
sharedField, ok := metadata.Lookup(Keys("catalog", "section", "shared"))
if !ok || len(sharedField.Origin.Locations) != 1 || sharedField.Origin.Locations[0].SourceID != "source-1" || sharedField.Origin.Locations[0].Line != 2 {
t.Fatalf("authored leaf origin = %#v, %v", sharedField, ok)
}
peerField, ok := metadata.Lookup(Keys("catalog", "section", "peer"))
if !ok || len(peerField.Origin.Locations) != 1 || peerField.Origin.Locations[0].SourceID != "source-2" {
t.Fatalf("peer leaf origin = %#v, %v", peerField, ok)
}
if _, ok := metadata.Lookup(Keys("catalog", "section", "branch", "child")); ok {
t.Fatal("replaced descendant remains effective")
}
removed := metadata.History(Keys("catalog", "section", "branch", "child"))
if len(removed) < 2 || removed[0].Origin.Locations[0].SourceID != "source-1" {
t.Fatalf("removed descendant history = %#v", removed)
}
backup, ok := metadata.Lookup(Keys("backup", "section", "shared"))
if !ok || len(backup.Origin.Locations) != 1 || backup.Origin.Locations[0].SourceID != "source-3" {
t.Fatalf("second-tier leaf origin = %#v, %v", backup, ok)
}
sources := result.Sources()
if len(sources) != 4 || sources[0].Path != sources[2].Path || sources[0].Destination.String() != "/catalog" || sources[2].Destination.String() != "/backup" {
t.Fatalf("same source in separate tiers = %#v", sources)
}
if sources[0].Layer != LayerUnderlay || sources[0].UnderlayIndex != 1 || sources[2].Layer != LayerUnderlay || sources[2].UnderlayIndex != 2 {
t.Fatalf("tier source records = %#v", sources)
}
other, err := load()
if err != nil {
t.Fatalf("independent load: %v", err)
}
differences, err := Diff(loaded.Inspection, other.Inspection)
if err != nil || len(differences) != 0 {
t.Fatalf("equivalent inspection diff = %#v, %v", differences, err)
}
sources[0].Destination.segments[0].key = "mutated"
sharedField.Origin.Locations[0].SourceID = "mutated"
removed[0].Path.segments[0].key = "mutated"
if got := result.Sources()[0].Destination.String(); got != "/catalog" {
t.Fatalf("source record copy changed after inspection: %q", got)
}
fresh, ok := result.Metadata().Lookup(Keys("catalog", "section", "shared"))
if !ok || fresh.Origin.Locations[0].SourceID != "source-1" {
t.Fatalf("effective origin changed after mutating returned records: %#v, %v", fresh, ok)
}
if got := result.Metadata().History(Keys("catalog", "section", "branch", "child")); len(got) < 2 || got[0].Path.String() != "/catalog/section/branch/child" {
t.Fatalf("historical path changed after mutating returned records: %#v", got)
}
if got := other.Inspection.sources[0].Destination.String(); got != "/catalog" {
t.Fatalf("independent load destination changed: %q", got)
}
}
func TestLayeredImportedInheritedValuesRetainResourceContexts(t *testing.T) {
t.Parallel()
type entry struct {
Extends string `yaml:"extends"`
Resource string `yaml:"resource"`
Count int `yaml:"count"`
}
type config struct {
Catalog struct {
Entries map[string]entry `yaml:"entries"`
} `yaml:"catalog"`
}
directory := t.TempDir()
mainPath := writeImportFile(t, directory, "config/main.yml", "child:\n extends: parent\n")
inputPath := writeImportFile(t, directory, "shared/input.yml", "configkit: {imports: [{path: parent.yml}]}\n")
writeImportFile(t, directory, "shared/parent.yml", "parent:\n resource: icon.txt\n count: 1\n")
writeImportFile(t, directory, "shared/icon.txt", "parent-resource")
var resolutionContext ResourceContext
loaded, err := LoadLayered(
Input{Source: File(mainPath), Destination: Keys("catalog", "entries")},
testSecretBinding(),
LayeredOptions[config]{
Underlays: []Underlay{{Inputs: []Input{{
Source: File(inputPath), Imports: true, Destination: Keys("catalog", "entries"),
}}}},
Definition: Definition[config]{Resolve: func(configuration *config, resolution *Resolution) error {
info, ok := resolution.InputInfo(Keys("catalog", "entries", "child", "resource"))
if !ok || len(info.Origin.Locations) != 1 || len(info.Origin.Inheritance) != 1 {
return errors.New("inherited resource lacks its source origin")
}
var found bool
resolutionContext, found = resolution.state.input.sourceContext(info.Origin.Locations[0].SourceID)
if !found || resolutionContext.BaseDir != "." || resolutionContext.FS == nil {
return errors.New("resolver could not find the declaring resource context")
}
data, err := fs.ReadFile(resolutionContext.FS, path.Join(resolutionContext.BaseDir, configuration.Catalog.Entries["child"].Resource))
if err != nil || string(data) != "parent-resource" {
return errors.New("resolver could not read the inherited relative resource")
}
return nil
}},
},
)
if err != nil {
t.Fatalf("LoadLayered: %v, diagnostics %#v", err, err.(*LoadError).Diagnostics())
}
result := testLoaded(loaded)
child := result.Config.Catalog.Entries["child"]
if child.Resource != "icon.txt" || child.Count != 1 || child.Extends != "" {
t.Fatalf("inherited child = %#v", child)
}
field, ok := result.Metadata().Lookup(Keys("catalog", "entries", "child", "resource"))
if !ok || len(field.Origin.Locations) != 1 || len(field.Origin.Inheritance) != 1 {
t.Fatalf("inherited resource origin = %#v, %v", field, ok)
}
context, ok := result.Inspection.SourceContext(field.Origin.Locations[0].SourceID)
if !ok || context.BaseDir != "." || context.FS == nil || resolutionContext.BaseDir != context.BaseDir {
t.Fatalf("completed resource contexts = %#v, %#v, %v", resolutionContext, context, ok)
}
data, err := fs.ReadFile(context.FS, path.Join(context.BaseDir, child.Resource))
if err != nil || string(data) != "parent-resource" {
t.Fatalf("completed source-relative resource = %q, %v", data, err)
}
if !reflect.DeepEqual(result.Config.Catalog.Entries["parent"], entry{Resource: "icon.txt", Count: 1}) {
t.Fatalf("surviving lower-tier parent = %#v", result.Config.Catalog.Entries["parent"])
}
for _, source := range result.Sources() {
if source.Layer == LayerUnderlay && source.Destination.String() != "/catalog/entries" {
t.Errorf("underlay destination = %#v", source)
}
}
}