102 lines
3.3 KiB
Go
102 lines
3.3 KiB
Go
package engine
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"os/exec"
|
|
"reflect"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
type sliceBudgetConfig struct {
|
|
Values []string `yaml:"values"`
|
|
}
|
|
|
|
type arrayBudgetConfig struct {
|
|
Values [1]string `yaml:"values"`
|
|
}
|
|
|
|
type mapBudgetConfig struct {
|
|
Values map[string]string `yaml:"values"`
|
|
}
|
|
|
|
type inlineBudgetFields struct {
|
|
Name string `yaml:"name"`
|
|
}
|
|
|
|
type inlineStructBudgetConfig struct {
|
|
Fields inlineBudgetFields `yaml:",inline"`
|
|
}
|
|
|
|
type inlineMapBudgetConfig struct {
|
|
Fields map[string]string `yaml:",inline"`
|
|
}
|
|
|
|
type hugeZeroBudgetConfig struct {
|
|
Values []struct{} `yaml:"values"`
|
|
}
|
|
|
|
func TestProjectionChecksMinimumContainerNodes(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
typeOf reflect.Type
|
|
value any
|
|
exact int
|
|
}{
|
|
{name: "slice", typeOf: reflect.TypeFor[sliceBudgetConfig](), value: sliceBudgetConfig{Values: []string{"x"}}, exact: 4},
|
|
{name: "array", typeOf: reflect.TypeFor[arrayBudgetConfig](), value: arrayBudgetConfig{Values: [1]string{"x"}}, exact: 4},
|
|
{name: "map", typeOf: reflect.TypeFor[mapBudgetConfig](), value: mapBudgetConfig{Values: map[string]string{"x": "y"}}, exact: 5},
|
|
{name: "inline struct", typeOf: reflect.TypeFor[inlineStructBudgetConfig](), value: inlineStructBudgetConfig{Fields: inlineBudgetFields{Name: "x"}}, exact: 3},
|
|
{name: "inline map", typeOf: reflect.TypeFor[inlineMapBudgetConfig](), value: inlineMapBudgetConfig{Fields: map[string]string{"x": "y"}}, exact: 3},
|
|
}
|
|
for _, test := range tests {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
schema, issue := buildSchema(test.typeOf, testSecretBinding())
|
|
if issue != nil {
|
|
t.Fatal(issue.message)
|
|
}
|
|
for _, limits := range []struct {
|
|
name string
|
|
nodes int
|
|
fail bool
|
|
}{{name: "exact", nodes: test.exact}, {name: "insufficient", nodes: test.exact - 1, fail: true}} {
|
|
t.Run(limits.name, func(t *testing.T) {
|
|
_, projectionIssue := projectConfiguration(schema, reflect.ValueOf(test.value), projectionLimits{depth: maxDocumentDepth, nodes: limits.nodes})
|
|
if limits.fail {
|
|
if projectionIssue == nil || projectionIssue.code != CodeSchemaProjectionLimit {
|
|
t.Fatalf("projection issue = %#v, want limit failure", projectionIssue)
|
|
}
|
|
} else if projectionIssue != nil {
|
|
t.Fatalf("exact-budget projection issue = %#v", projectionIssue)
|
|
}
|
|
})
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestProjectionRejectsMaximumZeroSizedSliceBeforeAllocation(t *testing.T) {
|
|
if os.Getenv("CONFIGKIT_HUGE_ZERO_SLICE_TEST") != "" {
|
|
schema := mustSchemaFor[hugeZeroBudgetConfig](t)
|
|
value := hugeZeroBudgetConfig{Values: make([]struct{}, int(^uint(0)>>1))}
|
|
_, issue := projectConfiguration(schema, reflect.ValueOf(value), defaultProjectionLimits())
|
|
if issue == nil || issue.code != CodeSchemaProjectionLimit {
|
|
t.Fatalf("projection issue = %#v, want a safe limit failure", issue)
|
|
}
|
|
return
|
|
}
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
|
defer cancel()
|
|
command := exec.CommandContext(ctx, os.Args[0], "-test.run=^TestProjectionRejectsMaximumZeroSizedSliceBeforeAllocation$")
|
|
command.Env = append(os.Environ(), "CONFIGKIT_HUGE_ZERO_SLICE_TEST=1")
|
|
output, err := command.CombinedOutput()
|
|
if ctx.Err() != nil {
|
|
t.Fatalf("maximum-length zero-sized slice projection did not terminate: %s", output)
|
|
}
|
|
if err != nil {
|
|
t.Fatalf("maximum-length zero-sized slice projection failed: %v, %s", err, output)
|
|
}
|
|
}
|