mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 03:41:45 +00:00
pkg/api/testing: split fuzzer between apimachinery and kube
This commit is contained in:
parent
a12c661773
commit
6b6b6c747e
@ -21,15 +21,16 @@ import (
|
||||
"math/rand"
|
||||
"testing"
|
||||
|
||||
apitesting "k8s.io/apimachinery/pkg/api/testing"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/diff"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/testapi"
|
||||
apitesting "k8s.io/kubernetes/pkg/api/testing"
|
||||
kapitesting "k8s.io/kubernetes/pkg/api/testing"
|
||||
)
|
||||
|
||||
func BenchmarkPodConversion(b *testing.B) {
|
||||
apiObjectFuzzer := apitesting.FuzzerFor(nil, api.SchemeGroupVersion, rand.NewSource(benchmarkSeed))
|
||||
apiObjectFuzzer := apitesting.FuzzerFor(kapitesting.FuzzerFuncs(b), rand.NewSource(benchmarkSeed))
|
||||
items := make([]api.Pod, 4)
|
||||
for i := range items {
|
||||
apiObjectFuzzer.Fuzz(&items[i])
|
||||
|
@ -22,11 +22,12 @@ import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
apitesting "k8s.io/apimachinery/pkg/api/testing"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/diff"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/testapi"
|
||||
apitesting "k8s.io/kubernetes/pkg/api/testing"
|
||||
kapitesting "k8s.io/kubernetes/pkg/api/testing"
|
||||
|
||||
"github.com/google/gofuzz"
|
||||
)
|
||||
@ -34,7 +35,7 @@ import (
|
||||
func TestDeepCopyApiObjects(t *testing.T) {
|
||||
for i := 0; i < *fuzzIters; i++ {
|
||||
for _, version := range []schema.GroupVersion{testapi.Default.InternalGroupVersion(), api.Registry.GroupOrDie(api.GroupName).GroupVersion} {
|
||||
f := apitesting.FuzzerFor(t, version, rand.NewSource(rand.Int63()))
|
||||
f := apitesting.FuzzerFor(kapitesting.FuzzerFuncs(t), rand.NewSource(rand.Int63()))
|
||||
for kind := range api.Scheme.KnownTypes(version) {
|
||||
doDeepCopyTest(t, version.WithKind(kind), f)
|
||||
}
|
||||
@ -83,7 +84,7 @@ func doDeepCopyTest(t *testing.T, kind schema.GroupVersionKind, f *fuzz.Fuzzer)
|
||||
func TestDeepCopySingleType(t *testing.T) {
|
||||
for i := 0; i < *fuzzIters; i++ {
|
||||
for _, version := range []schema.GroupVersion{testapi.Default.InternalGroupVersion(), api.Registry.GroupOrDie(api.GroupName).GroupVersion} {
|
||||
f := apitesting.FuzzerFor(t, version, rand.NewSource(rand.Int63()))
|
||||
f := apitesting.FuzzerFor(kapitesting.FuzzerFuncs(t), rand.NewSource(rand.Int63()))
|
||||
doDeepCopyTest(t, version.WithKind("Pod"), f)
|
||||
}
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
apitesting "k8s.io/apimachinery/pkg/api/testing"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
@ -31,7 +32,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/testapi"
|
||||
apitesting "k8s.io/kubernetes/pkg/api/testing"
|
||||
kapitesting "k8s.io/kubernetes/pkg/api/testing"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
_ "k8s.io/kubernetes/pkg/apis/extensions"
|
||||
_ "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
|
||||
@ -75,7 +76,7 @@ func TestUniversalDeserializer(t *testing.T) {
|
||||
|
||||
func TestProtobufRoundTrip(t *testing.T) {
|
||||
obj := &v1.Pod{}
|
||||
apitesting.FuzzerFor(t, v1.SchemeGroupVersion, rand.NewSource(benchmarkSeed)).Fuzz(obj)
|
||||
apitesting.FuzzerFor(kapitesting.FuzzerFuncs(t), rand.NewSource(benchmarkSeed)).Fuzz(obj)
|
||||
// InitContainers are turned into annotations by conversion.
|
||||
obj.Spec.InitContainers = nil
|
||||
obj.Status.InitContainerStatuses = nil
|
||||
@ -96,7 +97,7 @@ func TestProtobufRoundTrip(t *testing.T) {
|
||||
// BenchmarkEncodeCodec measures the cost of performing a codec encode, which includes
|
||||
// reflection (to clear APIVersion and Kind)
|
||||
func BenchmarkEncodeCodecProtobuf(b *testing.B) {
|
||||
items := benchmarkItems()
|
||||
items := benchmarkItems(b)
|
||||
width := len(items)
|
||||
s := protobuf.NewSerializer(nil, nil, "application/arbitrary.content.type")
|
||||
b.ResetTimer()
|
||||
@ -111,7 +112,7 @@ func BenchmarkEncodeCodecProtobuf(b *testing.B) {
|
||||
// BenchmarkEncodeCodecFromInternalProtobuf measures the cost of performing a codec encode,
|
||||
// including conversions and any type setting. This is a "full" encode.
|
||||
func BenchmarkEncodeCodecFromInternalProtobuf(b *testing.B) {
|
||||
items := benchmarkItems()
|
||||
items := benchmarkItems(b)
|
||||
width := len(items)
|
||||
encodable := make([]api.Pod, width)
|
||||
for i := range items {
|
||||
@ -131,7 +132,7 @@ func BenchmarkEncodeCodecFromInternalProtobuf(b *testing.B) {
|
||||
}
|
||||
|
||||
func BenchmarkEncodeProtobufGeneratedMarshal(b *testing.B) {
|
||||
items := benchmarkItems()
|
||||
items := benchmarkItems(b)
|
||||
width := len(items)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
@ -145,7 +146,7 @@ func BenchmarkEncodeProtobufGeneratedMarshal(b *testing.B) {
|
||||
// BenchmarkDecodeCodecToInternalProtobuf measures the cost of performing a codec decode,
|
||||
// including conversions and any type setting. This is a "full" decode.
|
||||
func BenchmarkDecodeCodecToInternalProtobuf(b *testing.B) {
|
||||
items := benchmarkItems()
|
||||
items := benchmarkItems(b)
|
||||
width := len(items)
|
||||
s := protobuf.NewSerializer(api.Scheme, api.Scheme, "application/arbitrary.content.type")
|
||||
encoder := api.Codecs.EncoderForVersion(s, v1.SchemeGroupVersion)
|
||||
@ -170,7 +171,7 @@ func BenchmarkDecodeCodecToInternalProtobuf(b *testing.B) {
|
||||
|
||||
// BenchmarkDecodeJSON provides a baseline for regular JSON decode performance
|
||||
func BenchmarkDecodeIntoProtobuf(b *testing.B) {
|
||||
items := benchmarkItems()
|
||||
items := benchmarkItems(b)
|
||||
width := len(items)
|
||||
encoded := make([][]byte, width)
|
||||
for i := range items {
|
||||
|
@ -33,6 +33,7 @@ import (
|
||||
"github.com/ugorji/go/codec"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
apitesting "k8s.io/apimachinery/pkg/api/testing"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/conversion"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
@ -43,7 +44,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/testapi"
|
||||
apitesting "k8s.io/kubernetes/pkg/api/testing"
|
||||
kapitesting "k8s.io/kubernetes/pkg/api/testing"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||
"k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
|
||||
@ -63,7 +64,7 @@ var codecsToTest = []func(version schema.GroupVersion, item runtime.Object) (run
|
||||
// fuzzInternalObject fuzzes an arbitrary runtime object using the appropriate
|
||||
// fuzzer registered with the apitesting package.
|
||||
func fuzzInternalObject(t *testing.T, forVersion schema.GroupVersion, item runtime.Object, seed int64) runtime.Object {
|
||||
apitesting.FuzzerFor(t, forVersion, rand.NewSource(seed)).Fuzz(item)
|
||||
apitesting.FuzzerFor(kapitesting.FuzzerFuncs(t), rand.NewSource(seed)).Fuzz(item)
|
||||
|
||||
j, err := meta.TypeAccessor(item)
|
||||
if err != nil {
|
||||
@ -440,7 +441,7 @@ func TestUnversionedTypes(t *testing.T) {
|
||||
// TestObjectWatchFraming establishes that a watch event can be encoded and
|
||||
// decoded correctly through each of the supported RFC2046 media types.
|
||||
func TestObjectWatchFraming(t *testing.T) {
|
||||
f := apitesting.FuzzerFor(nil, api.SchemeGroupVersion, rand.NewSource(benchmarkSeed))
|
||||
f := apitesting.FuzzerFor(kapitesting.FuzzerFuncs(t), rand.NewSource(benchmarkSeed))
|
||||
secret := &api.Secret{}
|
||||
f.Fuzz(secret)
|
||||
secret.Data["binary"] = []byte{0x00, 0x10, 0x30, 0x55, 0xff, 0x00}
|
||||
@ -521,8 +522,8 @@ func TestObjectWatchFraming(t *testing.T) {
|
||||
|
||||
const benchmarkSeed = 100
|
||||
|
||||
func benchmarkItems() []v1.Pod {
|
||||
apiObjectFuzzer := apitesting.FuzzerFor(nil, api.SchemeGroupVersion, rand.NewSource(benchmarkSeed))
|
||||
func benchmarkItems(b *testing.B) []v1.Pod {
|
||||
apiObjectFuzzer := apitesting.FuzzerFor(kapitesting.FuzzerFuncs(b), rand.NewSource(benchmarkSeed))
|
||||
items := make([]v1.Pod, 10)
|
||||
for i := range items {
|
||||
var pod api.Pod
|
||||
@ -540,7 +541,7 @@ func benchmarkItems() []v1.Pod {
|
||||
// BenchmarkEncodeCodec measures the cost of performing a codec encode, which includes
|
||||
// reflection (to clear APIVersion and Kind)
|
||||
func BenchmarkEncodeCodec(b *testing.B) {
|
||||
items := benchmarkItems()
|
||||
items := benchmarkItems(b)
|
||||
width := len(items)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
@ -554,7 +555,7 @@ func BenchmarkEncodeCodec(b *testing.B) {
|
||||
// BenchmarkEncodeCodecFromInternal measures the cost of performing a codec encode,
|
||||
// including conversions.
|
||||
func BenchmarkEncodeCodecFromInternal(b *testing.B) {
|
||||
items := benchmarkItems()
|
||||
items := benchmarkItems(b)
|
||||
width := len(items)
|
||||
encodable := make([]api.Pod, width)
|
||||
for i := range items {
|
||||
@ -573,7 +574,7 @@ func BenchmarkEncodeCodecFromInternal(b *testing.B) {
|
||||
|
||||
// BenchmarkEncodeJSONMarshal provides a baseline for regular JSON encode performance
|
||||
func BenchmarkEncodeJSONMarshal(b *testing.B) {
|
||||
items := benchmarkItems()
|
||||
items := benchmarkItems(b)
|
||||
width := len(items)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
@ -586,7 +587,7 @@ func BenchmarkEncodeJSONMarshal(b *testing.B) {
|
||||
|
||||
func BenchmarkDecodeCodec(b *testing.B) {
|
||||
codec := testapi.Default.Codec()
|
||||
items := benchmarkItems()
|
||||
items := benchmarkItems(b)
|
||||
width := len(items)
|
||||
encoded := make([][]byte, width)
|
||||
for i := range items {
|
||||
@ -608,7 +609,7 @@ func BenchmarkDecodeCodec(b *testing.B) {
|
||||
|
||||
func BenchmarkDecodeIntoExternalCodec(b *testing.B) {
|
||||
codec := testapi.Default.Codec()
|
||||
items := benchmarkItems()
|
||||
items := benchmarkItems(b)
|
||||
width := len(items)
|
||||
encoded := make([][]byte, width)
|
||||
for i := range items {
|
||||
@ -631,7 +632,7 @@ func BenchmarkDecodeIntoExternalCodec(b *testing.B) {
|
||||
|
||||
func BenchmarkDecodeIntoInternalCodec(b *testing.B) {
|
||||
codec := testapi.Default.Codec()
|
||||
items := benchmarkItems()
|
||||
items := benchmarkItems(b)
|
||||
width := len(items)
|
||||
encoded := make([][]byte, width)
|
||||
for i := range items {
|
||||
@ -655,7 +656,7 @@ func BenchmarkDecodeIntoInternalCodec(b *testing.B) {
|
||||
// BenchmarkDecodeJSON provides a baseline for regular JSON decode performance
|
||||
func BenchmarkDecodeIntoJSON(b *testing.B) {
|
||||
codec := testapi.Default.Codec()
|
||||
items := benchmarkItems()
|
||||
items := benchmarkItems(b)
|
||||
width := len(items)
|
||||
encoded := make([][]byte, width)
|
||||
for i := range items {
|
||||
@ -679,7 +680,7 @@ func BenchmarkDecodeIntoJSON(b *testing.B) {
|
||||
// BenchmarkDecodeJSON provides a baseline for codecgen JSON decode performance
|
||||
func BenchmarkDecodeIntoJSONCodecGen(b *testing.B) {
|
||||
kcodec := testapi.Default.Codec()
|
||||
items := benchmarkItems()
|
||||
items := benchmarkItems(b)
|
||||
width := len(items)
|
||||
encoded := make([][]byte, width)
|
||||
for i := range items {
|
||||
|
@ -18,19 +18,17 @@ package testing
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/google/gofuzz"
|
||||
|
||||
apitesting "k8s.io/apimachinery/pkg/api/testing"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/fields"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/resource"
|
||||
@ -44,51 +42,65 @@ import (
|
||||
"k8s.io/kubernetes/pkg/util/intstr"
|
||||
)
|
||||
|
||||
// FuzzerFor can randomly populate api objects that are destined for version.
|
||||
func FuzzerFor(t *testing.T, version schema.GroupVersion, src rand.Source) *fuzz.Fuzzer {
|
||||
f := fuzz.New().NilChance(.5).NumElements(0, 1)
|
||||
if src != nil {
|
||||
f.RandSource(src)
|
||||
}
|
||||
f.Funcs(
|
||||
func(j *int, c fuzz.Continue) {
|
||||
*j = int(c.Int31())
|
||||
},
|
||||
func(j **int, c fuzz.Continue) {
|
||||
if c.RandBool() {
|
||||
i := int(c.Int31())
|
||||
*j = &i
|
||||
// overrideGenericFuncs override some generic fuzzer funcs from k8s.io/apiserver in order to have more realistic
|
||||
// values in a Kubernetes context.
|
||||
func overrideGenericFuncs(t apitesting.TestingCommon) []interface{} {
|
||||
return []interface{}{
|
||||
func(j *runtime.Object, c fuzz.Continue) {
|
||||
// TODO: uncomment when round trip starts from a versioned object
|
||||
if true { //c.RandBool() {
|
||||
*j = &runtime.Unknown{
|
||||
// We do not set TypeMeta here because it is not carried through a round trip
|
||||
Raw: []byte(`{"apiVersion":"unknown.group/unknown","kind":"Something","someKey":"someValue"}`),
|
||||
ContentType: runtime.ContentTypeJSON,
|
||||
}
|
||||
} else {
|
||||
*j = nil
|
||||
types := []runtime.Object{&api.Pod{}, &api.ReplicationController{}}
|
||||
t := types[c.Rand.Intn(len(types))]
|
||||
c.Fuzz(t)
|
||||
*j = t
|
||||
}
|
||||
},
|
||||
func(r *runtime.RawExtension, c fuzz.Continue) {
|
||||
// Pick an arbitrary type and fuzz it
|
||||
types := []runtime.Object{&api.Pod{}, &extensions.Deployment{}, &api.Service{}}
|
||||
obj := types[c.Rand.Intn(len(types))]
|
||||
c.Fuzz(obj)
|
||||
|
||||
// Find a codec for converting the object to raw bytes. This is necessary for the
|
||||
// api version and kind to be correctly set be serialization.
|
||||
var codec runtime.Codec
|
||||
switch obj.(type) {
|
||||
case *api.Pod:
|
||||
codec = testapi.Default.Codec()
|
||||
case *extensions.Deployment:
|
||||
codec = testapi.Extensions.Codec()
|
||||
case *api.Service:
|
||||
codec = testapi.Default.Codec()
|
||||
default:
|
||||
|
||||
t.Errorf("Failed to find codec for object type: %T", obj)
|
||||
return
|
||||
}
|
||||
|
||||
// Convert the object to raw bytes
|
||||
bytes, err := runtime.Encode(codec, obj)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to encode object: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Set the bytes field on the RawExtension
|
||||
r.Raw = bytes
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func coreFuncs(t apitesting.TestingCommon) []interface{} {
|
||||
return []interface{}{
|
||||
func(q *resource.Quantity, c fuzz.Continue) {
|
||||
*q = *resource.NewQuantity(c.Int63n(1000), resource.DecimalExponent)
|
||||
},
|
||||
func(j *runtime.TypeMeta, c fuzz.Continue) {
|
||||
// We have to customize the randomization of TypeMetas because their
|
||||
// APIVersion and Kind must remain blank in memory.
|
||||
j.APIVersion = ""
|
||||
j.Kind = ""
|
||||
},
|
||||
func(j *metav1.TypeMeta, c fuzz.Continue) {
|
||||
// We have to customize the randomization of TypeMetas because their
|
||||
// APIVersion and Kind must remain blank in memory.
|
||||
j.APIVersion = ""
|
||||
j.Kind = ""
|
||||
},
|
||||
func(j *metav1.ObjectMeta, c fuzz.Continue) {
|
||||
j.Name = c.RandString()
|
||||
j.ResourceVersion = strconv.FormatUint(c.RandUint64(), 10)
|
||||
j.SelfLink = c.RandString()
|
||||
j.UID = types.UID(c.RandString())
|
||||
j.GenerateName = c.RandString()
|
||||
|
||||
var sec, nsec int64
|
||||
c.Fuzz(&sec)
|
||||
c.Fuzz(&nsec)
|
||||
j.CreationTimestamp = metav1.Unix(sec, nsec).Rfc3339Copy()
|
||||
},
|
||||
func(j *api.ObjectReference, c fuzz.Continue) {
|
||||
// We have to customize the randomization of TypeMetas because their
|
||||
// APIVersion and Kind must remain blank in memory.
|
||||
@ -99,10 +111,6 @@ func FuzzerFor(t *testing.T, version schema.GroupVersion, src rand.Source) *fuzz
|
||||
j.ResourceVersion = strconv.FormatUint(c.RandUint64(), 10)
|
||||
j.FieldPath = c.RandString()
|
||||
},
|
||||
func(j *metav1.ListMeta, c fuzz.Continue) {
|
||||
j.ResourceVersion = strconv.FormatUint(c.RandUint64(), 10)
|
||||
j.SelfLink = c.RandString()
|
||||
},
|
||||
func(j *api.ListOptions, c fuzz.Continue) {
|
||||
label, _ := labels.Parse("a=b")
|
||||
j.LabelSelector = label
|
||||
@ -158,48 +166,6 @@ func FuzzerFor(t *testing.T, version schema.GroupVersion, src rand.Source) *fuzz
|
||||
c.FuzzNoCustom(j) // fuzz self without calling this function again
|
||||
//j.TemplateRef = nil // this is required for round trip
|
||||
},
|
||||
func(j *extensions.DeploymentStrategy, c fuzz.Continue) {
|
||||
c.FuzzNoCustom(j) // fuzz self without calling this function again
|
||||
// Ensure that strategyType is one of valid values.
|
||||
strategyTypes := []extensions.DeploymentStrategyType{extensions.RecreateDeploymentStrategyType, extensions.RollingUpdateDeploymentStrategyType}
|
||||
j.Type = strategyTypes[c.Rand.Intn(len(strategyTypes))]
|
||||
if j.Type != extensions.RollingUpdateDeploymentStrategyType {
|
||||
j.RollingUpdate = nil
|
||||
} else {
|
||||
rollingUpdate := extensions.RollingUpdateDeployment{}
|
||||
if c.RandBool() {
|
||||
rollingUpdate.MaxUnavailable = intstr.FromInt(int(c.Rand.Int31()))
|
||||
rollingUpdate.MaxSurge = intstr.FromInt(int(c.Rand.Int31()))
|
||||
} else {
|
||||
rollingUpdate.MaxSurge = intstr.FromString(fmt.Sprintf("%d%%", c.Rand.Int31()))
|
||||
}
|
||||
j.RollingUpdate = &rollingUpdate
|
||||
}
|
||||
},
|
||||
func(j *batch.JobSpec, c fuzz.Continue) {
|
||||
c.FuzzNoCustom(j) // fuzz self without calling this function again
|
||||
completions := int32(c.Rand.Int31())
|
||||
parallelism := int32(c.Rand.Int31())
|
||||
j.Completions = &completions
|
||||
j.Parallelism = ¶llelism
|
||||
if c.Rand.Int31()%2 == 0 {
|
||||
j.ManualSelector = newBool(true)
|
||||
} else {
|
||||
j.ManualSelector = nil
|
||||
}
|
||||
},
|
||||
func(sj *batch.CronJobSpec, c fuzz.Continue) {
|
||||
c.FuzzNoCustom(sj)
|
||||
suspend := c.RandBool()
|
||||
sj.Suspend = &suspend
|
||||
sds := int64(c.RandUint64())
|
||||
sj.StartingDeadlineSeconds = &sds
|
||||
sj.Schedule = c.RandString()
|
||||
},
|
||||
func(cp *batch.ConcurrencyPolicy, c fuzz.Continue) {
|
||||
policies := []batch.ConcurrencyPolicy{batch.AllowConcurrent, batch.ForbidConcurrent, batch.ReplaceConcurrent}
|
||||
*cp = policies[c.Rand.Intn(len(policies))]
|
||||
},
|
||||
func(j *api.List, c fuzz.Continue) {
|
||||
c.FuzzNoCustom(j) // fuzz self without calling this function again
|
||||
// TODO: uncomment when round trip starts from a versioned object
|
||||
@ -207,21 +173,6 @@ func FuzzerFor(t *testing.T, version schema.GroupVersion, src rand.Source) *fuzz
|
||||
j.Items = []runtime.Object{}
|
||||
}
|
||||
},
|
||||
func(j *runtime.Object, c fuzz.Continue) {
|
||||
// TODO: uncomment when round trip starts from a versioned object
|
||||
if true { //c.RandBool() {
|
||||
*j = &runtime.Unknown{
|
||||
// We do not set TypeMeta here because it is not carried through a round trip
|
||||
Raw: []byte(`{"apiVersion":"unknown.group/unknown","kind":"Something","someKey":"someValue"}`),
|
||||
ContentType: runtime.ContentTypeJSON,
|
||||
}
|
||||
} else {
|
||||
types := []runtime.Object{&api.Pod{}, &api.ReplicationController{}}
|
||||
t := types[c.Rand.Intn(len(types))]
|
||||
c.Fuzz(t)
|
||||
*j = t
|
||||
}
|
||||
},
|
||||
func(q *api.ResourceRequirements, c fuzz.Continue) {
|
||||
randomQuantity := func() resource.Quantity {
|
||||
var q resource.Quantity
|
||||
@ -513,12 +464,28 @@ func FuzzerFor(t *testing.T, version schema.GroupVersion, src rand.Source) *fuzz
|
||||
c.FuzzNoCustom(s)
|
||||
s.Allocatable = s.Capacity
|
||||
},
|
||||
func(s *autoscaling.HorizontalPodAutoscalerSpec, c fuzz.Continue) {
|
||||
c.FuzzNoCustom(s) // fuzz self without calling this function again
|
||||
minReplicas := int32(c.Rand.Int31())
|
||||
s.MinReplicas = &minReplicas
|
||||
targetCpu := int32(c.RandUint64())
|
||||
s.TargetCPUUtilizationPercentage = &targetCpu
|
||||
}
|
||||
}
|
||||
|
||||
func extensionFuncs(t apitesting.TestingCommon) []interface{} {
|
||||
return []interface{}{
|
||||
func(j *extensions.DeploymentStrategy, c fuzz.Continue) {
|
||||
c.FuzzNoCustom(j) // fuzz self without calling this function again
|
||||
// Ensure that strategyType is one of valid values.
|
||||
strategyTypes := []extensions.DeploymentStrategyType{extensions.RecreateDeploymentStrategyType, extensions.RollingUpdateDeploymentStrategyType}
|
||||
j.Type = strategyTypes[c.Rand.Intn(len(strategyTypes))]
|
||||
if j.Type != extensions.RollingUpdateDeploymentStrategyType {
|
||||
j.RollingUpdate = nil
|
||||
} else {
|
||||
rollingUpdate := extensions.RollingUpdateDeployment{}
|
||||
if c.RandBool() {
|
||||
rollingUpdate.MaxUnavailable = intstr.FromInt(int(c.Rand.Int31()))
|
||||
rollingUpdate.MaxSurge = intstr.FromInt(int(c.Rand.Int31()))
|
||||
} else {
|
||||
rollingUpdate.MaxSurge = intstr.FromString(fmt.Sprintf("%d%%", c.Rand.Int31()))
|
||||
}
|
||||
j.RollingUpdate = &rollingUpdate
|
||||
}
|
||||
},
|
||||
func(psp *extensions.PodSecurityPolicySpec, c fuzz.Continue) {
|
||||
c.FuzzNoCustom(psp) // fuzz self without calling this function again
|
||||
@ -546,6 +513,52 @@ func FuzzerFor(t *testing.T, version schema.GroupVersion, src rand.Source) *fuzz
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func batchFuncs(t apitesting.TestingCommon) []interface{} {
|
||||
return []interface{}{
|
||||
func(j *batch.JobSpec, c fuzz.Continue) {
|
||||
c.FuzzNoCustom(j) // fuzz self without calling this function again
|
||||
completions := int32(c.Rand.Int31())
|
||||
parallelism := int32(c.Rand.Int31())
|
||||
j.Completions = &completions
|
||||
j.Parallelism = ¶llelism
|
||||
if c.Rand.Int31()%2 == 0 {
|
||||
j.ManualSelector = newBool(true)
|
||||
} else {
|
||||
j.ManualSelector = nil
|
||||
}
|
||||
},
|
||||
func(sj *batch.CronJobSpec, c fuzz.Continue) {
|
||||
c.FuzzNoCustom(sj)
|
||||
suspend := c.RandBool()
|
||||
sj.Suspend = &suspend
|
||||
sds := int64(c.RandUint64())
|
||||
sj.StartingDeadlineSeconds = &sds
|
||||
sj.Schedule = c.RandString()
|
||||
},
|
||||
func(cp *batch.ConcurrencyPolicy, c fuzz.Continue) {
|
||||
policies := []batch.ConcurrencyPolicy{batch.AllowConcurrent, batch.ForbidConcurrent, batch.ReplaceConcurrent}
|
||||
*cp = policies[c.Rand.Intn(len(policies))]
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func autoscalingFuncs(t apitesting.TestingCommon) []interface{} {
|
||||
return []interface{}{
|
||||
func(s *autoscaling.HorizontalPodAutoscalerSpec, c fuzz.Continue) {
|
||||
c.FuzzNoCustom(s) // fuzz self without calling this function again
|
||||
minReplicas := int32(c.Rand.Int31())
|
||||
s.MinReplicas = &minReplicas
|
||||
targetCpu := int32(c.RandUint64())
|
||||
s.TargetCPUUtilizationPercentage = &targetCpu
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func rbacFuncs(t apitesting.TestingCommon) []interface{} {
|
||||
return []interface{}{
|
||||
func(r *rbac.RoleRef, c fuzz.Continue) {
|
||||
c.FuzzNoCustom(r) // fuzz self without calling this function again
|
||||
|
||||
@ -554,37 +567,11 @@ func FuzzerFor(t *testing.T, version schema.GroupVersion, src rand.Source) *fuzz
|
||||
r.APIGroup = rbac.GroupName
|
||||
}
|
||||
},
|
||||
func(r *runtime.RawExtension, c fuzz.Continue) {
|
||||
// Pick an arbitrary type and fuzz it
|
||||
types := []runtime.Object{&api.Pod{}, &extensions.Deployment{}, &api.Service{}}
|
||||
obj := types[c.Rand.Intn(len(types))]
|
||||
c.Fuzz(obj)
|
||||
}
|
||||
}
|
||||
|
||||
// Find a codec for converting the object to raw bytes. This is necessary for the
|
||||
// api version and kind to be correctly set be serialization.
|
||||
var codec runtime.Codec
|
||||
switch obj.(type) {
|
||||
case *api.Pod:
|
||||
codec = testapi.Default.Codec()
|
||||
case *extensions.Deployment:
|
||||
codec = testapi.Extensions.Codec()
|
||||
case *api.Service:
|
||||
codec = testapi.Default.Codec()
|
||||
default:
|
||||
t.Errorf("Failed to find codec for object type: %T", obj)
|
||||
return
|
||||
}
|
||||
|
||||
// Convert the object to raw bytes
|
||||
bytes, err := runtime.Encode(codec, obj)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to encode object: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Set the bytes field on the RawExtension
|
||||
r.Raw = bytes
|
||||
},
|
||||
func kubeAdmFuncs(t apitesting.TestingCommon) []interface{} {
|
||||
return []interface{}{
|
||||
func(obj *kubeadm.MasterConfiguration, c fuzz.Continue) {
|
||||
c.FuzzNoCustom(obj)
|
||||
obj.KubernetesVersion = "v10"
|
||||
@ -594,16 +581,40 @@ func FuzzerFor(t *testing.T, version schema.GroupVersion, src rand.Source) *fuzz
|
||||
obj.AuthorizationMode = "foo"
|
||||
obj.Discovery.Token = &kubeadm.TokenDiscovery{}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func policyFuncs(t apitesting.TestingCommon) []interface{} {
|
||||
return []interface{}{
|
||||
func(s *policy.PodDisruptionBudgetStatus, c fuzz.Continue) {
|
||||
c.FuzzNoCustom(s) // fuzz self without calling this function again
|
||||
s.PodDisruptionsAllowed = int32(c.Rand.Intn(2))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func certificateFuncs(t apitesting.TestingCommon) []interface{} {
|
||||
return []interface{}{
|
||||
func(obj *certificates.CertificateSigningRequestSpec, c fuzz.Continue) {
|
||||
c.FuzzNoCustom(obj) // fuzz self without calling this function again
|
||||
obj.Usages = []certificates.KeyUsage{certificates.UsageKeyEncipherment}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func FuzzerFuncs(t apitesting.TestingCommon) []interface{} {
|
||||
return mergeFuncLists(t,
|
||||
apitesting.GenericFuzzerFuncs(t),
|
||||
overrideGenericFuncs(t),
|
||||
coreFuncs(t),
|
||||
extensionFuncs(t),
|
||||
batchFuncs(t),
|
||||
autoscalingFuncs(t),
|
||||
rbacFuncs(t),
|
||||
kubeAdmFuncs(t),
|
||||
policyFuncs(t),
|
||||
certificateFuncs(t),
|
||||
)
|
||||
return f
|
||||
}
|
||||
|
||||
func newBool(val bool) *bool {
|
||||
@ -611,3 +622,25 @@ func newBool(val bool) *bool {
|
||||
*p = val
|
||||
return p
|
||||
}
|
||||
|
||||
// mergeFuncLists will merge the given funcLists, overriding early funcs with later ones if there first
|
||||
// argument has the same type.
|
||||
func mergeFuncLists(t apitesting.TestingCommon, funcLists ...[]interface{}) []interface{} {
|
||||
funcMap := map[string]interface{}{}
|
||||
for _, list := range funcLists {
|
||||
for _, f := range list {
|
||||
fT := reflect.TypeOf(f)
|
||||
if fT.Kind() != reflect.Func || fT.NumIn() != 2 {
|
||||
t.Errorf("Fuzzer func with invalid type: %v", fT)
|
||||
continue
|
||||
}
|
||||
funcMap[fT.In(0).String()] = f
|
||||
}
|
||||
}
|
||||
|
||||
result := []interface{}{}
|
||||
for _, f := range funcMap {
|
||||
result = append(result, f)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
@ -21,9 +21,10 @@ import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
apitesting "k8s.io/apimachinery/pkg/api/testing"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/testapi"
|
||||
apitesting "k8s.io/kubernetes/pkg/api/testing"
|
||||
kapitesting "k8s.io/kubernetes/pkg/api/testing"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/diff"
|
||||
@ -41,7 +42,7 @@ func doRoundTrip(t *testing.T, group testapi.TestGroup, kind string) {
|
||||
t.Fatalf("Couldn't create internal object %v: %v", kind, err)
|
||||
}
|
||||
seed := rand.Int63()
|
||||
apitesting.FuzzerFor(t, group.InternalGroupVersion(), rand.NewSource(seed)).
|
||||
apitesting.FuzzerFor(kapitesting.FuzzerFuncs(t), rand.NewSource(seed)).
|
||||
// We are explicitly overwriting custom fuzzing functions, to ensure
|
||||
// that InitContainers and their statuses are not generated. This is
|
||||
// because in thise test we are simply doing json operations, in which
|
||||
@ -155,7 +156,7 @@ func BenchmarkToFromUnstructured(b *testing.B) {
|
||||
*/
|
||||
|
||||
func BenchmarkToFromUnstructuredViaJSON(b *testing.B) {
|
||||
items := benchmarkItems()
|
||||
items := benchmarkItems(b)
|
||||
size := len(items)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
|
@ -24,11 +24,12 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
apitesting "k8s.io/apimachinery/pkg/api/testing"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
k8syaml "k8s.io/apimachinery/pkg/util/yaml"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/testapi"
|
||||
apitesting "k8s.io/kubernetes/pkg/api/testing"
|
||||
kapitesting "k8s.io/kubernetes/pkg/api/testing"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
"k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
|
||||
|
||||
@ -148,7 +149,7 @@ func TestValidateOk(t *testing.T) {
|
||||
}
|
||||
|
||||
seed := rand.Int63()
|
||||
apiObjectFuzzer := apitesting.FuzzerFor(nil, testapi.Default.InternalGroupVersion(), rand.NewSource(seed))
|
||||
apiObjectFuzzer := apitesting.FuzzerFor(kapitesting.FuzzerFuncs(t), rand.NewSource(seed))
|
||||
for i := 0; i < 5; i++ {
|
||||
for _, test := range tests {
|
||||
testObj := test.obj
|
||||
|
@ -36,6 +36,7 @@ import (
|
||||
|
||||
apierrs "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
apitesting "k8s.io/apimachinery/pkg/api/testing"
|
||||
metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/fields"
|
||||
@ -48,7 +49,7 @@ import (
|
||||
"k8s.io/apiserver/pkg/admission"
|
||||
"k8s.io/apiserver/pkg/endpoints/request"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
apitesting "k8s.io/kubernetes/pkg/api/testing"
|
||||
kapitesting "k8s.io/kubernetes/pkg/api/testing"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
genericapifilters "k8s.io/kubernetes/pkg/genericapiserver/endpoints/filters"
|
||||
"k8s.io/kubernetes/pkg/genericapiserver/endpoints/handlers/responsewriters"
|
||||
@ -3338,7 +3339,7 @@ func readBodyOrDie(r io.Reader) []byte {
|
||||
|
||||
// BenchmarkUpdateProtobuf measures the cost of processing an update on the server in proto
|
||||
func BenchmarkUpdateProtobuf(b *testing.B) {
|
||||
items := benchmarkItems()
|
||||
items := benchmarkItems(b)
|
||||
|
||||
simpleStorage := &SimpleRESTStorage{}
|
||||
handler := handle(map[string]rest.Storage{"simples": simpleStorage})
|
||||
@ -3394,8 +3395,8 @@ func newTestRequestInfoResolver() *request.RequestInfoFactory {
|
||||
|
||||
const benchmarkSeed = 100
|
||||
|
||||
func benchmarkItems() []api.Pod {
|
||||
apiObjectFuzzer := apitesting.FuzzerFor(nil, api.SchemeGroupVersion, rand.NewSource(benchmarkSeed))
|
||||
func benchmarkItems(b *testing.B) []api.Pod {
|
||||
apiObjectFuzzer := apitesting.FuzzerFor(kapitesting.FuzzerFuncs(b), rand.NewSource(benchmarkSeed))
|
||||
items := make([]api.Pod, 3)
|
||||
for i := range items {
|
||||
apiObjectFuzzer.Fuzz(&items[i])
|
||||
|
@ -631,7 +631,7 @@ func TestWatchHTTPTimeout(t *testing.T) {
|
||||
|
||||
// BenchmarkWatchHTTP measures the cost of serving a watch.
|
||||
func BenchmarkWatchHTTP(b *testing.B) {
|
||||
items := benchmarkItems()
|
||||
items := benchmarkItems(b)
|
||||
|
||||
simpleStorage := &SimpleRESTStorage{}
|
||||
handler := handle(map[string]rest.Storage{"simples": simpleStorage})
|
||||
@ -678,7 +678,7 @@ func BenchmarkWatchHTTP(b *testing.B) {
|
||||
|
||||
// BenchmarkWatchWebsocket measures the cost of serving a watch.
|
||||
func BenchmarkWatchWebsocket(b *testing.B) {
|
||||
items := benchmarkItems()
|
||||
items := benchmarkItems(b)
|
||||
|
||||
simpleStorage := &SimpleRESTStorage{}
|
||||
handler := handle(map[string]rest.Storage{"simples": simpleStorage})
|
||||
@ -718,7 +718,7 @@ func BenchmarkWatchWebsocket(b *testing.B) {
|
||||
|
||||
// BenchmarkWatchProtobuf measures the cost of serving a watch.
|
||||
func BenchmarkWatchProtobuf(b *testing.B) {
|
||||
items := benchmarkItems()
|
||||
items := benchmarkItems(b)
|
||||
|
||||
simpleStorage := &SimpleRESTStorage{}
|
||||
handler := handle(map[string]rest.Storage{"simples": simpleStorage})
|
||||
|
133
staging/src/k8s.io/apimachinery/pkg/api/testing/fuzzer.go
Normal file
133
staging/src/k8s.io/apimachinery/pkg/api/testing/fuzzer.go
Normal file
@ -0,0 +1,133 @@
|
||||
/*
|
||||
Copyright 2017 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 (
|
||||
"strconv"
|
||||
"math/rand"
|
||||
"testing"
|
||||
|
||||
"github.com/google/gofuzz"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
)
|
||||
|
||||
func GenericFuzzerFuncs(t TestingCommon) []interface{} {
|
||||
return []interface{}{
|
||||
func(j *int, c fuzz.Continue) {
|
||||
*j = int(c.Int31())
|
||||
},
|
||||
func(j **int, c fuzz.Continue) {
|
||||
if c.RandBool() {
|
||||
i := int(c.Int31())
|
||||
*j = &i
|
||||
} else {
|
||||
*j = nil
|
||||
}
|
||||
},
|
||||
func(j *runtime.TypeMeta, c fuzz.Continue) {
|
||||
// We have to customize the randomization of TypeMetas because their
|
||||
// APIVersion and Kind must remain blank in memory.
|
||||
j.APIVersion = ""
|
||||
j.Kind = ""
|
||||
},
|
||||
func(j *metav1.TypeMeta, c fuzz.Continue) {
|
||||
// We have to customize the randomization of TypeMetas because their
|
||||
// APIVersion and Kind must remain blank in memory.
|
||||
j.APIVersion = ""
|
||||
j.Kind = ""
|
||||
},
|
||||
func(j *metav1.ObjectMeta, c fuzz.Continue) {
|
||||
j.Name = c.RandString()
|
||||
j.ResourceVersion = strconv.FormatUint(c.RandUint64(), 10)
|
||||
j.SelfLink = c.RandString()
|
||||
j.UID = types.UID(c.RandString())
|
||||
j.GenerateName = c.RandString()
|
||||
|
||||
var sec, nsec int64
|
||||
c.Fuzz(&sec)
|
||||
c.Fuzz(&nsec)
|
||||
j.CreationTimestamp = metav1.Unix(sec, nsec).Rfc3339Copy()
|
||||
},
|
||||
func(j *metav1.ListMeta, c fuzz.Continue) {
|
||||
j.ResourceVersion = strconv.FormatUint(c.RandUint64(), 10)
|
||||
j.SelfLink = c.RandString()
|
||||
},
|
||||
func(j *runtime.Object, c fuzz.Continue) {
|
||||
// TODO: uncomment when round trip starts from a versioned object
|
||||
if true { //c.RandBool() {
|
||||
*j = &runtime.Unknown{
|
||||
// We do not set TypeMeta here because it is not carried through a round trip
|
||||
Raw: []byte(`{"apiVersion":"unknown.group/unknown","kind":"Something","someKey":"someValue"}`),
|
||||
ContentType: runtime.ContentTypeJSON,
|
||||
}
|
||||
} else {
|
||||
types := []runtime.Object{&metav1.Status{}, &metav1.APIGroup{}}
|
||||
t := types[c.Rand.Intn(len(types))]
|
||||
c.Fuzz(t)
|
||||
*j = t
|
||||
}
|
||||
},
|
||||
func(r *runtime.RawExtension, c fuzz.Continue) {
|
||||
// Pick an arbitrary type and fuzz it
|
||||
types := []runtime.Object{&metav1.Status{}, &metav1.APIGroup{}}
|
||||
obj := types[c.Rand.Intn(len(types))]
|
||||
c.Fuzz(obj)
|
||||
|
||||
// Find a codec for converting the object to raw bytes. This is necessary for the
|
||||
// api version and kind to be correctly set be serialization.
|
||||
var codec = Codec(metav1.SchemeGroupVersion)
|
||||
|
||||
// Convert the object to raw bytes
|
||||
bytes, err := runtime.Encode(codec, obj)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to encode object: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Set the bytes field on the RawExtension
|
||||
r.Raw = bytes
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// TestingCommon abstracts testing.T and testing.B
|
||||
type TestingCommon interface {
|
||||
Log(args ...interface{})
|
||||
Logf(format string, args ...interface{})
|
||||
Error(args ...interface{})
|
||||
Errorf(format string, args ...interface{})
|
||||
Fatal(args ...interface{})
|
||||
Fatalf(format string, args ...interface{})
|
||||
}
|
||||
|
||||
var (
|
||||
_ TestingCommon = &testing.T{}
|
||||
_ TestingCommon = &testing.B{}
|
||||
)
|
||||
|
||||
// FuzzerFor can randomly populate api objects that are destined for version.
|
||||
func FuzzerFor(funcs []interface{}, src rand.Source) *fuzz.Fuzzer {
|
||||
f := fuzz.New().NilChance(.5).NumElements(0, 1)
|
||||
if src != nil {
|
||||
f.RandSource(src)
|
||||
}
|
||||
f.Funcs(funcs...)
|
||||
return f
|
||||
}
|
57
staging/src/k8s.io/apimachinery/pkg/api/testing/register.go
Normal file
57
staging/src/k8s.io/apimachinery/pkg/api/testing/register.go
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
Copyright 2017 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 (
|
||||
"os"
|
||||
"mime"
|
||||
"fmt"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
runtimeserializer "k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
var scheme = runtime.NewScheme()
|
||||
var codecs = runtimeserializer.NewCodecFactory(scheme)
|
||||
var serializer runtime.SerializerInfo
|
||||
|
||||
// Codec returns the codec for the API version to test against, as set by the
|
||||
// KUBE_TEST_API_TYPE env var.
|
||||
func Codec(gvs ...schema.GroupVersion) runtime.Codec {
|
||||
if serializer.Serializer == nil {
|
||||
return codecs.LegacyCodec(gvs...)
|
||||
}
|
||||
return codecs.CodecForVersions(serializer.Serializer, codecs.UniversalDeserializer(), schema.GroupVersions(gvs), nil)
|
||||
}
|
||||
|
||||
func init() {
|
||||
metav1.AddToGroupVersion(scheme, metav1.SchemeGroupVersion)
|
||||
|
||||
if apiMediaType := os.Getenv("KUBE_TEST_API_TYPE"); len(apiMediaType) > 0 {
|
||||
var ok bool
|
||||
mediaType, _, err := mime.ParseMediaType(apiMediaType)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
serializer, ok = runtime.SerializerInfoForMediaType(codecs.SupportedMediaTypes(), mediaType)
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("no serializer for %s", apiMediaType))
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user