107 lines
3.6 KiB
Go
107 lines
3.6 KiB
Go
package engine
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"testing"
|
|
"testing/fstest"
|
|
)
|
|
|
|
func TestNestedCollectionInitializationIsIndependentOfAncestorPresence(t *testing.T) {
|
|
t.Parallel()
|
|
for _, ancestor := range []string{"{}", "group: {}", "group: null"} {
|
|
for _, test := range []struct {
|
|
mode, key, value string
|
|
valid bool
|
|
}{
|
|
{mode: "append", value: "[{id: a}]"},
|
|
{mode: "upsert", value: "[{id: a}]"},
|
|
{mode: "append", value: "[]"},
|
|
{mode: "upsert", value: "[]"},
|
|
{mode: "append", key: ", key: id", value: "{}"},
|
|
{mode: "upsert", key: ", key: id", value: "null"},
|
|
{mode: "append", key: ", key: id", value: "[{id: a}]", valid: true},
|
|
{mode: "upsert", key: ", key: id", value: "[]", valid: true},
|
|
} {
|
|
t.Run(fmt.Sprintf("%s/%s/%s/%s", ancestor, test.mode, test.key, test.value), func(t *testing.T) {
|
|
main := "configkit:\n sequences: [{destination: [group, items], mode: " + test.mode + test.key + "}]\ngroup: {items: " + test.value + "}\n"
|
|
loaded, err := testGroupedLoad(loadRequest[map[string]any]{
|
|
main: loadInput{source: Bytes("main", []byte(main))},
|
|
underlays: []loadGroup{{inputs: []loadInput{{source: Bytes("lower", []byte(ancestor))}}}},
|
|
})
|
|
if test.valid {
|
|
if err != nil || loaded == nil {
|
|
t.Fatalf("valid initialization failed: %v", err)
|
|
}
|
|
return
|
|
}
|
|
var loadErr *LoadError
|
|
if !errors.As(err, &loadErr) || loaded != nil {
|
|
t.Fatalf("invalid collection operation succeeded: %#v, %v", loaded, err)
|
|
}
|
|
diagnostics := loadErr.Diagnostics()
|
|
if len(diagnostics) != 1 || diagnostics[0].Code != CodeSequenceInvalid || diagnostics[0].Path.String() != "/group/items" {
|
|
t.Fatalf("operation diagnostics = %#v", diagnostics)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestAddedAncestorTransfersNestedRecordPolicies(t *testing.T) {
|
|
t.Parallel()
|
|
type record struct {
|
|
ID string `yaml:"id"`
|
|
Steps []map[string]any `yaml:"steps"`
|
|
}
|
|
type config struct {
|
|
Group struct {
|
|
Items []record `yaml:"items"`
|
|
} `yaml:"group"`
|
|
}
|
|
files := fstest.MapFS{
|
|
"main.yml": {Data: []byte(`configkit:
|
|
sequences: [{destination: [group, items], key: id}]
|
|
imports: [{path: base.yml, destination: [group, items], placement: sequence-item}]
|
|
group:
|
|
items: [{id: child, extends: {id: base}, steps: [{name: child}]}]
|
|
`)},
|
|
"base.yml": {Data: []byte("configkit:\n sequences: [{destination: [steps], key: name}]\nid: base\nsteps: [{name: base}]\n")},
|
|
}
|
|
loaded, err := testGroupedLoad(loadRequest[config]{
|
|
main: loadInput{source: NewFilesystem("catalog", files).File("main.yml"), imports: true},
|
|
underlays: []loadGroup{{inputs: []loadInput{{source: Bytes("lower", []byte("{}"))}}}},
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, item := range loaded.Config.Group.Items {
|
|
if item.ID == "child" {
|
|
if len(item.Steps) != 2 || item.Steps[0]["name"] != "base" || item.Steps[1]["name"] != "child" {
|
|
t.Fatalf("record-local identity was lost when adding its ancestor: %#v", item.Steps)
|
|
}
|
|
return
|
|
}
|
|
}
|
|
t.Fatal("missing child record")
|
|
}
|
|
|
|
func TestInheritanceChecksCollectionOperationUnderAddedAncestor(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := testLoad[map[string]any](Bytes("inheritance", []byte(`configkit:
|
|
sequences: [{destination: [child, group, items], mode: append}]
|
|
base: {}
|
|
child:
|
|
extends: base
|
|
group: {items: [{id: a}]}
|
|
`)))
|
|
var loadErr *LoadError
|
|
if !errors.As(err, &loadErr) {
|
|
t.Fatalf("missing nested operation error: %v", err)
|
|
}
|
|
diagnostics := loadErr.Diagnostics()
|
|
if len(diagnostics) != 1 || diagnostics[0].Code != CodeSequenceInvalid || diagnostics[0].Path.String() != "/child/group/items" {
|
|
t.Fatalf("nested inheritance operation diagnostics = %#v", diagnostics)
|
|
}
|
|
}
|