diff --git a/pkg/apis/core/v1/conversion_test.go b/pkg/apis/core/v1/conversion_test.go index 12fba25cf0d..39e8ec3ccca 100644 --- a/pkg/apis/core/v1/conversion_test.go +++ b/pkg/apis/core/v1/conversion_test.go @@ -329,7 +329,106 @@ func TestReplicationControllerConversion(t *testing.T) { if !apiequality.Semantic.DeepEqual(in, out) { instr, _ := json.MarshalIndent(in, "", " ") outstr, _ := json.MarshalIndent(out, "", " ") - t.Errorf("RC-RS conversion round-trip failed:\nin:\n%s\nout:\n%s", instr, outstr) + t.Errorf("RC-RS conversion round-trip failed:\nin:\n%s\nout:\n%s\ndiff:\n%s", instr, outstr, cmp.Diff(in, out)) + } + } +} + +func TestReplicaSetConversion(t *testing.T) { + inputs := []*apps.ReplicaSet{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "name", + Namespace: "namespace", + Labels: map[string]string{"foo": "bar", "bar": "foo"}, // labels have to be defined everywhere not to trigger RC defaulting + }, + Spec: apps.ReplicaSetSpec{ + Replicas: 1, + MinReadySeconds: 32, + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"foo": "bar", "bar": "foo"}, + }, + Template: core.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{"foo": "bar", "bar": "foo"}, + }, + Spec: core.PodSpec{ + Containers: []core.Container{ + { + Name: "container", + Image: "image", + }, + }, + }, + }, + }, + Status: apps.ReplicaSetStatus{ + Replicas: 1, + FullyLabeledReplicas: 2, + ReadyReplicas: 3, + AvailableReplicas: 4, + TerminatingReplicas: nil, // ReplicationController does not support .status.terminatingReplicas + ObservedGeneration: 5, + Conditions: []apps.ReplicaSetCondition{ + { + Type: apps.ReplicaSetReplicaFailure, + Status: core.ConditionTrue, + LastTransitionTime: metav1.NewTime(time.Unix(123456789, 0)), + Reason: "Reason", + Message: "Message", + }, + }, + }, + }, + } + + // Add some fuzzed ReplicaSets. + apiObjectFuzzer := fuzzer.FuzzerFor(fuzzer.MergeFuzzerFuncs(metafuzzer.Funcs, corefuzzer.Funcs), rand.NewSource(152), legacyscheme.Codecs) + for i := 0; i < 100; i++ { + rs := &apps.ReplicaSet{} + apiObjectFuzzer.Fill(rs) + // if we have labels, they have to be set to satisfy RC defaulting + if labels := rs.Spec.Template.Labels; len(labels) > 0 { + rs.Labels = labels + + // forcefully set label selector, since the RC has only partial selector support (MatchLabels) + rs.Spec.Selector = &metav1.LabelSelector{ + MatchLabels: labels, + } + } else { + rs.Spec.Selector = nil + } + + // ReplicationController does not support .status.terminatingReplicas + if rs.Status.TerminatingReplicas != nil { + rs.Status.TerminatingReplicas = nil + } + inputs = append(inputs, rs) + } + + // Round-trip the input RSs before converting to RC. + for i := range inputs { + inputs[i] = roundTripRS(t, inputs[i]) + } + + for _, in := range inputs { + rc := &v1.ReplicationController{} + // Use in.DeepCopy() to avoid sharing pointers with `in`. + if err := corev1.Convert_apps_ReplicaSet_To_v1_ReplicationController(in.DeepCopy(), rc, nil); err != nil { + t.Errorf("can't convert RS to RC: %v", err) + continue + } + // Round-trip RC before converting back to RS. + rc = roundTrip(t, rc).(*v1.ReplicationController) + out := &apps.ReplicaSet{} + if err := corev1.Convert_v1_ReplicationController_To_apps_ReplicaSet(rc, out, nil); err != nil { + t.Errorf("can't convert RC to RS: %v", err) + continue + } + if !apiequality.Semantic.DeepEqual(in, out) { + instr, _ := json.MarshalIndent(in, "", " ") + outstr, _ := json.MarshalIndent(out, "", " ") + t.Errorf("RS-RC conversion round-trip failed:\nin:\n%s\nout:\n%s\ndiff:\n%s", instr, outstr, cmp.Diff(in, out)) } } }