diff --git a/pkg/api/testing/validation.go b/pkg/api/testing/validation.go index aab847ece4b..7bdd19fc64e 100644 --- a/pkg/api/testing/validation.go +++ b/pkg/api/testing/validation.go @@ -31,6 +31,7 @@ import ( utilfeature "k8s.io/apiserver/pkg/util/feature" featuregatetesting "k8s.io/component-base/featuregate/testing" "k8s.io/kubernetes/pkg/api/legacyscheme" + "sigs.k8s.io/randfill" ) // ValidateFunc is a function that runs validation. @@ -88,6 +89,13 @@ func VerifyVersionedValidationEquivalence(t *testing.T, obj, old runtime.Object, if internalObj == nil { return } + // We do fuzzing on the internal version of the object. + // This is because custom fuzzing function are only + // supported for internal objects. + // Fuzz the internal object if a fuzzer is provided. + if opts.Fuzzer != nil { + opts.Fuzzer.Fill(internalObj) + } if old == nil { runtimetest.RunValidationForEachVersion(t, legacyscheme.Scheme, []string{}, internalObj, accumulate, opts.IgnoreObjectConversionErrors, opts.SubResources...) } else { @@ -100,6 +108,10 @@ func VerifyVersionedValidationEquivalence(t *testing.T, obj, old runtime.Object, if internalOld == nil { return } + // Fuzz the internal old object if a fuzzer is provided. + if opts.Fuzzer != nil { + opts.Fuzzer.Fill(internalOld) + } runtimetest.RunUpdateValidationForEachVersion(t, legacyscheme.Scheme, []string{}, internalObj, internalOld, accumulate, opts.IgnoreObjectConversionErrors, opts.SubResources...) } @@ -205,6 +217,9 @@ type validationOption struct { // IgnoreObjectConversions skips the tests if the conversion from the internal object // to the versioned object fails. IgnoreObjectConversionErrors bool + + // Fuzzer is the fuzzer to use for generating test objects. + Fuzzer *randfill.Filler } func WithSubResources(subResources ...string) ValidationTestConfig { @@ -225,6 +240,12 @@ func WithIgnoreObjectConversionErrors() ValidationTestConfig { } } +func WithFuzzer(fuzzer *randfill.Filler) ValidationTestConfig { + return func(o *validationOption) { + o.Fuzzer = fuzzer + } +} + // VerifyValidationEquivalence provides a helper for testing the migration from // hand-written imperative validation to declarative validation. It ensures that // the validation logic remains consistent before and after the feature is enabled. diff --git a/pkg/api/testing/validation_test.go b/pkg/api/testing/validation_test.go index df8df8c8a78..62bee0bcef5 100644 --- a/pkg/api/testing/validation_test.go +++ b/pkg/api/testing/validation_test.go @@ -77,7 +77,6 @@ func TestVersionedValidationByFuzzing(t *testing.T) { if err != nil { t.Fatalf("could not create a %v: %s", kind, err) } - f.Fill(obj) var opts []ValidationTestConfig // TODO(API group level configuration): Consider configuring normalization rules at the @@ -85,9 +84,11 @@ func TestVersionedValidationByFuzzing(t *testing.T) { // This would allow each API group to register its own normalization rules independently. allRules := append([]field.NormalizationRule{}, resourcevalidation.ResourceNormalizationRules...) allRules = append(allRules, nodevalidation.NodeNormalizationRules...) - opts = append(opts, WithNormalizationRules(allRules...)) - if gv.Group == "autoscaling" { - opts = append(opts, WithIgnoreObjectConversionErrors()) + opts = append(opts, WithNormalizationRules(allRules...), WithFuzzer(f)) + + // Scale subresource needs to be specified explicitly. + if gv.Group == "autoscaling" && kind == "Scale" { + opts = append(opts, WithSubResources("scale")) } VerifyVersionedValidationEquivalence(t, obj, nil, opts...) @@ -96,7 +97,7 @@ func TestVersionedValidationByFuzzing(t *testing.T) { if err != nil { t.Fatalf("could not create a %v: %s", kind, err) } - f.Fill(old) + VerifyVersionedValidationEquivalence(t, obj, old, opts...) } })