2016-09-25 03:25:31 +00:00
/ *
2016-09-25 16:09:52 +00:00
Copyright 2016 The Kubernetes Authors .
2016-09-25 03:25:31 +00:00
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 .
* /
2017-10-09 13:53:03 +00:00
package testing
2016-09-25 03:25:31 +00:00
import (
"math/rand"
"reflect"
"sort"
"testing"
2017-08-24 22:49:22 +00:00
fuzz "github.com/google/gofuzz"
2016-09-25 03:25:31 +00:00
2017-04-21 17:35:43 +00:00
apiv1 "k8s.io/api/core/v1"
extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
2018-08-01 14:01:32 +00:00
roundtrip "k8s.io/apimachinery/pkg/api/apitesting/roundtrip"
2017-01-11 14:09:48 +00:00
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/diff"
2017-10-16 11:41:50 +00:00
"k8s.io/kubernetes/pkg/api/legacyscheme"
2016-09-25 03:25:31 +00:00
)
2016-11-21 02:55:31 +00:00
type orderedGroupVersionKinds [ ] schema . GroupVersionKind
2016-09-25 03:25:31 +00:00
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 ( )
}
2016-09-25 16:09:52 +00:00
// TODO: add a reflexive test that verifies that all SetDefaults functions are registered
2016-09-25 03:25:31 +00:00
func TestDefaulting ( t * testing . T ) {
2016-09-25 16:09:52 +00:00
// these are the known types with defaulters - you must add to this list if you add a top level defaulter
2016-11-21 02:55:31 +00:00
typesWithDefaulting := map [ schema . GroupVersionKind ] struct { } {
2017-01-12 20:23:11 +00:00
{ Group : "" , Version : "v1" , Kind : "ConfigMap" } : { } ,
{ Group : "" , Version : "v1" , Kind : "ConfigMapList" } : { } ,
{ Group : "" , Version : "v1" , Kind : "Endpoints" } : { } ,
{ Group : "" , Version : "v1" , Kind : "EndpointsList" } : { } ,
{ 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" } : { } ,
2017-07-10 23:08:41 +00:00
{ Group : "apps" , Version : "v1beta2" , Kind : "StatefulSet" } : { } ,
{ Group : "apps" , Version : "v1beta2" , Kind : "StatefulSetList" } : { } ,
2017-10-10 21:30:02 +00:00
{ Group : "apps" , Version : "v1" , Kind : "StatefulSet" } : { } ,
{ Group : "apps" , Version : "v1" , Kind : "StatefulSetList" } : { } ,
2017-01-12 20:23:11 +00:00
{ Group : "autoscaling" , Version : "v1" , Kind : "HorizontalPodAutoscaler" } : { } ,
{ Group : "autoscaling" , Version : "v1" , Kind : "HorizontalPodAutoscalerList" } : { } ,
2017-08-14 19:44:30 +00:00
{ Group : "autoscaling" , Version : "v2beta1" , Kind : "HorizontalPodAutoscaler" } : { } ,
{ Group : "autoscaling" , Version : "v2beta1" , Kind : "HorizontalPodAutoscalerList" } : { } ,
2017-01-12 20:23:11 +00:00
{ Group : "batch" , Version : "v1" , Kind : "Job" } : { } ,
{ Group : "batch" , Version : "v1" , Kind : "JobList" } : { } ,
2017-08-10 11:04:39 +00:00
{ Group : "batch" , Version : "v1beta1" , Kind : "CronJob" } : { } ,
{ Group : "batch" , Version : "v1beta1" , Kind : "CronJobList" } : { } ,
{ Group : "batch" , Version : "v1beta1" , Kind : "JobTemplate" } : { } ,
2017-01-12 20:23:11 +00:00
{ 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 : "kubeadm.k8s.io" , Version : "v1alpha1" , Kind : "MasterConfiguration" } : { } ,
2016-11-01 23:48:04 +00:00
// This object contains only int fields which currently breaks the defaulting test because
// it's pretty stupid. Once we add non integer fields, we should uncomment this.
// {Group: "kubeadm.k8s.io", Version: "v1alpha1", Kind: "NodeConfiguration"}: {},
2017-11-19 21:54:50 +00:00
{ 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 : "PodSecurityPolicy" } : { } ,
{ Group : "extensions" , Version : "v1beta1" , Kind : "PodSecurityPolicyList" } : { } ,
{ 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" } : { } ,
2018-01-10 16:52:26 +00:00
{ Group : "policy" , Version : "v1beta1" , Kind : "PodSecurityPolicy" } : { } ,
{ Group : "policy" , Version : "v1beta1" , Kind : "PodSecurityPolicyList" } : { } ,
2017-11-19 21:54:50 +00:00
{ 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 : "settings.k8s.io" , Version : "v1alpha1" , Kind : "PodPreset" } : { } ,
{ Group : "settings.k8s.io" , Version : "v1alpha1" , Kind : "PodPresetList" } : { } ,
{ 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 : "networking.k8s.io" , Version : "v1" , Kind : "NetworkPolicy" } : { } ,
{ Group : "networking.k8s.io" , Version : "v1" , Kind : "NetworkPolicyList" } : { } ,
{ Group : "storage.k8s.io" , Version : "v1beta1" , Kind : "StorageClass" } : { } ,
{ Group : "storage.k8s.io" , Version : "v1beta1" , Kind : "StorageClassList" } : { } ,
{ Group : "storage.k8s.io" , Version : "v1" , Kind : "StorageClass" } : { } ,
{ Group : "storage.k8s.io" , Version : "v1" , Kind : "StorageClassList" } : { } ,
2018-02-06 17:29:13 +00:00
{ Group : "authentication.k8s.io" , Version : "v1" , Kind : "TokenRequest" } : { } ,
2016-09-25 16:09:52 +00:00
}
f := fuzz . New ( ) . NilChance ( .5 ) . NumElements ( 1 , 1 ) . RandSource ( rand . NewSource ( 1 ) )
2016-09-25 03:25:31 +00:00
f . Funcs (
func ( s * runtime . RawExtension , c fuzz . Continue ) { } ,
2016-12-03 18:57:26 +00:00
func ( s * metav1 . LabelSelector , c fuzz . Continue ) {
2016-09-25 03:25:31 +00:00
c . FuzzNoCustom ( s )
s . MatchExpressions = nil // need to fuzz this specially
} ,
2018-03-28 02:31:41 +00:00
func ( s * metav1 . ListOptions , c fuzz . Continue ) {
2016-09-25 03:25:31 +00:00
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
} ,
)
2017-10-16 11:41:50 +00:00
scheme := legacyscheme . Scheme
2016-09-25 03:25:31 +00:00
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 {
2016-09-25 16:09:52 +00:00
_ , expectedChanged := typesWithDefaulting [ gvk ]
iter := 0
changedOnce := false
for {
2017-07-12 14:10:48 +00:00
if iter > * roundtrip . FuzzIters {
2016-09-25 16:09:52 +00:00
if ! expectedChanged || changedOnce {
break
}
2016-12-23 02:04:32 +00:00
if iter > 300 {
2016-09-25 16:09:52 +00:00
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 ++
2016-09-25 03:25:31 +00:00
src , err := scheme . New ( gvk )
if err != nil {
t . Fatal ( err )
}
f . Fuzz ( src )
2016-11-21 02:55:31 +00:00
src . GetObjectKind ( ) . SetGroupVersionKind ( schema . GroupVersionKind { } )
2016-09-25 03:25:31 +00:00
2017-08-15 12:16:45 +00:00
original := src . DeepCopyObject ( )
2016-09-25 03:25:31 +00:00
// get internal
2017-08-15 12:16:45 +00:00
withDefaults := src . DeepCopyObject ( )
2016-09-25 16:09:52 +00:00
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 , diff . ObjectReflectDiff ( original , withDefaults ) )
}
2016-09-25 03:25:31 +00:00
}
2016-09-25 16:09:52 +00:00
}
}
}
2016-09-25 03:25:31 +00:00
2016-09-25 16:09:52 +00:00
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 ] )
}
2016-09-25 03:25:31 +00:00
2017-10-16 11:41:50 +00:00
scheme := legacyscheme . Scheme
2016-09-25 16:09:52 +00:00
b . ResetTimer ( )
for i := 0 ; i < b . N ; i ++ {
pod := & items [ i % len ( items ) ]
scheme . Default ( pod )
2016-09-25 03:25:31 +00:00
}
2016-09-25 16:09:52 +00:00
b . StopTimer ( )
2016-09-25 03:25:31 +00:00
}