Integrate collection policies across layered assembly
This commit is contained in:
@@ -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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user