Migrate acquisition fixtures to document-root controls
This commit is contained in:
@@ -171,6 +171,8 @@ affected fixtures have been migrated.
|
||||
|
||||
## Stage 5 — Migrate engine source and acquisition fixtures
|
||||
|
||||
**Status:** Complete. Focused acquisition, import, destination, and source tests pass; structural fixtures remain for the next stage.
|
||||
|
||||
**Scope:** remaining engine source/discovery/import/placement/resource-context
|
||||
tests and acquisition-related benchmarks, excluding structural/history fixtures
|
||||
assigned to Stage 6.
|
||||
|
||||
@@ -72,7 +72,7 @@ func TestNestedItemGlobsShareUnderlayNodeBudget(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
directory := t.TempDir()
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `configkit:
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `config:
|
||||
imports:
|
||||
- glob: children/*.yml
|
||||
destination: [children]
|
||||
@@ -132,7 +132,7 @@ func TestImportedEmptyBodiesChargeEachDestinationWrapper(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
filesystem := NewFilesystem("bundle", fstest.MapFS{
|
||||
"main.yml": &fstest.MapFile{Data: []byte("configkit: {imports: [{path: fragment.yml}]}\n")},
|
||||
"main.yml": &fstest.MapFile{Data: []byte("config: {imports: [{path: fragment.yml}]}\n")},
|
||||
"fragment.yml": &fstest.MapFile{Data: []byte("{}\n")},
|
||||
})
|
||||
mainSource := filesystem.File("main.yml")
|
||||
@@ -186,7 +186,7 @@ func TestImportedEmptyBodiesChargeFullRelativeDestinations(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
directory := t.TempDir()
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `configkit:
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `config:
|
||||
imports:
|
||||
- path: empty.yml
|
||||
destination: [groups, empty]
|
||||
@@ -248,7 +248,7 @@ func TestGlobMatchesChargeTheirSharedRelativeDestination(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
directory := t.TempDir()
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `configkit:
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `config:
|
||||
imports:
|
||||
- glob: fragments/*.yml
|
||||
destination: [groups, empty]
|
||||
@@ -316,7 +316,7 @@ func TestRelativeImportDestinationUsesAccumulatedDocumentDepth(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
directory := t.TempDir()
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "configkit: {imports: [{path: fragment.yml, destination: [extra]}]}\n")
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "config: {imports: [{path: fragment.yml, destination: [extra]}]}\n")
|
||||
writeImportFile(t, directory, "fragment.yml", "value: nested\n")
|
||||
destination := Path{segments: make([]pathSegment, maxDocumentDepth)}
|
||||
for index := range destination.segments {
|
||||
@@ -351,11 +351,11 @@ func TestAbsentOptionalImportsDoNotChargeUnusedDeepDestinations(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
name: "optional missing path",
|
||||
body: "configkit: {imports: [{path: missing.yml, destination: [unused]}]}\n",
|
||||
body: "config: {imports: [{path: missing.yml, destination: [unused]}]}\n",
|
||||
},
|
||||
{
|
||||
name: "optional unmatched glob",
|
||||
body: "configkit: {imports: [{glob: empty/*.yml, destination: [unused]}]}\n",
|
||||
body: "config: {imports: [{glob: empty/*.yml, destination: [unused]}]}\n",
|
||||
setup: func(t *testing.T, directory string) {
|
||||
if err := os.Mkdir(filepath.Join(directory, "empty"), 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
|
||||
@@ -64,7 +64,7 @@ func TestLayeredDestinationDiagnosticsUseEffectivePathsAndAuthoredLocations(t *t
|
||||
t.Run("imported version failure uses effective path and import source", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
directory := t.TempDir()
|
||||
writeImportFile(t, directory, "main.yml", "configkit: {imports: [{path: fragment.yml}]}\n")
|
||||
writeImportFile(t, directory, "main.yml", "config: {imports: [{path: fragment.yml}]}\n")
|
||||
writeImportFile(t, directory, "fragment.yml", "version: forbidden\n")
|
||||
rule := &VersionRule{Path: Keys("application", "version"), Check: func(Version, *Validation) error { return nil }}
|
||||
loaded, err := LoadLayered(
|
||||
@@ -108,7 +108,7 @@ func TestLayeredDestinationDiagnosticsUseEffectivePathsAndAuthoredLocations(t *t
|
||||
t.Run("malformed source directive keeps its local path and location", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
filesystem := NewFilesystem("bundle", fstest.MapFS{
|
||||
"main.yml": &fstest.MapFile{Data: []byte("configkit: {imports: [true]}\nvalue: present\n")},
|
||||
"main.yml": &fstest.MapFile{Data: []byte("config: {imports: [true]}\nvalue: present\n")},
|
||||
})
|
||||
loaded, err := LoadLayered(
|
||||
Input{Source: filesystem.File("main.yml"), Imports: true, Destination: Keys("application")},
|
||||
@@ -119,7 +119,7 @@ func TestLayeredDestinationDiagnosticsUseEffectivePathsAndAuthoredLocations(t *t
|
||||
t.Fatalf("malformed directive returned a result: %#v", loaded)
|
||||
}
|
||||
diagnostic := firstDestinationDiagnostic(t, err)
|
||||
if diagnostic.Code != CodeImportInvalid || diagnostic.Path.String() != "/configkit/imports/0" {
|
||||
if diagnostic.Code != CodeImportInvalid || diagnostic.Path.String() != "/config/imports/0" {
|
||||
t.Fatalf("malformed directive diagnostic = %#v", diagnostic)
|
||||
}
|
||||
if diagnostic.Primary == nil || diagnostic.Primary.SourceID != "source-1" || diagnostic.Primary.Line != 1 {
|
||||
|
||||
@@ -28,7 +28,7 @@ func TestRelativeImportsFeedFinalInheritanceAndInspectionLifecycle(t *testing.T)
|
||||
load := func(dynamic string) *testResult[configuration] {
|
||||
t.Helper()
|
||||
directory := t.TempDir()
|
||||
mainPath := writeImportFile(t, directory, "entry.yml", `configkit:
|
||||
mainPath := writeImportFile(t, directory, "entry.yml", `config:
|
||||
imports:
|
||||
- path: parent.yml
|
||||
destination: [entries]
|
||||
@@ -166,7 +166,7 @@ func TestRelativeImportMatchesWrappedPlacementAndSafeDiff(t *testing.T) {
|
||||
options := LayeredOptions[map[string]any]{}
|
||||
if relativeImport {
|
||||
directory := t.TempDir()
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `configkit:
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `config:
|
||||
imports:
|
||||
- path: fragment.yml
|
||||
destination: [application]
|
||||
|
||||
@@ -13,17 +13,52 @@ type importDestinationConfig struct {
|
||||
Collections map[string]map[string]string `yaml:"collections"`
|
||||
}
|
||||
|
||||
func TestImportsKeepDocumentControlsBeforePlacement(t *testing.T) {
|
||||
directory := t.TempDir()
|
||||
main := writeImportFile(t, directory, "main.yml", "config: {imports: [{path: parent.yml, destination: [config]}]}\n")
|
||||
parent := writeImportFile(t, directory, "parent.yml", "config: {imports: [{path: leaf.yml, destination: [config]}]}\nimports: ordinary\n")
|
||||
leaf := writeImportFile(t, directory, "leaf.yml", "sequences: ordinary\n")
|
||||
loaded, err := LoadLayered(Input{Source: File(main), Imports: true}, testSecretBinding(), LayeredOptions[map[string]any]{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
root := loaded.Config["config"].(map[string]any)
|
||||
if root["imports"] != "ordinary" || root["config"].(map[string]any)["sequences"] != "ordinary" {
|
||||
t.Fatalf("assembled configuration = %#v", loaded.Config)
|
||||
}
|
||||
sources := testLoaded(loaded).Sources()
|
||||
if len(sources) != 3 || sources[1].Path != canonicalTestPath(t, parent) || sources[1].Destination.String() != "/config" || sources[2].Path != canonicalTestPath(t, leaf) || sources[2].Destination.String() != "/config/config" || sources[2].ImportedFrom == nil {
|
||||
t.Fatalf("sources = %#v", sources)
|
||||
}
|
||||
if info, ok := testLoaded(loaded).Metadata().Lookup(Keys("config", "config", "sequences")); !ok || len(info.Origin.Locations) == 0 || info.Origin.Locations[0].SourceID != sources[2].ID {
|
||||
t.Fatalf("leaf attribution = %#v, %t", info, ok)
|
||||
}
|
||||
}
|
||||
|
||||
func TestImportsLeaveNestedConfigDataUntouched(t *testing.T) {
|
||||
directory := t.TempDir()
|
||||
main := writeImportFile(t, directory, "main.yml", "nested: {config: {imports: ordinary}}\n")
|
||||
loaded, err := LoadLayered(Input{Source: File(main), Imports: true}, testSecretBinding(), LayeredOptions[map[string]any]{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
nested := loaded.Config["nested"].(map[string]any)["config"].(map[string]any)
|
||||
if nested["imports"] != "ordinary" {
|
||||
t.Fatalf("nested data = %#v", nested)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLayeredHostImportsInheritInputDestinationTransitively(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
directory := t.TempDir()
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `configkit:
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `config:
|
||||
imports:
|
||||
- path: first.yml
|
||||
- path: second.yml
|
||||
root: main
|
||||
`)
|
||||
firstPath := writeImportFile(t, directory, "first.yml", `configkit:
|
||||
firstPath := writeImportFile(t, directory, "first.yml", `config:
|
||||
imports:
|
||||
- path: nested/third.yml
|
||||
first: one
|
||||
@@ -52,7 +87,7 @@ first: one
|
||||
t.Errorf("mounted[%q] = %q, want %q", key, result.Config.Mounted[key], value)
|
||||
}
|
||||
}
|
||||
if _, ok := result.Metadata().Lookup(Keys("mounted", "configkit")); ok {
|
||||
if _, ok := result.Metadata().Lookup(Keys("mounted", "config")); ok {
|
||||
t.Fatal("source-root import directive leaked into application content")
|
||||
}
|
||||
sources := result.Sources()
|
||||
@@ -77,13 +112,13 @@ func TestImportTraversalUsesPerDeclarationDestinations(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
directory := t.TempDir()
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `configkit:
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `config:
|
||||
imports:
|
||||
- path: parent.yml
|
||||
- path: sibling.yml
|
||||
- glob: fragments/*.yml
|
||||
`)
|
||||
parentPath := writeImportFile(t, directory, "parent.yml", `configkit:
|
||||
parentPath := writeImportFile(t, directory, "parent.yml", `config:
|
||||
imports:
|
||||
- path: nested/child.yml
|
||||
parent: true
|
||||
@@ -163,7 +198,7 @@ func TestEntryDestinationSurvivesImportSetupAndParseFailures(t *testing.T) {
|
||||
|
||||
t.Run("import context failure", func(t *testing.T) {
|
||||
directory := t.TempDir()
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "configkit: {imports: [{path: child.yml}]}\n")
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "config: {imports: [{path: child.yml}]}\n")
|
||||
input, diagnostics := testAcquireInput(inputAcquisitionRequest{
|
||||
input: loadInput{source: File(mainPath), imports: true, filesystem: &FilesystemContext{Root: t.TempDir()}, destination: Keys("mounted")},
|
||||
role: sourceVersionMain, directiveContext: rootDirectiveContextImportsOnly,
|
||||
@@ -178,7 +213,7 @@ func TestEntryDestinationSurvivesImportSetupAndParseFailures(t *testing.T) {
|
||||
|
||||
t.Run("imported parse failure", func(t *testing.T) {
|
||||
directory := t.TempDir()
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "configkit: {imports: [{path: broken.yml}]}\n")
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "config: {imports: [{path: broken.yml}]}\n")
|
||||
writeImportFile(t, directory, "broken.yml", "broken: [\n")
|
||||
input, diagnostics := testAcquireInput(inputAcquisitionRequest{
|
||||
input: loadInput{source: File(mainPath), imports: true, destination: Keys("mounted")},
|
||||
@@ -211,39 +246,39 @@ func TestRelativeImportDestinationsKeepStrictCompositionBoundaries(t *testing.T)
|
||||
}{
|
||||
{
|
||||
name: "disjoint peers at one destination",
|
||||
main: "configkit:\n imports:\n - path: left.yml\n destination: [application]\n - path: right.yml\n destination: [application]\n",
|
||||
main: "config:\n imports:\n - path: left.yml\n destination: [application]\n - path: right.yml\n destination: [application]\n",
|
||||
files: map[string]string{"left.yml": "left: one\n", "right.yml": "right: two\n"},
|
||||
want: map[string]any{"/application/left": "one", "/application/right": "two"},
|
||||
},
|
||||
{
|
||||
name: "different destinations",
|
||||
main: "configkit:\n imports:\n - path: left.yml\n destination: [left]\n - path: right.yml\n destination: [right]\n",
|
||||
main: "config:\n imports:\n - path: left.yml\n destination: [left]\n - path: right.yml\n destination: [right]\n",
|
||||
files: map[string]string{"left.yml": "value: shared\n", "right.yml": "value: shared\n"},
|
||||
want: map[string]any{"/left/value": "shared", "/right/value": "shared"},
|
||||
},
|
||||
{
|
||||
name: "ancestor and descendant overlap",
|
||||
main: "configkit:\n imports:\n - path: parent.yml\n destination: [application]\n - path: child.yml\n destination: [application, branch]\n",
|
||||
main: "config:\n imports:\n - path: parent.yml\n destination: [application]\n - path: child.yml\n destination: [application, branch]\n",
|
||||
files: map[string]string{"parent.yml": "branch: {base: one}\n", "child.yml": "leaf: two\n"},
|
||||
want: map[string]any{"/application/branch/base": "one", "/application/branch/leaf": "two"},
|
||||
},
|
||||
{
|
||||
name: "collision with explicitly wrapped content",
|
||||
main: "configkit: {imports: [{path: fragment.yml, destination: [application]}]}\napplication: {value: root}\n",
|
||||
main: "config: {imports: [{path: fragment.yml, destination: [application]}]}\napplication: {value: root}\n",
|
||||
files: map[string]string{"fragment.yml": "value: imported\n"},
|
||||
conflict: true,
|
||||
wantPath: "/application/value",
|
||||
},
|
||||
{
|
||||
name: "equal peer values conflict",
|
||||
main: "configkit:\n imports:\n - path: left.yml\n destination: [application]\n - path: right.yml\n destination: [application]\n",
|
||||
main: "config:\n imports:\n - path: left.yml\n destination: [application]\n - path: right.yml\n destination: [application]\n",
|
||||
files: map[string]string{"left.yml": "value: same\n", "right.yml": "value: same\n"},
|
||||
conflict: true,
|
||||
wantPath: "/application/value",
|
||||
},
|
||||
{
|
||||
name: "unequal peer values conflict",
|
||||
main: "configkit:\n imports:\n - path: left.yml\n destination: [application]\n - path: right.yml\n destination: [application]\n",
|
||||
main: "config:\n imports:\n - path: left.yml\n destination: [application]\n - path: right.yml\n destination: [application]\n",
|
||||
files: map[string]string{"left.yml": "value: left\n", "right.yml": "value: right\n"},
|
||||
conflict: true,
|
||||
wantPath: "/application/value",
|
||||
@@ -291,7 +326,7 @@ func TestRelativeImportDestinationsKeepStrictCompositionBoundaries(t *testing.T)
|
||||
|
||||
t.Run("upper tier cannot repair a lower import conflict", func(t *testing.T) {
|
||||
directory := t.TempDir()
|
||||
lowerPath := writeImportFile(t, directory, "lower.yml", `configkit:
|
||||
lowerPath := writeImportFile(t, directory, "lower.yml", `config:
|
||||
imports:
|
||||
- path: left.yml
|
||||
destination: [application]
|
||||
@@ -324,12 +359,12 @@ func TestRelativeImportDestinationsUseEffectiveVersionOwnership(t *testing.T) {
|
||||
} {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
directory := t.TempDir()
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `configkit:
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `config:
|
||||
imports:
|
||||
- path: parent.yml
|
||||
destination: [group]
|
||||
`)
|
||||
writeImportFile(t, directory, "parent.yml", `configkit:
|
||||
writeImportFile(t, directory, "parent.yml", `config:
|
||||
imports:
|
||||
- path: fragment.yml
|
||||
destination: [nested]
|
||||
@@ -374,13 +409,13 @@ func TestRelativeImportDestinationsKeepMainVersionCheckScoped(t *testing.T) {
|
||||
} `yaml:"collection"`
|
||||
}
|
||||
directory := t.TempDir()
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `configkit:
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `config:
|
||||
imports:
|
||||
- path: parent.yml
|
||||
destination: [group]
|
||||
schema_version: 6
|
||||
`)
|
||||
writeImportFile(t, directory, "parent.yml", `configkit:
|
||||
writeImportFile(t, directory, "parent.yml", `config:
|
||||
imports:
|
||||
- path: fragment.yml
|
||||
destination: [nested]
|
||||
@@ -421,8 +456,8 @@ 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")},
|
||||
"main.yml": &fstest.MapFile{Data: []byte("config:\n imports:\n - path: first.yml\nroot: main\n")},
|
||||
"first.yml": &fstest.MapFile{Data: []byte("config: {imports: [{path: nested.yml}]}\nfirst: imported\n")},
|
||||
"nested.yml": &fstest.MapFile{Data: []byte("nested: imported\n")},
|
||||
}
|
||||
namespace := newNativeNamespace("bundle", native)
|
||||
@@ -451,7 +486,7 @@ func TestLayeredImportOnlyInputMaterializesDestination(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
directory := t.TempDir()
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `configkit:
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `config:
|
||||
imports:
|
||||
- path: optional.yml
|
||||
`)
|
||||
@@ -489,7 +524,7 @@ func TestLayeredImportedVersionClaimsUseEffectiveDestination(t *testing.T) {
|
||||
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, "main.yml", "config: {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(
|
||||
@@ -534,7 +569,7 @@ func TestLayeredDestinationsDoNotChangeRepeatedSourceIdentity(t *testing.T) {
|
||||
|
||||
directory := t.TempDir()
|
||||
writeImportFile(t, directory, "shared.yml", "value: shared\n")
|
||||
importerPath := writeImportFile(t, directory, "importer.yml", "configkit: {imports: [{path: shared.yml, destination: [nested]}]}\n")
|
||||
importerPath := writeImportFile(t, directory, "importer.yml", "config: {imports: [{path: shared.yml, destination: [nested]}]}\n")
|
||||
_, err := LoadLayered(
|
||||
Input{Source: NoSource()},
|
||||
testSecretBinding(),
|
||||
@@ -558,8 +593,8 @@ func TestLayeredDestinationsDoNotChangeRepeatedSourceIdentity(t *testing.T) {
|
||||
t.Run("placement does not break a physical cycle", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
directory := t.TempDir()
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "configkit: {imports: [{path: parent.yml, destination: [one]}]}\n")
|
||||
writeImportFile(t, directory, "parent.yml", "configkit: {imports: [{path: main.yml, destination: [two]}]}\n")
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "config: {imports: [{path: parent.yml, destination: [one]}]}\n")
|
||||
writeImportFile(t, directory, "parent.yml", "config: {imports: [{path: main.yml, destination: [two]}]}\n")
|
||||
_, err := LoadLayered(Input{Source: File(mainPath), Imports: true}, testSecretBinding(), LayeredOptions[map[string]any]{})
|
||||
loadError, ok := err.(*LoadError)
|
||||
if !ok || len(loadError.Diagnostics()) == 0 || loadError.Diagnostics()[0].Code != CodeImportCycle {
|
||||
|
||||
@@ -121,7 +121,7 @@ func TestLayeredImportedInheritedValuesRetainResourceContexts(t *testing.T) {
|
||||
}
|
||||
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")
|
||||
inputPath := writeImportFile(t, directory, "shared/input.yml", "config: {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
|
||||
|
||||
@@ -214,7 +214,7 @@ func TestLayeredDestinationChecksVersionOnceOnComposedMain(t *testing.T) {
|
||||
App appConfig `yaml:"app"`
|
||||
}
|
||||
filesystem := NewFilesystem("bundle", fstest.MapFS{
|
||||
"main.yml": &fstest.MapFile{Data: []byte("configkit: {imports: [{path: fragment.yml}]}\nversion: 6\ncount: 4\nmain: main\n")},
|
||||
"main.yml": &fstest.MapFile{Data: []byte("config: {imports: [{path: fragment.yml}]}\nversion: 6\ncount: 4\nmain: main\n")},
|
||||
"fragment.yml": &fstest.MapFile{Data: []byte("imported: included\n")},
|
||||
})
|
||||
checks := 0
|
||||
@@ -300,7 +300,7 @@ func TestLayeredDestinationVersionClaimsUsePlacedApplicationPaths(t *testing.T)
|
||||
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, "main.yml", "config: {imports: [{path: fragment.yml}]}\n")
|
||||
writeImportFile(t, directory, "fragment.yml", test.body)
|
||||
loaded, err := LoadLayered(
|
||||
Input{Source: NoSource()},
|
||||
|
||||
@@ -21,7 +21,7 @@ func TestSearchLoadMatchesExplicitFileThroughImportsAndContext(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
root := t.TempDir()
|
||||
mainPath := writeImportFile(t, root, "app.yml", `configkit:
|
||||
mainPath := writeImportFile(t, root, "app.yml", `config:
|
||||
imports: [{path: fragments/extra.yml}]
|
||||
settings: {main: selected}
|
||||
`)
|
||||
@@ -52,7 +52,7 @@ func TestSearchLayeredMainAndUnderlayMatchExplicitFiles(t *testing.T) {
|
||||
|
||||
root := t.TempDir()
|
||||
mainPath := writeImportFile(t, root, "main.yml", "settings: {main: value}\n")
|
||||
underlayPath := writeImportFile(t, root, "underlay/base.yml", `configkit:
|
||||
underlayPath := writeImportFile(t, root, "underlay/base.yml", `config:
|
||||
imports: [{path: extra.yml}]
|
||||
settings: {underlay: value}
|
||||
`)
|
||||
|
||||
@@ -11,13 +11,13 @@ import (
|
||||
|
||||
func TestLoadGlobImportsUseLexicalDeclarationOrderAndNestedDFS(t *testing.T) {
|
||||
directory := t.TempDir()
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `configkit:
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `config:
|
||||
imports:
|
||||
- glob: fragments/*.yml
|
||||
- path: after.yml
|
||||
items: {root: root}
|
||||
`)
|
||||
aPath := writeImportFile(t, directory, "fragments/a.yml", `configkit:
|
||||
aPath := writeImportFile(t, directory, "fragments/a.yml", `config:
|
||||
imports: [{path: nested/child.yml}]
|
||||
items: {alpha: alpha}
|
||||
`)
|
||||
@@ -57,7 +57,7 @@ items: {alpha: alpha}
|
||||
|
||||
func TestLoadGlobImportsSupportEscapesClassesAndExplicitConfD(t *testing.T) {
|
||||
directory := t.TempDir()
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `configkit:
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `config:
|
||||
imports:
|
||||
- glob: 'conf.d/literal\*.yml'
|
||||
- glob: 'conf.d/item-[ab].yml'
|
||||
@@ -127,7 +127,7 @@ func TestLoadGlobImportsPreserveIdentityAndFileRules(t *testing.T) {
|
||||
t.Run("overlapping declarations", func(t *testing.T) {
|
||||
directory := t.TempDir()
|
||||
writeImportFile(t, directory, "conf/value.yml", "items: {value: value}\n")
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `configkit:
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `config:
|
||||
imports:
|
||||
- glob: conf/*.yml
|
||||
- glob: conf/value.*
|
||||
@@ -318,5 +318,5 @@ func writeGlobRoot(t *testing.T, directory, pattern string, required bool) strin
|
||||
if required {
|
||||
requiredLine = "\n required: true"
|
||||
}
|
||||
return writeImportFile(t, directory, "main.yml", "configkit:\n imports:\n - glob: '"+pattern+"'"+requiredLine+"\n")
|
||||
return writeImportFile(t, directory, "main.yml", "config:\n imports:\n - glob: '"+pattern+"'"+requiredLine+"\n")
|
||||
}
|
||||
|
||||
@@ -12,14 +12,14 @@ func TestBroadEmptyImportSelectionsKeepDeclaringSourceOwnership(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
directory := t.TempDir()
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `configkit:
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `config:
|
||||
imports:
|
||||
- glob: fragments/*.yml
|
||||
- path: []
|
||||
`)
|
||||
const fragments = 32
|
||||
for index := 0; index < fragments; index++ {
|
||||
writeImportFile(t, directory, fmt.Sprintf("fragments/fragment-%02d.yml", index), `configkit:
|
||||
writeImportFile(t, directory, fmt.Sprintf("fragments/fragment-%02d.yml", index), `config:
|
||||
imports:
|
||||
- path: missing.yml
|
||||
- path: []
|
||||
@@ -34,7 +34,7 @@ func TestBroadEmptyImportSelectionsKeepDeclaringSourceOwnership(t *testing.T) {
|
||||
t.Fatalf("source count = %d, want %d", len(sources), fragments+1)
|
||||
}
|
||||
for index, source := range sources {
|
||||
wantPaths := []string{"/configkit/imports/0", "/configkit/imports/1"}
|
||||
wantPaths := []string{"/config/imports/0", "/config/imports/1"}
|
||||
if index == 0 {
|
||||
wantPaths = wantPaths[1:]
|
||||
}
|
||||
@@ -57,7 +57,7 @@ func TestOptionalEmptyImportSelectionsRemainSourceLocalAndDetached(t *testing.T)
|
||||
Value string `yaml:"value"`
|
||||
}
|
||||
directory := t.TempDir()
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `configkit:
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `config:
|
||||
imports:
|
||||
- dir: absent
|
||||
- path: missing.yml
|
||||
@@ -82,7 +82,7 @@ func TestOptionalEmptyImportSelectionsRemainSourceLocalAndDetached(t *testing.T)
|
||||
if len(sources) != 2 {
|
||||
t.Fatalf("sources = %#v", sources)
|
||||
}
|
||||
wantPaths := []string{"/configkit/imports/0", "/configkit/imports/1", "/configkit/imports/2", "/configkit/imports/3"}
|
||||
wantPaths := []string{"/config/imports/0", "/config/imports/1", "/config/imports/2", "/config/imports/3"}
|
||||
wantSelectors := []importSelector{importSelectorDirectory, importSelectorPath, importSelectorPath, importSelectorDirectory}
|
||||
evidence := sources[0].importSelections
|
||||
if len(evidence) != len(wantPaths) {
|
||||
@@ -119,7 +119,7 @@ func TestFailedLoadRetainsOnlyCompletedEmptyImportSelections(t *testing.T) {
|
||||
Value string `yaml:"value"`
|
||||
}
|
||||
directory := t.TempDir()
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `configkit:
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `config:
|
||||
imports:
|
||||
- glob: absent/*.yml
|
||||
- path: required-missing.yml
|
||||
@@ -137,11 +137,11 @@ value: main
|
||||
t.Fatalf("failed-load sources = %#v", sources)
|
||||
}
|
||||
selection := sources[0].importSelections[0]
|
||||
if selection.path.String() != "/configkit/imports/0" || selection.location.SourceID != sources[0].ID || selection.selector != importSelectorGlob {
|
||||
if selection.path.String() != "/config/imports/0" || selection.location.SourceID != sources[0].ID || selection.selector != importSelectorGlob {
|
||||
t.Fatalf("retained selection = %#v", selection)
|
||||
}
|
||||
sources[0].importSelections[0].path.segments[0].key = "changed"
|
||||
if got := loadError.Sources()[0].importSelections[0].path.String(); got != "/configkit/imports/0" {
|
||||
if got := loadError.Sources()[0].importSelections[0].path.String(); got != "/config/imports/0" {
|
||||
t.Fatalf("mutating failed-load snapshot changed retained evidence: %q", got)
|
||||
}
|
||||
}
|
||||
@@ -160,7 +160,7 @@ func TestImportSelectionEvidenceSurvivesCompositionUnderlaysAndResolutionEntry(t
|
||||
Overlay string `yaml:"overlay"`
|
||||
}
|
||||
directory := t.TempDir()
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `configkit:
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `config:
|
||||
imports:
|
||||
- path: helper.yml
|
||||
- path: item.yml
|
||||
@@ -169,24 +169,24 @@ func TestImportSelectionEvidenceSurvivesCompositionUnderlaysAndResolutionEntry(t
|
||||
- dir: absent-main
|
||||
value: main
|
||||
`)
|
||||
helperPath := writeImportFile(t, directory, "helper.yml", `configkit:
|
||||
helperPath := writeImportFile(t, directory, "helper.yml", `config:
|
||||
imports:
|
||||
- glob: absent-helper/*.yml
|
||||
helper: value
|
||||
`)
|
||||
itemPath := writeImportFile(t, directory, "item.yml", `configkit:
|
||||
itemPath := writeImportFile(t, directory, "item.yml", `config:
|
||||
imports:
|
||||
- path: []
|
||||
- path: item-helper.yml
|
||||
destination: [metadata]
|
||||
id: selected
|
||||
`)
|
||||
itemHelperPath := writeImportFile(t, directory, "item-helper.yml", `configkit:
|
||||
itemHelperPath := writeImportFile(t, directory, "item-helper.yml", `config:
|
||||
imports:
|
||||
- dir: absent-item-helper
|
||||
key: value
|
||||
`)
|
||||
underlayPath := writeImportFile(t, directory, "underlay.yml", `configkit:
|
||||
underlayPath := writeImportFile(t, directory, "underlay.yml", `config:
|
||||
imports:
|
||||
- path: []
|
||||
value: underlay
|
||||
@@ -216,11 +216,11 @@ value: underlay
|
||||
t.Fatalf("configuration = %#v", loaded.Config)
|
||||
}
|
||||
want := map[string]string{
|
||||
"source-1": "/configkit/imports/2",
|
||||
"source-2": "/configkit/imports/0",
|
||||
"source-3": "/configkit/imports/0",
|
||||
"source-4": "/configkit/imports/0",
|
||||
"source-5": "/configkit/imports/0",
|
||||
"source-1": "/config/imports/2",
|
||||
"source-2": "/config/imports/0",
|
||||
"source-3": "/config/imports/0",
|
||||
"source-4": "/config/imports/0",
|
||||
"source-5": "/config/imports/0",
|
||||
}
|
||||
sources := loaded.Inspection.Sources()
|
||||
if len(sources) != 6 {
|
||||
@@ -266,18 +266,18 @@ func TestFailedNestedItemLoadKeepsEvidenceWithUnresolvedDestination(t *testing.T
|
||||
Items []item `yaml:"items"`
|
||||
}
|
||||
directory := t.TempDir()
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `configkit:
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `config:
|
||||
imports:
|
||||
- path: item.yml
|
||||
destination: [items]
|
||||
placement: sequence-item
|
||||
`)
|
||||
writeImportFile(t, directory, "item.yml", `configkit:
|
||||
writeImportFile(t, directory, "item.yml", `config:
|
||||
imports:
|
||||
- path: helper.yml
|
||||
destination: [metadata]
|
||||
`)
|
||||
writeImportFile(t, directory, "helper.yml", `configkit:
|
||||
writeImportFile(t, directory, "helper.yml", `config:
|
||||
imports:
|
||||
- dir: absent
|
||||
- path: missing.yml
|
||||
@@ -294,7 +294,7 @@ key: value
|
||||
continue
|
||||
}
|
||||
if !source.destinationUnresolved || source.Destination.String() != "/items" || len(source.importSelections) != 1 ||
|
||||
source.importSelections[0].path.String() != "/configkit/imports/0" || source.importSelections[0].location.SourceID != source.ID {
|
||||
source.importSelections[0].path.String() != "/config/imports/0" || source.importSelections[0].location.SourceID != source.ID {
|
||||
t.Fatalf("failed nested item source = %#v", source)
|
||||
}
|
||||
return
|
||||
|
||||
@@ -17,9 +17,9 @@ func TestImportedAcquisitionClosesOwnedHostRootOnEveryExit(t *testing.T) {
|
||||
wantError bool
|
||||
wantPanic bool
|
||||
}{
|
||||
{name: "success", main: "configkit: {imports: [{path: child.yml}]}\n", child: "value: child\n"},
|
||||
{name: "error", main: "configkit: {imports: [{path: missing.yml, required: true}]}\n", wantError: true},
|
||||
{name: "version panic", main: "configkit: {imports: [{path: child.yml}]}\n", child: "version: v1\n", version: true, wantPanic: true},
|
||||
{name: "success", main: "config: {imports: [{path: child.yml}]}\n", child: "value: child\n"},
|
||||
{name: "error", main: "config: {imports: [{path: missing.yml, required: true}]}\n", wantError: true},
|
||||
{name: "version panic", main: "config: {imports: [{path: child.yml}]}\n", child: "version: v1\n", version: true, wantPanic: true},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
@@ -80,7 +80,7 @@ func TestImportedAcquisitionClosesOwnedHostRootOnEveryExit(t *testing.T) {
|
||||
|
||||
func TestImportedAcquisitionClosesChildFileBeforeVersionPanic(t *testing.T) {
|
||||
filesystem := &observedFilesystem{files: fstest.MapFS{
|
||||
"main.yml": &fstest.MapFile{Data: []byte("configkit: {imports: [{path: child.yml}]}\n")},
|
||||
"main.yml": &fstest.MapFile{Data: []byte("config: {imports: [{path: child.yml}]}\n")},
|
||||
"child.yml": &fstest.MapFile{Data: []byte("version: v1\n")},
|
||||
}}
|
||||
namespace := newNativeNamespace("bundle", filesystem)
|
||||
|
||||
@@ -72,7 +72,7 @@ func TestSelectNamedImportsChecksRequiredTargetsBeforeExclusions(t *testing.T) {
|
||||
t.Fatal(diagnostics)
|
||||
}
|
||||
_, diagnostics = selectNamedImportCandidates(access, root, specs[0], policy)
|
||||
if len(diagnostics) != 1 || diagnostics[0].Code != CodeImportMissing || diagnostics[0].Path.String() != "/configkit/imports/0/path" {
|
||||
if len(diagnostics) != 1 || diagnostics[0].Code != CodeImportMissing || diagnostics[0].Path.String() != "/config/imports/0/path" {
|
||||
t.Fatalf("required excluded missing target diagnostics = %#v", diagnostics)
|
||||
}
|
||||
}
|
||||
@@ -171,8 +171,8 @@ func TestSelectNamedImportsChecksNormalizedPathsLexically(t *testing.T) {
|
||||
}}
|
||||
failingAccess := newNativeAccess(failingFilesystem, ".", &namespaceToken{})
|
||||
_, diagnostics = selectNamedImportCandidates(failingAccess, ".", specs[0], resolvedImportPolicy{})
|
||||
if len(diagnostics) != 1 || diagnostics[0].Code != CodeImportInvalid || diagnostics[0].Path.String() != "/configkit/imports/0/path/1" {
|
||||
t.Fatalf("first lexical failure = %#v, want /configkit/imports/0/path/1", diagnostics)
|
||||
if len(diagnostics) != 1 || diagnostics[0].Code != CodeImportInvalid || diagnostics[0].Path.String() != "/config/imports/0/path/1" {
|
||||
t.Fatalf("first lexical failure = %#v, want /config/imports/0/path/1", diagnostics)
|
||||
}
|
||||
if diagnostics[0].Primary == nil || diagnostics[0].Primary.SourceID != "source-1" {
|
||||
t.Fatalf("first lexical failure location = %#v", diagnostics[0].Primary)
|
||||
|
||||
@@ -34,7 +34,7 @@ func TestParseImportDeclarationSpecNormalizesPresenceAndPlacement(t *testing.T)
|
||||
if first.required == nil || *first.required || first.destination.String() != "/services" || first.placement != PlacementModeSequenceItem {
|
||||
t.Fatalf("explicit declaration values = %#v", first)
|
||||
}
|
||||
if first.path.String() != "/configkit/imports/0" || first.fieldSites["required"].path.String() != "/configkit/imports/0/required" {
|
||||
if first.path.String() != "/config/imports/0" || first.fieldSites["required"].path.String() != "/config/imports/0/required" {
|
||||
t.Fatalf("stored paths = declaration %q, required %q", first.path.String(), first.fieldSites["required"].path.String())
|
||||
}
|
||||
second := specs[1]
|
||||
@@ -53,21 +53,21 @@ func TestParseImportDeclarationSpecValidatesSelectorMatrixAndTypes(t *testing.T)
|
||||
tests := []struct {
|
||||
name, yaml, path string
|
||||
}{
|
||||
{name: "missing selector", yaml: " - required: true\n", path: "/configkit/imports/0"},
|
||||
{name: "multiple selectors", yaml: " - path: one.yaml\n dir: fragments\n", path: "/configkit/imports/0"},
|
||||
{name: "removed optional", yaml: " - path: one.yaml\n optional: true\n", path: "/configkit/imports/0/optional"},
|
||||
{name: "inapplicable field", yaml: " - path: one.yaml\n pattern: '*.yaml'\n", path: "/configkit/imports/0/pattern"},
|
||||
{name: "selector null", yaml: " - path: null\n", path: "/configkit/imports/0/path"},
|
||||
{name: "empty path", yaml: " - path: ''\n", path: "/configkit/imports/0/path"},
|
||||
{name: "nested selector list", yaml: " - path: [[one.yaml]]\n", path: "/configkit/imports/0/path/0"},
|
||||
{name: "null selector member", yaml: " - dir: [fragments, null]\n", path: "/configkit/imports/0/dir/1"},
|
||||
{name: "empty glob", yaml: " - glob: ''\n", path: "/configkit/imports/0/glob"},
|
||||
{name: "recursive glob wildcard", yaml: " - glob: '**/*.yaml'\n", path: "/configkit/imports/0/glob"},
|
||||
{name: "null boolean", yaml: " - path: one.yaml\n required: null\n", path: "/configkit/imports/0/required"},
|
||||
{name: "bad pattern member with empty roots", yaml: " - dir: []\n pattern: ['*', '[']\n", path: "/configkit/imports/0/pattern/1"},
|
||||
{name: "bad exclusion member", yaml: " - glob: '*.yaml'\n exclude: ['[']\n", path: "/configkit/imports/0/exclude/0"},
|
||||
{name: "invalid destination", yaml: " - path: one.yaml\n destination: [configkit]\n", path: "/configkit/imports/0/destination/0"},
|
||||
{name: "invalid placement", yaml: " - path: one.yaml\n placement: sequence\n", path: "/configkit/imports/0/placement"},
|
||||
{name: "missing selector", yaml: " - required: true\n", path: "/config/imports/0"},
|
||||
{name: "multiple selectors", yaml: " - path: one.yaml\n dir: fragments\n", path: "/config/imports/0"},
|
||||
{name: "removed optional", yaml: " - path: one.yaml\n optional: true\n", path: "/config/imports/0/optional"},
|
||||
{name: "inapplicable field", yaml: " - path: one.yaml\n pattern: '*.yaml'\n", path: "/config/imports/0/pattern"},
|
||||
{name: "selector null", yaml: " - path: null\n", path: "/config/imports/0/path"},
|
||||
{name: "empty path", yaml: " - path: ''\n", path: "/config/imports/0/path"},
|
||||
{name: "nested selector list", yaml: " - path: [[one.yaml]]\n", path: "/config/imports/0/path/0"},
|
||||
{name: "null selector member", yaml: " - dir: [fragments, null]\n", path: "/config/imports/0/dir/1"},
|
||||
{name: "empty glob", yaml: " - glob: ''\n", path: "/config/imports/0/glob"},
|
||||
{name: "recursive glob wildcard", yaml: " - glob: '**/*.yaml'\n", path: "/config/imports/0/glob"},
|
||||
{name: "null boolean", yaml: " - path: one.yaml\n required: null\n", path: "/config/imports/0/required"},
|
||||
{name: "bad pattern member with empty roots", yaml: " - dir: []\n pattern: ['*', '[']\n", path: "/config/imports/0/pattern/1"},
|
||||
{name: "bad exclusion member", yaml: " - glob: '*.yaml'\n exclude: ['[']\n", path: "/config/imports/0/exclude/0"},
|
||||
{name: "invalid destination", yaml: " - path: one.yaml\n destination: [extends]\n", path: "/config/imports/0/destination/0"},
|
||||
{name: "invalid placement", yaml: " - path: one.yaml\n placement: sequence\n", path: "/config/imports/0/placement"},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
@@ -108,7 +108,7 @@ func TestParseImportDeclarationSpecValidatesDepthSyntaxAndPolicy(t *testing.T) {
|
||||
t.Parallel()
|
||||
specs, diagnostics := parseImportSpecsYAML(t, " - dir: []\n recursive: true\n depth: "+test.value+"\n")
|
||||
if !test.valid {
|
||||
if len(diagnostics) == 0 || diagnostics[0].Path.String() != "/configkit/imports/0/depth" {
|
||||
if len(diagnostics) == 0 || diagnostics[0].Path.String() != "/config/imports/0/depth" {
|
||||
t.Fatalf("diagnostics = %#v, want invalid depth", diagnostics)
|
||||
}
|
||||
return
|
||||
@@ -124,7 +124,7 @@ func TestParseImportDeclarationSpecValidatesDepthSyntaxAndPolicy(t *testing.T) {
|
||||
t.Fatalf("syntax-only parse diagnostics = %#v", diagnostics)
|
||||
}
|
||||
_, diagnostics = resolveImportPolicy(specs[0], ImportDefaults{})
|
||||
if len(diagnostics) != 1 || diagnostics[0].Path.String() != "/configkit/imports/0/depth" {
|
||||
if len(diagnostics) != 1 || diagnostics[0].Path.String() != "/config/imports/0/depth" {
|
||||
t.Fatalf("policy diagnostics = %#v, want depth applicability error", diagnostics)
|
||||
}
|
||||
|
||||
@@ -228,7 +228,7 @@ func TestInvalidImportDefaultPatternsFailBeforeReadingSource(t *testing.T) {
|
||||
|
||||
func parseImportSpecsYAML(t *testing.T, declarations string) ([]importDeclarationSpec, []Diagnostic) {
|
||||
t.Helper()
|
||||
parsed, diagnostics := parseSource(Bytes("import specification fixture", []byte("configkit:\n imports:\n"+declarations)), "source-1", defaultParseLimits())
|
||||
parsed, diagnostics := parseSource(Bytes("import specification fixture", []byte("config:\n imports:\n"+declarations)), "source-1", defaultParseLimits())
|
||||
if len(diagnostics) != 0 {
|
||||
return nil, diagnostics
|
||||
}
|
||||
|
||||
@@ -47,14 +47,14 @@ func TestLoadFormerDirectiveKeyIsApplicationData(t *testing.T) {
|
||||
|
||||
func TestLoadTraversesPathImportsDepthFirstAndComposesOrigins(t *testing.T) {
|
||||
directory := t.TempDir()
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `configkit:
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `config:
|
||||
imports:
|
||||
- path: first.yml
|
||||
- path: second.yml
|
||||
settings:
|
||||
root: root
|
||||
`)
|
||||
firstPath := writeImportFile(t, directory, "first.yml", `configkit:
|
||||
firstPath := writeImportFile(t, directory, "first.yml", `config:
|
||||
imports:
|
||||
- path: nested/third.yml
|
||||
settings:
|
||||
@@ -99,13 +99,13 @@ func TestLoadOrdinaryImportsUseDependencyReadyCompositionOrder(t *testing.T) {
|
||||
Tasks []task `yaml:"tasks"`
|
||||
}
|
||||
directory := t.TempDir()
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `configkit:
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `config:
|
||||
imports:
|
||||
- path: z-parent.yml
|
||||
- path: a-independent.yml
|
||||
tasks: [{id: main}]
|
||||
`)
|
||||
zParentPath := writeImportFile(t, directory, "z-parent.yml", `configkit:
|
||||
zParentPath := writeImportFile(t, directory, "z-parent.yml", `config:
|
||||
imports:
|
||||
- path: b-dependency.yml
|
||||
tasks: [{id: z-parent}]
|
||||
@@ -180,7 +180,7 @@ func TestAcquiredContextsUseSelectedFileWhenSourceRecordsAreReordered(t *testing
|
||||
|
||||
func TestLoadImportsFromProfilesDirectoryAsBaseInput(t *testing.T) {
|
||||
directory := t.TempDir()
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "configkit: {imports: [{path: profiles/shared.yml}]}\n")
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "config: {imports: [{path: profiles/shared.yml}]}\n")
|
||||
writeImportFile(t, directory, "profiles/shared.yml", "settings: {root: imported}\n")
|
||||
|
||||
result, err := testLoad[importTestConfig](File(mainPath), Options[importTestConfig]{Imports: true})
|
||||
@@ -193,7 +193,7 @@ func TestLoadImportsFromProfilesDirectoryAsBaseInput(t *testing.T) {
|
||||
func TestLoadRejectsImportConflictsAndFragmentVersions(t *testing.T) {
|
||||
t.Run("all duplicate claimants", func(t *testing.T) {
|
||||
directory := t.TempDir()
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `configkit:
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `config:
|
||||
imports:
|
||||
- path: one.yml
|
||||
- path: two.yml
|
||||
@@ -219,7 +219,7 @@ func TestLoadRejectsImportConflictsAndFragmentVersions(t *testing.T) {
|
||||
} {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
directory := t.TempDir()
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "configkit:\n imports:\n - path: fragment.yml\n")
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "config:\n imports:\n - path: fragment.yml\n")
|
||||
writeImportFile(t, directory, "fragment.yml", test.fragment)
|
||||
loadError := requireLoadCode(t, File(mainPath), Options[importTestConfig]{Imports: true, Definition: Definition[importTestConfig]{Version: versionRule}}, CodeImportVersion)
|
||||
diagnostic := loadError.Diagnostics()[0]
|
||||
@@ -236,18 +236,17 @@ func TestLoadImportDirectiveValidationAndTemporaryGlobGate(t *testing.T) {
|
||||
body string
|
||||
code Code
|
||||
}{
|
||||
{name: "directive kind", body: "configkit: []\n", code: CodeImportInvalid},
|
||||
{name: "unknown directive field", body: "configkit: {unknown: true}\n", code: CodeImportInvalid},
|
||||
{name: "imports kind", body: "configkit: {imports: {}}\n", code: CodeImportInvalid},
|
||||
{name: "declaration kind", body: "configkit: {imports: [file.yml]}\n", code: CodeImportInvalid},
|
||||
{name: "missing target", body: "configkit: {imports: [{required: true}]}\n", code: CodeImportInvalid},
|
||||
{name: "two targets", body: "configkit: {imports: [{path: a.yml, glob: '*.yml'}]}\n", code: CodeImportInvalid},
|
||||
{name: "unknown declaration field", body: "configkit: {imports: [{path: a.yml, extra: true}]}\n", code: CodeImportInvalid},
|
||||
{name: "removed optional field", body: "configkit: {imports: [{path: a.yml, optional: true}]}\n", code: CodeImportInvalid},
|
||||
{name: "required kind", body: "configkit: {imports: [{path: a.yml, required: 'yes'}]}\n", code: CodeImportInvalid},
|
||||
{name: "placement kind", body: "configkit: {imports: [{path: a.yml, placement: true}]}\n", code: CodeImportInvalid},
|
||||
{name: "placement value", body: "configkit: {imports: [{path: a.yml, placement: item}]}\n", code: CodeImportInvalid},
|
||||
{name: "nested directive", body: "nested: {configkit: {}}\n", code: CodeImportInvalid},
|
||||
{name: "directive kind", body: "config: []\n", code: CodeImportInvalid},
|
||||
{name: "unknown directive field", body: "config: {unknown: true}\n", code: CodeImportInvalid},
|
||||
{name: "imports kind", body: "config: {imports: {}}\n", code: CodeImportInvalid},
|
||||
{name: "declaration kind", body: "config: {imports: [file.yml]}\n", code: CodeImportInvalid},
|
||||
{name: "missing target", body: "config: {imports: [{required: true}]}\n", code: CodeImportInvalid},
|
||||
{name: "two targets", body: "config: {imports: [{path: a.yml, glob: '*.yml'}]}\n", code: CodeImportInvalid},
|
||||
{name: "unknown declaration field", body: "config: {imports: [{path: a.yml, extra: true}]}\n", code: CodeImportInvalid},
|
||||
{name: "removed optional field", body: "config: {imports: [{path: a.yml, optional: true}]}\n", code: CodeImportInvalid},
|
||||
{name: "required kind", body: "config: {imports: [{path: a.yml, required: 'yes'}]}\n", code: CodeImportInvalid},
|
||||
{name: "placement kind", body: "config: {imports: [{path: a.yml, placement: true}]}\n", code: CodeImportInvalid},
|
||||
{name: "placement value", body: "config: {imports: [{path: a.yml, placement: item}]}\n", code: CodeImportInvalid},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
@@ -274,13 +273,13 @@ func TestLoadItemImportComposesHelpersAndNestedItemsInDeclaringScope(t *testing.
|
||||
Items []record `yaml:"items"`
|
||||
}
|
||||
directory := t.TempDir()
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `configkit:
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `config:
|
||||
imports:
|
||||
- path: records/item.yml
|
||||
destination: [items]
|
||||
placement: sequence-item
|
||||
`)
|
||||
itemPath := writeImportFile(t, directory, "records/item.yml", `configkit:
|
||||
itemPath := writeImportFile(t, directory, "records/item.yml", `config:
|
||||
imports:
|
||||
- path: nested/helper.yml
|
||||
- path: child.yml
|
||||
@@ -288,7 +287,7 @@ func TestLoadItemImportComposesHelpersAndNestedItemsInDeclaringScope(t *testing.
|
||||
placement: sequence-item
|
||||
name: authored
|
||||
`)
|
||||
helperPath := writeImportFile(t, directory, "records/nested/helper.yml", `configkit:
|
||||
helperPath := writeImportFile(t, directory, "records/nested/helper.yml", `config:
|
||||
imports:
|
||||
- path: more.yml
|
||||
destination: [metadata]
|
||||
@@ -349,13 +348,13 @@ label: helper
|
||||
|
||||
t.Run("duplicate helper identity remains a mapping conflict", func(t *testing.T) {
|
||||
directory := t.TempDir()
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `configkit:
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `config:
|
||||
imports:
|
||||
- path: item.yml
|
||||
destination: [items]
|
||||
placement: sequence-item
|
||||
`)
|
||||
writeImportFile(t, directory, "item.yml", `configkit:
|
||||
writeImportFile(t, directory, "item.yml", `config:
|
||||
imports:
|
||||
- path: helper.yml
|
||||
id: authored
|
||||
@@ -392,7 +391,7 @@ func TestLayeredUnderlayItemImportRetainsNestedEvidenceAndDestinations(t *testin
|
||||
}
|
||||
|
||||
directory := t.TempDir()
|
||||
itemPath := writeImportFile(t, directory, "records/item.yml", `configkit:
|
||||
itemPath := writeImportFile(t, directory, "records/item.yml", `config:
|
||||
imports:
|
||||
- path: nested/helper.yml
|
||||
- path: children/child.yml
|
||||
@@ -400,7 +399,7 @@ func TestLayeredUnderlayItemImportRetainsNestedEvidenceAndDestinations(t *testin
|
||||
placement: sequence-item
|
||||
name: authored
|
||||
`)
|
||||
helperPath := writeImportFile(t, directory, "records/nested/helper.yml", `configkit:
|
||||
helperPath := writeImportFile(t, directory, "records/nested/helper.yml", `config:
|
||||
imports:
|
||||
- path: more.yml
|
||||
destination: [metadata]
|
||||
@@ -482,7 +481,7 @@ func TestLoadItemGlobKeepsDefaultModeIndependentAndOptionalMissesAbsent(t *testi
|
||||
Other map[string]string `yaml:"other"`
|
||||
}
|
||||
directory := t.TempDir()
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `configkit:
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `config:
|
||||
imports:
|
||||
- glob: records/*.yml
|
||||
destination: [items]
|
||||
@@ -518,7 +517,7 @@ func TestLoadMainItemPlacementKeepsItsHelpersInTheItem(t *testing.T) {
|
||||
Items []item `yaml:"items"`
|
||||
}
|
||||
directory := t.TempDir()
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "configkit:\n imports:\n - path: helper.yml\nid: main\n")
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "config:\n imports:\n - path: helper.yml\nid: main\n")
|
||||
helperPath := writeImportFile(t, directory, "helper.yml", "value: helper\n")
|
||||
result, err := testLoad[config](File(mainPath), Options[config]{
|
||||
Imports: true, Destination: Keys("items"), PlacementMode: PlacementModeSequenceItem,
|
||||
@@ -616,14 +615,14 @@ func TestProjectNestedEvidenceUsesMappedSequenceItemIndex(t *testing.T) {
|
||||
|
||||
func TestDeferredInputCompositionUsesRetainedAcquisitionScopes(t *testing.T) {
|
||||
directory := t.TempDir()
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `configkit:
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `config:
|
||||
imports:
|
||||
- path: item.yml
|
||||
destination: [records]
|
||||
placement: sequence-item
|
||||
name: main
|
||||
`)
|
||||
itemPath := writeImportFile(t, directory, "item.yml", `configkit:
|
||||
itemPath := writeImportFile(t, directory, "item.yml", `config:
|
||||
imports:
|
||||
- path: helper.yml
|
||||
id: item
|
||||
@@ -680,13 +679,13 @@ func TestItemImportCanJoinAnAuthoredListUnderRegisteredComposition(t *testing.T)
|
||||
Items []map[string]string `yaml:"items"`
|
||||
}
|
||||
directory := t.TempDir()
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `configkit:
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `config:
|
||||
imports:
|
||||
- path: item.yml
|
||||
destination: [items]
|
||||
placement: sequence-item
|
||||
`)
|
||||
writeImportFile(t, directory, "item.yml", "configkit: {imports: [{path: helper.yml}]}\nname: imported\n")
|
||||
writeImportFile(t, directory, "item.yml", "config: {imports: [{path: helper.yml}]}\nname: imported\n")
|
||||
writeImportFile(t, directory, "helper.yml", "id: helper-id\n")
|
||||
sequencePolicy := mustCompileSequenceIdentityPolicy(t, []sequenceIdentityRegistration{{selector: sequenceIdentitySelector{literalSequenceSelector("items")}, identityFields: []string{"id"}}})
|
||||
input, diagnostics := testAcquireInput(inputAcquisitionRequest{
|
||||
@@ -734,7 +733,7 @@ func TestParseImportDestinationUsesLiteralStringSegments(t *testing.T) {
|
||||
},
|
||||
} {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
body := "configkit:\n imports:\n - path: child.yml\n" + test.destination
|
||||
body := "config:\n imports:\n - path: child.yml\n" + test.destination
|
||||
declarations := parseImportSpecificationsYAML(t, body)
|
||||
if len(declarations) != 1 {
|
||||
t.Fatalf("declarations = %#v", declarations)
|
||||
@@ -754,7 +753,7 @@ func TestParseImportDestinationUsesLiteralStringSegments(t *testing.T) {
|
||||
|
||||
func TestParseImportPlacementDefaultsPerDeclaration(t *testing.T) {
|
||||
t.Parallel()
|
||||
declarations := parseImportSpecificationsYAML(t, `configkit:
|
||||
declarations := parseImportSpecificationsYAML(t, `config:
|
||||
imports:
|
||||
- path: mapping.yml
|
||||
- glob: records/*.yml
|
||||
@@ -774,18 +773,17 @@ func TestParseImportDestinationRejectsInvalidShapesAndMembers(t *testing.T) {
|
||||
wantPath string
|
||||
badMember string
|
||||
}{
|
||||
{name: "null", value: "null", wantPath: "/configkit/imports/0/destination", badMember: "null"},
|
||||
{name: "scalar string", value: "prompts", wantPath: "/configkit/imports/0/destination", badMember: "prompts"},
|
||||
{name: "number", value: "3", wantPath: "/configkit/imports/0/destination", badMember: "3"},
|
||||
{name: "non-string number", value: "[valid, 7]", wantPath: "/configkit/imports/0/destination/1", badMember: "7"},
|
||||
{name: "non-string null", value: "[valid, null]", wantPath: "/configkit/imports/0/destination/1", badMember: "null"},
|
||||
{name: "non-string boolean", value: "[valid, true]", wantPath: "/configkit/imports/0/destination/1", badMember: "true"},
|
||||
{name: "non-string mapping", value: "[valid, {key: value}]", wantPath: "/configkit/imports/0/destination/1", badMember: "{key"},
|
||||
{name: "reserved configkit", value: "[valid, configkit]", wantPath: "/configkit/imports/0/destination/1", badMember: "configkit"},
|
||||
{name: "reserved extends", value: "[valid, extends]", wantPath: "/configkit/imports/0/destination/1", badMember: "extends"},
|
||||
{name: "null", value: "null", wantPath: "/config/imports/0/destination", badMember: "null"},
|
||||
{name: "scalar string", value: "prompts", wantPath: "/config/imports/0/destination", badMember: "prompts"},
|
||||
{name: "number", value: "3", wantPath: "/config/imports/0/destination", badMember: "3"},
|
||||
{name: "non-string number", value: "[valid, 7]", wantPath: "/config/imports/0/destination/1", badMember: "7"},
|
||||
{name: "non-string null", value: "[valid, null]", wantPath: "/config/imports/0/destination/1", badMember: "null"},
|
||||
{name: "non-string boolean", value: "[valid, true]", wantPath: "/config/imports/0/destination/1", badMember: "true"},
|
||||
{name: "non-string mapping", value: "[valid, {key: value}]", wantPath: "/config/imports/0/destination/1", badMember: "{key"},
|
||||
{name: "reserved extends", value: "[valid, extends]", wantPath: "/config/imports/0/destination/1", badMember: "extends"},
|
||||
} {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
body := "configkit:\n imports:\n - path: child.yml\n destination: " + test.value + "\n"
|
||||
body := "config:\n imports:\n - path: child.yml\n destination: " + test.value + "\n"
|
||||
parsed, diagnostics := parseImportSpecificationYAML(body)
|
||||
if len(diagnostics) != 1 || diagnostics[0].Code != CodeImportInvalid || diagnostics[0].Path.String() != test.wantPath {
|
||||
t.Fatalf("parse = %#v, want import.invalid at %q", diagnostics, test.wantPath)
|
||||
@@ -809,13 +807,13 @@ func TestImportDestinationValidationPrecedesOptionalSuppression(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
name: "optional missing path",
|
||||
body: "configkit:\n imports:\n - path: absent.yml\n destination: null\n",
|
||||
path: "/configkit/imports/0/destination",
|
||||
body: "config:\n imports:\n - path: absent.yml\n destination: null\n",
|
||||
path: "/config/imports/0/destination",
|
||||
},
|
||||
{
|
||||
name: "optional unmatched glob",
|
||||
body: "configkit:\n imports:\n - glob: absent/*.yml\n destination: [extends]\n",
|
||||
path: "/configkit/imports/0/destination/0",
|
||||
body: "config:\n imports:\n - glob: absent/*.yml\n destination: [extends]\n",
|
||||
path: "/config/imports/0/destination/0",
|
||||
},
|
||||
} {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
@@ -832,7 +830,7 @@ func TestImportDestinationValidationPrecedesOptionalSuppression(t *testing.T) {
|
||||
func TestLoadImportMissingContainmentAndRegularFileRules(t *testing.T) {
|
||||
t.Run("optional missing", func(t *testing.T) {
|
||||
directory := t.TempDir()
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `configkit:
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `config:
|
||||
imports:
|
||||
- path: missing.yml
|
||||
settings: {root: retained}
|
||||
@@ -871,7 +869,7 @@ settings: {root: retained}
|
||||
if test.code == CodeImportMissing {
|
||||
required = "\n required: true"
|
||||
}
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "configkit:\n imports:\n - path: \""+test.path+"\""+required+"\n")
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "config:\n imports:\n - path: \""+test.path+"\""+required+"\n")
|
||||
requireLoadCode(t, File(mainPath), Options[importTestConfig]{Imports: true}, test.code)
|
||||
})
|
||||
}
|
||||
@@ -881,8 +879,8 @@ func TestImportDefaultsReachOrdinaryAndGroupedDeclarations(t *testing.T) {
|
||||
t.Parallel()
|
||||
required := true
|
||||
directory := t.TempDir()
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "configkit: {imports: [{path: child.yml}]}\n")
|
||||
writeImportFile(t, directory, "child.yml", "configkit: {imports: [{path: absent.yml}]}\n")
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "config: {imports: [{path: child.yml}]}\n")
|
||||
writeImportFile(t, directory, "child.yml", "config: {imports: [{path: absent.yml}]}\n")
|
||||
_, err := testLoad[importTestConfig](File(mainPath), Options[importTestConfig]{
|
||||
Imports: true, ImportDefaults: ImportDefaults{Required: &required},
|
||||
})
|
||||
@@ -892,7 +890,7 @@ func TestImportDefaultsReachOrdinaryAndGroupedDeclarations(t *testing.T) {
|
||||
}
|
||||
|
||||
basePath := writeImportFile(t, directory, "base.yml", "settings: {root: base}\n")
|
||||
underlayPath := writeImportFile(t, directory, "underlay.yml", "configkit: {imports: [{path: absent.yml}]}\n")
|
||||
underlayPath := writeImportFile(t, directory, "underlay.yml", "config: {imports: [{path: absent.yml}]}\n")
|
||||
_, err = loadGroupedWithSecretLookup(loadRequest[importTestConfig]{
|
||||
main: loadInput{source: File(basePath)},
|
||||
underlays: []loadGroup{{inputs: []loadInput{{source: File(underlayPath), imports: true}}}},
|
||||
@@ -906,9 +904,9 @@ func TestImportDefaultsReachOrdinaryAndGroupedDeclarations(t *testing.T) {
|
||||
func TestLoadImportIdentityReportsCyclesAndRepeatedRoutes(t *testing.T) {
|
||||
t.Run("cycle", func(t *testing.T) {
|
||||
directory := t.TempDir()
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "configkit:\n imports: [{path: a.yml}]\n")
|
||||
writeImportFile(t, directory, "a.yml", "configkit:\n imports: [{path: b.yml}]\n")
|
||||
writeImportFile(t, directory, "b.yml", "configkit:\n imports: [{path: main.yml}]\n")
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "config:\n imports: [{path: a.yml}]\n")
|
||||
writeImportFile(t, directory, "a.yml", "config:\n imports: [{path: b.yml}]\n")
|
||||
writeImportFile(t, directory, "b.yml", "config:\n imports: [{path: main.yml}]\n")
|
||||
loadError := requireLoadCode(t, File(mainPath), Options[importTestConfig]{Imports: true}, CodeImportCycle)
|
||||
diagnostic := loadError.Diagnostics()[0]
|
||||
if diagnostic.Primary == nil || len(diagnostic.Related) != 2 || !strings.Contains(diagnostic.Message, "main.yml") || !strings.Contains(diagnostic.Message, "a.yml") || !strings.Contains(diagnostic.Message, "b.yml") {
|
||||
@@ -918,13 +916,13 @@ func TestLoadImportIdentityReportsCyclesAndRepeatedRoutes(t *testing.T) {
|
||||
|
||||
t.Run("cycle through an item scope", func(t *testing.T) {
|
||||
directory := t.TempDir()
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `configkit:
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `config:
|
||||
imports:
|
||||
- path: item.yml
|
||||
destination: [items]
|
||||
placement: sequence-item
|
||||
`)
|
||||
writeImportFile(t, directory, "item.yml", "configkit: {imports: [{path: main.yml}]}\n")
|
||||
writeImportFile(t, directory, "item.yml", "config: {imports: [{path: main.yml}]}\n")
|
||||
loadError := requireLoadCode(t, File(mainPath), Options[importTestConfig]{Imports: true}, CodeImportCycle)
|
||||
diagnostic := loadError.Diagnostics()[0]
|
||||
if diagnostic.Primary == nil || len(diagnostic.Related) != 1 || !strings.Contains(diagnostic.Message, "main.yml") || !strings.Contains(diagnostic.Message, "item.yml") {
|
||||
@@ -934,9 +932,9 @@ func TestLoadImportIdentityReportsCyclesAndRepeatedRoutes(t *testing.T) {
|
||||
|
||||
t.Run("diamond", func(t *testing.T) {
|
||||
directory := t.TempDir()
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "configkit:\n imports: [{path: left.yml}, {path: right.yml}]\n")
|
||||
writeImportFile(t, directory, "left.yml", "configkit:\n imports: [{path: shared.yml}]\n")
|
||||
writeImportFile(t, directory, "right.yml", "configkit:\n imports: [{path: shared.yml}]\n")
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "config:\n imports: [{path: left.yml}, {path: right.yml}]\n")
|
||||
writeImportFile(t, directory, "left.yml", "config:\n imports: [{path: shared.yml}]\n")
|
||||
writeImportFile(t, directory, "right.yml", "config:\n imports: [{path: shared.yml}]\n")
|
||||
writeImportFile(t, directory, "shared.yml", "settings: {root: shared}\n")
|
||||
loadError := requireLoadCode(t, File(mainPath), Options[importTestConfig]{Imports: true}, CodeImportRepeated)
|
||||
diagnostic := loadError.Diagnostics()[0]
|
||||
@@ -957,20 +955,20 @@ func TestLoadImportIdentityReportsCyclesAndRepeatedRoutes(t *testing.T) {
|
||||
if err := os.Symlink("target.yml", filepath.Join(directory, "second-link.yml")); err != nil {
|
||||
t.Skipf("symlinks unavailable: %v", err)
|
||||
}
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "configkit: {imports: [{path: first-link.yml}, {path: second-link.yml}]}\n")
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "config: {imports: [{path: first-link.yml}, {path: second-link.yml}]}\n")
|
||||
requireLoadCode(t, File(mainPath), Options[importTestConfig]{Imports: true}, CodeImportRepeated)
|
||||
})
|
||||
}
|
||||
|
||||
func TestItemAcquisitionRetainsInclusionGraphAndScopeOwnership(t *testing.T) {
|
||||
directory := t.TempDir()
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `configkit:
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `config:
|
||||
imports:
|
||||
- path: item.yml
|
||||
destination: [items]
|
||||
placement: sequence-item
|
||||
`)
|
||||
itemPath := writeImportFile(t, directory, "item.yml", "configkit: {imports: [{path: helper.yml}]}\nname: item\n")
|
||||
itemPath := writeImportFile(t, directory, "item.yml", "config: {imports: [{path: helper.yml}]}\nname: item\n")
|
||||
helperPath := writeImportFile(t, directory, "helper.yml", "id: supplied\n")
|
||||
|
||||
input, diagnostics := testAcquireInput(inputAcquisitionRequest{
|
||||
@@ -1036,7 +1034,7 @@ func TestItemContributionsUseDependencyReadySchedules(t *testing.T) {
|
||||
}
|
||||
definition := Definition[config]{sequenceIdentityRegistrations: []sequenceIdentityRegistration{{selector: sequenceIdentitySelector{literalSequenceSelector("items")}, identityFields: []string{"id"}}}}
|
||||
directory := t.TempDir()
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `configkit:
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `config:
|
||||
imports:
|
||||
- path: z-item.yml
|
||||
destination: [items]
|
||||
@@ -1065,19 +1063,19 @@ items: []
|
||||
|
||||
t.Run("unequal helper branches", func(t *testing.T) {
|
||||
directory := t.TempDir()
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `configkit:
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `config:
|
||||
imports:
|
||||
- path: item.yml
|
||||
destination: [items]
|
||||
placement: sequence-item
|
||||
`)
|
||||
writeImportFile(t, directory, "item.yml", `configkit:
|
||||
writeImportFile(t, directory, "item.yml", `config:
|
||||
imports:
|
||||
- path: b-parent.yml
|
||||
- path: c-independent.yml
|
||||
id: item
|
||||
`)
|
||||
writeImportFile(t, directory, "b-parent.yml", "configkit: {imports: [{path: a-dependency.yml}]}\nid: b\n")
|
||||
writeImportFile(t, directory, "b-parent.yml", "config: {imports: [{path: a-dependency.yml}]}\nid: b\n")
|
||||
writeImportFile(t, directory, "a-dependency.yml", "id: a\n")
|
||||
writeImportFile(t, directory, "c-independent.yml", "id: c\n")
|
||||
loadError := requireLoadCode(t, File(mainPath), Options[importTestConfig]{Imports: true}, CodeComposeConflict)
|
||||
@@ -1104,7 +1102,7 @@ id: item
|
||||
|
||||
t.Run("selected main item dependencies", func(t *testing.T) {
|
||||
directory := t.TempDir()
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "configkit: {imports: [{path: helper.yml}]}\nid: main\n")
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "config: {imports: [{path: helper.yml}]}\nid: main\n")
|
||||
writeImportFile(t, directory, "helper.yml", "id: helper\n")
|
||||
options := Options[importTestConfig]{
|
||||
Imports: true, Destination: Keys("items"), PlacementMode: PlacementModeSequenceItem,
|
||||
@@ -1130,11 +1128,11 @@ func TestBroadItemScopesKeepHelperOriginsAndDestinations(t *testing.T) {
|
||||
directory := t.TempDir()
|
||||
const count = 32
|
||||
var main strings.Builder
|
||||
main.WriteString("configkit:\n imports:\n")
|
||||
main.WriteString("config:\n imports:\n")
|
||||
for index := count - 1; index >= 0; index-- {
|
||||
name := strconv.Itoa(100 + index)
|
||||
main.WriteString(" - path: item-" + name + ".yml\n destination: [items]\n placement: sequence-item\n")
|
||||
writeImportFile(t, directory, "item-"+name+".yml", "configkit: {imports: [{path: helper-"+name+".yml}]}\nid: item-"+name+"\n")
|
||||
writeImportFile(t, directory, "item-"+name+".yml", "config: {imports: [{path: helper-"+name+".yml}]}\nid: item-"+name+"\n")
|
||||
writeImportFile(t, directory, "helper-"+name+".yml", "value: helper-"+name+"\n")
|
||||
}
|
||||
mainPath := writeImportFile(t, directory, "main.yml", main.String())
|
||||
@@ -1183,14 +1181,14 @@ func TestBroadItemScopesKeepHelperOriginsAndDestinations(t *testing.T) {
|
||||
|
||||
func TestItemHelperScopeScheduleInterleavesUnequalBranches(t *testing.T) {
|
||||
directory := t.TempDir()
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `configkit:
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `config:
|
||||
imports:
|
||||
- path: item.yml
|
||||
destination: [items]
|
||||
placement: sequence-item
|
||||
`)
|
||||
writeImportFile(t, directory, "item.yml", "configkit: {imports: [{path: b-parent.yml}, {path: c-independent.yml}]}\nitem: true\n")
|
||||
writeImportFile(t, directory, "b-parent.yml", "configkit: {imports: [{path: a-dependency.yml}]}\nb: true\n")
|
||||
writeImportFile(t, directory, "item.yml", "config: {imports: [{path: b-parent.yml}, {path: c-independent.yml}]}\nitem: true\n")
|
||||
writeImportFile(t, directory, "b-parent.yml", "config: {imports: [{path: a-dependency.yml}]}\nb: true\n")
|
||||
writeImportFile(t, directory, "a-dependency.yml", "a: true\n")
|
||||
writeImportFile(t, directory, "c-independent.yml", "c: true\n")
|
||||
input, diagnostics := testAcquireInput(inputAcquisitionRequest{
|
||||
@@ -1232,7 +1230,7 @@ func TestLoadImportsCanonicalSymlinksAndKeepsHardLinksDistinct(t *testing.T) {
|
||||
if err := os.Symlink(target, filepath.Join(directory, "link.yml")); err != nil {
|
||||
t.Skipf("symlinks unavailable: %v", err)
|
||||
}
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "configkit: {imports: [{path: link.yml}]}\n")
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "config: {imports: [{path: link.yml}]}\n")
|
||||
result, err := testLoad[importTestConfig](File(mainPath), Options[importTestConfig]{Imports: true})
|
||||
if err != nil || result.Config.Settings.First != "linked" || result.Sources()[1].Path != canonicalTestPath(t, target) {
|
||||
t.Fatalf("symlink result = %#v, %v", result, err)
|
||||
@@ -1246,7 +1244,7 @@ func TestLoadImportsCanonicalSymlinksAndKeepsHardLinksDistinct(t *testing.T) {
|
||||
if err := os.Symlink(target, filepath.Join(root, "escape.yml")); err != nil {
|
||||
t.Skipf("symlinks unavailable: %v", err)
|
||||
}
|
||||
mainPath := writeImportFile(t, root, "main.yml", "configkit: {imports: [{path: escape.yml}]}\n")
|
||||
mainPath := writeImportFile(t, root, "main.yml", "config: {imports: [{path: escape.yml}]}\n")
|
||||
requireLoadCode(t, File(mainPath), Options[importTestConfig]{Imports: true}, CodeImportOutsideRoot)
|
||||
})
|
||||
|
||||
@@ -1256,7 +1254,7 @@ func TestLoadImportsCanonicalSymlinksAndKeepsHardLinksDistinct(t *testing.T) {
|
||||
if err := os.Link(one, filepath.Join(directory, "two.yml")); err != nil {
|
||||
t.Skipf("hard links unavailable: %v", err)
|
||||
}
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "configkit: {imports: [{path: one.yml}, {path: two.yml}]}\n")
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "config: {imports: [{path: one.yml}, {path: two.yml}]}\n")
|
||||
requireLoadCode(t, File(mainPath), Options[importTestConfig]{Imports: true}, CodeComposeConflict)
|
||||
})
|
||||
|
||||
@@ -1265,7 +1263,7 @@ func TestLoadImportsCanonicalSymlinksAndKeepsHardLinksDistinct(t *testing.T) {
|
||||
if err := os.Symlink("loop.yml", filepath.Join(directory, "loop.yml")); err != nil {
|
||||
t.Skipf("symlinks unavailable: %v", err)
|
||||
}
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "configkit: {imports: [{path: loop.yml}]}\n")
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "config: {imports: [{path: loop.yml}]}\n")
|
||||
requireLoadCode(t, File(mainPath), Options[importTestConfig]{Imports: true}, CodeImportInvalid)
|
||||
})
|
||||
}
|
||||
@@ -1273,7 +1271,7 @@ func TestLoadImportsCanonicalSymlinksAndKeepsHardLinksDistinct(t *testing.T) {
|
||||
func TestLoadByteAndReaderImportsRequireExplicitFilesystemContext(t *testing.T) {
|
||||
directory := t.TempDir()
|
||||
writeImportFile(t, directory, "fragment.yml", "settings: {first: imported}\n")
|
||||
input := []byte("configkit: {imports: [{path: fragment.yml}]}\n")
|
||||
input := []byte("config: {imports: [{path: fragment.yml}]}\n")
|
||||
context := &FilesystemContext{BaseDir: directory, Root: directory}
|
||||
for _, test := range []struct {
|
||||
name string
|
||||
@@ -1296,7 +1294,7 @@ func TestLoadByteAndReaderImportsRequireExplicitFilesystemContext(t *testing.T)
|
||||
|
||||
func TestFileImportRootCanContainTheSelectedFileDirectory(t *testing.T) {
|
||||
root := t.TempDir()
|
||||
mainPath := writeImportFile(t, root, "configs/main.yml", "configkit: {imports: [{path: ../shared.yml}]}\n")
|
||||
mainPath := writeImportFile(t, root, "configs/main.yml", "config: {imports: [{path: ../shared.yml}]}\n")
|
||||
writeImportFile(t, root, "shared.yml", "settings: {root: shared}\n")
|
||||
result, err := testLoad[importTestConfig](File(mainPath), Options[importTestConfig]{
|
||||
Imports: true, Filesystem: &FilesystemContext{Root: root},
|
||||
@@ -1310,7 +1308,7 @@ func TestFileImportRootCanContainTheSelectedFileDirectory(t *testing.T) {
|
||||
func TestImportedParseAndDecodeDiagnosticsKeepTheirSource(t *testing.T) {
|
||||
t.Run("parse", func(t *testing.T) {
|
||||
directory := t.TempDir()
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "configkit: {imports: [{path: broken.yml}]}\n")
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "config: {imports: [{path: broken.yml}]}\n")
|
||||
writeImportFile(t, directory, "broken.yml", "settings: [\n")
|
||||
loadError := requireAnyLoadError(t, File(mainPath), Options[importTestConfig]{Imports: true})
|
||||
diagnostics := loadError.Diagnostics()
|
||||
@@ -1321,7 +1319,7 @@ func TestImportedParseAndDecodeDiagnosticsKeepTheirSource(t *testing.T) {
|
||||
|
||||
t.Run("decode", func(t *testing.T) {
|
||||
directory := t.TempDir()
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "configkit: {imports: [{path: unknown.yml}]}\n")
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "config: {imports: [{path: unknown.yml}]}\n")
|
||||
writeImportFile(t, directory, "unknown.yml", "unknown: value\n")
|
||||
loadError := requireLoadCode(t, File(mainPath), Options[importTestConfig]{Imports: true}, CodeDecodeUnknownField)
|
||||
diagnostic := loadError.Diagnostics()[0]
|
||||
@@ -1333,7 +1331,7 @@ func TestImportedParseAndDecodeDiagnosticsKeepTheirSource(t *testing.T) {
|
||||
|
||||
func TestOptionalImportDoesNotSuppressUnsafeOrUnreadableTargets(t *testing.T) {
|
||||
directory := t.TempDir()
|
||||
mainPath := writeImportFile(t, directory, "outside.yml", "configkit: {imports: [{path: ../missing.yml}]}\n")
|
||||
mainPath := writeImportFile(t, directory, "outside.yml", "config: {imports: [{path: ../missing.yml}]}\n")
|
||||
requireLoadCode(t, File(mainPath), Options[importTestConfig]{Imports: true}, CodeImportOutsideRoot)
|
||||
|
||||
locked := writeImportFile(t, directory, "locked.yml", "settings: {root: locked}\n")
|
||||
@@ -1345,13 +1343,13 @@ func TestOptionalImportDoesNotSuppressUnsafeOrUnreadableTargets(t *testing.T) {
|
||||
_ = file.Close()
|
||||
t.Skip("filesystem does not enforce the unreadable-file fixture")
|
||||
}
|
||||
mainPath = writeImportFile(t, directory, "main.yml", "configkit: {imports: [{path: locked.yml}]}\n")
|
||||
mainPath = writeImportFile(t, directory, "main.yml", "config: {imports: [{path: locked.yml}]}\n")
|
||||
requireLoadCode(t, File(mainPath), Options[importTestConfig]{Imports: true}, CodeSourcePermission)
|
||||
}
|
||||
|
||||
func TestImportTraversalEnforcesPrivateBudgets(t *testing.T) {
|
||||
directory := t.TempDir()
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "configkit: {imports: [{path: one.yml}, {path: two.yml}]}\n")
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "config: {imports: [{path: one.yml}, {path: two.yml}]}\n")
|
||||
writeImportFile(t, directory, "one.yml", "settings: {first: one}\n")
|
||||
writeImportFile(t, directory, "two.yml", "settings: {second: two}\n")
|
||||
main := parseImportMain(t, mainPath)
|
||||
@@ -1372,7 +1370,7 @@ func TestImportTraversalEnforcesPrivateBudgets(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
writeImportFile(t, directory, "one.yml", "configkit: {imports: [{path: nested.yml}]}\n")
|
||||
writeImportFile(t, directory, "one.yml", "config: {imports: [{path: nested.yml}]}\n")
|
||||
writeImportFile(t, directory, "nested.yml", "settings: {nested: nested}\n")
|
||||
main = parseImportMain(t, mainPath)
|
||||
request := testImportRequest(File(mainPath), nil, main, Path{}, nil, nil)
|
||||
@@ -1401,10 +1399,10 @@ func TestImportDepthBudgetCountsSelectedEdges(t *testing.T) {
|
||||
} {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
directory := t.TempDir()
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "configkit: {imports: [{path: leaf.yml}]}\n")
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "config: {imports: [{path: leaf.yml}]}\n")
|
||||
leaf := "end: true\n"
|
||||
if test.declaration != "" {
|
||||
leaf += "configkit:\n imports:\n - " + test.declaration + "\n"
|
||||
leaf += "config:\n imports:\n - " + test.declaration + "\n"
|
||||
}
|
||||
writeImportFile(t, directory, "leaf.yml", leaf)
|
||||
writeImportFile(t, directory, "parts/next.yml", "next: true\n")
|
||||
@@ -1428,7 +1426,7 @@ func TestImportDepthBudgetCountsSelectedEdges(t *testing.T) {
|
||||
|
||||
func TestImportTraversalAcceptsExactPrivateBudgets(t *testing.T) {
|
||||
directory := t.TempDir()
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "configkit: {imports: [{path: imported.yml}]}\n")
|
||||
mainPath := writeImportFile(t, directory, "main.yml", "config: {imports: [{path: imported.yml}]}\n")
|
||||
importedPath := writeImportFile(t, directory, "imported.yml", "settings: {first: imported}\n")
|
||||
main := parseImportMain(t, mainPath)
|
||||
imported := parseImportMain(t, importedPath)
|
||||
|
||||
@@ -21,18 +21,18 @@ func testGroupedLoad[T any](request loadRequest[T]) (*testResult[T], error) {
|
||||
|
||||
func TestUnderlayGroupSchedulesInterleavedImportBranches(t *testing.T) {
|
||||
directory := t.TempDir()
|
||||
zRoot := writeImportFile(t, directory, "z-root.yml", `configkit:
|
||||
zRoot := writeImportFile(t, directory, "z-root.yml", `config:
|
||||
imports:
|
||||
- path: d-parent.yml
|
||||
items: [{id: z}]
|
||||
`)
|
||||
dParent := writeImportFile(t, directory, "d-parent.yml", `configkit:
|
||||
dParent := writeImportFile(t, directory, "d-parent.yml", `config:
|
||||
imports:
|
||||
- path: a-dependency.yml
|
||||
items: [{id: d}]
|
||||
`)
|
||||
aDependency := writeImportFile(t, directory, "a-dependency.yml", "items: [{id: a}]\n")
|
||||
bRoot := writeImportFile(t, directory, "b-root.yml", `configkit:
|
||||
bRoot := writeImportFile(t, directory, "b-root.yml", `config:
|
||||
imports:
|
||||
- path: c-helper.yml
|
||||
items: [{id: b}]
|
||||
@@ -75,7 +75,7 @@ items: [{id: b}]
|
||||
|
||||
func TestUnderlayGroupAcquisitionRetainsScopesUntilComposition(t *testing.T) {
|
||||
filesystem := NewFilesystem("handoff", fstest.MapFS{
|
||||
"main.yml": &fstest.MapFile{Data: []byte("configkit: {imports: [{path: child.yml}]}\nmain: retained\n")},
|
||||
"main.yml": &fstest.MapFile{Data: []byte("config: {imports: [{path: child.yml}]}\nmain: retained\n")},
|
||||
"child.yml": &fstest.MapFile{Data: []byte("child: retained\n")},
|
||||
})
|
||||
accounting := &importAccounting{}
|
||||
@@ -91,7 +91,7 @@ func TestUnderlayGroupAcquisitionRetainsScopesUntilComposition(t *testing.T) {
|
||||
if len(acquired.sources) != 2 || acquired.sources[0].UnderlayIndex != 2 || acquired.sources[1].ID != "source-2" {
|
||||
t.Fatalf("acquired source evidence = %#v", acquired.sources)
|
||||
}
|
||||
if acquired.inputBytes != int64(len("configkit: {imports: [{path: child.yml}]}\nmain: retained\n")+len("child: retained\n")) {
|
||||
if acquired.inputBytes != int64(len("config: {imports: [{path: child.yml}]}\nmain: retained\n")+len("child: retained\n")) {
|
||||
t.Fatalf("group input byte accounting = %d", acquired.inputBytes)
|
||||
}
|
||||
|
||||
@@ -199,7 +199,7 @@ func TestUnderlayItemConflictUsesScheduledGroupIndex(t *testing.T) {
|
||||
|
||||
func TestUnderlayItemHelperConflictUsesScheduledGroupIndex(t *testing.T) {
|
||||
directory := t.TempDir()
|
||||
zBad := writeImportFile(t, directory, "z-bad.yml", "configkit: {imports: [{path: helper.yml}]}\nid: duplicate\n")
|
||||
zBad := writeImportFile(t, directory, "z-bad.yml", "config: {imports: [{path: helper.yml}]}\nid: duplicate\n")
|
||||
helper := writeImportFile(t, directory, "helper.yml", "id: duplicate\n")
|
||||
aGood := writeImportFile(t, directory, "a-good.yml", "id: good\n")
|
||||
request := loadRequest[map[string]any]{
|
||||
@@ -246,7 +246,7 @@ func TestUnderlayItemHelperConflictUsesScheduledGroupIndex(t *testing.T) {
|
||||
|
||||
func TestGroupedLoadPrecedenceSourceOrderAndSingleLifecycle(t *testing.T) {
|
||||
filesystem := NewFilesystem("bundle", fstest.MapFS{
|
||||
"main.yml": &fstest.MapFile{Data: []byte("configkit: {imports: [{path: imported.yml}]}\nversion: v1\nport: 5\nsettings: {shared: main}\n")},
|
||||
"main.yml": &fstest.MapFile{Data: []byte("config: {imports: [{path: imported.yml}]}\nversion: v1\nport: 5\nsettings: {shared: main}\n")},
|
||||
"imported.yml": &fstest.MapFile{Data: []byte("settings: {imported: included}\n")},
|
||||
"overlays/test.yml": &fstest.MapFile{Data: []byte("settings: {shared: overlay}\n")},
|
||||
})
|
||||
@@ -340,7 +340,7 @@ func TestGroupedLoadAbsentMainAndVersionProtection(t *testing.T) {
|
||||
t.Fatalf("underlay version code = %s", got)
|
||||
}
|
||||
filesystem := NewFilesystem("bundle", fstest.MapFS{
|
||||
"main.yml": &fstest.MapFile{Data: []byte("configkit: {imports: [{path: fragment.yml}]}\n")},
|
||||
"main.yml": &fstest.MapFile{Data: []byte("config: {imports: [{path: fragment.yml}]}\n")},
|
||||
"fragment.yml": &fstest.MapFile{Data: []byte("version: forbidden\n")},
|
||||
})
|
||||
request.underlays[1].inputs[0] = loadInput{source: filesystem.File("main.yml"), imports: true}
|
||||
@@ -359,7 +359,7 @@ func TestGroupedLoadAbsentMainAndVersionProtection(t *testing.T) {
|
||||
func TestLayeredCollectionPolicyFlowsBetweenTiers(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
policyOnly := Bytes("lower-policy", []byte("configkit:\n sequences:\n - destination: [items]\n key: id\n mode: append\n"))
|
||||
policyOnly := Bytes("lower-policy", []byte("config:\n sequences:\n - destination: [items]\n key: id\n mode: append\n"))
|
||||
duplicate := func(name string) loadInput {
|
||||
return loadInput{source: Bytes(name, []byte("items: [{id: repeated}]\n"))}
|
||||
}
|
||||
@@ -380,7 +380,7 @@ func TestLayeredCollectionPolicyFlowsBetweenTiers(t *testing.T) {
|
||||
request = loadRequest[map[string]any]{
|
||||
main: loadInput{source: NoSource()},
|
||||
underlays: []loadGroup{
|
||||
{inputs: []loadInput{{source: Bytes("lower", []byte("configkit:\n sequences:\n - destination: [items]\n key: id\n mode: append\nitems: [{id: repeated}]\n"))}}},
|
||||
{inputs: []loadInput{{source: Bytes("lower", []byte("config:\n sequences:\n - destination: [items]\n key: id\n mode: append\nitems: [{id: repeated}]\n"))}}},
|
||||
{inputs: []loadInput{duplicate("higher")}},
|
||||
},
|
||||
}
|
||||
@@ -389,8 +389,8 @@ func TestLayeredCollectionPolicyFlowsBetweenTiers(t *testing.T) {
|
||||
}
|
||||
|
||||
request = loadRequest[map[string]any]{
|
||||
main: loadInput{source: Bytes("main", []byte("configkit:\n sequences:\n - destination: [items]\n key: name\n mode: replace\nitems: [{name: higher}]\n"))},
|
||||
underlays: []loadGroup{{inputs: []loadInput{{source: Bytes("lower", []byte("configkit:\n sequences:\n - destination: [items]\n key: id\n mode: append\nitems: [{id: lower}]\n"))}}}},
|
||||
main: loadInput{source: Bytes("main", []byte("config:\n sequences:\n - destination: [items]\n key: name\n mode: replace\nitems: [{name: higher}]\n"))},
|
||||
underlays: []loadGroup{{inputs: []loadInput{{source: Bytes("lower", []byte("config:\n sequences:\n - destination: [items]\n key: id\n mode: append\nitems: [{id: lower}]\n"))}}}},
|
||||
}
|
||||
result, err := testGroupedLoad(request)
|
||||
if err != nil || !reflect.DeepEqual(result.Config["items"], []any{map[string]any{"name": "higher"}}) {
|
||||
@@ -402,7 +402,7 @@ func TestLayeredCollectionPolicyFlowsBetweenTiers(t *testing.T) {
|
||||
}
|
||||
|
||||
filesystem := NewFilesystem("overlay", fstest.MapFS{
|
||||
"overlays/testing.yml": &fstest.MapFile{Data: []byte("configkit:\n sequences:\n - destination: [items]\n key: id\n mode: append\nitems: [{id: overlay}]\n")},
|
||||
"overlays/testing.yml": &fstest.MapFile{Data: []byte("config:\n sequences:\n - destination: [items]\n key: id\n mode: append\nitems: [{id: overlay}]\n")},
|
||||
})
|
||||
definition := Definition[map[string]any]{sequenceIdentityRegistrations: []sequenceIdentityRegistration{{selector: sequenceIdentitySelector{literalSequenceSelector("items")}, identityFields: []string{"id"}}}}
|
||||
request = loadRequest[map[string]any]{
|
||||
@@ -433,7 +433,7 @@ func TestGroupedLoadStrictConflictsRepetitionAndBudgets(t *testing.T) {
|
||||
t.Fatalf("strict conflict code = %s", got)
|
||||
}
|
||||
conflicting := NewFilesystem("bundle", fstest.MapFS{
|
||||
"main.yml": &fstest.MapFile{Data: []byte("configkit: {imports: [{path: fragment.yml}]}\nport: 1\n")},
|
||||
"main.yml": &fstest.MapFile{Data: []byte("config: {imports: [{path: fragment.yml}]}\nport: 1\n")},
|
||||
"fragment.yml": &fstest.MapFile{Data: []byte("port: 2\n")},
|
||||
})
|
||||
request.main = loadInput{source: conflicting.File("main.yml"), imports: true}
|
||||
@@ -514,9 +514,9 @@ func groupedErrorCode(t *testing.T, err error) Code {
|
||||
|
||||
func TestGroupedAccountingChargesMixedOccurrencesOnce(t *testing.T) {
|
||||
const (
|
||||
one = "configkit: {imports: [{path: child-one.yml}]}\nleft: first\n"
|
||||
one = "config: {imports: [{path: child-one.yml}]}\nleft: first\n"
|
||||
child = "extra: imported\n"
|
||||
two = "configkit: {imports: [{path: child-two.yml}]}\nright: second\n"
|
||||
two = "config: {imports: [{path: child-two.yml}]}\nright: second\n"
|
||||
)
|
||||
filesystem := NewFilesystem("bundle", fstest.MapFS{
|
||||
"one.yml": &fstest.MapFile{Data: []byte(one)},
|
||||
@@ -551,7 +551,7 @@ func TestGroupedAccountingChargesMixedOccurrencesOnce(t *testing.T) {
|
||||
|
||||
func TestGroupedGlobEntryBudgetIsShared(t *testing.T) {
|
||||
filesystem := NewFilesystem("bundle", fstest.MapFS{
|
||||
"main.yml": &fstest.MapFile{Data: []byte("configkit: {imports: [{glob: 'parts/*.yml'}]}\n")},
|
||||
"main.yml": &fstest.MapFile{Data: []byte("config: {imports: [{glob: 'parts/*.yml'}]}\n")},
|
||||
"parts/a.yml": &fstest.MapFile{Data: []byte("left: one\n")},
|
||||
"parts/b.yml": &fstest.MapFile{Data: []byte("right: two\n")},
|
||||
})
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
|
||||
func TestNativeFilesystemImportsAndOverlay(t *testing.T) {
|
||||
filesystem := fstest.MapFS{
|
||||
"config/main.yml": &fstest.MapFile{Data: []byte(`configkit:
|
||||
"config/main.yml": &fstest.MapFile{Data: []byte(`config:
|
||||
imports:
|
||||
- path: ../shared.yml
|
||||
- glob: fragments/*.yml
|
||||
@@ -52,8 +52,8 @@ func TestNativeFilesystemItemImportUsesSharedScopedAssembly(t *testing.T) {
|
||||
Items []item `yaml:"items"`
|
||||
}
|
||||
filesystem := fstest.MapFS{
|
||||
"main.yml": &fstest.MapFile{Data: []byte("configkit:\n imports:\n - path: records/item.yml\n destination: [items]\n placement: sequence-item\n")},
|
||||
"records/item.yml": &fstest.MapFile{Data: []byte("configkit:\n imports:\n - path: helper.yml\nid: native\n")},
|
||||
"main.yml": &fstest.MapFile{Data: []byte("config:\n imports:\n - path: records/item.yml\n destination: [items]\n placement: sequence-item\n")},
|
||||
"records/item.yml": &fstest.MapFile{Data: []byte("config:\n imports:\n - path: helper.yml\nid: native\n")},
|
||||
"records/helper.yml": &fstest.MapFile{Data: []byte("name: helper\n")},
|
||||
}
|
||||
namespace := newNativeNamespace("bundle", filesystem)
|
||||
@@ -109,7 +109,7 @@ func TestNativeFilesystemNamespaceAndPathFailures(t *testing.T) {
|
||||
t.Errorf("%q diagnostics = %#v", name, diagnostics)
|
||||
}
|
||||
}
|
||||
missingImport := fstest.MapFS{"main.yml": &fstest.MapFile{Data: []byte("configkit: {imports: [{path: host-only.yml, required: true}]}\n")}}
|
||||
missingImport := fstest.MapFS{"main.yml": &fstest.MapFile{Data: []byte("config: {imports: [{path: host-only.yml, required: true}]}\n")}}
|
||||
_, err := testLoad[importTestConfig](filesystemFile(newNativeNamespace("bundle", missingImport), "main.yml"), Options[importTestConfig]{Imports: true})
|
||||
if err == nil {
|
||||
t.Fatal("missing virtual import fell back to the host filesystem")
|
||||
@@ -124,7 +124,7 @@ func TestNativeFilesystemClosesFilesOnSuccessAndFailure(t *testing.T) {
|
||||
for _, fallback := range []bool{false, true} {
|
||||
t.Run(map[bool]string{false: "ReadDirFile", true: "ReadDir fallback"}[fallback], func(t *testing.T) {
|
||||
filesystem := &observedFilesystem{files: fstest.MapFS{
|
||||
"main.yml": &fstest.MapFile{Data: []byte("configkit: {imports: [{glob: 'parts/*.yml'}]}\nitems: {main: main}\n")},
|
||||
"main.yml": &fstest.MapFile{Data: []byte("config: {imports: [{glob: 'parts/*.yml'}]}\nitems: {main: main}\n")},
|
||||
"parts/one.yml": &fstest.MapFile{Data: []byte("items: {one: one}\n")},
|
||||
}, fallback: fallback}
|
||||
result, err := testLoad[importTestConfig](filesystemFile(newNativeNamespace("bundle", filesystem), "main.yml"), Options[importTestConfig]{Imports: true})
|
||||
@@ -149,7 +149,7 @@ func TestNativeFilesystemClosesFilesOnSuccessAndFailure(t *testing.T) {
|
||||
} {
|
||||
t.Run(failure.name, func(t *testing.T) {
|
||||
filesystem := &observedFilesystem{files: fstest.MapFS{
|
||||
"main.yml": &fstest.MapFile{Data: []byte("configkit: {imports: [{glob: 'parts/*.yml'}]}\n")},
|
||||
"main.yml": &fstest.MapFile{Data: []byte("config: {imports: [{glob: 'parts/*.yml'}]}\n")},
|
||||
"parts/one.yml": &fstest.MapFile{Data: []byte(failure.file)},
|
||||
}, failRead: failure.failRead, failStat: failure.failStat, failDir: failure.failDir}
|
||||
_, err := testLoad[importTestConfig](filesystemFile(newNativeNamespace("bundle", filesystem), "main.yml"), Options[importTestConfig]{Imports: true})
|
||||
@@ -166,7 +166,7 @@ func TestNativeFilesystemClosesFilesOnSuccessAndFailure(t *testing.T) {
|
||||
|
||||
func TestNativeFilesystemRootAndOptionalImports(t *testing.T) {
|
||||
filesystem := fstest.MapFS{
|
||||
"config/sub/main.yml": &fstest.MapFile{Data: []byte(`configkit:
|
||||
"config/sub/main.yml": &fstest.MapFile{Data: []byte(`config:
|
||||
imports:
|
||||
- path: ../shared.yml
|
||||
- path: absent.yml
|
||||
@@ -193,7 +193,7 @@ func TestNativeFilesystemRootAndOptionalImports(t *testing.T) {
|
||||
}
|
||||
|
||||
outside := fstest.MapFS{
|
||||
"config/sub/main.yml": &fstest.MapFile{Data: []byte("configkit: {imports: [{path: ../../outside.yml}]}\n")},
|
||||
"config/sub/main.yml": &fstest.MapFile{Data: []byte("config: {imports: [{path: ../../outside.yml}]}\n")},
|
||||
"outside.yml": &fstest.MapFile{Data: []byte("items: {outside: blocked}\n")},
|
||||
}
|
||||
outsideNamespace := newNativeNamespace("bundle", outside)
|
||||
@@ -221,7 +221,7 @@ func TestNativeFilesystemDetectsRepeatedAndCyclicImports(t *testing.T) {
|
||||
{
|
||||
name: "repeated",
|
||||
files: fstest.MapFS{
|
||||
"main.yml": &fstest.MapFile{Data: []byte("configkit: {imports: [{path: child.yml}, {path: child.yml}]}\n")},
|
||||
"main.yml": &fstest.MapFile{Data: []byte("config: {imports: [{path: child.yml}, {path: child.yml}]}\n")},
|
||||
"child.yml": &fstest.MapFile{Data: []byte("items: {child: child}\n")},
|
||||
},
|
||||
code: CodeImportRepeated,
|
||||
@@ -229,8 +229,8 @@ func TestNativeFilesystemDetectsRepeatedAndCyclicImports(t *testing.T) {
|
||||
{
|
||||
name: "cycle",
|
||||
files: fstest.MapFS{
|
||||
"main.yml": &fstest.MapFile{Data: []byte("configkit: {imports: [{path: child.yml}]}\n")},
|
||||
"child.yml": &fstest.MapFile{Data: []byte("configkit: {imports: [{path: main.yml}]}\n")},
|
||||
"main.yml": &fstest.MapFile{Data: []byte("config: {imports: [{path: child.yml}]}\n")},
|
||||
"child.yml": &fstest.MapFile{Data: []byte("config: {imports: [{path: main.yml}]}\n")},
|
||||
},
|
||||
code: CodeImportCycle,
|
||||
},
|
||||
|
||||
@@ -28,7 +28,7 @@ type layeredConfig struct {
|
||||
|
||||
func TestLayeredProvenanceAgreesWithResolvedSnapshot(t *testing.T) {
|
||||
directory := t.TempDir()
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `configkit:
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `config:
|
||||
imports: [{path: imported.yml}]
|
||||
shared: {equal: same}
|
||||
values: [1, 2]
|
||||
@@ -209,7 +209,7 @@ func TestSelectedOverlayLoadsRemainIndependentConcurrently(t *testing.T) {
|
||||
|
||||
func TestResolutionInputKeepsLayeredOriginsAndSources(t *testing.T) {
|
||||
directory := t.TempDir()
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `configkit:
|
||||
mainPath := writeImportFile(t, directory, "main.yml", `config:
|
||||
imports: [{path: first.yml}, {path: second.yml}]
|
||||
main: main
|
||||
equal: same
|
||||
@@ -361,7 +361,7 @@ func TestResolutionInputDistinguishesNonFileRootsAndImportedFiles(t *testing.T)
|
||||
Imported string `yaml:"imported"`
|
||||
Default string `yaml:"default"`
|
||||
}
|
||||
input := "configkit: {imports: [{path: fragment.yml}]}\nroot: memory\n"
|
||||
input := "config: {imports: [{path: fragment.yml}]}\nroot: memory\n"
|
||||
context := &FilesystemContext{BaseDir: directory, Root: directory}
|
||||
for _, test := range []struct {
|
||||
name string
|
||||
|
||||
@@ -151,11 +151,11 @@ func TestLoadingClosesNativeFilesAcrossPipelineOutcomes(t *testing.T) {
|
||||
{name: "success", main: "value: retained\n"},
|
||||
{name: "acquisition", main: "value: retained\n", failRead: "main.yml", wantErr: true},
|
||||
{name: "parse", main: "value: [broken\n", wantErr: true},
|
||||
{name: "composition", main: "configkit: {imports: [{path: child.yml}]}\nvalue: first\n", child: "value: second\n", options: Options[config]{Imports: true}, wantErr: true},
|
||||
{name: "composition", main: "config: {imports: [{path: child.yml}]}\nvalue: first\n", child: "value: second\n", options: Options[config]{Imports: true}, wantErr: true},
|
||||
{
|
||||
name: "nested item composition",
|
||||
main: "configkit: {imports: [{path: child.yml, destination: [children], placement: sequence-item}]}\nid: parent\n",
|
||||
child: "configkit: {imports: [{path: helper.yml}]}\nid: child\nvalue: child\n",
|
||||
main: "config: {imports: [{path: child.yml, destination: [children], placement: sequence-item}]}\nid: parent\n",
|
||||
child: "config: {imports: [{path: helper.yml}]}\nid: child\nvalue: child\n",
|
||||
helper: "value: helper\n",
|
||||
options: Options[config]{
|
||||
Imports: true, Destination: Keys("groups"), PlacementMode: PlacementModeSequenceItem,
|
||||
@@ -206,7 +206,7 @@ func TestDirectorySelectorsFailOnPostOpenNotExistErrors(t *testing.T) {
|
||||
{name: "glob no progress", selector: "glob", noProgress: true},
|
||||
} {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
main := "configkit:\n imports:\n"
|
||||
main := "config:\n imports:\n"
|
||||
if test.selector == "directory" {
|
||||
main += " - dir: [broken, good]\n pattern: '*.yml'\n"
|
||||
} else {
|
||||
@@ -324,7 +324,7 @@ func TestReadDirectoryVisitStopCloseNotExistIsPostOpen(t *testing.T) {
|
||||
func TestDirectorySelectorsKeepMissingRootsOptional(t *testing.T) {
|
||||
for _, selector := range []string{"directory", "glob"} {
|
||||
t.Run(selector, func(t *testing.T) {
|
||||
main := "configkit:\n imports:\n"
|
||||
main := "config:\n imports:\n"
|
||||
if selector == "directory" {
|
||||
main += " - dir: [missing, good]\n pattern: '*.yml'\n required: true\n"
|
||||
} else {
|
||||
@@ -347,7 +347,7 @@ func TestDirectorySelectorsKeepMissingRootsOptional(t *testing.T) {
|
||||
func TestDirectorySelectorsTreatMissingOnOpenAsOptional(t *testing.T) {
|
||||
for _, selector := range []string{"directory", "glob"} {
|
||||
t.Run(selector, func(t *testing.T) {
|
||||
main := "configkit:\n imports:\n"
|
||||
main := "config:\n imports:\n"
|
||||
if selector == "directory" {
|
||||
main += " - dir: [broken, good]\n pattern: '*.yml'\n required: true\n"
|
||||
} else {
|
||||
|
||||
@@ -43,7 +43,7 @@ func TestNonregularSourcesDoNotBlock(t *testing.T) {
|
||||
root := t.TempDir()
|
||||
input := "value: 1\n"
|
||||
if mode == "import" {
|
||||
input = "configkit:\n imports:\n - path: pipe.yml\n"
|
||||
input = "config:\n imports:\n - path: pipe.yml\n"
|
||||
}
|
||||
if err := os.WriteFile(filepath.Join(root, "config.yml"), []byte(input), 0600); err != nil {
|
||||
t.Fatal(err)
|
||||
|
||||
@@ -87,7 +87,7 @@ func BenchmarkUnderlayNativeImports(b *testing.B) {
|
||||
for _, count := range []int{16, 32, 64} {
|
||||
b.Run(strconv.Itoa(count), func(b *testing.B) {
|
||||
files := fstest.MapFS{
|
||||
"main.yml": &fstest.MapFile{Data: []byte("configkit: {imports: [{glob: 'defaults/*.yml'}]}\n")},
|
||||
"main.yml": &fstest.MapFile{Data: []byte("config: {imports: [{glob: 'defaults/*.yml'}]}\n")},
|
||||
}
|
||||
for index := range count {
|
||||
name := "item-" + strconv.Itoa(index)
|
||||
|
||||
Reference in New Issue
Block a user