api test: update TestDefaulting

Logging and sub-tests were added to help debug this problem:
the test passes for ResourceClaim (same defaulting!) and fails
for the list, but only if run together with the other test cases?!

    $ go test ./pkg/api/testing
    --- FAIL: TestDefaulting (1.76s)
        --- FAIL: TestDefaulting/resource.k8s.io/v1alpha3,_Kind=ResourceClaimList (0.01s)
            defaulting_test.go:238: expected resource.k8s.io/v1alpha3, Kind=ResourceClaimList to trigger defaulting due to fuzzing
    FAIL
    FAIL	k8s.io/kubernetes/pkg/api/testing	17.294s
    FAIL
    $ go test -run=TestDefaulting/resource.k8s.io/v1alpha3,_Kind=ResourceClaimList ./pkg/api/testing
    ok  	k8s.io/kubernetes/pkg/api/testing	0.062s

What fixed that problem was increasing the likelihood of generating the right
test object by iterating more often before giving up.
This commit is contained in:
Patrick Ohly
2024-07-11 13:50:09 +02:00
parent 8a629b9f15
commit 62d21589ef

View File

@@ -192,24 +192,6 @@ func TestDefaulting(t *testing.T) {
{Group: "flowcontrol.apiserver.k8s.io", Version: "v1", Kind: "PriorityLevelConfigurationList"}: {},
}
f := fuzz.New().NilChance(.5).NumElements(1, 1).RandSource(rand.NewSource(1))
f.Funcs(
func(s *runtime.RawExtension, c fuzz.Continue) {},
func(s *metav1.LabelSelector, c fuzz.Continue) {
c.FuzzNoCustom(s)
s.MatchExpressions = nil // need to fuzz this specially
},
func(s *metav1.ListOptions, c fuzz.Continue) {
c.FuzzNoCustom(s)
s.LabelSelector = "" // need to fuzz requirement strings specially
s.FieldSelector = "" // need to fuzz requirement strings specially
},
func(s *extensionsv1beta1.ScaleStatus, c fuzz.Continue) {
c.FuzzNoCustom(s)
s.TargetSelector = "" // need to fuzz requirement strings specially
},
)
scheme := legacyscheme.Scheme
var testTypes orderedGroupVersionKinds
for gvk := range scheme.AllKnownTypes() {
@@ -221,45 +203,77 @@ func TestDefaulting(t *testing.T) {
sort.Sort(testTypes)
for _, gvk := range testTypes {
_, expectedChanged := typesWithDefaulting[gvk]
iter := 0
changedOnce := false
for {
if iter > *roundtrip.FuzzIters {
if !expectedChanged || changedOnce {
break
gvk := gvk
t.Run(gvk.String(), func(t *testing.T) {
// Each sub-tests gets its own fuzzer instance to make running it independent
// from what other tests ran before.
f := fuzz.New().NilChance(.5).NumElements(1, 1).RandSource(rand.NewSource(1))
f.Funcs(
func(s *runtime.RawExtension, c fuzz.Continue) {},
func(s *metav1.LabelSelector, c fuzz.Continue) {
c.FuzzNoCustom(s)
s.MatchExpressions = nil // need to fuzz this specially
},
func(s *metav1.ListOptions, c fuzz.Continue) {
c.FuzzNoCustom(s)
s.LabelSelector = "" // need to fuzz requirement strings specially
s.FieldSelector = "" // need to fuzz requirement strings specially
},
func(s *extensionsv1beta1.ScaleStatus, c fuzz.Continue) {
c.FuzzNoCustom(s)
s.TargetSelector = "" // need to fuzz requirement strings specially
},
)
_, expectedChanged := typesWithDefaulting[gvk]
iter := 0
changedOnce := false
for {
if iter > *roundtrip.FuzzIters {
if !expectedChanged || changedOnce {
break
}
// This uses to be 300, but for ResourceClaimList that was not high enough
// because depending on the starting conditions, the fuzzer never created the
// one combination where defaulting kicked in (empty string in non-empty slice
// in another non-empty slice).
if iter > 3000 {
t.Errorf("expected %s to trigger defaulting due to fuzzing", gvk)
break
}
// if we expected defaulting, continue looping until the fuzzer gives us one
// at worst, we will timeout
}
if iter > 300 {
t.Errorf("expected %s to trigger defaulting due to fuzzing", gvk)
break
iter++
src, err := scheme.New(gvk)
if err != nil {
t.Fatal(err)
}
// if we expected defaulting, continue looping until the fuzzer gives us one
// at worst, we will timeout
}
iter++
f.Fuzz(src)
src, err := scheme.New(gvk)
if err != nil {
t.Fatal(err)
}
f.Fuzz(src)
src.GetObjectKind().SetGroupVersionKind(schema.GroupVersionKind{})
src.GetObjectKind().SetGroupVersionKind(schema.GroupVersionKind{})
original := src.DeepCopyObject()
original := src.DeepCopyObject()
// get internal
withDefaults := src.DeepCopyObject()
scheme.Default(withDefaults)
// get internal
withDefaults := src.DeepCopyObject()
scheme.Default(withDefaults.(runtime.Object))
if !reflect.DeepEqual(original, withDefaults) {
changedOnce = true
if !expectedChanged {
t.Errorf("{Group: \"%s\", Version: \"%s\", Kind: \"%s\"} did not expect defaults to be set - update expected or check defaulter registering: %s", gvk.Group, gvk.Version, gvk.Kind, cmp.Diff(original, withDefaults))
if !reflect.DeepEqual(original, withDefaults) {
diff := cmp.Diff(original, withDefaults)
if !changedOnce {
t.Logf("got diff (-fuzzed, +with defaults):\n%s", diff)
changedOnce = true
}
if !expectedChanged {
t.Errorf("{Group: \"%s\", Version: \"%s\", Kind: \"%s\"} did not expect defaults to be set - update expected or check defaulter registering: %s", gvk.Group, gvk.Version, gvk.Kind, diff)
}
}
}
}
})
}
}
func BenchmarkPodDefaulting(b *testing.B) {