Skip to content

Commit c137738

Browse files
committed
Add fuzz test for RC/RS conversion.
1 parent 89cfaf9 commit c137738

File tree

5 files changed

+165
-45
lines changed

5 files changed

+165
-45
lines changed

hack/.golint_failures

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -541,7 +541,6 @@ staging/src/k8s.io/apimachinery/pkg/apimachinery/announced
541541
staging/src/k8s.io/apimachinery/pkg/apimachinery/registered
542542
staging/src/k8s.io/apimachinery/pkg/apis/meta/fuzzer
543543
staging/src/k8s.io/apimachinery/pkg/apis/meta/internalversion
544-
staging/src/k8s.io/apimachinery/pkg/apis/meta/v1
545544
staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured
546545
staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/validation
547546
staging/src/k8s.io/apimachinery/pkg/apis/meta/v1alpha1

pkg/api/v1/BUILD

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,14 @@ go_test(
4646
"//pkg/api:go_default_library",
4747
"//pkg/api/legacyscheme:go_default_library",
4848
"//pkg/api/testapi:go_default_library",
49+
"//pkg/api/testing:go_default_library",
4950
"//pkg/apis/extensions:go_default_library",
51+
"//pkg/util/pointer:go_default_library",
5052
"//vendor/k8s.io/api/core/v1:go_default_library",
53+
"//vendor/k8s.io/api/extensions/v1beta1:go_default_library",
5154
"//vendor/k8s.io/apimachinery/pkg/api/equality:go_default_library",
5255
"//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
56+
"//vendor/k8s.io/apimachinery/pkg/api/testing/fuzzer:go_default_library",
5357
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
5458
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
5559
"//vendor/k8s.io/apimachinery/pkg/util/diff:go_default_library",

pkg/api/v1/conversion_test.go

Lines changed: 102 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -18,21 +18,26 @@ package v1_test
1818

1919
import (
2020
"encoding/json"
21+
"math/rand"
2122
"net/url"
2223
"reflect"
2324
"testing"
2425
"time"
2526

2627
"k8s.io/api/core/v1"
28+
extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
2729
apiequality "k8s.io/apimachinery/pkg/api/equality"
2830
"k8s.io/apimachinery/pkg/api/resource"
31+
"k8s.io/apimachinery/pkg/api/testing/fuzzer"
2932
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3033
"k8s.io/apimachinery/pkg/runtime"
3134
"k8s.io/apimachinery/pkg/util/diff"
3235
"k8s.io/kubernetes/pkg/api"
3336
"k8s.io/kubernetes/pkg/api/legacyscheme"
37+
kapitesting "k8s.io/kubernetes/pkg/api/testing"
3438
k8s_api_v1 "k8s.io/kubernetes/pkg/api/v1"
3539
"k8s.io/kubernetes/pkg/apis/extensions"
40+
utilpointer "k8s.io/kubernetes/pkg/util/pointer"
3641

3742
// enforce that all types are installed
3843
_ "k8s.io/kubernetes/pkg/api/testapi"
@@ -231,59 +236,112 @@ func TestResourceListConversion(t *testing.T) {
231236

232237
func TestReplicationControllerConversion(t *testing.T) {
233238
// If we start with a RC, we should always have round-trip fidelity.
234-
replicas := int32(1)
235-
in := &v1.ReplicationController{
236-
ObjectMeta: metav1.ObjectMeta{
237-
Name: "name",
238-
Namespace: "namespace",
239-
},
240-
Spec: v1.ReplicationControllerSpec{
241-
Replicas: &replicas,
242-
MinReadySeconds: 32,
243-
Selector: map[string]string{"foo": "bar", "bar": "foo"},
244-
Template: &v1.PodTemplateSpec{
245-
ObjectMeta: metav1.ObjectMeta{
246-
Labels: map[string]string{"foo": "bar", "bar": "foo"},
247-
},
248-
Spec: v1.PodSpec{
249-
Containers: []v1.Container{
250-
{
251-
Name: "container",
252-
Image: "image",
239+
inputs := []*v1.ReplicationController{
240+
{
241+
ObjectMeta: metav1.ObjectMeta{
242+
Name: "name",
243+
Namespace: "namespace",
244+
},
245+
Spec: v1.ReplicationControllerSpec{
246+
Replicas: utilpointer.Int32Ptr(1),
247+
MinReadySeconds: 32,
248+
Selector: map[string]string{"foo": "bar", "bar": "foo"},
249+
Template: &v1.PodTemplateSpec{
250+
ObjectMeta: metav1.ObjectMeta{
251+
Labels: map[string]string{"foo": "bar", "bar": "foo"},
252+
},
253+
Spec: v1.PodSpec{
254+
Containers: []v1.Container{
255+
{
256+
Name: "container",
257+
Image: "image",
258+
},
253259
},
254260
},
255261
},
256262
},
257-
},
258-
Status: v1.ReplicationControllerStatus{
259-
Replicas: 1,
260-
FullyLabeledReplicas: 2,
261-
ReadyReplicas: 3,
262-
AvailableReplicas: 4,
263-
ObservedGeneration: 5,
264-
Conditions: []v1.ReplicationControllerCondition{
265-
{
266-
Type: v1.ReplicationControllerReplicaFailure,
267-
Status: v1.ConditionTrue,
268-
LastTransitionTime: metav1.NewTime(time.Unix(123456789, 0)),
269-
Reason: "Reason",
270-
Message: "Message",
263+
Status: v1.ReplicationControllerStatus{
264+
Replicas: 1,
265+
FullyLabeledReplicas: 2,
266+
ReadyReplicas: 3,
267+
AvailableReplicas: 4,
268+
ObservedGeneration: 5,
269+
Conditions: []v1.ReplicationControllerCondition{
270+
{
271+
Type: v1.ReplicationControllerReplicaFailure,
272+
Status: v1.ConditionTrue,
273+
LastTransitionTime: metav1.NewTime(time.Unix(123456789, 0)),
274+
Reason: "Reason",
275+
Message: "Message",
276+
},
271277
},
272278
},
273279
},
274280
}
275-
in = roundTrip(t, in).(*v1.ReplicationController)
276-
rs := &extensions.ReplicaSet{}
277-
if err := k8s_api_v1.Convert_v1_ReplicationController_to_extensions_ReplicaSet(in, rs, nil); err != nil {
278-
t.Fatalf("can't convert RC to RS: %v", err)
281+
282+
// Add some fuzzed RCs.
283+
apiObjectFuzzer := fuzzer.FuzzerFor(kapitesting.FuzzerFuncs, rand.NewSource(152), legacyscheme.Codecs)
284+
for i := 0; i < 100; i++ {
285+
rc := &v1.ReplicationController{}
286+
apiObjectFuzzer.Fuzz(rc)
287+
// Sometimes the fuzzer decides to leave Spec.Template nil.
288+
// We can't support that because Spec.Template is not a pointer in RS,
289+
// so it will round-trip as non-nil but empty.
290+
if rc.Spec.Template == nil {
291+
rc.Spec.Template = &v1.PodTemplateSpec{}
292+
}
293+
// Sometimes the fuzzer decides to insert an empty label key.
294+
// This doesn't round-trip properly because it's invalid.
295+
if rc.Spec.Selector != nil {
296+
delete(rc.Spec.Selector, "")
297+
}
298+
inputs = append(inputs, rc)
299+
}
300+
301+
// Round-trip the input RCs before converting to RS.
302+
for i := range inputs {
303+
inputs[i] = roundTrip(t, inputs[i]).(*v1.ReplicationController)
304+
}
305+
306+
for _, in := range inputs {
307+
rs := &extensions.ReplicaSet{}
308+
// Use in.DeepCopy() to avoid sharing pointers with `in`.
309+
if err := k8s_api_v1.Convert_v1_ReplicationController_to_extensions_ReplicaSet(in.DeepCopy(), rs, nil); err != nil {
310+
t.Errorf("can't convert RC to RS: %v", err)
311+
continue
312+
}
313+
// Round-trip RS before converting back to RC.
314+
rs = roundTripRS(t, rs)
315+
out := &v1.ReplicationController{}
316+
if err := k8s_api_v1.Convert_extensions_ReplicaSet_to_v1_ReplicationController(rs, out, nil); err != nil {
317+
t.Errorf("can't convert RS to RC: %v", err)
318+
continue
319+
}
320+
if !apiequality.Semantic.DeepEqual(in, out) {
321+
instr, _ := json.MarshalIndent(in, "", " ")
322+
outstr, _ := json.MarshalIndent(out, "", " ")
323+
t.Errorf("RC-RS conversion round-trip failed:\nin:\n%s\nout:\n%s", instr, outstr)
324+
}
325+
}
326+
}
327+
328+
func roundTripRS(t *testing.T, rs *extensions.ReplicaSet) *extensions.ReplicaSet {
329+
codec := legacyscheme.Codecs.LegacyCodec(extensionsv1beta1.SchemeGroupVersion)
330+
data, err := runtime.Encode(codec, rs)
331+
if err != nil {
332+
t.Errorf("%v\n %#v", err, rs)
333+
return nil
279334
}
280-
out := &v1.ReplicationController{}
281-
if err := k8s_api_v1.Convert_extensions_ReplicaSet_to_v1_ReplicationController(rs, out, nil); err != nil {
282-
t.Fatalf("can't convert RS to RC: %v", err)
335+
obj2, err := runtime.Decode(codec, data)
336+
if err != nil {
337+
t.Errorf("%v\nData: %s\nSource: %#v", err, string(data), rs)
338+
return nil
283339
}
284-
if !apiequality.Semantic.DeepEqual(in, out) {
285-
instr, _ := json.MarshalIndent(in, "", " ")
286-
outstr, _ := json.MarshalIndent(out, "", " ")
287-
t.Errorf("RC-RS conversion round-trip failed:\nin:\n%s\nout:\n%s", instr, outstr)
340+
obj3 := &extensions.ReplicaSet{}
341+
err = legacyscheme.Scheme.Convert(obj2, obj3, nil)
342+
if err != nil {
343+
t.Errorf("%v\nSource: %#v", err, obj2)
344+
return nil
288345
}
346+
return obj3
289347
}

staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/BUILD

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,3 +93,13 @@ filegroup(
9393
srcs = ["generated.proto"],
9494
visibility = ["//visibility:public"],
9595
)
96+
97+
go_test(
98+
name = "go_default_xtest",
99+
srcs = ["conversion_test.go"],
100+
importpath = "k8s.io/apimachinery/pkg/apis/meta/v1_test",
101+
deps = [
102+
"//vendor/k8s.io/apimachinery/pkg/api/equality:go_default_library",
103+
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
104+
],
105+
)
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
Copyright 2017 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package v1_test
18+
19+
import (
20+
"testing"
21+
22+
apiequality "k8s.io/apimachinery/pkg/api/equality"
23+
"k8s.io/apimachinery/pkg/apis/meta/v1"
24+
)
25+
26+
func TestMapToLabelSelectorRoundTrip(t *testing.T) {
27+
// We should be able to round-trip a map-only selector through LabelSelector.
28+
inputs := []map[string]string{
29+
nil,
30+
{},
31+
{"one": "foo"},
32+
{"one": "foo", "two": "bar"},
33+
}
34+
for _, in := range inputs {
35+
ls := &v1.LabelSelector{}
36+
if err := v1.Convert_map_to_unversioned_LabelSelector(&in, ls, nil); err != nil {
37+
t.Errorf("Convert_map_to_unversioned_LabelSelector(%#v): %v", in, err)
38+
continue
39+
}
40+
out := map[string]string{}
41+
if err := v1.Convert_unversioned_LabelSelector_to_map(ls, &out, nil); err != nil {
42+
t.Errorf("Convert_unversioned_LabelSelector_to_map(%#v): %v", ls, err)
43+
continue
44+
}
45+
if !apiequality.Semantic.DeepEqual(in, out) {
46+
t.Errorf("map-selector conversion round-trip failed: got %v; want %v", out, in)
47+
}
48+
}
49+
}

0 commit comments

Comments
 (0)