Squashed 'k8smain/' content from commit 719158d
git-subtree-dir: k8smain git-subtree-split: 719158d2c8788c30cc9e1c51bbebb53c5801524e
This commit is contained in:
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
Copyright 2015 The Kubernetes Authors All rights reserved.
|
||||
|
||||
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 compat
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
"k8s.io/kubernetes/pkg/util/validation/field"
|
||||
)
|
||||
|
||||
// Based on: https://github.com/openshift/origin/blob/master/pkg/api/compatibility_test.go
|
||||
//
|
||||
// TestCompatibility reencodes the input using the codec for the given
|
||||
// version and checks for the presence of the expected keys and absent
|
||||
// keys in the resulting JSON.
|
||||
func TestCompatibility(
|
||||
t *testing.T,
|
||||
version unversioned.GroupVersion,
|
||||
input []byte,
|
||||
validator func(obj runtime.Object) field.ErrorList,
|
||||
expectedKeys map[string]string,
|
||||
absentKeys []string,
|
||||
) {
|
||||
|
||||
// Decode
|
||||
codec := api.Codecs.LegacyCodec(version)
|
||||
obj, err := runtime.Decode(codec, input)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
|
||||
// Validate
|
||||
errs := validator(obj)
|
||||
if len(errs) != 0 {
|
||||
t.Fatalf("Unexpected validation errors: %v", errs)
|
||||
}
|
||||
|
||||
// Encode
|
||||
output, err := runtime.Encode(codec, obj)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
|
||||
// Validate old and new fields are encoded
|
||||
generic := map[string]interface{}{}
|
||||
if err := json.Unmarshal(output, &generic); err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
|
||||
hasError := false
|
||||
for k, expectedValue := range expectedKeys {
|
||||
keys := strings.Split(k, ".")
|
||||
if actualValue, ok, err := getJSONValue(generic, keys...); err != nil || !ok {
|
||||
t.Errorf("Unexpected error for %s: %v", k, err)
|
||||
hasError = true
|
||||
} else if !reflect.DeepEqual(expectedValue, fmt.Sprintf("%v", actualValue)) {
|
||||
hasError = true
|
||||
t.Errorf("Unexpected value for %v: expected %v, got %v", k, expectedValue, actualValue)
|
||||
}
|
||||
}
|
||||
|
||||
for _, absentKey := range absentKeys {
|
||||
keys := strings.Split(absentKey, ".")
|
||||
actualValue, ok, err := getJSONValue(generic, keys...)
|
||||
if err == nil || ok {
|
||||
t.Errorf("Unexpected value found for for key %s: %v", absentKey, actualValue)
|
||||
hasError = true
|
||||
}
|
||||
}
|
||||
|
||||
if hasError {
|
||||
printer := new(kubectl.JSONPrinter)
|
||||
printer.PrintObj(obj, os.Stdout)
|
||||
t.Logf("2: Encoded value: %#v", string(output))
|
||||
}
|
||||
}
|
||||
|
||||
func getJSONValue(data map[string]interface{}, keys ...string) (interface{}, bool, error) {
|
||||
// No keys, current value is it
|
||||
if len(keys) == 0 {
|
||||
return data, true, nil
|
||||
}
|
||||
|
||||
// Get the key (and optional index)
|
||||
key := keys[0]
|
||||
index := -1
|
||||
if matches := regexp.MustCompile(`^(.*)\[(\d+)\]$`).FindStringSubmatch(key); len(matches) > 0 {
|
||||
key = matches[1]
|
||||
index, _ = strconv.Atoi(matches[2])
|
||||
}
|
||||
|
||||
// Look up the value
|
||||
value, ok := data[key]
|
||||
if !ok {
|
||||
return nil, false, fmt.Errorf("No key %s found", key)
|
||||
}
|
||||
|
||||
// Get the indexed value if an index is specified
|
||||
if index >= 0 {
|
||||
valueSlice, ok := value.([]interface{})
|
||||
if !ok {
|
||||
return nil, false, fmt.Errorf("Key %s did not hold a slice", key)
|
||||
}
|
||||
if index >= len(valueSlice) {
|
||||
return nil, false, fmt.Errorf("Index %d out of bounds for slice at key: %v", index, key)
|
||||
}
|
||||
value = valueSlice[index]
|
||||
}
|
||||
|
||||
if len(keys) == 1 {
|
||||
return value, true, nil
|
||||
}
|
||||
|
||||
childData, ok := value.(map[string]interface{})
|
||||
if !ok {
|
||||
return nil, false, fmt.Errorf("Key %s did not hold a map", keys[0])
|
||||
}
|
||||
return getJSONValue(childData, keys[1:]...)
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
Copyright 2015 The Kubernetes Authors All rights reserved.
|
||||
|
||||
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 (
|
||||
"testing"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/labels"
|
||||
)
|
||||
|
||||
// TestSelectableFieldLabelConversions verifies that given resource have field
|
||||
// label conversion defined for each its selectable field.
|
||||
// fields contains selectable fields of the resource.
|
||||
// labelMap maps deprecated labels to their canonical names.
|
||||
func TestSelectableFieldLabelConversionsOfKind(t *testing.T, apiVersion string, kind string, fields labels.Set, labelMap map[string]string) {
|
||||
badFieldLabels := []string{
|
||||
"name",
|
||||
".name",
|
||||
"bad",
|
||||
"metadata",
|
||||
"foo.bar",
|
||||
}
|
||||
|
||||
value := "value"
|
||||
|
||||
if len(fields) == 0 {
|
||||
t.Logf("no selectable fields for kind %q, skipping", kind)
|
||||
}
|
||||
for label := range fields {
|
||||
if label == "name" {
|
||||
t.Logf("FIXME: \"name\" is deprecated by \"metadata.name\", it should be removed from selectable fields of kind=%s", kind)
|
||||
continue
|
||||
}
|
||||
newLabel, newValue, err := api.Scheme.ConvertFieldLabel(apiVersion, kind, label, value)
|
||||
if err != nil {
|
||||
t.Errorf("kind=%s label=%s: got unexpected error: %v", kind, label, err)
|
||||
} else {
|
||||
expectedLabel := label
|
||||
if l, exists := labelMap[label]; exists {
|
||||
expectedLabel = l
|
||||
}
|
||||
if newLabel != expectedLabel {
|
||||
t.Errorf("kind=%s label=%s: got unexpected label name (%q != %q)", kind, label, newLabel, expectedLabel)
|
||||
}
|
||||
if newValue != value {
|
||||
t.Errorf("kind=%s label=%s: got unexpected new value (%q != %q)", kind, label, newValue, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, label := range badFieldLabels {
|
||||
_, _, err := api.Scheme.ConvertFieldLabel(apiVersion, kind, label, "value")
|
||||
if err == nil {
|
||||
t.Errorf("kind=%s label=%s: got unexpected non-error", kind, label)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,424 @@
|
||||
/*
|
||||
Copyright 2015 The Kubernetes Authors All rights reserved.
|
||||
|
||||
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 (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
docker "github.com/fsouza/go-dockerclient"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/resource"
|
||||
"k8s.io/kubernetes/pkg/api/testapi"
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||
"k8s.io/kubernetes/pkg/fields"
|
||||
"k8s.io/kubernetes/pkg/labels"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
"k8s.io/kubernetes/pkg/types"
|
||||
"k8s.io/kubernetes/pkg/util/intstr"
|
||||
|
||||
"github.com/google/gofuzz"
|
||||
)
|
||||
|
||||
// FuzzerFor can randomly populate api objects that are destined for version.
|
||||
func FuzzerFor(t *testing.T, version unversioned.GroupVersion, src rand.Source) *fuzz.Fuzzer {
|
||||
f := fuzz.New().NilChance(.5).NumElements(1, 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
|
||||
} else {
|
||||
*j = nil
|
||||
}
|
||||
},
|
||||
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 *unversioned.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 *api.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 = unversioned.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.
|
||||
j.APIVersion = c.RandString()
|
||||
j.Kind = c.RandString()
|
||||
j.Namespace = c.RandString()
|
||||
j.Name = c.RandString()
|
||||
j.ResourceVersion = strconv.FormatUint(c.RandUint64(), 10)
|
||||
j.FieldPath = c.RandString()
|
||||
},
|
||||
func(j *unversioned.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
|
||||
field, _ := fields.ParseSelector("a=b")
|
||||
j.FieldSelector = field
|
||||
},
|
||||
func(j *api.PodExecOptions, c fuzz.Continue) {
|
||||
j.Stdout = true
|
||||
j.Stderr = true
|
||||
},
|
||||
func(j *api.PodAttachOptions, c fuzz.Continue) {
|
||||
j.Stdout = true
|
||||
j.Stderr = true
|
||||
},
|
||||
func(s *api.PodSpec, c fuzz.Continue) {
|
||||
c.FuzzNoCustom(s)
|
||||
// has a default value
|
||||
ttl := int64(30)
|
||||
if c.RandBool() {
|
||||
ttl = int64(c.Uint32())
|
||||
}
|
||||
s.TerminationGracePeriodSeconds = &ttl
|
||||
|
||||
c.Fuzz(s.SecurityContext)
|
||||
|
||||
if s.SecurityContext == nil {
|
||||
s.SecurityContext = new(api.PodSecurityContext)
|
||||
}
|
||||
},
|
||||
func(j *api.PodPhase, c fuzz.Continue) {
|
||||
statuses := []api.PodPhase{api.PodPending, api.PodRunning, api.PodFailed, api.PodUnknown}
|
||||
*j = statuses[c.Rand.Intn(len(statuses))]
|
||||
},
|
||||
func(j *api.Binding, c fuzz.Continue) {
|
||||
c.Fuzz(&j.ObjectMeta)
|
||||
j.Target.Name = c.RandString()
|
||||
},
|
||||
func(j *api.ReplicationControllerSpec, c fuzz.Continue) {
|
||||
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.RandUint64()))
|
||||
rollingUpdate.MaxSurge = intstr.FromInt(int(c.RandUint64()))
|
||||
} else {
|
||||
rollingUpdate.MaxSurge = intstr.FromString(fmt.Sprintf("%d%%", c.RandUint64()))
|
||||
}
|
||||
j.RollingUpdate = &rollingUpdate
|
||||
}
|
||||
},
|
||||
func(j *extensions.JobSpec, c fuzz.Continue) {
|
||||
c.FuzzNoCustom(j) // fuzz self without calling this function again
|
||||
completions := int(c.Rand.Int31())
|
||||
parallelism := int(c.Rand.Int31())
|
||||
j.Completions = &completions
|
||||
j.Parallelism = ¶llelism
|
||||
if c.Rand.Int31()%2 == 0 {
|
||||
j.ManualSelector = newBool(true)
|
||||
} else {
|
||||
j.ManualSelector = nil
|
||||
}
|
||||
},
|
||||
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
|
||||
if false { //j.Items == nil {
|
||||
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
|
||||
RawJSON: []byte(`{"apiVersion":"unknown.group/unknown","kind":"Something","someKey":"someValue"}`),
|
||||
}
|
||||
} else {
|
||||
types := []runtime.Object{&api.Pod{}, &api.ReplicationController{}}
|
||||
t := types[c.Rand.Intn(len(types))]
|
||||
c.Fuzz(t)
|
||||
*j = t
|
||||
}
|
||||
},
|
||||
func(pb map[docker.Port][]docker.PortBinding, c fuzz.Continue) {
|
||||
// This is necessary because keys with nil values get omitted.
|
||||
// TODO: Is this a bug?
|
||||
pb[docker.Port(c.RandString())] = []docker.PortBinding{
|
||||
{c.RandString(), c.RandString()},
|
||||
{c.RandString(), c.RandString()},
|
||||
}
|
||||
},
|
||||
func(pm map[string]docker.PortMapping, c fuzz.Continue) {
|
||||
// This is necessary because keys with nil values get omitted.
|
||||
// TODO: Is this a bug?
|
||||
pm[c.RandString()] = docker.PortMapping{
|
||||
c.RandString(): c.RandString(),
|
||||
}
|
||||
},
|
||||
func(q *api.ResourceRequirements, c fuzz.Continue) {
|
||||
randomQuantity := func() resource.Quantity {
|
||||
var q resource.Quantity
|
||||
c.Fuzz(&q)
|
||||
return q
|
||||
}
|
||||
q.Limits = make(api.ResourceList)
|
||||
q.Requests = make(api.ResourceList)
|
||||
cpuLimit := randomQuantity()
|
||||
q.Limits[api.ResourceCPU] = *cpuLimit.Copy()
|
||||
q.Requests[api.ResourceCPU] = *cpuLimit.Copy()
|
||||
memoryLimit := randomQuantity()
|
||||
q.Limits[api.ResourceMemory] = *memoryLimit.Copy()
|
||||
q.Requests[api.ResourceMemory] = *memoryLimit.Copy()
|
||||
storageLimit := randomQuantity()
|
||||
q.Limits[api.ResourceStorage] = *storageLimit.Copy()
|
||||
q.Requests[api.ResourceStorage] = *storageLimit.Copy()
|
||||
},
|
||||
func(q *api.LimitRangeItem, c fuzz.Continue) {
|
||||
var cpuLimit resource.Quantity
|
||||
c.Fuzz(&cpuLimit)
|
||||
|
||||
q.Type = api.LimitTypeContainer
|
||||
q.Default = make(api.ResourceList)
|
||||
q.Default[api.ResourceCPU] = *(cpuLimit.Copy())
|
||||
|
||||
q.DefaultRequest = make(api.ResourceList)
|
||||
q.DefaultRequest[api.ResourceCPU] = *(cpuLimit.Copy())
|
||||
|
||||
q.Max = make(api.ResourceList)
|
||||
q.Max[api.ResourceCPU] = *(cpuLimit.Copy())
|
||||
|
||||
q.Min = make(api.ResourceList)
|
||||
q.Min[api.ResourceCPU] = *(cpuLimit.Copy())
|
||||
|
||||
q.MaxLimitRequestRatio = make(api.ResourceList)
|
||||
q.MaxLimitRequestRatio[api.ResourceCPU] = resource.MustParse("10")
|
||||
},
|
||||
func(p *api.PullPolicy, c fuzz.Continue) {
|
||||
policies := []api.PullPolicy{api.PullAlways, api.PullNever, api.PullIfNotPresent}
|
||||
*p = policies[c.Rand.Intn(len(policies))]
|
||||
},
|
||||
func(rp *api.RestartPolicy, c fuzz.Continue) {
|
||||
policies := []api.RestartPolicy{api.RestartPolicyAlways, api.RestartPolicyNever, api.RestartPolicyOnFailure}
|
||||
*rp = policies[c.Rand.Intn(len(policies))]
|
||||
},
|
||||
// Only api.DownwardAPIVolumeFile needs to have a specific func since FieldRef has to be
|
||||
// defaulted to a version otherwise roundtrip will fail
|
||||
// For the remaining volume plugins the default fuzzer is enough.
|
||||
func(m *api.DownwardAPIVolumeFile, c fuzz.Continue) {
|
||||
m.Path = c.RandString()
|
||||
versions := []string{"v1"}
|
||||
m.FieldRef.APIVersion = versions[c.Rand.Intn(len(versions))]
|
||||
m.FieldRef.FieldPath = c.RandString()
|
||||
},
|
||||
func(vs *api.VolumeSource, c fuzz.Continue) {
|
||||
// Exactly one of the fields must be set.
|
||||
v := reflect.ValueOf(vs).Elem()
|
||||
i := int(c.RandUint64() % uint64(v.NumField()))
|
||||
t := v.Field(i).Addr()
|
||||
for v.Field(i).IsNil() {
|
||||
c.Fuzz(t.Interface())
|
||||
}
|
||||
},
|
||||
func(i *api.ISCSIVolumeSource, c fuzz.Continue) {
|
||||
i.ISCSIInterface = c.RandString()
|
||||
if i.ISCSIInterface == "" {
|
||||
i.ISCSIInterface = "default"
|
||||
}
|
||||
},
|
||||
func(d *api.DNSPolicy, c fuzz.Continue) {
|
||||
policies := []api.DNSPolicy{api.DNSClusterFirst, api.DNSDefault}
|
||||
*d = policies[c.Rand.Intn(len(policies))]
|
||||
},
|
||||
func(p *api.Protocol, c fuzz.Continue) {
|
||||
protocols := []api.Protocol{api.ProtocolTCP, api.ProtocolUDP}
|
||||
*p = protocols[c.Rand.Intn(len(protocols))]
|
||||
},
|
||||
func(p *api.ServiceAffinity, c fuzz.Continue) {
|
||||
types := []api.ServiceAffinity{api.ServiceAffinityClientIP, api.ServiceAffinityNone}
|
||||
*p = types[c.Rand.Intn(len(types))]
|
||||
},
|
||||
func(p *api.ServiceType, c fuzz.Continue) {
|
||||
types := []api.ServiceType{api.ServiceTypeClusterIP, api.ServiceTypeNodePort, api.ServiceTypeLoadBalancer}
|
||||
*p = types[c.Rand.Intn(len(types))]
|
||||
},
|
||||
func(ct *api.Container, c fuzz.Continue) {
|
||||
c.FuzzNoCustom(ct) // fuzz self without calling this function again
|
||||
ct.TerminationMessagePath = "/" + ct.TerminationMessagePath // Must be non-empty
|
||||
},
|
||||
func(p *api.Probe, c fuzz.Continue) {
|
||||
c.FuzzNoCustom(p)
|
||||
// These fields have default values.
|
||||
intFieldsWithDefaults := [...]string{"TimeoutSeconds", "PeriodSeconds", "SuccessThreshold", "FailureThreshold"}
|
||||
v := reflect.ValueOf(p).Elem()
|
||||
for _, field := range intFieldsWithDefaults {
|
||||
f := v.FieldByName(field)
|
||||
if f.Int() == 0 {
|
||||
f.SetInt(1)
|
||||
}
|
||||
}
|
||||
},
|
||||
func(ev *api.EnvVar, c fuzz.Continue) {
|
||||
ev.Name = c.RandString()
|
||||
if c.RandBool() {
|
||||
ev.Value = c.RandString()
|
||||
} else {
|
||||
ev.ValueFrom = &api.EnvVarSource{}
|
||||
ev.ValueFrom.FieldRef = &api.ObjectFieldSelector{}
|
||||
|
||||
var versions []unversioned.GroupVersion
|
||||
for _, testGroup := range testapi.Groups {
|
||||
versions = append(versions, *testGroup.GroupVersion())
|
||||
}
|
||||
|
||||
ev.ValueFrom.FieldRef.APIVersion = versions[c.Rand.Intn(len(versions))].String()
|
||||
ev.ValueFrom.FieldRef.FieldPath = c.RandString()
|
||||
}
|
||||
},
|
||||
func(sc *api.SecurityContext, c fuzz.Continue) {
|
||||
c.FuzzNoCustom(sc) // fuzz self without calling this function again
|
||||
if c.RandBool() {
|
||||
priv := c.RandBool()
|
||||
sc.Privileged = &priv
|
||||
}
|
||||
|
||||
if c.RandBool() {
|
||||
sc.Capabilities = &api.Capabilities{
|
||||
Add: make([]api.Capability, 0),
|
||||
Drop: make([]api.Capability, 0),
|
||||
}
|
||||
c.Fuzz(&sc.Capabilities.Add)
|
||||
c.Fuzz(&sc.Capabilities.Drop)
|
||||
}
|
||||
},
|
||||
func(s *api.Secret, c fuzz.Continue) {
|
||||
c.FuzzNoCustom(s) // fuzz self without calling this function again
|
||||
s.Type = api.SecretTypeOpaque
|
||||
},
|
||||
func(pv *api.PersistentVolume, c fuzz.Continue) {
|
||||
c.FuzzNoCustom(pv) // fuzz self without calling this function again
|
||||
types := []api.PersistentVolumePhase{api.VolumeAvailable, api.VolumePending, api.VolumeBound, api.VolumeReleased, api.VolumeFailed}
|
||||
pv.Status.Phase = types[c.Rand.Intn(len(types))]
|
||||
pv.Status.Message = c.RandString()
|
||||
reclamationPolicies := []api.PersistentVolumeReclaimPolicy{api.PersistentVolumeReclaimRecycle, api.PersistentVolumeReclaimRetain}
|
||||
pv.Spec.PersistentVolumeReclaimPolicy = reclamationPolicies[c.Rand.Intn(len(reclamationPolicies))]
|
||||
},
|
||||
func(pvc *api.PersistentVolumeClaim, c fuzz.Continue) {
|
||||
c.FuzzNoCustom(pvc) // fuzz self without calling this function again
|
||||
types := []api.PersistentVolumeClaimPhase{api.ClaimBound, api.ClaimPending}
|
||||
pvc.Status.Phase = types[c.Rand.Intn(len(types))]
|
||||
},
|
||||
func(s *api.NamespaceSpec, c fuzz.Continue) {
|
||||
s.Finalizers = []api.FinalizerName{api.FinalizerKubernetes}
|
||||
},
|
||||
func(s *api.NamespaceStatus, c fuzz.Continue) {
|
||||
s.Phase = api.NamespaceActive
|
||||
},
|
||||
func(http *api.HTTPGetAction, c fuzz.Continue) {
|
||||
c.FuzzNoCustom(http) // fuzz self without calling this function again
|
||||
http.Path = "/" + http.Path // can't be blank
|
||||
http.Scheme = "x" + http.Scheme // can't be blank
|
||||
},
|
||||
func(ss *api.ServiceSpec, c fuzz.Continue) {
|
||||
c.FuzzNoCustom(ss) // fuzz self without calling this function again
|
||||
if len(ss.Ports) == 0 {
|
||||
// There must be at least 1 port.
|
||||
ss.Ports = append(ss.Ports, api.ServicePort{})
|
||||
c.Fuzz(&ss.Ports[0])
|
||||
}
|
||||
for i := range ss.Ports {
|
||||
switch ss.Ports[i].TargetPort.Type {
|
||||
case intstr.Int:
|
||||
ss.Ports[i].TargetPort.IntVal = 1 + ss.Ports[i].TargetPort.IntVal%65535 // non-zero
|
||||
case intstr.String:
|
||||
ss.Ports[i].TargetPort.StrVal = "x" + ss.Ports[i].TargetPort.StrVal // non-empty
|
||||
}
|
||||
}
|
||||
},
|
||||
func(n *api.Node, c fuzz.Continue) {
|
||||
c.FuzzNoCustom(n)
|
||||
n.Spec.ExternalID = "external"
|
||||
},
|
||||
func(s *api.NodeStatus, c fuzz.Continue) {
|
||||
c.FuzzNoCustom(s)
|
||||
s.Allocatable = s.Capacity
|
||||
},
|
||||
func(s *extensions.APIVersion, c fuzz.Continue) {
|
||||
// We can't use c.RandString() here because it may generate empty
|
||||
// string, which will cause tests failure.
|
||||
s.APIGroup = "something"
|
||||
},
|
||||
func(s *extensions.HorizontalPodAutoscalerSpec, c fuzz.Continue) {
|
||||
c.FuzzNoCustom(s) // fuzz self without calling this function again
|
||||
minReplicas := int(c.Rand.Int31())
|
||||
s.MinReplicas = &minReplicas
|
||||
s.CPUUtilization = &extensions.CPUTargetUtilization{TargetPercentage: int(int32(c.RandUint64()))}
|
||||
},
|
||||
func(s *extensions.SubresourceReference, c fuzz.Continue) {
|
||||
c.FuzzNoCustom(s) // fuzz self without calling this function again
|
||||
s.Subresource = "scale"
|
||||
},
|
||||
func(psp *extensions.PodSecurityPolicySpec, c fuzz.Continue) {
|
||||
c.FuzzNoCustom(psp) // fuzz self without calling this function again
|
||||
userTypes := []extensions.RunAsUserStrategy{extensions.RunAsUserStrategyMustRunAsNonRoot, extensions.RunAsUserStrategyMustRunAs, extensions.RunAsUserStrategyRunAsAny}
|
||||
psp.RunAsUser.Type = userTypes[c.Rand.Intn(len(userTypes))]
|
||||
seLinuxTypes := []extensions.SELinuxContextStrategy{extensions.SELinuxStrategyRunAsAny, extensions.SELinuxStrategyMustRunAs}
|
||||
psp.SELinuxContext.Type = seLinuxTypes[c.Rand.Intn(len(seLinuxTypes))]
|
||||
},
|
||||
)
|
||||
return f
|
||||
}
|
||||
|
||||
func newBool(val bool) *bool {
|
||||
p := new(bool)
|
||||
*p = val
|
||||
return p
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
Copyright 2015 The Kubernetes Authors All rights reserved.
|
||||
|
||||
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 (
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
)
|
||||
|
||||
// DeepEqualSafePodSpec returns a PodSpec which is ready to be used with api.Semantic.DeepEqual
|
||||
func DeepEqualSafePodSpec() api.PodSpec {
|
||||
grace := int64(30)
|
||||
return api.PodSpec{
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
TerminationGracePeriodSeconds: &grace,
|
||||
SecurityContext: &api.PodSecurityContext{},
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user