func runTest(t *testing.T, source interface{}) { name := reflect.TypeOf(source).Elem().Name() TestObjectFuzzer.Fuzz(source) _, codec := GetTestScheme() data, err := runtime.Encode(codec, source.(runtime.Object)) if err != nil { t.Errorf("%v: %v (%#v)", name, err, source) return } obj2, err := runtime.Decode(codec, data) if err != nil { t.Errorf("%v: %v (%v)", name, err, string(data)) return } if !semantic.DeepEqual(source, obj2) { t.Errorf("1: %v: diff: %v", name, util.ObjectGoPrintSideBySide(source, obj2)) return } obj3 := reflect.New(reflect.TypeOf(source).Elem()).Interface() if err := runtime.DecodeInto(codec, data, obj3.(runtime.Object)); err != nil { t.Errorf("2: %v: %v", name, err) return } if !semantic.DeepEqual(source, obj3) { t.Errorf("3: %v: diff: %v", name, objDiff(source, obj3)) return } }
func TestExternalToInternalMapping(t *testing.T) { internalGV := unversioned.GroupVersion{Group: "test.group", Version: runtime.APIVersionInternal} externalGV := unversioned.GroupVersion{Group: "test.group", Version: "testExternal"} scheme := runtime.NewScheme() scheme.AddKnownTypeWithName(internalGV.WithKind("OptionalExtensionType"), &InternalOptionalExtensionType{}) scheme.AddKnownTypeWithName(externalGV.WithKind("OptionalExtensionType"), &ExternalOptionalExtensionType{}) codec := serializer.NewCodecFactory(scheme).LegacyCodec(externalGV) table := []struct { obj runtime.Object encoded string }{ { &InternalOptionalExtensionType{Extension: nil}, `{"kind":"OptionalExtensionType","apiVersion":"` + externalGV.String() + `"}`, }, } for i, item := range table { gotDecoded, err := runtime.Decode(codec, []byte(item.encoded)) if err != nil { t.Errorf("unexpected error '%v' (%v)", err, item.encoded) } else if e, a := item.obj, gotDecoded; !reflect.DeepEqual(e, a) { t.Errorf("%d: unexpected objects:\n%s", i, util.ObjectGoPrintSideBySide(e, a)) } } }
func doDeepCopyTest(t *testing.T, kind unversioned.GroupVersionKind, f *fuzz.Fuzzer) { item, err := api.Scheme.New(kind) if err != nil { t.Fatalf("Could not create a %v: %s", kind, err) } f.Fuzz(item) itemCopy, err := api.Scheme.DeepCopy(item) if err != nil { t.Errorf("Could not deep copy a %v: %s", kind, err) return } if !reflect.DeepEqual(item, itemCopy) { t.Errorf("\nexpected: %#v\n\ngot: %#v\n\ndiff: %v", item, itemCopy, util.ObjectGoPrintSideBySide(item, itemCopy)) } }
func TestProtobufRoundTrip(t *testing.T) { obj := &v1.Pod{} apitesting.FuzzerFor(t, "v1", rand.NewSource(benchmarkSeed)).Fuzz(obj) data, err := obj.Marshal() if err != nil { t.Fatal(err) } out := &v1.Pod{} if err := out.Unmarshal(data); err != nil { t.Fatal(err) } if !api.Semantic.Equalities.DeepEqual(out, obj) { t.Logf("marshal\n%s", hex.Dump(data)) t.Fatalf("Unmarshal is unequal\n%s", util.ObjectGoPrintSideBySide(out, obj)) } }
func TestDefaults(t *testing.T) { defaultIntOrString := intstr.FromString("25%") differentIntOrString := intstr.FromInt(5) tests := []struct { original *deployv1.DeploymentConfig expected *deployv1.DeploymentConfig }{ { original: &deployv1.DeploymentConfig{}, expected: &deployv1.DeploymentConfig{ Spec: deployv1.DeploymentConfigSpec{ Strategy: deployv1.DeploymentStrategy{ Type: deployv1.DeploymentStrategyTypeRolling, RollingParams: &deployv1.RollingDeploymentStrategyParams{ UpdatePeriodSeconds: newInt64(deployapi.DefaultRollingUpdatePeriodSeconds), IntervalSeconds: newInt64(deployapi.DefaultRollingIntervalSeconds), TimeoutSeconds: newInt64(deployapi.DefaultRollingTimeoutSeconds), MaxSurge: &defaultIntOrString, MaxUnavailable: &defaultIntOrString, }, }, Triggers: []deployv1.DeploymentTriggerPolicy{ { Type: deployv1.DeploymentTriggerOnConfigChange, }, }, }, }, }, { original: &deployv1.DeploymentConfig{ Spec: deployv1.DeploymentConfigSpec{ Strategy: deployv1.DeploymentStrategy{ Type: deployv1.DeploymentStrategyTypeRecreate, RecreateParams: &deployv1.RecreateDeploymentStrategyParams{ TimeoutSeconds: newInt64(deployapi.DefaultRollingTimeoutSeconds), }, RollingParams: &deployv1.RollingDeploymentStrategyParams{ UpdatePeriodSeconds: newInt64(5), IntervalSeconds: newInt64(6), TimeoutSeconds: newInt64(7), MaxSurge: &differentIntOrString, MaxUnavailable: &differentIntOrString, }, }, Triggers: []deployv1.DeploymentTriggerPolicy{ { Type: deployv1.DeploymentTriggerOnImageChange, }, }, }, }, expected: &deployv1.DeploymentConfig{ Spec: deployv1.DeploymentConfigSpec{ Strategy: deployv1.DeploymentStrategy{ Type: deployv1.DeploymentStrategyTypeRecreate, RecreateParams: &deployv1.RecreateDeploymentStrategyParams{ TimeoutSeconds: newInt64(deployapi.DefaultRollingTimeoutSeconds), }, RollingParams: &deployv1.RollingDeploymentStrategyParams{ UpdatePeriodSeconds: newInt64(5), IntervalSeconds: newInt64(6), TimeoutSeconds: newInt64(7), MaxSurge: &differentIntOrString, MaxUnavailable: &differentIntOrString, }, }, Triggers: []deployv1.DeploymentTriggerPolicy{ { Type: deployv1.DeploymentTriggerOnImageChange, }, }, }, }, }, { original: &deployv1.DeploymentConfig{ Spec: deployv1.DeploymentConfigSpec{ Strategy: deployv1.DeploymentStrategy{ Type: deployv1.DeploymentStrategyTypeRolling, RollingParams: &deployv1.RollingDeploymentStrategyParams{ UpdatePeriodSeconds: newInt64(5), IntervalSeconds: newInt64(6), TimeoutSeconds: newInt64(7), UpdatePercent: newInt(50), }, }, Triggers: []deployv1.DeploymentTriggerPolicy{ { Type: deployv1.DeploymentTriggerOnImageChange, }, }, }, }, expected: &deployv1.DeploymentConfig{ Spec: deployv1.DeploymentConfigSpec{ Strategy: deployv1.DeploymentStrategy{ Type: deployv1.DeploymentStrategyTypeRolling, RollingParams: &deployv1.RollingDeploymentStrategyParams{ UpdatePeriodSeconds: newInt64(5), IntervalSeconds: newInt64(6), TimeoutSeconds: newInt64(7), UpdatePercent: newInt(50), MaxSurge: newIntOrString(intstr.FromString("50%")), MaxUnavailable: newIntOrString(intstr.FromInt(0)), }, }, Triggers: []deployv1.DeploymentTriggerPolicy{ { Type: deployv1.DeploymentTriggerOnImageChange, }, }, }, }, }, { original: &deployv1.DeploymentConfig{ Spec: deployv1.DeploymentConfigSpec{ Strategy: deployv1.DeploymentStrategy{ Type: deployv1.DeploymentStrategyTypeRolling, RollingParams: &deployv1.RollingDeploymentStrategyParams{ UpdatePeriodSeconds: newInt64(5), IntervalSeconds: newInt64(6), TimeoutSeconds: newInt64(7), UpdatePercent: newInt(-25), }, }, Triggers: []deployv1.DeploymentTriggerPolicy{ { Type: deployv1.DeploymentTriggerOnImageChange, }, }, }, }, expected: &deployv1.DeploymentConfig{ Spec: deployv1.DeploymentConfigSpec{ Strategy: deployv1.DeploymentStrategy{ Type: deployv1.DeploymentStrategyTypeRolling, RollingParams: &deployv1.RollingDeploymentStrategyParams{ UpdatePeriodSeconds: newInt64(5), IntervalSeconds: newInt64(6), TimeoutSeconds: newInt64(7), UpdatePercent: newInt(-25), MaxSurge: newIntOrString(intstr.FromInt(0)), MaxUnavailable: newIntOrString(intstr.FromString("25%")), }, }, Triggers: []deployv1.DeploymentTriggerPolicy{ { Type: deployv1.DeploymentTriggerOnImageChange, }, }, }, }, }, } for i, test := range tests { t.Logf("test %d", i) original := test.original expected := test.expected obj2 := roundTrip(t, runtime.Object(original)) got, ok := obj2.(*deployv1.DeploymentConfig) if !ok { t.Errorf("unexpected object: %v", got) t.FailNow() } if !reflect.DeepEqual(got.Spec, expected.Spec) { t.Errorf("got different than expected:\nA:\t%#v\nB:\t%#v\n\nDiff:\n%s\n\n%s", got, expected, util.ObjectDiff(expected, got), util.ObjectGoPrintSideBySide(expected, got)) } } }
func roundTrip(t *testing.T, codec runtime.Codec, originalItem runtime.Object) { // Make a copy of the originalItem to give to conversion functions // This lets us know if conversion messed with the input object deepCopy, err := api.Scheme.DeepCopy(originalItem) if err != nil { t.Errorf("Could not copy object: %v", err) return } item := deepCopy.(runtime.Object) name := reflect.TypeOf(item).Elem().Name() data, err := codec.Encode(item) if err != nil { if conversion.IsNotRegisteredError(err) { t.Logf("%v is not registered", name) return } t.Errorf("%v: %v (%#v)", name, err, item) return } obj2, err := codec.Decode(data) if err != nil { t.Errorf("0: %v: %v\nCodec: %v\nData: %s\nSource: %#v", name, err, codec, string(data), originalItem) return } if reflect.TypeOf(item) != reflect.TypeOf(obj2) { obj2conv := reflect.New(reflect.TypeOf(item).Elem()).Interface().(runtime.Object) if err := api.Scheme.Convert(obj2, obj2conv); err != nil { t.Errorf("0X: no conversion from %v to %v: %v", reflect.TypeOf(item), reflect.TypeOf(obj2), err) return } obj2 = obj2conv } if !api.Semantic.DeepEqual(originalItem, obj2) { t.Errorf("1: %v: diff: %v\nCodec: %v\nData: %s\nSource: %s", name, util.ObjectDiff(originalItem, obj2), codec, string(data), util.ObjectGoPrintSideBySide(originalItem, obj2)) return } obj3 := reflect.New(reflect.TypeOf(item).Elem()).Interface().(runtime.Object) err = codec.DecodeInto(data, obj3) if err != nil { t.Errorf("2: %v: %v", name, err) return } if !api.Semantic.DeepEqual(originalItem, obj3) { t.Errorf("3: %v: diff: %v\nCodec: %v", name, util.ObjectDiff(originalItem, obj3), codec) return } }
func TestDecode(t *testing.T) { testCases := []struct { creater runtime.ObjectCreater typer runtime.Typer yaml bool pretty bool data []byte defaultGVK *unversioned.GroupVersionKind into runtime.Object errFn func(error) bool expectedObject runtime.Object expectedGVK *unversioned.GroupVersionKind }{ { data: []byte("{}"), expectedGVK: &unversioned.GroupVersionKind{}, errFn: func(err error) bool { return strings.Contains(err.Error(), "Object 'Kind' is missing in") }, }, { data: []byte("{}"), defaultGVK: &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"}, creater: &mockCreater{err: fmt.Errorf("fake error")}, expectedGVK: &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"}, errFn: func(err error) bool { return err.Error() == "fake error" }, }, { data: []byte("{}"), defaultGVK: &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"}, creater: &mockCreater{err: fmt.Errorf("fake error")}, expectedGVK: &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"}, errFn: func(err error) bool { return err.Error() == "fake error" }, }, { data: []byte("{}"), defaultGVK: &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"}, creater: &mockCreater{obj: &testDecodable{}}, expectedObject: &testDecodable{ gvk: nil, // json serializer does NOT set GVK }, expectedGVK: &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"}, }, // version without group is not defaulted { data: []byte(`{"apiVersion":"blah"}`), defaultGVK: &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"}, creater: &mockCreater{obj: &testDecodable{}}, expectedObject: &testDecodable{ gvk: nil, // json serializer does NOT set GVK }, expectedGVK: &unversioned.GroupVersionKind{Kind: "Test", Group: "", Version: "blah"}, }, // group without version is defaulted { data: []byte(`{"apiVersion":"other/"}`), defaultGVK: &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"}, creater: &mockCreater{obj: &testDecodable{}}, expectedObject: &testDecodable{ gvk: nil, // json serializer does NOT set GVK }, expectedGVK: &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"}, }, // accept runtime.Unknown as into and bypass creator { data: []byte(`{}`), into: &runtime.Unknown{}, expectedGVK: &unversioned.GroupVersionKind{}, expectedObject: &runtime.Unknown{ RawJSON: []byte(`{}`), }, }, { data: []byte(`{"test":"object"}`), into: &runtime.Unknown{}, expectedGVK: &unversioned.GroupVersionKind{}, expectedObject: &runtime.Unknown{ RawJSON: []byte(`{"test":"object"}`), }, }, { data: []byte(`{"test":"object"}`), into: &runtime.Unknown{}, defaultGVK: &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"}, expectedGVK: &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"}, expectedObject: &runtime.Unknown{ TypeMeta: runtime.TypeMeta{APIVersion: "other/blah", Kind: "Test"}, RawJSON: []byte(`{"test":"object"}`), }, }, // unregistered objects can be decoded into directly { data: []byte(`{"kind":"Test","apiVersion":"other/blah","value":1,"Other":"test"}`), into: &testDecodable{}, typer: &mockTyper{err: runtime.NewNotRegisteredErr(unversioned.GroupVersionKind{}, nil)}, expectedGVK: &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"}, expectedObject: &testDecodable{ Other: "test", Value: 1, }, }, // registered types get defaulted by the into object kind { data: []byte(`{"value":1,"Other":"test"}`), into: &testDecodable{}, typer: &mockTyper{gvk: &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"}}, expectedGVK: &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"}, expectedObject: &testDecodable{ Other: "test", Value: 1, }, }, // registered types get defaulted by the into object kind even without version, but return an error { data: []byte(`{"value":1,"Other":"test"}`), into: &testDecodable{}, typer: &mockTyper{gvk: &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: ""}}, expectedGVK: &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: ""}, errFn: func(err error) bool { return strings.Contains(err.Error(), "Object 'apiVersion' is missing in") }, expectedObject: &testDecodable{ Other: "test", Value: 1, }, }, // runtime.VersionedObjects are decoded { data: []byte(`{"value":1,"Other":"test"}`), into: &runtime.VersionedObjects{Objects: []runtime.Object{}}, creater: &mockCreater{obj: &testDecodable{}}, typer: &mockTyper{gvk: &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"}}, defaultGVK: &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"}, expectedGVK: &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"}, expectedObject: &runtime.VersionedObjects{ Objects: []runtime.Object{ &testDecodable{ Other: "test", Value: 1, }, }, }, }, // runtime.VersionedObjects with an object are decoded into { data: []byte(`{"Other":"test"}`), into: &runtime.VersionedObjects{Objects: []runtime.Object{&testDecodable{Value: 2}}}, typer: &mockTyper{gvk: &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"}}, expectedGVK: &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"}, expectedObject: &runtime.VersionedObjects{ Objects: []runtime.Object{ &testDecodable{ Other: "test", Value: 2, }, }, }, }, } for i, test := range testCases { var s runtime.Serializer if test.yaml { s = json.NewYAMLSerializer(json.DefaultMetaFactory, test.creater, test.typer) } else { s = json.NewSerializer(json.DefaultMetaFactory, test.creater, test.typer, test.pretty) } obj, gvk, err := s.Decode([]byte(test.data), test.defaultGVK, test.into) if !reflect.DeepEqual(test.expectedGVK, gvk) { t.Errorf("%d: unexpected GVK: %v", i, gvk) } switch { case err == nil && test.errFn != nil: t.Errorf("%d: failed: %v", i, err) continue case err != nil && test.errFn == nil: t.Errorf("%d: failed: %v", i, err) continue case err != nil: if !test.errFn(err) { t.Errorf("%d: failed: %v", i, err) } if obj != nil { t.Errorf("%d: should have returned nil object", i) } continue } if test.into != nil && test.into != obj { t.Errorf("%d: expected into to be returned: %v", i, obj) continue } if !reflect.DeepEqual(test.expectedObject, obj) { t.Errorf("%d: unexpected object:\n%s", i, util.ObjectGoPrintSideBySide(test.expectedObject, obj)) } } }
func TestDefaults(t *testing.T) { defaultIntOrString := intstr.FromString("25%") differentIntOrString := intstr.FromInt(5) tests := []struct { original *deployv1.DeploymentConfig expected *deployv1.DeploymentConfig }{ { original: &deployv1.DeploymentConfig{}, expected: &deployv1.DeploymentConfig{ Spec: deployv1.DeploymentConfigSpec{ Strategy: deployv1.DeploymentStrategy{ Type: deployv1.DeploymentStrategyTypeRolling, RollingParams: &deployv1.RollingDeploymentStrategyParams{ UpdatePeriodSeconds: newInt64(deployapi.DefaultRollingUpdatePeriodSeconds), IntervalSeconds: newInt64(deployapi.DefaultRollingIntervalSeconds), TimeoutSeconds: newInt64(deployapi.DefaultRollingTimeoutSeconds), MaxSurge: &defaultIntOrString, MaxUnavailable: &defaultIntOrString, }, }, Triggers: []deployv1.DeploymentTriggerPolicy{ { Type: deployv1.DeploymentTriggerOnConfigChange, }, }, }, }, }, { original: &deployv1.DeploymentConfig{ Spec: deployv1.DeploymentConfigSpec{ Strategy: deployv1.DeploymentStrategy{ Type: deployv1.DeploymentStrategyTypeRecreate, RecreateParams: &deployv1.RecreateDeploymentStrategyParams{ TimeoutSeconds: newInt64(deployapi.DefaultRollingTimeoutSeconds), Pre: &deployv1.LifecycleHook{ TagImages: []deployv1.TagImageHook{{}, {}}, }, Mid: &deployv1.LifecycleHook{ TagImages: []deployv1.TagImageHook{{}, {}}, }, Post: &deployv1.LifecycleHook{ TagImages: []deployv1.TagImageHook{{}, {}}, }, }, RollingParams: &deployv1.RollingDeploymentStrategyParams{ Pre: &deployv1.LifecycleHook{ TagImages: []deployv1.TagImageHook{{}, {}}, }, Post: &deployv1.LifecycleHook{ TagImages: []deployv1.TagImageHook{{}, {}}, }, UpdatePeriodSeconds: newInt64(5), IntervalSeconds: newInt64(6), TimeoutSeconds: newInt64(7), MaxSurge: &differentIntOrString, MaxUnavailable: &differentIntOrString, }, }, Triggers: []deployv1.DeploymentTriggerPolicy{ { Type: deployv1.DeploymentTriggerOnImageChange, }, }, Template: &kapiv1.PodTemplateSpec{ Spec: kapiv1.PodSpec{ Containers: []kapiv1.Container{ { Name: "test", }, }, }, }, }, }, expected: &deployv1.DeploymentConfig{ Spec: deployv1.DeploymentConfigSpec{ Strategy: deployv1.DeploymentStrategy{ Type: deployv1.DeploymentStrategyTypeRecreate, RecreateParams: &deployv1.RecreateDeploymentStrategyParams{ TimeoutSeconds: newInt64(deployapi.DefaultRollingTimeoutSeconds), Pre: &deployv1.LifecycleHook{ TagImages: []deployv1.TagImageHook{{ContainerName: "test"}, {ContainerName: "test"}}, }, Mid: &deployv1.LifecycleHook{ TagImages: []deployv1.TagImageHook{{ContainerName: "test"}, {ContainerName: "test"}}, }, Post: &deployv1.LifecycleHook{ TagImages: []deployv1.TagImageHook{{ContainerName: "test"}, {ContainerName: "test"}}, }, }, RollingParams: &deployv1.RollingDeploymentStrategyParams{ Pre: &deployv1.LifecycleHook{ TagImages: []deployv1.TagImageHook{{ContainerName: "test"}, {ContainerName: "test"}}, }, Post: &deployv1.LifecycleHook{ TagImages: []deployv1.TagImageHook{{ContainerName: "test"}, {ContainerName: "test"}}, }, UpdatePeriodSeconds: newInt64(5), IntervalSeconds: newInt64(6), TimeoutSeconds: newInt64(7), MaxSurge: &differentIntOrString, MaxUnavailable: &differentIntOrString, }, }, Triggers: []deployv1.DeploymentTriggerPolicy{ { Type: deployv1.DeploymentTriggerOnImageChange, }, }, Template: &kapiv1.PodTemplateSpec{ Spec: kapiv1.PodSpec{ SecurityContext: &kapiv1.PodSecurityContext{}, RestartPolicy: kapiv1.RestartPolicyAlways, TerminationGracePeriodSeconds: mkintp(30), DNSPolicy: kapiv1.DNSClusterFirst, Containers: []kapiv1.Container{ { Name: "test", TerminationMessagePath: "/dev/termination-log", ImagePullPolicy: kapiv1.PullAlways, }, }, }, }, }, }, }, { original: &deployv1.DeploymentConfig{ Spec: deployv1.DeploymentConfigSpec{ Strategy: deployv1.DeploymentStrategy{ Type: deployv1.DeploymentStrategyTypeRolling, RollingParams: &deployv1.RollingDeploymentStrategyParams{ UpdatePeriodSeconds: newInt64(5), IntervalSeconds: newInt64(6), TimeoutSeconds: newInt64(7), UpdatePercent: newInt(50), }, }, Triggers: []deployv1.DeploymentTriggerPolicy{ { Type: deployv1.DeploymentTriggerOnImageChange, }, }, }, }, expected: &deployv1.DeploymentConfig{ Spec: deployv1.DeploymentConfigSpec{ Strategy: deployv1.DeploymentStrategy{ Type: deployv1.DeploymentStrategyTypeRolling, RollingParams: &deployv1.RollingDeploymentStrategyParams{ UpdatePeriodSeconds: newInt64(5), IntervalSeconds: newInt64(6), TimeoutSeconds: newInt64(7), UpdatePercent: newInt(50), MaxSurge: newIntOrString(intstr.FromString("50%")), MaxUnavailable: newIntOrString(intstr.FromInt(0)), }, }, Triggers: []deployv1.DeploymentTriggerPolicy{ { Type: deployv1.DeploymentTriggerOnImageChange, }, }, }, }, }, { original: &deployv1.DeploymentConfig{ Spec: deployv1.DeploymentConfigSpec{ Strategy: deployv1.DeploymentStrategy{ Type: deployv1.DeploymentStrategyTypeRolling, RollingParams: &deployv1.RollingDeploymentStrategyParams{ UpdatePeriodSeconds: newInt64(5), IntervalSeconds: newInt64(6), TimeoutSeconds: newInt64(7), UpdatePercent: newInt(-25), }, }, Triggers: []deployv1.DeploymentTriggerPolicy{ { Type: deployv1.DeploymentTriggerOnImageChange, }, }, }, }, expected: &deployv1.DeploymentConfig{ Spec: deployv1.DeploymentConfigSpec{ Strategy: deployv1.DeploymentStrategy{ Type: deployv1.DeploymentStrategyTypeRolling, RollingParams: &deployv1.RollingDeploymentStrategyParams{ UpdatePeriodSeconds: newInt64(5), IntervalSeconds: newInt64(6), TimeoutSeconds: newInt64(7), UpdatePercent: newInt(-25), MaxSurge: newIntOrString(intstr.FromInt(0)), MaxUnavailable: newIntOrString(intstr.FromString("25%")), }, }, Triggers: []deployv1.DeploymentTriggerPolicy{ { Type: deployv1.DeploymentTriggerOnImageChange, }, }, }, }, }, } for i, test := range tests { t.Logf("test %d", i) original := test.original expected := test.expected obj2 := roundTrip(t, runtime.Object(original)) got, ok := obj2.(*deployv1.DeploymentConfig) if !ok { t.Errorf("unexpected object: %v", got) t.FailNow() } if !reflect.DeepEqual(got.Spec, expected.Spec) { t.Errorf("got different than expected:\nA:\t%#v\nB:\t%#v\n\nDiff:\n%s\n\n%s", got, expected, util.ObjectDiff(expected, got), util.ObjectGoPrintSideBySide(expected, got)) } } }
func Test_convert_v1_RollingDeploymentStrategyParams_To_api_RollingDeploymentStrategyParams(t *testing.T) { tests := []struct { in *RollingDeploymentStrategyParams out *newer.RollingDeploymentStrategyParams }{ { in: &RollingDeploymentStrategyParams{ UpdatePeriodSeconds: newInt64(5), IntervalSeconds: newInt64(6), TimeoutSeconds: newInt64(7), UpdatePercent: newInt(-25), }, out: &newer.RollingDeploymentStrategyParams{ UpdatePeriodSeconds: newInt64(5), IntervalSeconds: newInt64(6), TimeoutSeconds: newInt64(7), UpdatePercent: newInt(-25), MaxSurge: util.NewIntOrStringFromInt(0), MaxUnavailable: util.NewIntOrStringFromString("25%"), }, }, { in: &RollingDeploymentStrategyParams{ UpdatePeriodSeconds: newInt64(5), IntervalSeconds: newInt64(6), TimeoutSeconds: newInt64(7), UpdatePercent: newInt(25), }, out: &newer.RollingDeploymentStrategyParams{ UpdatePeriodSeconds: newInt64(5), IntervalSeconds: newInt64(6), TimeoutSeconds: newInt64(7), UpdatePercent: newInt(25), MaxSurge: util.NewIntOrStringFromString("25%"), MaxUnavailable: util.NewIntOrStringFromInt(0), }, }, { in: &RollingDeploymentStrategyParams{ UpdatePeriodSeconds: newInt64(5), IntervalSeconds: newInt64(6), TimeoutSeconds: newInt64(7), MaxSurge: newIntOrString(util.NewIntOrStringFromInt(10)), MaxUnavailable: newIntOrString(util.NewIntOrStringFromInt(20)), }, out: &newer.RollingDeploymentStrategyParams{ UpdatePeriodSeconds: newInt64(5), IntervalSeconds: newInt64(6), TimeoutSeconds: newInt64(7), MaxSurge: util.NewIntOrStringFromInt(10), MaxUnavailable: util.NewIntOrStringFromInt(20), }, }, } for _, test := range tests { out := &newer.RollingDeploymentStrategyParams{} if err := kapi.Scheme.Convert(test.in, out); err != nil { t.Errorf("unexpected error: %v", err) } if !reflect.DeepEqual(out, test.out) { t.Errorf("got different than expected:\nA:\t%#v\nB:\t%#v\n\nDiff:\n%s\n\n%s", out, test.out, util.ObjectDiff(test.out, out), util.ObjectGoPrintSideBySide(test.out, out)) } } }
func TestArrayOfRuntimeObject(t *testing.T) { internalGV := unversioned.GroupVersion{Group: "test.group", Version: runtime.APIVersionInternal} externalGV := unversioned.GroupVersion{Group: "test.group", Version: "v1test"} s := runtime.NewScheme() s.AddKnownTypes(internalGV, &EmbeddedTest{}) s.AddKnownTypeWithName(externalGV.WithKind("EmbeddedTest"), &EmbeddedTestExternal{}) s.AddKnownTypes(internalGV, &ObjectTest{}) s.AddKnownTypeWithName(externalGV.WithKind("ObjectTest"), &ObjectTestExternal{}) codec := serializer.NewCodecFactory(s).LegacyCodec(externalGV) innerItems := []runtime.Object{ &EmbeddedTest{ID: "baz"}, } items := []runtime.Object{ &EmbeddedTest{ID: "foo"}, &EmbeddedTest{ID: "bar"}, // TODO: until YAML is removed, this JSON must be in ascending key order to ensure consistent roundtrip serialization &runtime.Unknown{RawJSON: []byte(`{"apiVersion":"unknown.group/unknown","foo":"bar","kind":"OtherTest"}`)}, &ObjectTest{ Items: runtime.NewEncodableList(codec, innerItems), }, } internal := &ObjectTest{ Items: runtime.NewEncodableList(codec, items), } wire, err := runtime.Encode(codec, internal) if err != nil { t.Fatalf("unexpected error: %v", err) } t.Logf("Wire format is:\n%s\n", string(wire)) obj := &ObjectTestExternal{} if err := json.Unmarshal(wire, obj); err != nil { t.Fatalf("unexpected error: %v", err) } t.Logf("exact wire is: %s", string(obj.Items[0].RawJSON)) items[3] = &ObjectTest{Items: innerItems} internal.Items = items decoded, err := runtime.Decode(codec, wire) if err != nil { t.Fatalf("unexpected error: %v", err) } list, err := meta.ExtractList(decoded) if err != nil { t.Fatalf("unexpected error: %v", err) } if errs := runtime.DecodeList(list, codec); len(errs) > 0 { t.Fatalf("unexpected error: %v", errs) } list2, err := meta.ExtractList(list[3]) if err != nil { t.Fatalf("unexpected error: %v", err) } if errs := runtime.DecodeList(list2, codec); len(errs) > 0 { t.Fatalf("unexpected error: %v", errs) } if err := meta.SetList(list[3], list2); err != nil { t.Fatalf("unexpected error: %v", err) } // we want DecodeList to set type meta if possible, even on runtime.Unknown objects internal.Items[2].(*runtime.Unknown).TypeMeta = runtime.TypeMeta{Kind: "OtherTest", APIVersion: "unknown.group/unknown"} if e, a := internal.Items, list; !reflect.DeepEqual(e, a) { t.Errorf("mismatched decoded: %s", util.ObjectGoPrintSideBySide(e, a)) } }
func TestExtensionMapping(t *testing.T) { internalGV := unversioned.GroupVersion{Group: "test.group", Version: runtime.APIVersionInternal} externalGV := unversioned.GroupVersion{Group: "test.group", Version: "testExternal"} scheme := runtime.NewScheme() scheme.AddKnownTypeWithName(internalGV.WithKind("ExtensionType"), &InternalExtensionType{}) scheme.AddKnownTypeWithName(internalGV.WithKind("OptionalExtensionType"), &InternalOptionalExtensionType{}) scheme.AddKnownTypeWithName(externalGV.WithKind("ExtensionType"), &ExternalExtensionType{}) scheme.AddKnownTypeWithName(externalGV.WithKind("OptionalExtensionType"), &ExternalOptionalExtensionType{}) // register external first when the object is the same in both schemes, so ObjectVersionAndKind reports the // external version. scheme.AddKnownTypeWithName(externalGV.WithKind("A"), &ExtensionA{}) scheme.AddKnownTypeWithName(externalGV.WithKind("B"), &ExtensionB{}) scheme.AddKnownTypeWithName(internalGV.WithKind("A"), &ExtensionA{}) scheme.AddKnownTypeWithName(internalGV.WithKind("B"), &ExtensionB{}) codec := serializer.NewCodecFactory(scheme).LegacyCodec(externalGV) table := []struct { obj runtime.Object expected runtime.Object encoded string }{ { &InternalExtensionType{ Extension: runtime.NewEncodable(codec, &ExtensionA{TestString: "foo"}), }, &InternalExtensionType{ Extension: &runtime.Unknown{ RawJSON: []byte(`{"kind":"A","apiVersion":"test.group/testExternal","testString":"foo"}`), }, }, // apiVersion is set in the serialized object for easier consumption by clients `{"kind":"ExtensionType","apiVersion":"` + externalGV.String() + `","extension":{"kind":"A","apiVersion":"test.group/testExternal","testString":"foo"}} `, }, { &InternalExtensionType{Extension: runtime.NewEncodable(codec, &ExtensionB{TestString: "bar"})}, &InternalExtensionType{ Extension: &runtime.Unknown{ RawJSON: []byte(`{"kind":"B","apiVersion":"test.group/testExternal","testString":"bar"}`), }, }, // apiVersion is set in the serialized object for easier consumption by clients `{"kind":"ExtensionType","apiVersion":"` + externalGV.String() + `","extension":{"kind":"B","apiVersion":"test.group/testExternal","testString":"bar"}} `, }, { &InternalExtensionType{Extension: nil}, &InternalExtensionType{ Extension: nil, }, `{"kind":"ExtensionType","apiVersion":"` + externalGV.String() + `","extension":null} `, }, } for i, item := range table { gotEncoded, err := runtime.Encode(codec, item.obj) if err != nil { t.Errorf("unexpected error '%v' (%#v)", err, item.obj) } else if e, a := item.encoded, string(gotEncoded); e != a { t.Errorf("expected\n%#v\ngot\n%#v\n", e, a) } gotDecoded, err := runtime.Decode(codec, []byte(item.encoded)) if err != nil { t.Errorf("unexpected error '%v' (%v)", err, item.encoded) } else if e, a := item.expected, gotDecoded; !reflect.DeepEqual(e, a) { t.Errorf("%d: unexpected objects:\n%s", i, util.ObjectGoPrintSideBySide(e, a)) } } }
func TestDefaults(t *testing.T) { tests := []struct { original *podnodeconstraintsv1.PodNodeConstraintsConfig expected *podnodeconstraintsv1.PodNodeConstraintsConfig }{ { original: &podnodeconstraintsv1.PodNodeConstraintsConfig{}, expected: &podnodeconstraintsv1.PodNodeConstraintsConfig{ NodeSelectorLabelBlacklist: []string{"kubernetes.io/hostname"}, }, }, } for i, test := range tests { t.Logf("test %d", i) original := test.original expected := test.expected obj2 := roundTrip(t, runtime.Object(original)) got, ok := obj2.(*podnodeconstraintsv1.PodNodeConstraintsConfig) if !ok { t.Errorf("unexpected object: %v", got) t.FailNow() } if !reflect.DeepEqual(got, expected) { t.Errorf("got different than expected:\nA:\t%#v\nB:\t%#v\n\nDiff:\n%s\n\n%s", got, expected, util.ObjectDiff(expected, got), util.ObjectGoPrintSideBySide(expected, got)) } } }
func TestDecode(t *testing.T) { gvk1 := &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"} decodable1 := &testDecodable{} decodable2 := &testDecodable{} decodable3 := &testDecodable{} versionedDecodable1 := &runtime.VersionedObjects{Objects: []runtime.Object{decodable1}} testCases := []struct { serializer runtime.Serializer convertor runtime.ObjectConvertor creater runtime.ObjectCreater copier runtime.ObjectCopier typer runtime.Typer yaml bool pretty bool encodes, decodes []unversioned.GroupVersion defaultGVK *unversioned.GroupVersionKind into runtime.Object errFn func(error) bool expectedObject runtime.Object sameObject runtime.Object expectedGVK *unversioned.GroupVersionKind }{ { serializer: &mockSerializer{actual: gvk1}, convertor: &checkConvertor{groupVersion: "other/__internal"}, expectedGVK: gvk1, }, { serializer: &mockSerializer{actual: gvk1, obj: decodable1}, convertor: &checkConvertor{in: decodable1, obj: decodable2, groupVersion: "other/__internal"}, expectedGVK: gvk1, sameObject: decodable2, }, // defaultGVK.Group is allowed to force a conversion to the destination group { serializer: &mockSerializer{actual: gvk1, obj: decodable1}, defaultGVK: &unversioned.GroupVersionKind{Group: "force"}, convertor: &checkConvertor{in: decodable1, obj: decodable2, groupVersion: "force/__internal"}, expectedGVK: gvk1, sameObject: decodable2, }, // uses direct conversion for into when objects differ { into: decodable3, serializer: &mockSerializer{actual: gvk1, obj: decodable1}, convertor: &checkConvertor{in: decodable1, obj: decodable3, directConvert: true}, expectedGVK: gvk1, sameObject: decodable3, }, { into: versionedDecodable1, serializer: &mockSerializer{actual: gvk1, obj: decodable3}, convertor: &checkConvertor{in: decodable3, obj: decodable1, directConvert: true}, expectedGVK: gvk1, sameObject: versionedDecodable1, }, // returns directly when serializer returns into { into: decodable3, serializer: &mockSerializer{actual: gvk1, obj: decodable3}, expectedGVK: gvk1, sameObject: decodable3, }, // returns directly when serializer returns into { into: versionedDecodable1, serializer: &mockSerializer{actual: gvk1, obj: decodable1}, expectedGVK: gvk1, sameObject: versionedDecodable1, }, // runtime.VersionedObjects are decoded { into: &runtime.VersionedObjects{Objects: []runtime.Object{}}, serializer: &mockSerializer{actual: gvk1, obj: decodable1}, copier: &checkCopy{in: decodable1, obj: decodable1}, convertor: &checkConvertor{in: decodable1, obj: decodable2, groupVersion: "other/__internal"}, expectedGVK: gvk1, expectedObject: &runtime.VersionedObjects{Objects: []runtime.Object{decodable1, decodable2}}, }, { into: &runtime.VersionedObjects{Objects: []runtime.Object{}}, serializer: &mockSerializer{actual: gvk1, obj: decodable1}, copier: &checkCopy{in: decodable1, obj: nil, err: fmt.Errorf("error on copy")}, convertor: &checkConvertor{in: decodable1, obj: decodable2, groupVersion: "other/__internal"}, expectedGVK: gvk1, expectedObject: &runtime.VersionedObjects{Objects: []runtime.Object{decodable1, decodable2}}, }, // decode into the same version as the serialized object { decodes: []unversioned.GroupVersion{gvk1.GroupVersion()}, serializer: &mockSerializer{actual: gvk1, obj: decodable1}, expectedGVK: gvk1, expectedObject: decodable1, }, { into: &runtime.VersionedObjects{Objects: []runtime.Object{}}, decodes: []unversioned.GroupVersion{gvk1.GroupVersion()}, serializer: &mockSerializer{actual: gvk1, obj: decodable1}, expectedGVK: gvk1, expectedObject: &runtime.VersionedObjects{Objects: []runtime.Object{decodable1}}, }, // codec with non matching version skips conversion altogether { decodes: []unversioned.GroupVersion{{Group: "something", Version: "else"}}, serializer: &mockSerializer{actual: gvk1, obj: decodable1}, expectedGVK: gvk1, expectedObject: decodable1, }, { into: &runtime.VersionedObjects{Objects: []runtime.Object{}}, decodes: []unversioned.GroupVersion{{Group: "something", Version: "else"}}, serializer: &mockSerializer{actual: gvk1, obj: decodable1}, expectedGVK: gvk1, expectedObject: &runtime.VersionedObjects{Objects: []runtime.Object{decodable1}}, }, } for i, test := range testCases { t.Logf("%d", i) s := NewCodec(test.serializer, test.convertor, test.creater, test.copier, test.typer, test.encodes, test.decodes) obj, gvk, err := s.Decode([]byte(`{}`), test.defaultGVK, test.into) if !reflect.DeepEqual(test.expectedGVK, gvk) { t.Errorf("%d: unexpected GVK: %v", i, gvk) } switch { case err == nil && test.errFn != nil: t.Errorf("%d: failed: %v", i, err) continue case err != nil && test.errFn == nil: t.Errorf("%d: failed: %v", i, err) continue case err != nil: if !test.errFn(err) { t.Errorf("%d: failed: %v", i, err) } if obj != nil { t.Errorf("%d: should have returned nil object", i) } continue } if test.into != nil && test.into != obj { t.Errorf("%d: expected into to be returned: %v", i, obj) continue } switch { case test.expectedObject != nil: if !reflect.DeepEqual(test.expectedObject, obj) { t.Errorf("%d: unexpected object:\n%s", i, util.ObjectGoPrintSideBySide(test.expectedObject, obj)) } case test.sameObject != nil: if test.sameObject != obj { t.Errorf("%d: unexpected object:\n%s", i, util.ObjectGoPrintSideBySide(test.sameObject, obj)) } case obj != nil: t.Errorf("%d: unexpected object: %#v", i, obj) } } }
func TestPodLogOptions(t *testing.T) { sinceSeconds := int64(1) sinceTime := unversioned.NewTime(time.Date(2000, 1, 1, 12, 34, 56, 0, time.UTC).Local()) tailLines := int64(2) limitBytes := int64(3) versionedLogOptions := &versioned.PodLogOptions{ Container: "mycontainer", Follow: true, Previous: true, SinceSeconds: &sinceSeconds, SinceTime: &sinceTime, Timestamps: true, TailLines: &tailLines, LimitBytes: &limitBytes, } unversionedLogOptions := &api.PodLogOptions{ Container: "mycontainer", Follow: true, Previous: true, SinceSeconds: &sinceSeconds, SinceTime: &sinceTime, Timestamps: true, TailLines: &tailLines, LimitBytes: &limitBytes, } expectedParameters := url.Values{ "container": {"mycontainer"}, "follow": {"true"}, "previous": {"true"}, "sinceSeconds": {"1"}, "sinceTime": {"2000-01-01T12:34:56Z"}, "timestamps": {"true"}, "tailLines": {"2"}, "limitBytes": {"3"}, } codec := runtime.NewParameterCodec(api.Scheme) // unversioned -> query params { actualParameters, err := codec.EncodeParameters(unversionedLogOptions, versioned.SchemeGroupVersion) if err != nil { t.Fatal(err) } if !reflect.DeepEqual(actualParameters, expectedParameters) { t.Fatalf("Expected\n%#v\ngot\n%#v", expectedParameters, actualParameters) } } // versioned -> query params { actualParameters, err := codec.EncodeParameters(versionedLogOptions, versioned.SchemeGroupVersion) if err != nil { t.Fatal(err) } if !reflect.DeepEqual(actualParameters, expectedParameters) { t.Fatalf("Expected\n%#v\ngot\n%#v", expectedParameters, actualParameters) } } // query params -> versioned { convertedLogOptions := &versioned.PodLogOptions{} err := codec.DecodeParameters(expectedParameters, versioned.SchemeGroupVersion, convertedLogOptions) if err != nil { t.Fatal(err) } if !reflect.DeepEqual(convertedLogOptions, versionedLogOptions) { t.Fatalf("Unexpected deserialization:\n%s", util.ObjectGoPrintSideBySide(versionedLogOptions, convertedLogOptions)) } } // query params -> unversioned { convertedLogOptions := &api.PodLogOptions{} err := codec.DecodeParameters(expectedParameters, versioned.SchemeGroupVersion, convertedLogOptions) if err != nil { t.Fatal(err) } if !reflect.DeepEqual(convertedLogOptions, unversionedLogOptions) { t.Fatalf("Unexpected deserialization:\n%s", util.ObjectGoPrintSideBySide(unversionedLogOptions, convertedLogOptions)) } } }