kubernetes/pkg/api/testing/defaulting_test.go
2023-01-06 17:07:02 +08:00

277 lines
19 KiB
Go

/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package testing
import (
"math/rand"
"reflect"
"sort"
"testing"
"github.com/google/go-cmp/cmp"
fuzz "github.com/google/gofuzz"
apiv1 "k8s.io/api/core/v1"
extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
"k8s.io/apimachinery/pkg/api/apitesting/roundtrip"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/kubernetes/pkg/api/legacyscheme"
)
type orderedGroupVersionKinds []schema.GroupVersionKind
func (o orderedGroupVersionKinds) Len() int { return len(o) }
func (o orderedGroupVersionKinds) Swap(i, j int) { o[i], o[j] = o[j], o[i] }
func (o orderedGroupVersionKinds) Less(i, j int) bool {
return o[i].String() < o[j].String()
}
// TODO: add a reflexive test that verifies that all SetDefaults functions are registered
func TestDefaulting(t *testing.T) {
// these are the known types with defaulters - you must add to this list if you add a top level defaulter
typesWithDefaulting := map[schema.GroupVersionKind]struct{}{
{Group: "", Version: "v1", Kind: "ConfigMap"}: {},
{Group: "", Version: "v1", Kind: "ConfigMapList"}: {},
{Group: "", Version: "v1", Kind: "Endpoints"}: {},
{Group: "", Version: "v1", Kind: "EndpointsList"}: {},
{Group: "", Version: "v1", Kind: "EphemeralContainers"}: {},
{Group: "", Version: "v1", Kind: "Namespace"}: {},
{Group: "", Version: "v1", Kind: "NamespaceList"}: {},
{Group: "", Version: "v1", Kind: "Node"}: {},
{Group: "", Version: "v1", Kind: "NodeList"}: {},
{Group: "", Version: "v1", Kind: "PersistentVolume"}: {},
{Group: "", Version: "v1", Kind: "PersistentVolumeList"}: {},
{Group: "", Version: "v1", Kind: "PersistentVolumeClaim"}: {},
{Group: "", Version: "v1", Kind: "PersistentVolumeClaimList"}: {},
{Group: "", Version: "v1", Kind: "Pod"}: {},
{Group: "", Version: "v1", Kind: "PodList"}: {},
{Group: "", Version: "v1", Kind: "PodTemplate"}: {},
{Group: "", Version: "v1", Kind: "PodTemplateList"}: {},
{Group: "", Version: "v1", Kind: "ReplicationController"}: {},
{Group: "", Version: "v1", Kind: "ReplicationControllerList"}: {},
{Group: "", Version: "v1", Kind: "Secret"}: {},
{Group: "", Version: "v1", Kind: "SecretList"}: {},
{Group: "", Version: "v1", Kind: "Service"}: {},
{Group: "", Version: "v1", Kind: "ServiceList"}: {},
{Group: "apps", Version: "v1beta1", Kind: "StatefulSet"}: {},
{Group: "apps", Version: "v1beta1", Kind: "StatefulSetList"}: {},
{Group: "apps", Version: "v1beta2", Kind: "StatefulSet"}: {},
{Group: "apps", Version: "v1beta2", Kind: "StatefulSetList"}: {},
{Group: "apps", Version: "v1", Kind: "StatefulSet"}: {},
{Group: "apps", Version: "v1", Kind: "StatefulSetList"}: {},
{Group: "autoscaling", Version: "v1", Kind: "HorizontalPodAutoscaler"}: {},
{Group: "autoscaling", Version: "v1", Kind: "HorizontalPodAutoscalerList"}: {},
{Group: "autoscaling", Version: "v2", Kind: "HorizontalPodAutoscaler"}: {},
{Group: "autoscaling", Version: "v2", Kind: "HorizontalPodAutoscalerList"}: {},
{Group: "autoscaling", Version: "v2beta1", Kind: "HorizontalPodAutoscaler"}: {},
{Group: "autoscaling", Version: "v2beta1", Kind: "HorizontalPodAutoscalerList"}: {},
{Group: "autoscaling", Version: "v2beta2", Kind: "HorizontalPodAutoscaler"}: {},
{Group: "autoscaling", Version: "v2beta2", Kind: "HorizontalPodAutoscalerList"}: {},
{Group: "batch", Version: "v1", Kind: "CronJob"}: {},
{Group: "batch", Version: "v1", Kind: "CronJobList"}: {},
{Group: "batch", Version: "v1", Kind: "Job"}: {},
{Group: "batch", Version: "v1", Kind: "JobList"}: {},
{Group: "batch", Version: "v1beta1", Kind: "CronJob"}: {},
{Group: "batch", Version: "v1beta1", Kind: "CronJobList"}: {},
{Group: "batch", Version: "v1beta1", Kind: "JobTemplate"}: {},
{Group: "batch", Version: "v2alpha1", Kind: "CronJob"}: {},
{Group: "batch", Version: "v2alpha1", Kind: "CronJobList"}: {},
{Group: "batch", Version: "v2alpha1", Kind: "JobTemplate"}: {},
{Group: "certificates.k8s.io", Version: "v1beta1", Kind: "CertificateSigningRequest"}: {},
{Group: "certificates.k8s.io", Version: "v1beta1", Kind: "CertificateSigningRequestList"}: {},
{Group: "discovery.k8s.io", Version: "v1", Kind: "EndpointSlice"}: {},
{Group: "discovery.k8s.io", Version: "v1", Kind: "EndpointSliceList"}: {},
{Group: "discovery.k8s.io", Version: "v1beta1", Kind: "EndpointSlice"}: {},
{Group: "discovery.k8s.io", Version: "v1beta1", Kind: "EndpointSliceList"}: {},
{Group: "extensions", Version: "v1beta1", Kind: "DaemonSet"}: {},
{Group: "extensions", Version: "v1beta1", Kind: "DaemonSetList"}: {},
{Group: "apps", Version: "v1beta2", Kind: "DaemonSet"}: {},
{Group: "apps", Version: "v1beta2", Kind: "DaemonSetList"}: {},
{Group: "apps", Version: "v1", Kind: "DaemonSet"}: {},
{Group: "apps", Version: "v1", Kind: "DaemonSetList"}: {},
{Group: "extensions", Version: "v1beta1", Kind: "Deployment"}: {},
{Group: "extensions", Version: "v1beta1", Kind: "DeploymentList"}: {},
{Group: "apps", Version: "v1beta1", Kind: "Deployment"}: {},
{Group: "apps", Version: "v1beta1", Kind: "DeploymentList"}: {},
{Group: "apps", Version: "v1beta2", Kind: "Deployment"}: {},
{Group: "apps", Version: "v1beta2", Kind: "DeploymentList"}: {},
{Group: "apps", Version: "v1", Kind: "Deployment"}: {},
{Group: "apps", Version: "v1", Kind: "DeploymentList"}: {},
{Group: "extensions", Version: "v1beta1", Kind: "Ingress"}: {},
{Group: "extensions", Version: "v1beta1", Kind: "IngressList"}: {},
{Group: "apps", Version: "v1beta2", Kind: "ReplicaSet"}: {},
{Group: "apps", Version: "v1beta2", Kind: "ReplicaSetList"}: {},
{Group: "apps", Version: "v1", Kind: "ReplicaSet"}: {},
{Group: "apps", Version: "v1", Kind: "ReplicaSetList"}: {},
{Group: "extensions", Version: "v1beta1", Kind: "ReplicaSet"}: {},
{Group: "extensions", Version: "v1beta1", Kind: "ReplicaSetList"}: {},
{Group: "extensions", Version: "v1beta1", Kind: "NetworkPolicy"}: {},
{Group: "extensions", Version: "v1beta1", Kind: "NetworkPolicyList"}: {},
{Group: "policy", Version: "v1beta1", Kind: "PodSecurityPolicy"}: {},
{Group: "policy", Version: "v1beta1", Kind: "PodSecurityPolicyList"}: {},
{Group: "rbac.authorization.k8s.io", Version: "v1alpha1", Kind: "ClusterRoleBinding"}: {},
{Group: "rbac.authorization.k8s.io", Version: "v1alpha1", Kind: "ClusterRoleBindingList"}: {},
{Group: "rbac.authorization.k8s.io", Version: "v1alpha1", Kind: "RoleBinding"}: {},
{Group: "rbac.authorization.k8s.io", Version: "v1alpha1", Kind: "RoleBindingList"}: {},
{Group: "rbac.authorization.k8s.io", Version: "v1beta1", Kind: "ClusterRoleBinding"}: {},
{Group: "rbac.authorization.k8s.io", Version: "v1beta1", Kind: "ClusterRoleBindingList"}: {},
{Group: "rbac.authorization.k8s.io", Version: "v1beta1", Kind: "RoleBinding"}: {},
{Group: "rbac.authorization.k8s.io", Version: "v1beta1", Kind: "RoleBindingList"}: {},
{Group: "rbac.authorization.k8s.io", Version: "v1", Kind: "ClusterRoleBinding"}: {},
{Group: "rbac.authorization.k8s.io", Version: "v1", Kind: "ClusterRoleBindingList"}: {},
{Group: "rbac.authorization.k8s.io", Version: "v1", Kind: "RoleBinding"}: {},
{Group: "rbac.authorization.k8s.io", Version: "v1", Kind: "RoleBindingList"}: {},
{Group: "resource.k8s.io", Version: "v1alpha1", Kind: "ResourceClaim"}: {},
{Group: "resource.k8s.io", Version: "v1alpha1", Kind: "ResourceClaimList"}: {},
{Group: "resource.k8s.io", Version: "v1alpha1", Kind: "ResourceClaimTemplate"}: {},
{Group: "resource.k8s.io", Version: "v1alpha1", Kind: "ResourceClaimTemplateList"}: {},
{Group: "admissionregistration.k8s.io", Version: "v1alpha1", Kind: "ValidatingAdmissionPolicy"}: {},
{Group: "admissionregistration.k8s.io", Version: "v1alpha1", Kind: "ValidatingAdmissionPolicyList"}: {},
{Group: "admissionregistration.k8s.io", Version: "v1alpha1", Kind: "ValidatingAdmissionPolicyBinding"}: {},
{Group: "admissionregistration.k8s.io", Version: "v1alpha1", Kind: "ValidatingAdmissionPolicyBindingList"}: {},
{Group: "admissionregistration.k8s.io", Version: "v1beta1", Kind: "ValidatingWebhookConfiguration"}: {},
{Group: "admissionregistration.k8s.io", Version: "v1beta1", Kind: "ValidatingWebhookConfigurationList"}: {},
{Group: "admissionregistration.k8s.io", Version: "v1beta1", Kind: "MutatingWebhookConfiguration"}: {},
{Group: "admissionregistration.k8s.io", Version: "v1beta1", Kind: "MutatingWebhookConfigurationList"}: {},
{Group: "admissionregistration.k8s.io", Version: "v1", Kind: "ValidatingWebhookConfiguration"}: {},
{Group: "admissionregistration.k8s.io", Version: "v1", Kind: "ValidatingWebhookConfigurationList"}: {},
{Group: "admissionregistration.k8s.io", Version: "v1", Kind: "MutatingWebhookConfiguration"}: {},
{Group: "admissionregistration.k8s.io", Version: "v1", Kind: "MutatingWebhookConfigurationList"}: {},
{Group: "networking.k8s.io", Version: "v1", Kind: "NetworkPolicy"}: {},
{Group: "networking.k8s.io", Version: "v1", Kind: "NetworkPolicyList"}: {},
{Group: "networking.k8s.io", Version: "v1beta1", Kind: "Ingress"}: {},
{Group: "networking.k8s.io", Version: "v1beta1", Kind: "IngressList"}: {},
{Group: "networking.k8s.io", Version: "v1", Kind: "IngressClass"}: {},
{Group: "networking.k8s.io", Version: "v1", Kind: "IngressClassList"}: {},
{Group: "storage.k8s.io", Version: "v1beta1", Kind: "StorageClass"}: {},
{Group: "storage.k8s.io", Version: "v1beta1", Kind: "StorageClassList"}: {},
{Group: "storage.k8s.io", Version: "v1beta1", Kind: "CSIDriver"}: {},
{Group: "storage.k8s.io", Version: "v1beta1", Kind: "CSIDriverList"}: {},
{Group: "storage.k8s.io", Version: "v1", Kind: "StorageClass"}: {},
{Group: "storage.k8s.io", Version: "v1", Kind: "StorageClassList"}: {},
{Group: "storage.k8s.io", Version: "v1", Kind: "VolumeAttachment"}: {},
{Group: "storage.k8s.io", Version: "v1", Kind: "VolumeAttachmentList"}: {},
{Group: "storage.k8s.io", Version: "v1", Kind: "CSIDriver"}: {},
{Group: "storage.k8s.io", Version: "v1", Kind: "CSIDriverList"}: {},
{Group: "storage.k8s.io", Version: "v1beta1", Kind: "VolumeAttachment"}: {},
{Group: "storage.k8s.io", Version: "v1beta1", Kind: "VolumeAttachmentList"}: {},
{Group: "authentication.k8s.io", Version: "v1", Kind: "TokenRequest"}: {},
{Group: "scheduling.k8s.io", Version: "v1alpha1", Kind: "PriorityClass"}: {},
{Group: "scheduling.k8s.io", Version: "v1beta1", Kind: "PriorityClass"}: {},
{Group: "scheduling.k8s.io", Version: "v1", Kind: "PriorityClass"}: {},
{Group: "scheduling.k8s.io", Version: "v1alpha1", Kind: "PriorityClassList"}: {},
{Group: "scheduling.k8s.io", Version: "v1beta1", Kind: "PriorityClassList"}: {},
{Group: "scheduling.k8s.io", Version: "v1", Kind: "PriorityClassList"}: {},
{Group: "flowcontrol.apiserver.k8s.io", Version: "v1alpha1", Kind: "PriorityLevelConfiguration"}: {},
{Group: "flowcontrol.apiserver.k8s.io", Version: "v1alpha1", Kind: "PriorityLevelConfigurationList"}: {},
{Group: "flowcontrol.apiserver.k8s.io", Version: "v1beta1", Kind: "PriorityLevelConfiguration"}: {},
{Group: "flowcontrol.apiserver.k8s.io", Version: "v1beta1", Kind: "PriorityLevelConfigurationList"}: {},
{Group: "flowcontrol.apiserver.k8s.io", Version: "v1beta2", Kind: "PriorityLevelConfiguration"}: {},
{Group: "flowcontrol.apiserver.k8s.io", Version: "v1beta2", Kind: "PriorityLevelConfigurationList"}: {},
{Group: "flowcontrol.apiserver.k8s.io", Version: "v1beta3", Kind: "PriorityLevelConfiguration"}: {},
{Group: "flowcontrol.apiserver.k8s.io", Version: "v1beta3", 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() {
if gvk.Version == runtime.APIVersionInternal {
continue
}
testTypes = append(testTypes, gvk)
}
sort.Sort(testTypes)
for _, gvk := range testTypes {
_, expectedChanged := typesWithDefaulting[gvk]
iter := 0
changedOnce := false
for {
if iter > *roundtrip.FuzzIters {
if !expectedChanged || changedOnce {
break
}
if iter > 300 {
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
}
iter++
src, err := scheme.New(gvk)
if err != nil {
t.Fatal(err)
}
f.Fuzz(src)
src.GetObjectKind().SetGroupVersionKind(schema.GroupVersionKind{})
original := src.DeepCopyObject()
// 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))
}
}
}
}
}
func BenchmarkPodDefaulting(b *testing.B) {
f := fuzz.New().NilChance(.5).NumElements(1, 1).RandSource(rand.NewSource(1))
items := make([]apiv1.Pod, 100)
for i := range items {
f.Fuzz(&items[i])
}
scheme := legacyscheme.Scheme
b.ResetTimer()
for i := 0; i < b.N; i++ {
pod := &items[i%len(items)]
scheme.Default(pod)
}
b.StopTimer()
}