package engine import ( "testing" "gitea.maximumdirect.net/eric/ConfigKit/internal/document" ) type historyBudgetSimpleConfig struct { Value string } type historyBudgetRecord struct { Value string Credential Secret } type historyBudgetLayeredConfig struct { Parent historyBudgetRecord Child historyBudgetRecord } func retainedInspectionNodeCountForTest(inspection *Inspection) int { seen := make(map[*document.Node]struct{}) stack := []*document.Node{inspection.baseline, inspection.input, inspection.final, inspection.preCLI} for _, application := range inspection.applications { stack = append(stack, application.value) } for _, application := range inspection.postDecodeApps { stack = append(stack, application.value) } for _, snapshot := range inspection.resolution { stack = append(stack, snapshot.before, snapshot.after) } for _, snapshot := range inspection.resolutionReplay { stack = append(stack, snapshot.before, snapshot.after) } for _, operation := range inspection.inheritance { stack = append(stack, operation.parent, operation.effective) } for _, operation := range inspection.metadata.inheritance { stack = append(stack, operation.parent, operation.effective) } for len(stack) != 0 { last := len(stack) - 1 node := stack[last] stack = stack[:last] if node == nil { continue } if _, exists := seen[node]; exists { continue } seen[node] = struct{}{} for _, entry := range node.Mapping { stack = append(stack, entry.Value) } stack = append(stack, node.Sequence...) } return len(seen) } func TestLoadHistoryBudgetUsesExactRetainedNodeCount(t *testing.T) { load := func(historyLimit int, validations *int) (*Loaded[historyBudgetSimpleConfig], error) { return loadWithSecretLookupLimit( Bytes("main", []byte("value: retained\n")), testSecretBinding(), func(string) (string, bool) { return "", false }, historyLimit, Options[historyBudgetSimpleConfig]{Definition: Definition[historyBudgetSimpleConfig]{ Validate: func(*historyBudgetSimpleConfig, *Validation) { *validations++ }, }}, ) } var baselineValidations int baseline, err := load(10000, &baselineValidations) if err != nil { t.Fatalf("baseline load: %v", err) } want := retainedInspectionNodeCountForTest(baseline.Inspection) if want == 0 { t.Fatal("independent retained-tree count was empty") } var exactValidations int loaded, err := load(want, &exactValidations) if err != nil || loaded == nil { t.Fatalf("load at exact retained-node count %d: result=%v error=%v", want, loaded, err) } if got := retainedInspectionNodeCountForTest(loaded.Inspection); got != want { t.Fatalf("retained node count = %d, want %d", got, want) } if exactValidations != 1 { t.Fatalf("validation calls at exact count = %d, want 1", exactValidations) } var rejectedValidations int loaded, err = load(want-1, &rejectedValidations) if loaded != nil || !hasHistoryLimitDiagnostic(t, err) { t.Fatalf("load below retained-node count: result=%v error=%v", loaded, err) } if rejectedValidations != 0 { t.Fatalf("validation ran before history rejection: %d calls", rejectedValidations) } } func TestLayeredHistoryBudgetRejectsBeforeSecretsAndValidation(t *testing.T) { type callbackCounts struct { lookups int validations int } makeRequest := func(counts *callbackCounts) loadRequest[historyBudgetLayeredConfig] { return loadRequest[historyBudgetLayeredConfig]{ main: loadInput{source: Bytes("main", []byte("child:\n extends: parent\n"))}, underlays: []loadGroup{{inputs: []loadInput{{source: Bytes("underlay", []byte( "parent:\n value: inherited\n credential: HISTORY_BUDGET_SECRET\n", ))}}}}, overrides: []Override{{Path: Keys("child", "value"), Value: "cli", Flag: "--child-value"}}, definition: Definition[historyBudgetLayeredConfig]{ Resolve: func(configuration *historyBudgetLayeredConfig, resolution *Resolution) error { configuration.Child.Value += "-resolved" resolution.Record(Keys("child", "value"), ChangeNormalization, "normalize child") return nil }, Validate: func(*historyBudgetLayeredConfig, *Validation) { counts.validations++ }, }, } } lookup := func(counts *callbackCounts) secretLookup { return func(name string) (string, bool) { counts.lookups++ if name != "HISTORY_BUDGET_SECRET" { t.Errorf("secret lookup name = %q", name) } return "resolved-secret", true } } baselineCounts := &callbackCounts{} baseline, err := loadGroupedWithSecretLookupLimit(makeRequest(baselineCounts), testSecretBinding(), lookup(baselineCounts), 10000) if err != nil { t.Fatalf("baseline grouped load: %v", err) } want := retainedInspectionNodeCountForTest(baseline.Inspection) if want == 0 { t.Fatal("independent retained-tree count was empty") } if len(baseline.Inspection.inheritance) == 0 || len(baseline.Inspection.metadata.inheritance) == 0 { t.Fatal("layered load did not retain both inheritance evidence copies") } exactCounts := &callbackCounts{} loaded, err := loadGroupedWithSecretLookupLimit(makeRequest(exactCounts), testSecretBinding(), lookup(exactCounts), want) if err != nil || loaded == nil { t.Fatalf("grouped load at exact retained-node count %d: result=%v error=%v", want, loaded, err) } if got := retainedInspectionNodeCountForTest(loaded.Inspection); got != want { t.Fatalf("grouped retained node count = %d, want %d", got, want) } if loaded.Config.Child.Value != "cli-resolved" || exactCounts.lookups != 1 || exactCounts.validations != 1 { t.Fatalf("grouped lifecycle result=%#v callbacks=%#v", loaded.Config, exactCounts) } rejectedCounts := &callbackCounts{} loaded, err = loadGroupedWithSecretLookupLimit(makeRequest(rejectedCounts), testSecretBinding(), lookup(rejectedCounts), want-1) if loaded != nil || !hasHistoryLimitDiagnostic(t, err) { t.Fatalf("grouped load below retained-node count: result=%v error=%v", loaded, err) } if rejectedCounts.lookups != 0 || rejectedCounts.validations != 0 { t.Fatalf("callbacks ran before history rejection: %#v", rejectedCounts) } } func TestPreparedInheritanceEvidenceOwnsDistinctTrees(t *testing.T) { root := &document.Node{Kind: document.Mapping, Mapping: []document.Entry{{Key: "value", Value: &document.Node{Kind: document.String, Text: "shared"}}}} resolved := resolvedLoad[historyBudgetSimpleConfig]{ inheritance: &inheritanceScope{operations: []inheritanceOperation{{parent: root, effective: root}}}, } counter := newRetainedNodeCounter(8) inspection, ok := prepareInspectionHistory(resolved, counter) if !ok { t.Fatal("preparation rejected the exact size of the distinct retained copies") } if len(inspection.inheritance) != 1 || len(inspection.metadata.inheritance) != 1 { t.Fatalf("inheritance copies = inspection %#v, metadata %#v", inspection.inheritance, inspection.metadata.inheritance) } inspectionOperation := inspection.inheritance[0] metadataOperation := inspection.metadata.inheritance[0] if inspectionOperation.parent == metadataOperation.parent || inspectionOperation.effective == metadataOperation.effective || counter.count != 8 { t.Fatalf("separate inheritance copies were not counted independently: inspection=(%p, %p) metadata=(%p, %p) count=%d", inspectionOperation.parent, inspectionOperation.effective, metadataOperation.parent, metadataOperation.effective, counter.count) } } func hasHistoryLimitDiagnostic(t *testing.T, err error) bool { t.Helper() if err == nil { return false } loadErr, ok := err.(*LoadError) if !ok { t.Fatalf("error type = %T, want *LoadError", err) } for _, diagnostic := range loadErr.Diagnostics() { if diagnostic.Code == CodeExplainLimitExceeded { return true } } return false }