k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/pkg/api/testing/defaulting_test.go (about) 1 /* 2 Copyright 2016 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package testing 18 19 import ( 20 "math/rand" 21 "reflect" 22 "sort" 23 "testing" 24 25 "github.com/google/go-cmp/cmp" 26 fuzz "github.com/google/gofuzz" 27 28 apiv1 "k8s.io/api/core/v1" 29 extensionsv1beta1 "k8s.io/api/extensions/v1beta1" 30 "k8s.io/apimachinery/pkg/api/apitesting/roundtrip" 31 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 32 "k8s.io/apimachinery/pkg/runtime" 33 "k8s.io/apimachinery/pkg/runtime/schema" 34 "k8s.io/kubernetes/pkg/api/legacyscheme" 35 ) 36 37 type orderedGroupVersionKinds []schema.GroupVersionKind 38 39 func (o orderedGroupVersionKinds) Len() int { return len(o) } 40 func (o orderedGroupVersionKinds) Swap(i, j int) { o[i], o[j] = o[j], o[i] } 41 func (o orderedGroupVersionKinds) Less(i, j int) bool { 42 return o[i].String() < o[j].String() 43 } 44 45 // TODO: add a reflexive test that verifies that all SetDefaults functions are registered 46 func TestDefaulting(t *testing.T) { 47 // these are the known types with defaulters - you must add to this list if you add a top level defaulter 48 typesWithDefaulting := map[schema.GroupVersionKind]struct{}{ 49 {Group: "", Version: "v1", Kind: "ConfigMap"}: {}, 50 {Group: "", Version: "v1", Kind: "ConfigMapList"}: {}, 51 {Group: "", Version: "v1", Kind: "Endpoints"}: {}, 52 {Group: "", Version: "v1", Kind: "EndpointsList"}: {}, 53 {Group: "", Version: "v1", Kind: "EphemeralContainers"}: {}, 54 {Group: "", Version: "v1", Kind: "Namespace"}: {}, 55 {Group: "", Version: "v1", Kind: "NamespaceList"}: {}, 56 {Group: "", Version: "v1", Kind: "Node"}: {}, 57 {Group: "", Version: "v1", Kind: "NodeList"}: {}, 58 {Group: "", Version: "v1", Kind: "PersistentVolume"}: {}, 59 {Group: "", Version: "v1", Kind: "PersistentVolumeList"}: {}, 60 {Group: "", Version: "v1", Kind: "PersistentVolumeClaim"}: {}, 61 {Group: "", Version: "v1", Kind: "PersistentVolumeClaimList"}: {}, 62 {Group: "", Version: "v1", Kind: "Pod"}: {}, 63 {Group: "", Version: "v1", Kind: "PodList"}: {}, 64 {Group: "", Version: "v1", Kind: "PodTemplate"}: {}, 65 {Group: "", Version: "v1", Kind: "PodTemplateList"}: {}, 66 {Group: "", Version: "v1", Kind: "ReplicationController"}: {}, 67 {Group: "", Version: "v1", Kind: "ReplicationControllerList"}: {}, 68 {Group: "", Version: "v1", Kind: "Secret"}: {}, 69 {Group: "", Version: "v1", Kind: "SecretList"}: {}, 70 {Group: "", Version: "v1", Kind: "Service"}: {}, 71 {Group: "", Version: "v1", Kind: "ServiceList"}: {}, 72 {Group: "apps", Version: "v1beta1", Kind: "StatefulSet"}: {}, 73 {Group: "apps", Version: "v1beta1", Kind: "StatefulSetList"}: {}, 74 {Group: "apps", Version: "v1beta2", Kind: "StatefulSet"}: {}, 75 {Group: "apps", Version: "v1beta2", Kind: "StatefulSetList"}: {}, 76 {Group: "apps", Version: "v1", Kind: "StatefulSet"}: {}, 77 {Group: "apps", Version: "v1", Kind: "StatefulSetList"}: {}, 78 {Group: "autoscaling", Version: "v1", Kind: "HorizontalPodAutoscaler"}: {}, 79 {Group: "autoscaling", Version: "v1", Kind: "HorizontalPodAutoscalerList"}: {}, 80 {Group: "autoscaling", Version: "v2", Kind: "HorizontalPodAutoscaler"}: {}, 81 {Group: "autoscaling", Version: "v2", Kind: "HorizontalPodAutoscalerList"}: {}, 82 {Group: "autoscaling", Version: "v2beta1", Kind: "HorizontalPodAutoscaler"}: {}, 83 {Group: "autoscaling", Version: "v2beta1", Kind: "HorizontalPodAutoscalerList"}: {}, 84 {Group: "autoscaling", Version: "v2beta2", Kind: "HorizontalPodAutoscaler"}: {}, 85 {Group: "autoscaling", Version: "v2beta2", Kind: "HorizontalPodAutoscalerList"}: {}, 86 {Group: "batch", Version: "v1", Kind: "CronJob"}: {}, 87 {Group: "batch", Version: "v1", Kind: "CronJobList"}: {}, 88 {Group: "batch", Version: "v1", Kind: "Job"}: {}, 89 {Group: "batch", Version: "v1", Kind: "JobList"}: {}, 90 {Group: "batch", Version: "v1beta1", Kind: "CronJob"}: {}, 91 {Group: "batch", Version: "v1beta1", Kind: "CronJobList"}: {}, 92 {Group: "batch", Version: "v1beta1", Kind: "JobTemplate"}: {}, 93 {Group: "batch", Version: "v2alpha1", Kind: "CronJob"}: {}, 94 {Group: "batch", Version: "v2alpha1", Kind: "CronJobList"}: {}, 95 {Group: "batch", Version: "v2alpha1", Kind: "JobTemplate"}: {}, 96 {Group: "certificates.k8s.io", Version: "v1beta1", Kind: "CertificateSigningRequest"}: {}, 97 {Group: "certificates.k8s.io", Version: "v1beta1", Kind: "CertificateSigningRequestList"}: {}, 98 {Group: "discovery.k8s.io", Version: "v1", Kind: "EndpointSlice"}: {}, 99 {Group: "discovery.k8s.io", Version: "v1", Kind: "EndpointSliceList"}: {}, 100 {Group: "discovery.k8s.io", Version: "v1beta1", Kind: "EndpointSlice"}: {}, 101 {Group: "discovery.k8s.io", Version: "v1beta1", Kind: "EndpointSliceList"}: {}, 102 {Group: "extensions", Version: "v1beta1", Kind: "DaemonSet"}: {}, 103 {Group: "extensions", Version: "v1beta1", Kind: "DaemonSetList"}: {}, 104 {Group: "apps", Version: "v1beta2", Kind: "DaemonSet"}: {}, 105 {Group: "apps", Version: "v1beta2", Kind: "DaemonSetList"}: {}, 106 {Group: "apps", Version: "v1", Kind: "DaemonSet"}: {}, 107 {Group: "apps", Version: "v1", Kind: "DaemonSetList"}: {}, 108 {Group: "extensions", Version: "v1beta1", Kind: "Deployment"}: {}, 109 {Group: "extensions", Version: "v1beta1", Kind: "DeploymentList"}: {}, 110 {Group: "apps", Version: "v1beta1", Kind: "Deployment"}: {}, 111 {Group: "apps", Version: "v1beta1", Kind: "DeploymentList"}: {}, 112 {Group: "apps", Version: "v1beta2", Kind: "Deployment"}: {}, 113 {Group: "apps", Version: "v1beta2", Kind: "DeploymentList"}: {}, 114 {Group: "apps", Version: "v1", Kind: "Deployment"}: {}, 115 {Group: "apps", Version: "v1", Kind: "DeploymentList"}: {}, 116 {Group: "extensions", Version: "v1beta1", Kind: "Ingress"}: {}, 117 {Group: "extensions", Version: "v1beta1", Kind: "IngressList"}: {}, 118 {Group: "apps", Version: "v1beta2", Kind: "ReplicaSet"}: {}, 119 {Group: "apps", Version: "v1beta2", Kind: "ReplicaSetList"}: {}, 120 {Group: "apps", Version: "v1", Kind: "ReplicaSet"}: {}, 121 {Group: "apps", Version: "v1", Kind: "ReplicaSetList"}: {}, 122 {Group: "extensions", Version: "v1beta1", Kind: "ReplicaSet"}: {}, 123 {Group: "extensions", Version: "v1beta1", Kind: "ReplicaSetList"}: {}, 124 {Group: "extensions", Version: "v1beta1", Kind: "NetworkPolicy"}: {}, 125 {Group: "extensions", Version: "v1beta1", Kind: "NetworkPolicyList"}: {}, 126 {Group: "rbac.authorization.k8s.io", Version: "v1alpha1", Kind: "ClusterRoleBinding"}: {}, 127 {Group: "rbac.authorization.k8s.io", Version: "v1alpha1", Kind: "ClusterRoleBindingList"}: {}, 128 {Group: "rbac.authorization.k8s.io", Version: "v1alpha1", Kind: "RoleBinding"}: {}, 129 {Group: "rbac.authorization.k8s.io", Version: "v1alpha1", Kind: "RoleBindingList"}: {}, 130 {Group: "rbac.authorization.k8s.io", Version: "v1beta1", Kind: "ClusterRoleBinding"}: {}, 131 {Group: "rbac.authorization.k8s.io", Version: "v1beta1", Kind: "ClusterRoleBindingList"}: {}, 132 {Group: "rbac.authorization.k8s.io", Version: "v1beta1", Kind: "RoleBinding"}: {}, 133 {Group: "rbac.authorization.k8s.io", Version: "v1beta1", Kind: "RoleBindingList"}: {}, 134 {Group: "rbac.authorization.k8s.io", Version: "v1", Kind: "ClusterRoleBinding"}: {}, 135 {Group: "rbac.authorization.k8s.io", Version: "v1", Kind: "ClusterRoleBindingList"}: {}, 136 {Group: "rbac.authorization.k8s.io", Version: "v1", Kind: "RoleBinding"}: {}, 137 {Group: "rbac.authorization.k8s.io", Version: "v1", Kind: "RoleBindingList"}: {}, 138 {Group: "resource.k8s.io", Version: "v1alpha2", Kind: "ResourceClaim"}: {}, 139 {Group: "resource.k8s.io", Version: "v1alpha2", Kind: "ResourceClaimList"}: {}, 140 {Group: "resource.k8s.io", Version: "v1alpha2", Kind: "ResourceClaimTemplate"}: {}, 141 {Group: "resource.k8s.io", Version: "v1alpha2", Kind: "ResourceClaimTemplateList"}: {}, 142 {Group: "admissionregistration.k8s.io", Version: "v1alpha1", Kind: "ValidatingAdmissionPolicy"}: {}, 143 {Group: "admissionregistration.k8s.io", Version: "v1alpha1", Kind: "ValidatingAdmissionPolicyList"}: {}, 144 {Group: "admissionregistration.k8s.io", Version: "v1alpha1", Kind: "ValidatingAdmissionPolicyBinding"}: {}, 145 {Group: "admissionregistration.k8s.io", Version: "v1alpha1", Kind: "ValidatingAdmissionPolicyBindingList"}: {}, 146 {Group: "admissionregistration.k8s.io", Version: "v1beta1", Kind: "ValidatingWebhookConfiguration"}: {}, 147 {Group: "admissionregistration.k8s.io", Version: "v1beta1", Kind: "ValidatingWebhookConfigurationList"}: {}, 148 {Group: "admissionregistration.k8s.io", Version: "v1beta1", Kind: "MutatingWebhookConfiguration"}: {}, 149 {Group: "admissionregistration.k8s.io", Version: "v1beta1", Kind: "MutatingWebhookConfigurationList"}: {}, 150 {Group: "admissionregistration.k8s.io", Version: "v1beta1", Kind: "ValidatingAdmissionPolicy"}: {}, 151 {Group: "admissionregistration.k8s.io", Version: "v1beta1", Kind: "ValidatingAdmissionPolicyList"}: {}, 152 {Group: "admissionregistration.k8s.io", Version: "v1beta1", Kind: "ValidatingAdmissionPolicyBinding"}: {}, 153 {Group: "admissionregistration.k8s.io", Version: "v1beta1", Kind: "ValidatingAdmissionPolicyBindingList"}: {}, 154 {Group: "admissionregistration.k8s.io", Version: "v1", Kind: "ValidatingAdmissionPolicy"}: {}, 155 {Group: "admissionregistration.k8s.io", Version: "v1", Kind: "ValidatingAdmissionPolicyList"}: {}, 156 {Group: "admissionregistration.k8s.io", Version: "v1", Kind: "ValidatingAdmissionPolicyBinding"}: {}, 157 {Group: "admissionregistration.k8s.io", Version: "v1", Kind: "ValidatingAdmissionPolicyBindingList"}: {}, 158 {Group: "admissionregistration.k8s.io", Version: "v1", Kind: "ValidatingWebhookConfiguration"}: {}, 159 {Group: "admissionregistration.k8s.io", Version: "v1", Kind: "ValidatingWebhookConfigurationList"}: {}, 160 {Group: "admissionregistration.k8s.io", Version: "v1", Kind: "MutatingWebhookConfiguration"}: {}, 161 {Group: "admissionregistration.k8s.io", Version: "v1", Kind: "MutatingWebhookConfigurationList"}: {}, 162 {Group: "networking.k8s.io", Version: "v1", Kind: "NetworkPolicy"}: {}, 163 {Group: "networking.k8s.io", Version: "v1", Kind: "NetworkPolicyList"}: {}, 164 {Group: "networking.k8s.io", Version: "v1beta1", Kind: "Ingress"}: {}, 165 {Group: "networking.k8s.io", Version: "v1beta1", Kind: "IngressList"}: {}, 166 {Group: "networking.k8s.io", Version: "v1", Kind: "IngressClass"}: {}, 167 {Group: "networking.k8s.io", Version: "v1", Kind: "IngressClassList"}: {}, 168 {Group: "storage.k8s.io", Version: "v1beta1", Kind: "StorageClass"}: {}, 169 {Group: "storage.k8s.io", Version: "v1beta1", Kind: "StorageClassList"}: {}, 170 {Group: "storage.k8s.io", Version: "v1beta1", Kind: "CSIDriver"}: {}, 171 {Group: "storage.k8s.io", Version: "v1beta1", Kind: "CSIDriverList"}: {}, 172 {Group: "storage.k8s.io", Version: "v1", Kind: "StorageClass"}: {}, 173 {Group: "storage.k8s.io", Version: "v1", Kind: "StorageClassList"}: {}, 174 {Group: "storage.k8s.io", Version: "v1", Kind: "VolumeAttachment"}: {}, 175 {Group: "storage.k8s.io", Version: "v1", Kind: "VolumeAttachmentList"}: {}, 176 {Group: "storage.k8s.io", Version: "v1", Kind: "CSIDriver"}: {}, 177 {Group: "storage.k8s.io", Version: "v1", Kind: "CSIDriverList"}: {}, 178 {Group: "storage.k8s.io", Version: "v1beta1", Kind: "VolumeAttachment"}: {}, 179 {Group: "storage.k8s.io", Version: "v1beta1", Kind: "VolumeAttachmentList"}: {}, 180 {Group: "authentication.k8s.io", Version: "v1", Kind: "TokenRequest"}: {}, 181 {Group: "scheduling.k8s.io", Version: "v1alpha1", Kind: "PriorityClass"}: {}, 182 {Group: "scheduling.k8s.io", Version: "v1beta1", Kind: "PriorityClass"}: {}, 183 {Group: "scheduling.k8s.io", Version: "v1", Kind: "PriorityClass"}: {}, 184 {Group: "scheduling.k8s.io", Version: "v1alpha1", Kind: "PriorityClassList"}: {}, 185 {Group: "scheduling.k8s.io", Version: "v1beta1", Kind: "PriorityClassList"}: {}, 186 {Group: "scheduling.k8s.io", Version: "v1", Kind: "PriorityClassList"}: {}, 187 {Group: "flowcontrol.apiserver.k8s.io", Version: "v1alpha1", Kind: "PriorityLevelConfiguration"}: {}, 188 {Group: "flowcontrol.apiserver.k8s.io", Version: "v1alpha1", Kind: "PriorityLevelConfigurationList"}: {}, 189 {Group: "flowcontrol.apiserver.k8s.io", Version: "v1beta1", Kind: "PriorityLevelConfiguration"}: {}, 190 {Group: "flowcontrol.apiserver.k8s.io", Version: "v1beta1", Kind: "PriorityLevelConfigurationList"}: {}, 191 {Group: "flowcontrol.apiserver.k8s.io", Version: "v1beta2", Kind: "PriorityLevelConfiguration"}: {}, 192 {Group: "flowcontrol.apiserver.k8s.io", Version: "v1beta2", Kind: "PriorityLevelConfigurationList"}: {}, 193 {Group: "flowcontrol.apiserver.k8s.io", Version: "v1beta3", Kind: "PriorityLevelConfiguration"}: {}, 194 {Group: "flowcontrol.apiserver.k8s.io", Version: "v1beta3", Kind: "PriorityLevelConfigurationList"}: {}, 195 {Group: "flowcontrol.apiserver.k8s.io", Version: "v1", Kind: "PriorityLevelConfiguration"}: {}, 196 {Group: "flowcontrol.apiserver.k8s.io", Version: "v1", Kind: "PriorityLevelConfigurationList"}: {}, 197 } 198 199 f := fuzz.New().NilChance(.5).NumElements(1, 1).RandSource(rand.NewSource(1)) 200 f.Funcs( 201 func(s *runtime.RawExtension, c fuzz.Continue) {}, 202 func(s *metav1.LabelSelector, c fuzz.Continue) { 203 c.FuzzNoCustom(s) 204 s.MatchExpressions = nil // need to fuzz this specially 205 }, 206 func(s *metav1.ListOptions, c fuzz.Continue) { 207 c.FuzzNoCustom(s) 208 s.LabelSelector = "" // need to fuzz requirement strings specially 209 s.FieldSelector = "" // need to fuzz requirement strings specially 210 }, 211 func(s *extensionsv1beta1.ScaleStatus, c fuzz.Continue) { 212 c.FuzzNoCustom(s) 213 s.TargetSelector = "" // need to fuzz requirement strings specially 214 }, 215 ) 216 217 scheme := legacyscheme.Scheme 218 var testTypes orderedGroupVersionKinds 219 for gvk := range scheme.AllKnownTypes() { 220 if gvk.Version == runtime.APIVersionInternal { 221 continue 222 } 223 testTypes = append(testTypes, gvk) 224 } 225 sort.Sort(testTypes) 226 227 for _, gvk := range testTypes { 228 _, expectedChanged := typesWithDefaulting[gvk] 229 iter := 0 230 changedOnce := false 231 for { 232 if iter > *roundtrip.FuzzIters { 233 if !expectedChanged || changedOnce { 234 break 235 } 236 if iter > 300 { 237 t.Errorf("expected %s to trigger defaulting due to fuzzing", gvk) 238 break 239 } 240 // if we expected defaulting, continue looping until the fuzzer gives us one 241 // at worst, we will timeout 242 } 243 iter++ 244 245 src, err := scheme.New(gvk) 246 if err != nil { 247 t.Fatal(err) 248 } 249 f.Fuzz(src) 250 251 src.GetObjectKind().SetGroupVersionKind(schema.GroupVersionKind{}) 252 253 original := src.DeepCopyObject() 254 255 // get internal 256 withDefaults := src.DeepCopyObject() 257 scheme.Default(withDefaults.(runtime.Object)) 258 259 if !reflect.DeepEqual(original, withDefaults) { 260 changedOnce = true 261 if !expectedChanged { 262 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)) 263 } 264 } 265 } 266 } 267 } 268 269 func BenchmarkPodDefaulting(b *testing.B) { 270 f := fuzz.New().NilChance(.5).NumElements(1, 1).RandSource(rand.NewSource(1)) 271 items := make([]apiv1.Pod, 100) 272 for i := range items { 273 f.Fuzz(&items[i]) 274 } 275 276 scheme := legacyscheme.Scheme 277 b.ResetTimer() 278 for i := 0; i < b.N; i++ { 279 pod := &items[i%len(items)] 280 281 scheme.Default(pod) 282 } 283 b.StopTimer() 284 }