209 lines
7.3 KiB
Go
209 lines
7.3 KiB
Go
package engine
|
|
|
|
import (
|
|
"path/filepath"
|
|
"testing"
|
|
"testing/fstest"
|
|
)
|
|
|
|
type importDestinationConfig struct {
|
|
Mounted map[string]string `yaml:"mounted"`
|
|
Collections map[string]map[string]string `yaml:"collections"`
|
|
}
|
|
|
|
func TestLayeredHostImportsInheritInputDestinationTransitively(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
directory := t.TempDir()
|
|
mainPath := writeImportFile(t, directory, "main.yml", `configkit:
|
|
imports:
|
|
- path: first.yml
|
|
- path: second.yml
|
|
root: main
|
|
`)
|
|
firstPath := writeImportFile(t, directory, "first.yml", `configkit:
|
|
imports:
|
|
- path: nested/third.yml
|
|
first: one
|
|
`)
|
|
thirdPath := writeImportFile(t, directory, "nested/third.yml", "nested: three\n")
|
|
secondPath := writeImportFile(t, directory, "second.yml", "second: two\n")
|
|
|
|
loaded, err := LoadLayered(
|
|
Input{Source: File(mainPath), Imports: true, Destination: Keys("mounted")},
|
|
testSecretBinding(),
|
|
LayeredOptions[importDestinationConfig]{},
|
|
)
|
|
if err != nil {
|
|
if loadError, ok := err.(*LoadError); ok {
|
|
t.Fatalf("LoadLayered diagnostics: %#v", loadError.Diagnostics())
|
|
}
|
|
t.Fatalf("LoadLayered: %v", err)
|
|
}
|
|
result := testLoaded(loaded)
|
|
want := map[string]string{"root": "main", "first": "one", "nested": "three", "second": "two"}
|
|
if len(result.Config.Mounted) != len(want) {
|
|
t.Fatalf("mounted values = %#v", result.Config.Mounted)
|
|
}
|
|
for key, value := range want {
|
|
if result.Config.Mounted[key] != value {
|
|
t.Errorf("mounted[%q] = %q, want %q", key, result.Config.Mounted[key], value)
|
|
}
|
|
}
|
|
if _, ok := result.Metadata().Lookup(Keys("mounted", "configkit")); ok {
|
|
t.Fatal("source-root import directive leaked into application content")
|
|
}
|
|
sources := result.Sources()
|
|
wantPaths := []string{canonicalTestPath(t, mainPath), canonicalTestPath(t, firstPath), canonicalTestPath(t, thirdPath), canonicalTestPath(t, secondPath)}
|
|
if len(sources) != len(wantPaths) {
|
|
t.Fatalf("sources = %#v", sources)
|
|
}
|
|
for index, source := range sources {
|
|
if source.Destination.String() != "/mounted" {
|
|
t.Errorf("source %d destination = %q", index, source.Destination.String())
|
|
}
|
|
if source.Path != wantPaths[index] {
|
|
t.Errorf("source %d path = %q, want %q", index, source.Path, wantPaths[index])
|
|
}
|
|
if index > 0 && source.ImportedFrom == nil {
|
|
t.Errorf("imported source %d has no physical import location", index)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestLayeredNativeFilesystemImportsInheritInputDestination(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
native := fstest.MapFS{
|
|
"main.yml": &fstest.MapFile{Data: []byte("configkit:\n imports:\n - path: first.yml\nroot: main\n")},
|
|
"first.yml": &fstest.MapFile{Data: []byte("configkit: {imports: [{path: nested.yml}]}\nfirst: imported\n")},
|
|
"nested.yml": &fstest.MapFile{Data: []byte("nested: imported\n")},
|
|
}
|
|
namespace := newNativeNamespace("bundle", native)
|
|
loaded, err := LoadLayered(
|
|
Input{Source: filesystemFile(namespace, "main.yml"), Imports: true, Destination: Keys("mounted")},
|
|
testSecretBinding(),
|
|
LayeredOptions[importDestinationConfig]{},
|
|
)
|
|
if err != nil {
|
|
if loadError, ok := err.(*LoadError); ok {
|
|
t.Fatalf("LoadLayered diagnostics: %#v", loadError.Diagnostics())
|
|
}
|
|
t.Fatalf("LoadLayered: %v", err)
|
|
}
|
|
result := testLoaded(loaded)
|
|
if result.Config.Mounted["root"] != "main" || result.Config.Mounted["first"] != "imported" || result.Config.Mounted["nested"] != "imported" {
|
|
t.Fatalf("mounted native filesystem values = %#v", result.Config.Mounted)
|
|
}
|
|
sources := result.Sources()
|
|
if len(sources) != 3 || sources[0].Destination.String() != "/mounted" || sources[1].Destination.String() != "/mounted" || sources[2].Destination.String() != "/mounted" {
|
|
t.Fatalf("native source destinations = %#v", sources)
|
|
}
|
|
}
|
|
|
|
func TestLayeredImportOnlyInputMaterializesDestination(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
directory := t.TempDir()
|
|
mainPath := writeImportFile(t, directory, "main.yml", `configkit:
|
|
imports:
|
|
- path: optional.yml
|
|
optional: true
|
|
`)
|
|
loaded, err := LoadLayered(
|
|
Input{Source: File(mainPath), Imports: true, Destination: Keys("collections", "empty")},
|
|
testSecretBinding(),
|
|
LayeredOptions[importDestinationConfig]{},
|
|
)
|
|
if err != nil {
|
|
t.Fatalf("LoadLayered: %v", err)
|
|
}
|
|
result := testLoaded(loaded)
|
|
info, ok := result.Metadata().Lookup(Keys("collections", "empty"))
|
|
if !ok || !info.Explicit {
|
|
t.Fatalf("import-only body destination = %#v, %v", info, ok)
|
|
}
|
|
sources := result.Sources()
|
|
if len(sources) != 1 || sources[0].Destination.String() != "/collections/empty" {
|
|
t.Fatalf("sources = %#v", sources)
|
|
}
|
|
}
|
|
|
|
func TestLayeredImportedVersionClaimsUseEffectiveDestination(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
for _, test := range []struct {
|
|
name string
|
|
rulePath Path
|
|
destination Path
|
|
wantCode Code
|
|
}{
|
|
{name: "protected effective path", rulePath: Keys("mounted", "version"), destination: Keys("mounted"), wantCode: CodeImportVersion},
|
|
{name: "ordinary nested domain version", rulePath: Keys("version"), destination: Keys("collections", "entry")},
|
|
} {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
directory := t.TempDir()
|
|
writeImportFile(t, directory, "main.yml", "configkit: {imports: [{path: fragment.yml}]}\n")
|
|
writeImportFile(t, directory, "fragment.yml", "version: v2\n")
|
|
rule := &VersionRule{Path: test.rulePath, Check: func(Version, *Validation) error { return nil }}
|
|
loaded, err := LoadLayered(
|
|
Input{Source: NoSource()},
|
|
testSecretBinding(),
|
|
LayeredOptions[importDestinationConfig]{
|
|
Definition: Definition[importDestinationConfig]{Version: rule},
|
|
Underlays: []Underlay{{Inputs: []Input{{
|
|
Source: File(filepath.Join(directory, "main.yml")), Imports: true, Destination: test.destination,
|
|
}}}},
|
|
},
|
|
)
|
|
if test.wantCode != "" {
|
|
if err == nil {
|
|
t.Fatal("protected imported version claim was accepted")
|
|
}
|
|
loadError, ok := err.(*LoadError)
|
|
if !ok || len(loadError.Diagnostics()) == 0 || loadError.Diagnostics()[0].Code != test.wantCode {
|
|
t.Fatalf("load error = %#v", err)
|
|
}
|
|
if test.name == "protected effective path" {
|
|
sources := loadError.Sources()
|
|
if len(sources) != 2 || sources[0].Destination.String() != "/mounted" || sources[1].Destination.String() != "/mounted" {
|
|
t.Fatalf("error source destinations = %#v", sources)
|
|
}
|
|
}
|
|
return
|
|
}
|
|
if err != nil {
|
|
t.Fatalf("ordinary nested version was rejected: %v", err)
|
|
}
|
|
result := testLoaded(loaded)
|
|
if got := result.Config.Collections["entry"]["version"]; got != "v2" {
|
|
t.Fatalf("nested version = %q", got)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestLayeredDestinationsDoNotChangeRepeatedSourceIdentity(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
directory := t.TempDir()
|
|
writeImportFile(t, directory, "shared.yml", "value: shared\n")
|
|
importerPath := writeImportFile(t, directory, "importer.yml", "configkit: {imports: [{path: shared.yml}]}\n")
|
|
_, err := LoadLayered(
|
|
Input{Source: NoSource()},
|
|
testSecretBinding(),
|
|
LayeredOptions[importDestinationConfig]{Underlays: []Underlay{{Inputs: []Input{
|
|
{Source: File(importerPath), Imports: true, Destination: Keys("imported")},
|
|
{Source: File(filepath.Join(directory, "shared.yml")), Destination: Keys("direct")},
|
|
}}}},
|
|
)
|
|
if err == nil {
|
|
t.Fatal("the same physical source was accepted at two destinations in one group")
|
|
}
|
|
loadError, ok := err.(*LoadError)
|
|
if !ok || len(loadError.Diagnostics()) == 0 || loadError.Diagnostics()[0].Code != CodeImportRepeated {
|
|
t.Fatalf("load error = %#v", err)
|
|
}
|
|
}
|