pkg/api/testing: split fuzzer between apimachinery and kube

This commit is contained in:
Dr. Stefan Schimanski 2017-01-24 20:34:00 +01:00 committed by Dr. Stefan Schimanski
parent a12c661773
commit 6b6b6c747e
11 changed files with 407 additions and 177 deletions

View File

@ -21,15 +21,16 @@ import (
"math/rand" "math/rand"
"testing" "testing"
apitesting "k8s.io/apimachinery/pkg/api/testing"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/diff" "k8s.io/apimachinery/pkg/util/diff"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/testapi" "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) { 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) items := make([]api.Pod, 4)
for i := range items { for i := range items {
apiObjectFuzzer.Fuzz(&items[i]) apiObjectFuzzer.Fuzz(&items[i])

View File

@ -22,11 +22,12 @@ import (
"reflect" "reflect"
"testing" "testing"
apitesting "k8s.io/apimachinery/pkg/api/testing"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/diff" "k8s.io/apimachinery/pkg/util/diff"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/testapi" "k8s.io/kubernetes/pkg/api/testapi"
apitesting "k8s.io/kubernetes/pkg/api/testing" kapitesting "k8s.io/kubernetes/pkg/api/testing"
"github.com/google/gofuzz" "github.com/google/gofuzz"
) )
@ -34,7 +35,7 @@ import (
func TestDeepCopyApiObjects(t *testing.T) { func TestDeepCopyApiObjects(t *testing.T) {
for i := 0; i < *fuzzIters; i++ { for i := 0; i < *fuzzIters; i++ {
for _, version := range []schema.GroupVersion{testapi.Default.InternalGroupVersion(), api.Registry.GroupOrDie(api.GroupName).GroupVersion} { 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) { for kind := range api.Scheme.KnownTypes(version) {
doDeepCopyTest(t, version.WithKind(kind), f) 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) { func TestDeepCopySingleType(t *testing.T) {
for i := 0; i < *fuzzIters; i++ { for i := 0; i < *fuzzIters; i++ {
for _, version := range []schema.GroupVersion{testapi.Default.InternalGroupVersion(), api.Registry.GroupOrDie(api.GroupName).GroupVersion} { 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) doDeepCopyTest(t, version.WithKind("Pod"), f)
} }
} }

View File

@ -23,6 +23,7 @@ import (
"testing" "testing"
"github.com/gogo/protobuf/proto" "github.com/gogo/protobuf/proto"
apitesting "k8s.io/apimachinery/pkg/api/testing"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
@ -31,7 +32,7 @@ import (
"k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/sets"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/testapi" "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/api/v1"
_ "k8s.io/kubernetes/pkg/apis/extensions" _ "k8s.io/kubernetes/pkg/apis/extensions"
_ "k8s.io/kubernetes/pkg/apis/extensions/v1beta1" _ "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
@ -75,7 +76,7 @@ func TestUniversalDeserializer(t *testing.T) {
func TestProtobufRoundTrip(t *testing.T) { func TestProtobufRoundTrip(t *testing.T) {
obj := &v1.Pod{} 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. // InitContainers are turned into annotations by conversion.
obj.Spec.InitContainers = nil obj.Spec.InitContainers = nil
obj.Status.InitContainerStatuses = 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 // BenchmarkEncodeCodec measures the cost of performing a codec encode, which includes
// reflection (to clear APIVersion and Kind) // reflection (to clear APIVersion and Kind)
func BenchmarkEncodeCodecProtobuf(b *testing.B) { func BenchmarkEncodeCodecProtobuf(b *testing.B) {
items := benchmarkItems() items := benchmarkItems(b)
width := len(items) width := len(items)
s := protobuf.NewSerializer(nil, nil, "application/arbitrary.content.type") s := protobuf.NewSerializer(nil, nil, "application/arbitrary.content.type")
b.ResetTimer() b.ResetTimer()
@ -111,7 +112,7 @@ func BenchmarkEncodeCodecProtobuf(b *testing.B) {
// BenchmarkEncodeCodecFromInternalProtobuf measures the cost of performing a codec encode, // BenchmarkEncodeCodecFromInternalProtobuf measures the cost of performing a codec encode,
// including conversions and any type setting. This is a "full" encode. // including conversions and any type setting. This is a "full" encode.
func BenchmarkEncodeCodecFromInternalProtobuf(b *testing.B) { func BenchmarkEncodeCodecFromInternalProtobuf(b *testing.B) {
items := benchmarkItems() items := benchmarkItems(b)
width := len(items) width := len(items)
encodable := make([]api.Pod, width) encodable := make([]api.Pod, width)
for i := range items { for i := range items {
@ -131,7 +132,7 @@ func BenchmarkEncodeCodecFromInternalProtobuf(b *testing.B) {
} }
func BenchmarkEncodeProtobufGeneratedMarshal(b *testing.B) { func BenchmarkEncodeProtobufGeneratedMarshal(b *testing.B) {
items := benchmarkItems() items := benchmarkItems(b)
width := len(items) width := len(items)
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { 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, // BenchmarkDecodeCodecToInternalProtobuf measures the cost of performing a codec decode,
// including conversions and any type setting. This is a "full" decode. // including conversions and any type setting. This is a "full" decode.
func BenchmarkDecodeCodecToInternalProtobuf(b *testing.B) { func BenchmarkDecodeCodecToInternalProtobuf(b *testing.B) {
items := benchmarkItems() items := benchmarkItems(b)
width := len(items) width := len(items)
s := protobuf.NewSerializer(api.Scheme, api.Scheme, "application/arbitrary.content.type") s := protobuf.NewSerializer(api.Scheme, api.Scheme, "application/arbitrary.content.type")
encoder := api.Codecs.EncoderForVersion(s, v1.SchemeGroupVersion) 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 // BenchmarkDecodeJSON provides a baseline for regular JSON decode performance
func BenchmarkDecodeIntoProtobuf(b *testing.B) { func BenchmarkDecodeIntoProtobuf(b *testing.B) {
items := benchmarkItems() items := benchmarkItems(b)
width := len(items) width := len(items)
encoded := make([][]byte, width) encoded := make([][]byte, width)
for i := range items { for i := range items {

View File

@ -33,6 +33,7 @@ import (
"github.com/ugorji/go/codec" "github.com/ugorji/go/codec"
"k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/api/meta"
apitesting "k8s.io/apimachinery/pkg/api/testing"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/conversion" "k8s.io/apimachinery/pkg/conversion"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
@ -43,7 +44,7 @@ import (
"k8s.io/apimachinery/pkg/watch" "k8s.io/apimachinery/pkg/watch"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/testapi" "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/api/v1"
"k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/apis/extensions/v1beta1" "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 // fuzzInternalObject fuzzes an arbitrary runtime object using the appropriate
// fuzzer registered with the apitesting package. // fuzzer registered with the apitesting package.
func fuzzInternalObject(t *testing.T, forVersion schema.GroupVersion, item runtime.Object, seed int64) runtime.Object { 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) j, err := meta.TypeAccessor(item)
if err != nil { if err != nil {
@ -440,7 +441,7 @@ func TestUnversionedTypes(t *testing.T) {
// TestObjectWatchFraming establishes that a watch event can be encoded and // TestObjectWatchFraming establishes that a watch event can be encoded and
// decoded correctly through each of the supported RFC2046 media types. // decoded correctly through each of the supported RFC2046 media types.
func TestObjectWatchFraming(t *testing.T) { 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{} secret := &api.Secret{}
f.Fuzz(secret) f.Fuzz(secret)
secret.Data["binary"] = []byte{0x00, 0x10, 0x30, 0x55, 0xff, 0x00} secret.Data["binary"] = []byte{0x00, 0x10, 0x30, 0x55, 0xff, 0x00}
@ -521,8 +522,8 @@ func TestObjectWatchFraming(t *testing.T) {
const benchmarkSeed = 100 const benchmarkSeed = 100
func benchmarkItems() []v1.Pod { func benchmarkItems(b *testing.B) []v1.Pod {
apiObjectFuzzer := apitesting.FuzzerFor(nil, api.SchemeGroupVersion, rand.NewSource(benchmarkSeed)) apiObjectFuzzer := apitesting.FuzzerFor(kapitesting.FuzzerFuncs(b), rand.NewSource(benchmarkSeed))
items := make([]v1.Pod, 10) items := make([]v1.Pod, 10)
for i := range items { for i := range items {
var pod api.Pod var pod api.Pod
@ -540,7 +541,7 @@ func benchmarkItems() []v1.Pod {
// BenchmarkEncodeCodec measures the cost of performing a codec encode, which includes // BenchmarkEncodeCodec measures the cost of performing a codec encode, which includes
// reflection (to clear APIVersion and Kind) // reflection (to clear APIVersion and Kind)
func BenchmarkEncodeCodec(b *testing.B) { func BenchmarkEncodeCodec(b *testing.B) {
items := benchmarkItems() items := benchmarkItems(b)
width := len(items) width := len(items)
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { 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, // BenchmarkEncodeCodecFromInternal measures the cost of performing a codec encode,
// including conversions. // including conversions.
func BenchmarkEncodeCodecFromInternal(b *testing.B) { func BenchmarkEncodeCodecFromInternal(b *testing.B) {
items := benchmarkItems() items := benchmarkItems(b)
width := len(items) width := len(items)
encodable := make([]api.Pod, width) encodable := make([]api.Pod, width)
for i := range items { for i := range items {
@ -573,7 +574,7 @@ func BenchmarkEncodeCodecFromInternal(b *testing.B) {
// BenchmarkEncodeJSONMarshal provides a baseline for regular JSON encode performance // BenchmarkEncodeJSONMarshal provides a baseline for regular JSON encode performance
func BenchmarkEncodeJSONMarshal(b *testing.B) { func BenchmarkEncodeJSONMarshal(b *testing.B) {
items := benchmarkItems() items := benchmarkItems(b)
width := len(items) width := len(items)
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
@ -586,7 +587,7 @@ func BenchmarkEncodeJSONMarshal(b *testing.B) {
func BenchmarkDecodeCodec(b *testing.B) { func BenchmarkDecodeCodec(b *testing.B) {
codec := testapi.Default.Codec() codec := testapi.Default.Codec()
items := benchmarkItems() items := benchmarkItems(b)
width := len(items) width := len(items)
encoded := make([][]byte, width) encoded := make([][]byte, width)
for i := range items { for i := range items {
@ -608,7 +609,7 @@ func BenchmarkDecodeCodec(b *testing.B) {
func BenchmarkDecodeIntoExternalCodec(b *testing.B) { func BenchmarkDecodeIntoExternalCodec(b *testing.B) {
codec := testapi.Default.Codec() codec := testapi.Default.Codec()
items := benchmarkItems() items := benchmarkItems(b)
width := len(items) width := len(items)
encoded := make([][]byte, width) encoded := make([][]byte, width)
for i := range items { for i := range items {
@ -631,7 +632,7 @@ func BenchmarkDecodeIntoExternalCodec(b *testing.B) {
func BenchmarkDecodeIntoInternalCodec(b *testing.B) { func BenchmarkDecodeIntoInternalCodec(b *testing.B) {
codec := testapi.Default.Codec() codec := testapi.Default.Codec()
items := benchmarkItems() items := benchmarkItems(b)
width := len(items) width := len(items)
encoded := make([][]byte, width) encoded := make([][]byte, width)
for i := range items { for i := range items {
@ -655,7 +656,7 @@ func BenchmarkDecodeIntoInternalCodec(b *testing.B) {
// BenchmarkDecodeJSON provides a baseline for regular JSON decode performance // BenchmarkDecodeJSON provides a baseline for regular JSON decode performance
func BenchmarkDecodeIntoJSON(b *testing.B) { func BenchmarkDecodeIntoJSON(b *testing.B) {
codec := testapi.Default.Codec() codec := testapi.Default.Codec()
items := benchmarkItems() items := benchmarkItems(b)
width := len(items) width := len(items)
encoded := make([][]byte, width) encoded := make([][]byte, width)
for i := range items { for i := range items {
@ -679,7 +680,7 @@ func BenchmarkDecodeIntoJSON(b *testing.B) {
// BenchmarkDecodeJSON provides a baseline for codecgen JSON decode performance // BenchmarkDecodeJSON provides a baseline for codecgen JSON decode performance
func BenchmarkDecodeIntoJSONCodecGen(b *testing.B) { func BenchmarkDecodeIntoJSONCodecGen(b *testing.B) {
kcodec := testapi.Default.Codec() kcodec := testapi.Default.Codec()
items := benchmarkItems() items := benchmarkItems(b)
width := len(items) width := len(items)
encoded := make([][]byte, width) encoded := make([][]byte, width)
for i := range items { for i := range items {

View File

@ -18,19 +18,17 @@ package testing
import ( import (
"fmt" "fmt"
"math/rand"
"reflect" "reflect"
"strconv" "strconv"
"testing"
"github.com/google/gofuzz" "github.com/google/gofuzz"
apitesting "k8s.io/apimachinery/pkg/api/testing"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/resource" "k8s.io/kubernetes/pkg/api/resource"
@ -44,51 +42,65 @@ import (
"k8s.io/kubernetes/pkg/util/intstr" "k8s.io/kubernetes/pkg/util/intstr"
) )
// FuzzerFor can randomly populate api objects that are destined for version. // overrideGenericFuncs override some generic fuzzer funcs from k8s.io/apiserver in order to have more realistic
func FuzzerFor(t *testing.T, version schema.GroupVersion, src rand.Source) *fuzz.Fuzzer { // values in a Kubernetes context.
f := fuzz.New().NilChance(.5).NumElements(0, 1) func overrideGenericFuncs(t apitesting.TestingCommon) []interface{} {
if src != nil { return []interface{}{
f.RandSource(src) 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,
} }
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
} else { } 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) { func(q *resource.Quantity, c fuzz.Continue) {
*q = *resource.NewQuantity(c.Int63n(1000), resource.DecimalExponent) *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) { func(j *api.ObjectReference, c fuzz.Continue) {
// We have to customize the randomization of TypeMetas because their // We have to customize the randomization of TypeMetas because their
// APIVersion and Kind must remain blank in memory. // 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.ResourceVersion = strconv.FormatUint(c.RandUint64(), 10)
j.FieldPath = c.RandString() 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) { func(j *api.ListOptions, c fuzz.Continue) {
label, _ := labels.Parse("a=b") label, _ := labels.Parse("a=b")
j.LabelSelector = label 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 c.FuzzNoCustom(j) // fuzz self without calling this function again
//j.TemplateRef = nil // this is required for round trip //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 = &parallelism
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) { func(j *api.List, c fuzz.Continue) {
c.FuzzNoCustom(j) // fuzz self without calling this function again c.FuzzNoCustom(j) // fuzz self without calling this function again
// TODO: uncomment when round trip starts from a versioned object // 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{} 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) { func(q *api.ResourceRequirements, c fuzz.Continue) {
randomQuantity := func() resource.Quantity { randomQuantity := func() resource.Quantity {
var q 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) c.FuzzNoCustom(s)
s.Allocatable = s.Capacity 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 func extensionFuncs(t apitesting.TestingCommon) []interface{} {
targetCpu := int32(c.RandUint64()) return []interface{}{
s.TargetCPUUtilizationPercentage = &targetCpu 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) { func(psp *extensions.PodSecurityPolicySpec, c fuzz.Continue) {
c.FuzzNoCustom(psp) // fuzz self without calling this function again 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 = &parallelism
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) { func(r *rbac.RoleRef, c fuzz.Continue) {
c.FuzzNoCustom(r) // fuzz self without calling this function again 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 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 func kubeAdmFuncs(t apitesting.TestingCommon) []interface{} {
bytes, err := runtime.Encode(codec, obj) return []interface{}{
if err != nil {
t.Errorf("Failed to encode object: %v", err)
return
}
// Set the bytes field on the RawExtension
r.Raw = bytes
},
func(obj *kubeadm.MasterConfiguration, c fuzz.Continue) { func(obj *kubeadm.MasterConfiguration, c fuzz.Continue) {
c.FuzzNoCustom(obj) c.FuzzNoCustom(obj)
obj.KubernetesVersion = "v10" obj.KubernetesVersion = "v10"
@ -594,16 +581,40 @@ func FuzzerFor(t *testing.T, version schema.GroupVersion, src rand.Source) *fuzz
obj.AuthorizationMode = "foo" obj.AuthorizationMode = "foo"
obj.Discovery.Token = &kubeadm.TokenDiscovery{} obj.Discovery.Token = &kubeadm.TokenDiscovery{}
}, },
}
}
func policyFuncs(t apitesting.TestingCommon) []interface{} {
return []interface{}{
func(s *policy.PodDisruptionBudgetStatus, c fuzz.Continue) { func(s *policy.PodDisruptionBudgetStatus, c fuzz.Continue) {
c.FuzzNoCustom(s) // fuzz self without calling this function again c.FuzzNoCustom(s) // fuzz self without calling this function again
s.PodDisruptionsAllowed = int32(c.Rand.Intn(2)) s.PodDisruptionsAllowed = int32(c.Rand.Intn(2))
}, },
}
}
func certificateFuncs(t apitesting.TestingCommon) []interface{} {
return []interface{}{
func(obj *certificates.CertificateSigningRequestSpec, c fuzz.Continue) { func(obj *certificates.CertificateSigningRequestSpec, c fuzz.Continue) {
c.FuzzNoCustom(obj) // fuzz self without calling this function again c.FuzzNoCustom(obj) // fuzz self without calling this function again
obj.Usages = []certificates.KeyUsage{certificates.UsageKeyEncipherment} 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 { func newBool(val bool) *bool {
@ -611,3 +622,25 @@ func newBool(val bool) *bool {
*p = val *p = val
return p 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
}

View File

@ -21,9 +21,10 @@ import (
"reflect" "reflect"
"testing" "testing"
apitesting "k8s.io/apimachinery/pkg/api/testing"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/testapi" "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/api/v1"
"k8s.io/apimachinery/pkg/util/diff" "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) t.Fatalf("Couldn't create internal object %v: %v", kind, err)
} }
seed := rand.Int63() 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 // We are explicitly overwriting custom fuzzing functions, to ensure
// that InitContainers and their statuses are not generated. This is // that InitContainers and their statuses are not generated. This is
// because in thise test we are simply doing json operations, in which // 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) { func BenchmarkToFromUnstructuredViaJSON(b *testing.B) {
items := benchmarkItems() items := benchmarkItems(b)
size := len(items) size := len(items)
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {

View File

@ -24,11 +24,12 @@ import (
"strings" "strings"
"testing" "testing"
apitesting "k8s.io/apimachinery/pkg/api/testing"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
k8syaml "k8s.io/apimachinery/pkg/util/yaml" k8syaml "k8s.io/apimachinery/pkg/util/yaml"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/testapi" "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/api/v1"
"k8s.io/kubernetes/pkg/apis/extensions/v1beta1" "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
@ -148,7 +149,7 @@ func TestValidateOk(t *testing.T) {
} }
seed := rand.Int63() 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 i := 0; i < 5; i++ {
for _, test := range tests { for _, test := range tests {
testObj := test.obj testObj := test.obj

View File

@ -36,6 +36,7 @@ import (
apierrs "k8s.io/apimachinery/pkg/api/errors" apierrs "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/api/meta"
apitesting "k8s.io/apimachinery/pkg/api/testing"
metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion" metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/fields"
@ -48,7 +49,7 @@ import (
"k8s.io/apiserver/pkg/admission" "k8s.io/apiserver/pkg/admission"
"k8s.io/apiserver/pkg/endpoints/request" "k8s.io/apiserver/pkg/endpoints/request"
"k8s.io/kubernetes/pkg/api" "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" "k8s.io/kubernetes/pkg/api/v1"
genericapifilters "k8s.io/kubernetes/pkg/genericapiserver/endpoints/filters" genericapifilters "k8s.io/kubernetes/pkg/genericapiserver/endpoints/filters"
"k8s.io/kubernetes/pkg/genericapiserver/endpoints/handlers/responsewriters" "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 // BenchmarkUpdateProtobuf measures the cost of processing an update on the server in proto
func BenchmarkUpdateProtobuf(b *testing.B) { func BenchmarkUpdateProtobuf(b *testing.B) {
items := benchmarkItems() items := benchmarkItems(b)
simpleStorage := &SimpleRESTStorage{} simpleStorage := &SimpleRESTStorage{}
handler := handle(map[string]rest.Storage{"simples": simpleStorage}) handler := handle(map[string]rest.Storage{"simples": simpleStorage})
@ -3394,8 +3395,8 @@ func newTestRequestInfoResolver() *request.RequestInfoFactory {
const benchmarkSeed = 100 const benchmarkSeed = 100
func benchmarkItems() []api.Pod { func benchmarkItems(b *testing.B) []api.Pod {
apiObjectFuzzer := apitesting.FuzzerFor(nil, api.SchemeGroupVersion, rand.NewSource(benchmarkSeed)) apiObjectFuzzer := apitesting.FuzzerFor(kapitesting.FuzzerFuncs(b), rand.NewSource(benchmarkSeed))
items := make([]api.Pod, 3) items := make([]api.Pod, 3)
for i := range items { for i := range items {
apiObjectFuzzer.Fuzz(&items[i]) apiObjectFuzzer.Fuzz(&items[i])

View File

@ -631,7 +631,7 @@ func TestWatchHTTPTimeout(t *testing.T) {
// BenchmarkWatchHTTP measures the cost of serving a watch. // BenchmarkWatchHTTP measures the cost of serving a watch.
func BenchmarkWatchHTTP(b *testing.B) { func BenchmarkWatchHTTP(b *testing.B) {
items := benchmarkItems() items := benchmarkItems(b)
simpleStorage := &SimpleRESTStorage{} simpleStorage := &SimpleRESTStorage{}
handler := handle(map[string]rest.Storage{"simples": simpleStorage}) 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. // BenchmarkWatchWebsocket measures the cost of serving a watch.
func BenchmarkWatchWebsocket(b *testing.B) { func BenchmarkWatchWebsocket(b *testing.B) {
items := benchmarkItems() items := benchmarkItems(b)
simpleStorage := &SimpleRESTStorage{} simpleStorage := &SimpleRESTStorage{}
handler := handle(map[string]rest.Storage{"simples": simpleStorage}) 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. // BenchmarkWatchProtobuf measures the cost of serving a watch.
func BenchmarkWatchProtobuf(b *testing.B) { func BenchmarkWatchProtobuf(b *testing.B) {
items := benchmarkItems() items := benchmarkItems(b)
simpleStorage := &SimpleRESTStorage{} simpleStorage := &SimpleRESTStorage{}
handler := handle(map[string]rest.Storage{"simples": simpleStorage}) handler := handle(map[string]rest.Storage{"simples": simpleStorage})

View 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
}

View 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))
}
}
}