package v1_test import ( "reflect" "testing" kapi "k8s.io/kubernetes/pkg/api" // required to register defaulting functions for containers _ "k8s.io/kubernetes/pkg/api/install" kapiv1 "k8s.io/kubernetes/pkg/api/v1" "k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/util/diff" "k8s.io/kubernetes/pkg/util/intstr" v1 "github.com/openshift/origin/pkg/api/v1" deployapi "github.com/openshift/origin/pkg/deploy/api" _ "github.com/openshift/origin/pkg/deploy/api/install" deployv1 "github.com/openshift/origin/pkg/deploy/api/v1" ) func mkintp(i int64) *int64 { return &i } 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, }, ActiveDeadlineSeconds: newInt64(deployapi.MaxDeploymentDurationSeconds), }, 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, }, ActiveDeadlineSeconds: newInt64(deployapi.MaxDeploymentDurationSeconds), }, 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", // The pull policy will be "PullAlways" only when the // image tag is 'latest'. In other case it will be // "PullIfNotPresent". ImagePullPolicy: kapiv1.PullIfNotPresent, }, }, }, }, }, }, }, { original: &deployv1.DeploymentConfig{ Spec: deployv1.DeploymentConfigSpec{ Strategy: deployv1.DeploymentStrategy{ Type: deployv1.DeploymentStrategyTypeRolling, RollingParams: &deployv1.RollingDeploymentStrategyParams{ UpdatePeriodSeconds: newInt64(5), IntervalSeconds: newInt64(6), TimeoutSeconds: newInt64(7), MaxSurge: newIntOrString(intstr.FromString("50%")), }, ActiveDeadlineSeconds: newInt64(3600), }, 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), MaxSurge: newIntOrString(intstr.FromString("50%")), MaxUnavailable: newIntOrString(intstr.FromInt(0)), }, ActiveDeadlineSeconds: newInt64(3600), }, 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), MaxUnavailable: newIntOrString(intstr.FromString("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), MaxSurge: newIntOrString(intstr.FromInt(0)), MaxUnavailable: newIntOrString(intstr.FromString("25%")), }, ActiveDeadlineSeconds: newInt64(deployapi.MaxDeploymentDurationSeconds), }, 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), MaxSurge: newIntOrString(intstr.FromInt(0)), }, }, Triggers: []deployv1.DeploymentTriggerPolicy{ {}, }, }, }, expected: &deployv1.DeploymentConfig{ Spec: deployv1.DeploymentConfigSpec{ Strategy: deployv1.DeploymentStrategy{ Type: deployv1.DeploymentStrategyTypeRolling, RollingParams: &deployv1.RollingDeploymentStrategyParams{ UpdatePeriodSeconds: newInt64(5), IntervalSeconds: newInt64(6), TimeoutSeconds: newInt64(7), MaxUnavailable: newIntOrString(intstr.FromString("25%")), MaxSurge: newIntOrString(intstr.FromInt(0)), }, ActiveDeadlineSeconds: newInt64(deployapi.MaxDeploymentDurationSeconds), }, Triggers: []deployv1.DeploymentTriggerPolicy{ {}, }, }, }, }, } 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, diff.ObjectDiff(expected, got), diff.ObjectGoPrintSideBySide(expected, got)) } } } func roundTrip(t *testing.T, obj runtime.Object) runtime.Object { data, err := runtime.Encode(kapi.Codecs.LegacyCodec(v1.SchemeGroupVersion), obj) if err != nil { t.Errorf("%v\n %#v", err, obj) return nil } obj2, err := runtime.Decode(kapi.Codecs.UniversalDecoder(), data) if err != nil { t.Errorf("%v\nData: %s\nSource: %#v", err, string(data), obj) return nil } obj3 := reflect.New(reflect.TypeOf(obj).Elem()).Interface().(runtime.Object) err = kapi.Scheme.Convert(obj2, obj3, nil) if err != nil { t.Errorf("%v\nSource: %#v", err, obj2) return nil } return obj3 } func newInt64(val int64) *int64 { return &val } func newInt32(val int32) *int32 { return &val } func newIntOrString(ios intstr.IntOrString) *intstr.IntOrString { return &ios } func TestDeepDefaults(t *testing.T) { testCases := []struct { External runtime.Object Internal runtime.Object Ok func(runtime.Object) bool }{ { External: &deployv1.DeploymentConfig{ Spec: deployv1.DeploymentConfigSpec{ Strategy: deployv1.DeploymentStrategy{ Type: deployv1.DeploymentStrategyTypeRolling, RollingParams: &deployv1.RollingDeploymentStrategyParams{}, }, }, }, Internal: &deployapi.DeploymentConfig{}, Ok: func(out runtime.Object) bool { obj := out.(*deployapi.DeploymentConfig) if *obj.Spec.Strategy.RollingParams.IntervalSeconds != deployapi.DefaultRollingIntervalSeconds { return false } if *obj.Spec.Strategy.RollingParams.UpdatePeriodSeconds != deployapi.DefaultRollingUpdatePeriodSeconds { return false } if *obj.Spec.Strategy.RollingParams.TimeoutSeconds != deployapi.DefaultRollingTimeoutSeconds { return false } if obj.Spec.Strategy.RollingParams.MaxSurge.String() != "25%" || obj.Spec.Strategy.RollingParams.MaxUnavailable.String() != "25%" { return false } return true }, }, { External: &deployv1.DeploymentConfig{ Spec: deployv1.DeploymentConfigSpec{ Strategy: deployv1.DeploymentStrategy{ Type: deployv1.DeploymentStrategyTypeRecreate, RecreateParams: &deployv1.RecreateDeploymentStrategyParams{}, }, }, }, Internal: &deployapi.DeploymentConfig{}, Ok: func(out runtime.Object) bool { obj := out.(*deployapi.DeploymentConfig) return *obj.Spec.Strategy.RecreateParams.TimeoutSeconds == deployapi.DefaultRollingTimeoutSeconds }, }, { External: &deployv1.DeploymentConfig{ Spec: deployv1.DeploymentConfigSpec{ Template: &kapiv1.PodTemplateSpec{ Spec: kapiv1.PodSpec{ Containers: []kapiv1.Container{ {Name: "first"}, }, }, }, Strategy: deployv1.DeploymentStrategy{ Type: deployv1.DeploymentStrategyTypeRecreate, RecreateParams: &deployv1.RecreateDeploymentStrategyParams{ Pre: &deployv1.LifecycleHook{ TagImages: []deployv1.TagImageHook{{}}, ExecNewPod: &deployv1.ExecNewPodHook{}, }, Mid: &deployv1.LifecycleHook{ TagImages: []deployv1.TagImageHook{{}}, ExecNewPod: &deployv1.ExecNewPodHook{}, }, Post: &deployv1.LifecycleHook{ TagImages: []deployv1.TagImageHook{{}}, ExecNewPod: &deployv1.ExecNewPodHook{}, }, }, }, }, }, Internal: &deployapi.DeploymentConfig{}, Ok: func(out runtime.Object) bool { obj := out.(*deployapi.DeploymentConfig) return obj.Spec.Strategy.RecreateParams.Pre.ExecNewPod.ContainerName == "first" && obj.Spec.Strategy.RecreateParams.Mid.ExecNewPod.ContainerName == "first" && obj.Spec.Strategy.RecreateParams.Post.ExecNewPod.ContainerName == "first" && obj.Spec.Strategy.RecreateParams.Pre.TagImages[0].ContainerName == "first" && obj.Spec.Strategy.RecreateParams.Mid.TagImages[0].ContainerName == "first" && obj.Spec.Strategy.RecreateParams.Post.TagImages[0].ContainerName == "first" }, }, { External: &deployv1.DeploymentConfig{ Spec: deployv1.DeploymentConfigSpec{ Template: &kapiv1.PodTemplateSpec{ Spec: kapiv1.PodSpec{ Containers: []kapiv1.Container{ {Name: "first"}, }, }, }, Strategy: deployv1.DeploymentStrategy{ Type: deployv1.DeploymentStrategyTypeRecreate, RollingParams: &deployv1.RollingDeploymentStrategyParams{ Pre: &deployv1.LifecycleHook{ TagImages: []deployv1.TagImageHook{{}}, ExecNewPod: &deployv1.ExecNewPodHook{}, }, Post: &deployv1.LifecycleHook{ TagImages: []deployv1.TagImageHook{{}}, ExecNewPod: &deployv1.ExecNewPodHook{}, }, }, }, }, }, Internal: &deployapi.DeploymentConfig{}, Ok: func(out runtime.Object) bool { obj := out.(*deployapi.DeploymentConfig) return obj.Spec.Strategy.RollingParams.Pre.ExecNewPod.ContainerName == "first" && obj.Spec.Strategy.RollingParams.Post.ExecNewPod.ContainerName == "first" && obj.Spec.Strategy.RollingParams.Pre.TagImages[0].ContainerName == "first" && obj.Spec.Strategy.RollingParams.Post.TagImages[0].ContainerName == "first" }, }, { External: &deployv1.DeploymentConfig{ Spec: deployv1.DeploymentConfigSpec{ Strategy: deployv1.DeploymentStrategy{ Type: deployv1.DeploymentStrategyTypeRecreate, }, }, }, Internal: &deployapi.DeploymentConfig{}, Ok: func(out runtime.Object) bool { obj := out.(*deployapi.DeploymentConfig) return obj.Spec.Strategy.RecreateParams != nil }, }, { External: &deployv1.DeploymentConfig{ Spec: deployv1.DeploymentConfigSpec{ Triggers: []deployv1.DeploymentTriggerPolicy{ { Type: deployv1.DeploymentTriggerOnImageChange, ImageChangeParams: &deployv1.DeploymentTriggerImageChangeParams{}, }, }, }, }, Internal: &deployapi.DeploymentConfig{}, Ok: func(out runtime.Object) bool { obj := out.(*deployapi.DeploymentConfig) t.Logf("%#v", obj.Spec.Triggers[0].ImageChangeParams) return obj.Spec.Triggers[0].ImageChangeParams.From.Kind == "ImageStreamTag" }, }, } for i, test := range testCases { if err := kapi.Scheme.Convert(test.External, test.Internal, nil); err != nil { t.Fatal(err) } if !test.Ok(test.Internal) { t.Errorf("%d: did not match: %#v", i, test.Internal) } } }