Merge pull request #136620 from yongruilin/master_vg-fix-fuzz

fix DeclarativeValidation fuzzing test panic and refactor subresource handlin
This commit is contained in:
Kubernetes Prow Robot 2026-01-30 03:08:04 +05:30 committed by GitHub
commit c8e45a3331
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 42 additions and 5 deletions

View file

@ -32,6 +32,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.
@ -89,6 +90,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 {
@ -101,6 +109,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...)
}
@ -206,6 +218,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 {
@ -226,6 +241,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.

View file

@ -65,6 +65,18 @@ func TestVersionedValidationByFuzzing(t *testing.T) {
{Group: "admissionregistration.k8s.io", Version: "v1alpha1"},
}
// subresourceOnly specifies the subresource path for types that can only be validated
// as subresources (e.g. autoscaling/Scale) and do not support root-level validation.
// For GVKs not in this map, the test defaults to fuzzing the root resource ("").
// Other resources with subresources (e.g. Pod status, exec) share validation logic with
// the root resource, so fuzzing the root is sufficient to verify validation equivalence.
subresourceOnly := map[schema.GroupVersionKind]string{
{Group: "autoscaling", Version: "v1", Kind: "Scale"}: "scale",
{Group: "autoscaling", Version: "v1beta1", Kind: "Scale"}: "scale",
{Group: "autoscaling", Version: "v1beta2", Kind: "Scale"}: "scale",
{Group: "autoscaling", Version: "v2", Kind: "Scale"}: "scale",
}
fuzzIters := *roundtrip.FuzzIters / 10 // TODO: Find a better way to manage test running time
f := fuzzer.FuzzerFor(FuzzerFuncs, rand.NewSource(rand.Int63()), legacyscheme.Codecs)
@ -77,7 +89,11 @@ func TestVersionedValidationByFuzzing(t *testing.T) {
if err != nil {
t.Fatalf("could not create a %v: %s", kind, err)
}
f.Fill(obj)
subresource := ""
if specific, ok := subresourceOnly[gvk]; ok {
subresource = specific
}
var opts []ValidationTestConfig
// TODO(API group level configuration): Consider configuring normalization rules at the
@ -85,9 +101,9 @@ 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))
if subresource != "" {
opts = append(opts, WithSubResources(subresource))
}
VerifyVersionedValidationEquivalence(t, obj, nil, opts...)
@ -96,7 +112,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...)
}
})