Integrate collection policies across layered assembly

This commit is contained in:
2026-10-23 19:49:12 +00:00
parent 89a9684f0d
commit acd9e9a9fa
15 changed files with 269 additions and 93 deletions

View File

@@ -34,7 +34,7 @@ func TestDestinationPlacementCountsAgainstSharedNodeBudget(t *testing.T) {
t.Run(test.name, func(t *testing.T) {
t.Parallel()
accounting := &importAccounting{nodes: limits.nodes - perInput + test.delta}
composition, _, _, diagnostics := acquireUnderlayGroup(loadGroup{inputs: []loadInput{{
composition, _, _, diagnostics := testAcquireUnderlayGroup(loadGroup{inputs: []loadInput{{
source: empty, destination: destination,
}}}, 1, nil, accounting)
if test.wantError {
@@ -62,7 +62,7 @@ func TestMultipleMountedInputsSharePlacementCharges(t *testing.T) {
perInput := countInputNodes(&document.Node{Kind: document.Mapping}) + destinationWrapperNodeCount(Keys("collection", "one"))
charge := len(inputs) * perInput
accounting := &importAccounting{nodes: limits.nodes - charge}
composition, _, _, diagnostics := acquireUnderlayGroup(loadGroup{inputs: inputs}, 1, nil, accounting)
composition, _, _, diagnostics := testAcquireUnderlayGroup(loadGroup{inputs: inputs}, 1, nil, accounting)
if len(diagnostics) != 0 || composition == nil || accounting.nodes != limits.nodes || composition.inputNodes != charge {
t.Fatalf("shared placement accounting = %#v, %#v, accounting %#v; want charge %d", composition, diagnostics, accounting, charge)
}
@@ -107,7 +107,7 @@ id: parent
} {
t.Run(test.name, func(t *testing.T) {
accounting := &importAccounting{nodes: limits.nodes - wantNodes + test.delta}
composition, sources, _, diagnostics := acquireUnderlayGroup(loadGroup{inputs: []loadInput{{
composition, sources, _, diagnostics := testAcquireUnderlayGroup(loadGroup{inputs: []loadInput{{
source: File(mainPath), imports: true, destination: destination, placementMode: placementModeSequenceItem,
}, {
source: Mapping("other", map[string]any{"id": "other"}), destination: otherDestination, placementMode: placementModeSequenceItem,
@@ -160,7 +160,7 @@ func TestImportedEmptyBodiesChargeEachDestinationWrapper(t *testing.T) {
t.Run(test.name, func(t *testing.T) {
t.Parallel()
accounting := &importAccounting{nodes: limits.nodes - rawNodes - placementNodes + test.delta}
composition, sources, _, diagnostics := acquireUnderlayGroup(loadGroup{inputs: []loadInput{{
composition, sources, _, diagnostics := testAcquireUnderlayGroup(loadGroup{inputs: []loadInput{{
source: mainSource, imports: true, destination: destination,
}}}, 1, nil, accounting)
if test.wantError {
@@ -387,7 +387,7 @@ func TestNoSourceAndRootPlacementAddNoWrapperCharges(t *testing.T) {
t.Parallel()
accounting := &importAccounting{}
composition, sources, _, diagnostics := acquireUnderlayGroup(loadGroup{inputs: []loadInput{
composition, sources, _, diagnostics := testAcquireUnderlayGroup(loadGroup{inputs: []loadInput{
{source: NoSource(), destination: Keys("absent")},
{source: Mapping("root", map[string]any{})},
}}, 1, nil, accounting)

View File

@@ -224,7 +224,7 @@ func TestLayeredItemVersionProtectionTracksAssignedPeerIndexes(t *testing.T) {
t.Fatalf("unrelated appended peer rejected: %v", err)
}
entries := layeredMapValue(t, testLoaded(loaded).Config, "catalog", "entries").([]any)
if len(entries) != 1 || entries[0].(map[string]any)["id"] != "main" {
if len(entries) != 3 || entries[0].(map[string]any)["id"] != "first" || entries[1].(map[string]any)["id"] != "peer" || entries[2].(map[string]any)["id"] != "main" {
t.Fatalf("main item projection = %#v", entries)
}
})

View File

@@ -15,6 +15,7 @@ const (
rootDirectiveContextImportsOnly rootDirectiveContext = iota + 1
rootDirectiveContextSource
rootDirectiveContextOverlay
rootDirectiveContextLayered
)
type rootDirectiveExtraction struct {
@@ -78,7 +79,7 @@ func parseRootDirectiveBlock(node *document.Node, directivePath Path, context ro
diagnostics = append(diagnostics, nodeImportDiagnostic(CodeOverlayDirective, fieldPath, "overlays cannot contain imports", entry.Value))
continue
}
if context != rootDirectiveContextImportsOnly && context != rootDirectiveContextSource {
if context != rootDirectiveContextImportsOnly && context != rootDirectiveContextSource && context != rootDirectiveContextLayered {
diagnostics = append(diagnostics, nodeImportDiagnostic(CodeImportInvalid, fieldPath, "directive extraction context is invalid", entry.Value))
continue
}
@@ -91,7 +92,7 @@ func parseRootDirectiveBlock(node *document.Node, directivePath Path, context ro
diagnostics = append(diagnostics, sequenceDeclarationDiagnostic(fieldPath, "sequence declarations are not enabled in this extraction context", entry.Value))
continue
}
if context != rootDirectiveContextSource && context != rootDirectiveContextOverlay {
if context != rootDirectiveContextSource && context != rootDirectiveContextOverlay && context != rootDirectiveContextLayered {
diagnostics = append(diagnostics, sequenceDeclarationDiagnostic(fieldPath, "directive extraction context is invalid", entry.Value))
continue
}

View File

@@ -286,7 +286,7 @@ func loadImportedWithAccessTrackedAndProcessingPolicyDeferred(access *filesystem
parsed: main, composition: acquired, acquisition: cloneAcquisitionScopes(acquired.acquisition),
sources: state.sources, versionState: versionState, accounting: accounting,
}
composed, diagnostics := composeAcquiredInputWithPolicy(input, policy)
composed, diagnostics := composeAcquiredInputWithPolicies(input, collectionPolicyScope{}, policy)
return composed, cloneSourceInfos(state.sources), diagnostics
}
@@ -294,10 +294,6 @@ func loadImportedWithAccessTrackedAndProcessingPolicyDeferred(access *filesystem
// acquisition scopes to the established strict-composition behavior. It uses
// the already acquired documents and graph; source handles are closed before
// this handoff.
func composeAcquiredInputWithPolicy(input assembledInput, policy sequencePolicy) (*composedDocument, []Diagnostic) {
return composeAcquiredInputWithPolicies(input, collectionPolicyScope{}, policy)
}
func composeAcquiredInputWithPolicies(input assembledInput, lower collectionPolicyScope, policy sequencePolicy) (*composedDocument, []Diagnostic) {
if input.composition == nil || input.composition.root != nil || len(input.composition.acquisition) == 0 {
return input.composition, nil

View File

@@ -169,13 +169,15 @@ func executeLoadRequest[T any](request loadRequest[T], secrets SecretBinding, lo
mainOptions := Options[T]{Definition: request.definition, Imports: request.main.imports, Filesystem: request.main.filesystem, destination: request.main.destination.clone(), placementMode: request.main.placementMode}
mainOptions.importDefaults = snapshotImportDefaults(request.importDefaults)
mainOptions.sequencePolicy = request.sequencePolicy
mainOptions.deferAssembly = request.ordinary
mainOptions.deferAssembly = true
mainOptions.SourceVersionMode = request.sourceVersionMode
mainOptions.Definition.Version = request.protectionVersion()
mainOptions.Overrides = request.overrides
if request.ordinary {
mainOptions.Overlay = request.overlay
mainOptions.directiveContext = rootDirectiveContextSource
} else {
mainOptions.directiveContext = rootDirectiveContextLayered
}
var schema *schemaDescriptor
@@ -216,7 +218,7 @@ func executeLoadRequest[T any](request loadRequest[T], secrets SecretBinding, lo
}
input.document = input.composition.root
}
if request.sourceVersionMode == sourceVersionModeDefault {
if request.sourceVersionMode == sourceVersionModeDefault && request.ordinary {
versionDiagnostics := checkVersion(request.definition.Version, input.document)
accumulator.add(versionDiagnostics...)
if hasErrors(versionDiagnostics) {

View File

@@ -129,7 +129,7 @@ func assembleBaseInputTrackedForRole[T any](source Source, options Options[T], d
}
if !options.Imports && parsed.document != nil {
var directiveDiagnostics []Diagnostic
if directiveContext == rootDirectiveContextSource {
if directiveContext == rootDirectiveContextSource || directiveContext == rootDirectiveContextLayered {
directiveDiagnostics = disabledRootImportDiagnostics(parsed.document)
} else {
directiveDiagnostics = disabledDirectiveDiagnostics(parsed.document, Path{})
@@ -159,6 +159,33 @@ func assembleBaseInputTrackedForRole[T any](source Source, options Options[T], d
if role == sourceVersionMain && versionState != nil {
versionState.mainProcessing = &processed
}
} else if directiveContext == rootDirectiveContextLayered {
extracted, failures := extractRootDirectives(parsed.document, rootDirectiveContextLayered)
if len(failures) != 0 {
return input, failures
}
processed := sourceVersionProcessingResult{
payload: extracted.body, imports: extracted.imports, sequences: extracted.sequences,
directiveContext: rootDirectiveContextLayered,
}
if versionState != nil && versionState.mode != sourceVersionModeDefault {
var sourceID string
if parsed.source != nil {
sourceID = parsed.source.ID
}
versionProcessed, versionFailures := versionState.process(extracted.body, role, destination, sourceID, options.placementMode)
if len(versionFailures) != 0 {
return input, versionFailures
}
versionProcessed.imports = extracted.imports
versionProcessed.sequences = append(cloneSequenceDeclarations(extracted.sequences), versionProcessed.sequences...)
versionProcessed.directiveContext = rootDirectiveContextLayered
processed = versionProcessed
if role == sourceVersionMain {
versionState.mainProcessing = &processed
}
}
versionProcessing = &processed
} else if versionState != nil && versionState.mode != sourceVersionModeDefault {
var sourceID string
if parsed.source != nil {
@@ -302,9 +329,13 @@ func compositionForInput(input assembledInput) (*composedDocument, []Diagnostic)
}
func compositionForInputWithPolicy(input assembledInput, policy sequencePolicy) (*composedDocument, []Diagnostic) {
return compositionForInputWithPolicies(input, collectionPolicyScope{}, policy)
}
func compositionForInputWithPolicies(input assembledInput, lower collectionPolicyScope, policy sequencePolicy) (*composedDocument, []Diagnostic) {
if input.composition != nil {
if input.composition.root == nil && len(input.composition.acquisition) != 0 {
return composeAcquiredInputWithPolicy(input, policy)
return composeAcquiredInputWithPolicies(input, lower, policy)
}
return input.composition, nil
}
@@ -318,12 +349,12 @@ func compositionForInputWithPolicy(input assembledInput, policy sequencePolicy)
acquired.inputNodes = countInputNodes(input.parsed.document)
}
input.composition = acquired
return composeAcquiredInputWithPolicy(input, policy)
return composeAcquiredInputWithPolicies(input, lower, policy)
}
if input.document == nil {
return &composedDocument{root: &document.Node{Kind: document.Mapping}, origins: make(map[string]Origin)}, nil
}
composition, diagnostics := composeDocumentsWithPolicy(policy, input.document)
composition, diagnostics := composeDocumentsWithCollectionPolicy(policy, lower, nil, input.document)
if len(diagnostics) != 0 {
return nil, diagnostics
}

View File

@@ -92,7 +92,7 @@ func loadGroupedWithSecretLookup[T any](request loadRequest[T], secrets SecretBi
}
func assembleLayeredInput[T any](request loadRequest[T], input assembledInput, accounting *importAccounting) (assembledInput, []Diagnostic) {
groups := make([]*composedDocument, 0, len(request.underlays))
var assembly *assemblyAccumulator
for index, group := range request.underlays {
acquired, diagnostics := acquireUnderlayGroupScopes(group, index+1, request.protectionVersion(), accounting, input.versionState, request.sequencePolicy)
mergeResourceContexts(&input.contexts, acquired.contexts)
@@ -100,35 +100,71 @@ func assembleLayeredInput[T any](request loadRequest[T], input assembledInput, a
input.sources = append(input.sources, acquired.sources...)
return input, diagnostics
}
composition, diagnostics := composeUnderlayGroup(acquired, request.protectionVersion(), request.sequencePolicy, collectionPolicyScope{})
var lower collectionPolicyScope
if assembly != nil && assembly.current != nil {
lower = assembly.current.collectionPolicies
}
composition, diagnostics := composeUnderlayGroup(acquired, request.protectionVersion(), request.sequencePolicy, lower)
input.sources = append(input.sources, acquired.sources...)
if len(diagnostics) != 0 {
return input, diagnostics
}
if composition != nil {
groups = append(groups, composition)
if assembly == nil {
assembly = newAssemblyAccumulator(composition)
} else {
var declarations []sequenceDeclarationSpec
for _, scope := range composition.acquisition {
declarations = append(declarations, acquiredSequenceDeclarations(scope)...)
}
if diagnostics := assembly.applyOverlayWithCollectionPolicy(
composition.root, composition.origins, composition.applications, LayerUnderlay,
request.sequencePolicy, declarations,
); len(diagnostics) != 0 {
return input, diagnostics
}
}
}
}
var assembly *assemblyAccumulator
for _, group := range groups {
if assembly == nil {
assembly = newAssemblyAccumulator(group)
continue
mainPresent := input.document != nil || input.composition != nil || len(input.acquisition) != 0
var mainComposition *composedDocument
if mainPresent {
var lower collectionPolicyScope
if assembly != nil && assembly.current != nil {
lower = assembly.current.collectionPolicies
}
if diagnostics := assembly.applyOverlay(group.root, group.origins, group.applications, LayerUnderlay); len(diagnostics) != 0 {
return input, diagnostics
}
}
if input.document != nil {
mainComposition, diagnostics := compositionForInputWithPolicy(input, request.sequencePolicy)
var diagnostics []Diagnostic
mainComposition, diagnostics = compositionForInputWithPolicies(input, lower, request.sequencePolicy)
if len(diagnostics) != 0 {
return input, diagnostics
}
}
if request.sourceVersionMode == sourceVersionModeDefault {
var mainRoot *document.Node
if mainComposition != nil {
mainRoot = mainComposition.root
} else if input.document != nil {
mainRoot = input.document
}
if diagnostics := checkVersion(request.definition.Version, mainRoot); hasErrors(diagnostics) {
return input, diagnostics
}
}
if mainComposition != nil {
if assembly == nil {
assembly = newAssemblyAccumulator(mainComposition)
} else if diagnostics := assembly.applyOverlay(mainComposition.root, mainComposition.origins, mainComposition.applications, LayerBase); len(diagnostics) != 0 {
return input, diagnostics
} else {
var declarations []sequenceDeclarationSpec
for _, scope := range mainComposition.acquisition {
declarations = append(declarations, acquiredSequenceDeclarations(scope)...)
}
if diagnostics := assembly.applyOverlayWithCollectionPolicy(
mainComposition.root, mainComposition.origins, mainComposition.applications, LayerBase,
request.sequencePolicy, declarations,
); len(diagnostics) != 0 {
return input, diagnostics
}
}
}
if assembly == nil && (activeOverlay(request.overlay) || len(request.overrides) != 0) {
@@ -146,10 +182,7 @@ func assembleLayeredInput[T any](request loadRequest[T], input assembledInput, a
selection := Source{kind: sourceBytes}
selected := parsedSource{document: &document.Node{Kind: document.Mapping}, source: &SourceInfo{}}
var diagnostics []Diagnostic
var overlayPolicy []sequencePolicy
if request.ordinary {
overlayPolicy = []sequencePolicy{request.sequencePolicy}
}
overlayPolicy := []sequencePolicy{request.sequencePolicy}
input.sources, diagnostics = loadSelectedOverlayIntoWithVersion(selection, request.overlayFilesystem, selected, assembly, input.sources, request.overlay, request.protectionVersion(), defaultImportLimits(), input.versionState, overlayPolicy...)
if len(diagnostics) != 0 {
return input, diagnostics
@@ -172,23 +205,6 @@ func assembleLayeredInput[T any](request loadRequest[T], input assembledInput, a
return input, nil
}
func acquireUnderlayGroup(group loadGroup, index int, rule *VersionRule, accounting *importAccounting) (*composedDocument, []SourceInfo, map[string]ResourceContext, []Diagnostic) {
return acquireUnderlayGroupWithVersion(group, index, rule, accounting, nil)
}
func acquireUnderlayGroupWithVersion(group loadGroup, index int, rule *VersionRule, accounting *importAccounting, versionState *sourceVersionState) (*composedDocument, []SourceInfo, map[string]ResourceContext, []Diagnostic) {
return acquireUnderlayGroupWithPolicyVersion(group, index, rule, accounting, versionState, sequencePolicy{})
}
func acquireUnderlayGroupWithPolicyVersion(group loadGroup, index int, rule *VersionRule, accounting *importAccounting, versionState *sourceVersionState, policy sequencePolicy) (*composedDocument, []SourceInfo, map[string]ResourceContext, []Diagnostic) {
acquired, diagnostics := acquireUnderlayGroupScopes(group, index, rule, accounting, versionState, policy)
if len(diagnostics) != 0 {
return nil, acquired.sources, acquired.contexts, diagnostics
}
composition, diagnostics := composeUnderlayGroup(acquired, rule, policy, collectionPolicyScope{})
return composition, acquired.sources, acquired.contexts, diagnostics
}
func acquireUnderlayGroupScopes(group loadGroup, index int, rule *VersionRule, accounting *importAccounting, versionState *sourceVersionState, policy sequencePolicy) (*acquiredUnderlayGroup, []Diagnostic) {
initialBytes, initialNodes := accounting.bytes, accounting.nodes
visited := make(map[resourceIdentity]importRoute)
@@ -208,6 +224,7 @@ func acquireUnderlayGroupScopes(group loadGroup, index int, rule *VersionRule, a
Imports: contribution.imports, Filesystem: contribution.filesystem,
Definition: Definition[struct{}]{Version: rule}, destination: contribution.destination.clone(),
placementMode: contribution.placementMode, sequencePolicy: policy, deferAssembly: true,
directiveContext: rootDirectiveContextLayered,
importDefaults: func() importDefaults {
if versionState == nil {
return importDefaults{}

View File

@@ -355,6 +355,69 @@ 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"))
duplicate := func(name string) loadInput {
return loadInput{source: Bytes(name, []byte("items: [{id: repeated}]\n"))}
}
request := loadRequest[map[string]any]{
main: loadInput{source: NoSource()},
underlays: []loadGroup{
{inputs: []loadInput{{source: policyOnly}}},
{inputs: []loadInput{duplicate("first-peer"), duplicate("second-peer")}},
},
}
if _, err := testGroupedLoad(request); err != nil && groupedErrorCode(t, err) != CodeComposeConflict {
loadErr, _ := err.(*LoadError)
t.Fatalf("higher strict group code = %s, want %s: %#v", groupedErrorCode(t, err), CodeComposeConflict, loadErr.Diagnostics())
} else if err == nil {
t.Fatal("higher strict group accepted duplicate inherited identities")
}
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{duplicate("higher")}},
},
}
if _, err := testGroupedLoad(request); err == nil || groupedErrorCode(t, err) != CodeSequenceConflict {
t.Fatalf("higher tier did not inherit explicit append mode: %v", err)
}
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"))}}}},
}
result, err := testGroupedLoad(request)
if err != nil || !reflect.DeepEqual(result.Config["items"], []any{map[string]any{"name": "higher"}}) {
var diagnostics []Diagnostic
if loadErr, ok := err.(*LoadError); ok {
diagnostics = loadErr.Diagnostics()
}
t.Fatalf("replacement did not retire lower identity: %#v, %v (%#v)", result, err, diagnostics)
}
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")},
})
definition := Definition[map[string]any]{sequenceRegistrations: []sequenceRegistration{{path: Keys("items"), identityField: "id"}}}
request = loadRequest[map[string]any]{
main: loadInput{source: Bytes("main", []byte("items: [{id: main}]\n"))},
underlays: []loadGroup{{inputs: []loadInput{{source: Bytes("lower", []byte("items: [{id: lower}]\n"))}}}},
definition: definition, sequencePolicy: mustCompileSequencePolicy(t, definition.sequenceRegistrations),
overlay: "testing", overlayFilesystem: &FilesystemContext{Root: ".", BaseDir: ".", FS: &filesystem},
}
result, err = testGroupedLoad(request)
if err != nil || !reflect.DeepEqual(result.Config["items"], []any{
map[string]any{"id": "lower"}, map[string]any{"id": "main"}, map[string]any{"id": "overlay"},
}) {
t.Fatalf("layered selected overlay sequence policy = %#v, %v", result, err)
}
}
func TestGroupedLoadStrictConflictsRepetitionAndBudgets(t *testing.T) {
main := loadInput{source: Bytes("main", []byte("port: 5\n"))}
request := loadRequest[groupedConfig]{
@@ -393,18 +456,27 @@ func TestGroupedLoadStrictConflictsRepetitionAndBudgets(t *testing.T) {
accounting := &importAccounting{sources: maxImportSources - 1}
group := loadGroup{inputs: []loadInput{{source: Mapping("first", map[string]any{})}, {source: Mapping("second", map[string]any{})}}}
_, _, _, diagnostics := acquireUnderlayGroup(group, 1, nil, accounting)
_, _, _, diagnostics := testAcquireUnderlayGroup(group, 1, nil, accounting)
if len(diagnostics) == 0 || diagnostics[0].Code != CodeSourceLimitExceeded {
t.Fatalf("shared source budget = %#v", diagnostics)
}
accounting = &importAccounting{bytes: maxTotalBytes - 2}
group.inputs = []loadInput{{source: Mapping("first", map[string]any{"port": "one"})}}
_, _, _, diagnostics = acquireUnderlayGroup(group, 1, nil, accounting)
_, _, _, diagnostics = testAcquireUnderlayGroup(group, 1, nil, accounting)
if len(diagnostics) == 0 || diagnostics[0].Code != CodeSourceLimitExceeded {
t.Fatalf("shared byte budget = %#v", diagnostics)
}
}
func testAcquireUnderlayGroup(group loadGroup, index int, rule *VersionRule, accounting *importAccounting) (*composedDocument, []SourceInfo, map[string]ResourceContext, []Diagnostic) {
acquired, diagnostics := acquireUnderlayGroupScopes(group, index, rule, accounting, nil, sequencePolicy{})
if len(diagnostics) != 0 {
return nil, acquired.sources, acquired.contexts, diagnostics
}
composition, diagnostics := composeUnderlayGroup(acquired, rule, sequencePolicy{}, collectionPolicyScope{})
return composition, acquired.sources, acquired.contexts, diagnostics
}
func TestGroupedLoadInvalidIntermediateTypeCanBeReplaced(t *testing.T) {
request := loadRequest[groupedConfig]{
main: loadInput{source: Bytes("main", []byte("port: 9\n"))},
@@ -446,11 +518,11 @@ func TestGroupedAccountingChargesMixedOccurrencesOnce(t *testing.T) {
"child-two.yml": &fstest.MapFile{Data: []byte(child)},
})
accounting := &importAccounting{}
first, sources, _, diagnostics := acquireUnderlayGroup(loadGroup{inputs: []loadInput{{source: filesystem.File("one.yml"), imports: true}}}, 1, nil, accounting)
first, sources, _, diagnostics := testAcquireUnderlayGroup(loadGroup{inputs: []loadInput{{source: filesystem.File("one.yml"), imports: true}}}, 1, nil, accounting)
if len(diagnostics) != 0 || first == nil || len(sources) != 2 || accounting.sources != 2 || accounting.bytes != int64(len(one)+len(child)) {
t.Fatalf("first acquisition = %#v, %#v, %#v, accounting %#v", first, sources, diagnostics, accounting)
}
second, sources, _, diagnostics := acquireUnderlayGroup(loadGroup{inputs: []loadInput{{source: filesystem.File("two.yml"), imports: true}}}, 2, nil, accounting)
second, sources, _, diagnostics := testAcquireUnderlayGroup(loadGroup{inputs: []loadInput{{source: filesystem.File("two.yml"), imports: true}}}, 2, nil, accounting)
if len(diagnostics) != 0 || second == nil || len(sources) != 2 || sources[0].ID != "source-3" || sources[1].ID != "source-4" || accounting.sources != 4 || accounting.bytes != int64(len(one)+len(two)+2*len(child)) {
t.Fatalf("second acquisition = %#v, %#v, %#v, accounting %#v", second, sources, diagnostics, accounting)
}
@@ -477,7 +549,7 @@ func TestGroupedGlobEntryBudgetIsShared(t *testing.T) {
"parts/b.yml": &fstest.MapFile{Data: []byte("right: two\n")},
})
accounting := &importAccounting{entries: maxGlobEntries - 1}
_, _, _, diagnostics := acquireUnderlayGroup(loadGroup{inputs: []loadInput{{source: filesystem.File("main.yml"), imports: true}}}, 1, nil, accounting)
_, _, _, diagnostics := testAcquireUnderlayGroup(loadGroup{inputs: []loadInput{{source: filesystem.File("main.yml"), imports: true}}}, 1, nil, accounting)
if len(diagnostics) == 0 || diagnostics[0].Code != CodeImportLimitExceeded || accounting.entries <= maxGlobEntries {
t.Fatalf("shared glob budget = %#v, accounting %#v", diagnostics, accounting)
}

View File

@@ -320,7 +320,7 @@ func TestRegisteredSequencePolicyAcrossLoadingLifecycle(t *testing.T) {
}
})
t.Run("strict underlay group appends while separate tiers reset identities", func(t *testing.T) {
t.Run("registered sequence policy appends across strict groups and tiers", func(t *testing.T) {
request := loadRequest[config]{
main: loadInput{source: Bytes("main", []byte("items: [{id: shared}]\n"))},
underlays: []loadGroup{{inputs: []loadInput{
@@ -330,7 +330,7 @@ func TestRegisteredSequencePolicyAcrossLoadingLifecycle(t *testing.T) {
definition: definition, sequencePolicy: mustCompileSequencePolicy(t, definition.sequenceRegistrations),
}
result, err := testGroupedLoad(request)
if err != nil || len(result.Config.Items) != 1 || result.Config.Items[0].ID != "shared" {
if err != nil || len(result.Config.Items) != 3 || result.Config.Items[0].ID != "lower" || result.Config.Items[1].ID != "other" || result.Config.Items[2].ID != "shared" {
t.Fatalf("grouped load = %#v, %v", result, err)
}
@@ -344,7 +344,7 @@ func TestRegisteredSequencePolicyAcrossLoadingLifecycle(t *testing.T) {
}
})
t.Run("empty registered contribution clears lower sequence", func(t *testing.T) {
t.Run("empty registered contribution follows the accumulated sequence mode", func(t *testing.T) {
result, err := testLoad[config](Bytes("main", []byte("items: []\n")), registered)
if err != nil || len(result.Config.Items) != 0 {
t.Fatalf("empty sequence load = %#v, %v", result, err)
@@ -355,7 +355,7 @@ func TestRegisteredSequencePolicyAcrossLoadingLifecycle(t *testing.T) {
definition: definition, sequencePolicy: mustCompileSequencePolicy(t, definition.sequenceRegistrations),
}
result, err = testGroupedLoad(request)
if err != nil || len(result.Config.Items) != 0 {
if err != nil || len(result.Config.Items) != 1 || result.Config.Items[0].ID != "lower" {
t.Fatalf("empty higher tier = %#v, %v", result, err)
}
})