// prevDeployment is the old object tested for both old and new client updates. func prevDeployment() *deployapi.DeploymentConfig { return &deployapi.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{Name: "foo", Namespace: "default", Generation: 4, Annotations: make(map[string]string)}, Spec: deploytest.OkDeploymentConfigSpec(), Status: deploytest.OkDeploymentConfigStatus(1), } }
func TestDeploymentConfigStrategy(t *testing.T) { ctx := kapi.NewDefaultContext() if !Strategy.NamespaceScoped() { t.Errorf("DeploymentConfig is namespace scoped") } if Strategy.AllowCreateOnUpdate() { t.Errorf("DeploymentConfig should not allow create on update") } deploymentConfig := &deployapi.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{Name: "foo", Namespace: "default"}, Spec: deploytest.OkDeploymentConfigSpec(), } Strategy.PrepareForCreate(deploymentConfig) errs := Strategy.Validate(ctx, deploymentConfig) if len(errs) != 0 { t.Errorf("Unexpected error validating %v", errs) } updatedDeploymentConfig := &deployapi.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{Name: "bar", Namespace: "default", Generation: 1}, Spec: deploytest.OkDeploymentConfigSpec(), } errs = Strategy.ValidateUpdate(ctx, updatedDeploymentConfig, deploymentConfig) if len(errs) == 0 { t.Errorf("Expected error validating") } // name must match, and resource version must be provided updatedDeploymentConfig.Name = "foo" updatedDeploymentConfig.ResourceVersion = "1" errs = Strategy.ValidateUpdate(ctx, updatedDeploymentConfig, deploymentConfig) if len(errs) != 0 { t.Errorf("Unexpected error validating %v", errs) } invalidDeploymentConfig := &deployapi.DeploymentConfig{} errs = Strategy.Validate(ctx, invalidDeploymentConfig) if len(errs) == 0 { t.Errorf("Expected error validating") } }
func TestValidateDeploymentConfigMissingFields(t *testing.T) { errorCases := map[string]struct { DeploymentConfig api.DeploymentConfig ErrorType field.ErrorType Field string }{ "missing name": { api.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{Name: "", Namespace: "bar"}, Spec: test.OkDeploymentConfigSpec(), }, field.ErrorTypeRequired, "metadata.name", }, "missing namespace": { api.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{Name: "foo", Namespace: ""}, Spec: test.OkDeploymentConfigSpec(), }, field.ErrorTypeRequired, "metadata.namespace", }, "invalid name": { api.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{Name: "-foo", Namespace: "bar"}, Spec: test.OkDeploymentConfigSpec(), }, field.ErrorTypeInvalid, "metadata.name", }, "invalid namespace": { api.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{Name: "foo", Namespace: "-bar"}, Spec: test.OkDeploymentConfigSpec(), }, field.ErrorTypeInvalid, "metadata.namespace", }, "missing trigger.type": { api.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{Name: "foo", Namespace: "bar"}, Spec: api.DeploymentConfigSpec{ Replicas: 1, Triggers: []api.DeploymentTriggerPolicy{ { ImageChangeParams: &api.DeploymentTriggerImageChangeParams{ ContainerNames: []string{"foo"}, }, }, }, Selector: test.OkSelector(), Strategy: test.OkStrategy(), Template: test.OkPodTemplate(), }, }, field.ErrorTypeRequired, "spec.triggers[0].type", }, "missing Trigger imageChangeParams.from": { api.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{Name: "foo", Namespace: "bar"}, Spec: api.DeploymentConfigSpec{ Replicas: 1, Triggers: []api.DeploymentTriggerPolicy{ { Type: api.DeploymentTriggerOnImageChange, ImageChangeParams: &api.DeploymentTriggerImageChangeParams{ ContainerNames: []string{"foo"}, }, }, }, Selector: test.OkSelector(), Strategy: test.OkStrategy(), Template: test.OkPodTemplate(), }, }, field.ErrorTypeRequired, "spec.triggers[0].imageChangeParams.from", }, "invalid Trigger imageChangeParams.from.kind": { api.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{Name: "foo", Namespace: "bar"}, Spec: api.DeploymentConfigSpec{ Replicas: 1, Triggers: []api.DeploymentTriggerPolicy{ { Type: api.DeploymentTriggerOnImageChange, ImageChangeParams: &api.DeploymentTriggerImageChangeParams{ From: kapi.ObjectReference{ Kind: "Invalid", Name: "name:tag", }, ContainerNames: []string{"foo"}, }, }, }, Selector: test.OkSelector(), Strategy: test.OkStrategy(), Template: test.OkPodTemplate(), }, }, field.ErrorTypeInvalid, "spec.triggers[0].imageChangeParams.from.kind", }, "missing Trigger imageChangeParams.containerNames": { api.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{Name: "foo", Namespace: "bar"}, Spec: api.DeploymentConfigSpec{ Replicas: 1, Triggers: []api.DeploymentTriggerPolicy{ { Type: api.DeploymentTriggerOnImageChange, ImageChangeParams: &api.DeploymentTriggerImageChangeParams{ From: kapi.ObjectReference{ Kind: "ImageStreamTag", Name: "foo:v1", }, }, }, }, Selector: test.OkSelector(), Strategy: test.OkStrategy(), Template: test.OkPodTemplate(), }, }, field.ErrorTypeRequired, "spec.triggers[0].imageChangeParams.containerNames", }, "missing strategy.type": { api.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{Name: "foo", Namespace: "bar"}, Spec: api.DeploymentConfigSpec{ Replicas: 1, Triggers: manualTrigger(), Selector: test.OkSelector(), Strategy: api.DeploymentStrategy{ CustomParams: test.OkCustomParams(), }, Template: test.OkPodTemplate(), }, }, field.ErrorTypeRequired, "spec.strategy.type", }, "missing strategy.customParams": { api.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{Name: "foo", Namespace: "bar"}, Spec: api.DeploymentConfigSpec{ Replicas: 1, Triggers: manualTrigger(), Selector: test.OkSelector(), Strategy: api.DeploymentStrategy{ Type: api.DeploymentStrategyTypeCustom, }, Template: test.OkPodTemplate(), }, }, field.ErrorTypeRequired, "spec.strategy.customParams", }, "missing spec.strategy.customParams.image": { api.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{Name: "foo", Namespace: "bar"}, Spec: api.DeploymentConfigSpec{ Replicas: 1, Triggers: manualTrigger(), Selector: test.OkSelector(), Strategy: api.DeploymentStrategy{ Type: api.DeploymentStrategyTypeCustom, CustomParams: &api.CustomDeploymentStrategyParams{}, }, Template: test.OkPodTemplate(), }, }, field.ErrorTypeRequired, "spec.strategy.customParams.image", }, "missing spec.strategy.recreateParams.pre.failurePolicy": { api.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{Name: "foo", Namespace: "bar"}, Spec: api.DeploymentConfigSpec{ Replicas: 1, Strategy: api.DeploymentStrategy{ Type: api.DeploymentStrategyTypeRecreate, RecreateParams: &api.RecreateDeploymentStrategyParams{ Pre: &api.LifecycleHook{ ExecNewPod: &api.ExecNewPodHook{ Command: []string{"cmd"}, ContainerName: "container", }, }, }, }, Template: test.OkPodTemplate(), Selector: test.OkSelector(), }, }, field.ErrorTypeRequired, "spec.strategy.recreateParams.pre.failurePolicy", }, "missing spec.strategy.recreateParams.pre.execNewPod": { api.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{Name: "foo", Namespace: "bar"}, Spec: api.DeploymentConfigSpec{ Replicas: 1, Strategy: api.DeploymentStrategy{ Type: api.DeploymentStrategyTypeRecreate, RecreateParams: &api.RecreateDeploymentStrategyParams{ Pre: &api.LifecycleHook{ FailurePolicy: api.LifecycleHookFailurePolicyRetry, }, }, }, Template: test.OkPodTemplate(), Selector: test.OkSelector(), }, }, field.ErrorTypeRequired, "spec.strategy.recreateParams.pre.execNewPod", }, "missing spec.strategy.recreateParams.pre.execNewPod.command": { api.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{Name: "foo", Namespace: "bar"}, Spec: api.DeploymentConfigSpec{ Replicas: 1, Strategy: api.DeploymentStrategy{ Type: api.DeploymentStrategyTypeRecreate, RecreateParams: &api.RecreateDeploymentStrategyParams{ Pre: &api.LifecycleHook{ FailurePolicy: api.LifecycleHookFailurePolicyRetry, ExecNewPod: &api.ExecNewPodHook{ ContainerName: "container", }, }, }, }, Template: test.OkPodTemplate(), Selector: test.OkSelector(), }, }, field.ErrorTypeRequired, "spec.strategy.recreateParams.pre.execNewPod.command", }, "missing spec.strategy.recreateParams.pre.execNewPod.containerName": { api.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{Name: "foo", Namespace: "bar"}, Spec: api.DeploymentConfigSpec{ Replicas: 1, Strategy: api.DeploymentStrategy{ Type: api.DeploymentStrategyTypeRecreate, RecreateParams: &api.RecreateDeploymentStrategyParams{ Pre: &api.LifecycleHook{ FailurePolicy: api.LifecycleHookFailurePolicyRetry, ExecNewPod: &api.ExecNewPodHook{ Command: []string{"cmd"}, }, }, }, }, Template: test.OkPodTemplate(), Selector: test.OkSelector(), }, }, field.ErrorTypeRequired, "spec.strategy.recreateParams.pre.execNewPod.containerName", }, "invalid spec.strategy.recreateParams.pre.execNewPod.volumes": { api.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{Name: "foo", Namespace: "bar"}, Spec: api.DeploymentConfigSpec{ Replicas: 1, Strategy: api.DeploymentStrategy{ Type: api.DeploymentStrategyTypeRecreate, RecreateParams: &api.RecreateDeploymentStrategyParams{ Pre: &api.LifecycleHook{ FailurePolicy: api.LifecycleHookFailurePolicyRetry, ExecNewPod: &api.ExecNewPodHook{ ContainerName: "container", Command: []string{"cmd"}, Volumes: []string{"good", ""}, }, }, }, }, Template: test.OkPodTemplate(), Selector: test.OkSelector(), }, }, field.ErrorTypeInvalid, "spec.strategy.recreateParams.pre.execNewPod.volumes[1]", }, "invalid spec.strategy.rollingParams.intervalSeconds": { rollingConfig(-20, 1, 1), field.ErrorTypeInvalid, "spec.strategy.rollingParams.intervalSeconds", }, "invalid spec.strategy.rollingParams.updatePeriodSeconds": { rollingConfig(1, -20, 1), field.ErrorTypeInvalid, "spec.strategy.rollingParams.updatePeriodSeconds", }, "invalid spec.strategy.rollingParams.timeoutSeconds": { rollingConfig(1, 1, -20), field.ErrorTypeInvalid, "spec.strategy.rollingParams.timeoutSeconds", }, "missing spec.strategy.rollingParams.pre.failurePolicy": { api.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{Name: "foo", Namespace: "bar"}, Spec: api.DeploymentConfigSpec{ Replicas: 1, Strategy: api.DeploymentStrategy{ Type: api.DeploymentStrategyTypeRolling, RollingParams: &api.RollingDeploymentStrategyParams{ IntervalSeconds: mkint64p(1), UpdatePeriodSeconds: mkint64p(1), TimeoutSeconds: mkint64p(20), MaxSurge: intstr.FromInt(1), Pre: &api.LifecycleHook{ ExecNewPod: &api.ExecNewPodHook{ Command: []string{"cmd"}, ContainerName: "container", }, }, }, }, Template: test.OkPodTemplate(), Selector: test.OkSelector(), }, }, field.ErrorTypeRequired, "spec.strategy.rollingParams.pre.failurePolicy", }, "both maxSurge and maxUnavailable 0 spec.strategy.rollingParams.maxUnavailable": { rollingConfigMax(intstr.FromInt(0), intstr.FromInt(0)), field.ErrorTypeInvalid, "spec.strategy.rollingParams.maxUnavailable", }, "invalid lower bound spec.strategy.rollingParams.maxUnavailable": { rollingConfigMax(intstr.FromInt(0), intstr.FromInt(-100)), field.ErrorTypeInvalid, "spec.strategy.rollingParams.maxUnavailable", }, "invalid lower bound spec.strategy.rollingParams.maxSurge": { rollingConfigMax(intstr.FromInt(-1), intstr.FromInt(0)), field.ErrorTypeInvalid, "spec.strategy.rollingParams.maxSurge", }, "both maxSurge and maxUnavailable 0 percent spec.strategy.rollingParams.maxUnavailable": { rollingConfigMax(intstr.FromString("0%"), intstr.FromString("0%")), field.ErrorTypeInvalid, "spec.strategy.rollingParams.maxUnavailable", }, "invalid lower bound percent spec.strategy.rollingParams.maxUnavailable": { rollingConfigMax(intstr.FromInt(0), intstr.FromString("-1%")), field.ErrorTypeInvalid, "spec.strategy.rollingParams.maxUnavailable", }, "invalid upper bound percent spec.strategy.rollingParams.maxUnavailable": { rollingConfigMax(intstr.FromInt(0), intstr.FromString("101%")), field.ErrorTypeInvalid, "spec.strategy.rollingParams.maxUnavailable", }, "invalid percent spec.strategy.rollingParams.maxUnavailable": { rollingConfigMax(intstr.FromInt(0), intstr.FromString("foo")), field.ErrorTypeInvalid, "spec.strategy.rollingParams.maxUnavailable", }, "invalid percent spec.strategy.rollingParams.maxSurge": { rollingConfigMax(intstr.FromString("foo"), intstr.FromString("100%")), field.ErrorTypeInvalid, "spec.strategy.rollingParams.maxSurge", }, } for testName, v := range errorCases { errs := ValidateDeploymentConfig(&v.DeploymentConfig) if len(v.ErrorType) == 0 { if len(errs) > 0 { for _, e := range errs { t.Errorf("%s: unexpected error: %s", testName, e) } } continue } if len(errs) == 0 { t.Errorf("%s: expected test failure, got success", testName) } for i := range errs { if got, exp := errs[i].Type, v.ErrorType; got != exp { t.Errorf("%s: expected error \"%v\" to have type %q, but got %q", testName, errs[i], exp, got) } if got, exp := errs[i].Field, v.Field; got != exp { t.Errorf("%s: expected error \"%v\" to have field %q, but got %q", testName, errs[i], exp, got) } } } }
func TestExport(t *testing.T) { exporter := &defaultExporter{} baseSA := &kapi.ServiceAccount{} baseSA.Name = "my-sa" tests := []struct { name string object runtime.Object exact bool expectedObj runtime.Object expectedErr error }{ { name: "export deploymentConfig", object: deploytest.OkDeploymentConfig(1), expectedObj: &deployapi.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{ Name: "config", }, Spec: deploytest.OkDeploymentConfigSpec(), Status: deploytest.OkDeploymentConfigStatus(0), }, expectedErr: nil, }, { name: "export imageStream", object: &imageapi.ImageStream{ ObjectMeta: kapi.ObjectMeta{ Name: "test", Namespace: "other", }, Spec: imageapi.ImageStreamSpec{ Tags: map[string]imageapi.TagReference{ "v1": { Annotations: map[string]string{"an": "annotation"}, }, }, }, Status: imageapi.ImageStreamStatus{ DockerImageRepository: "foo/bar", Tags: map[string]imageapi.TagEventList{ "v1": { Items: []imageapi.TagEvent{{Image: "the image"}}, }, }, }, }, expectedObj: &imageapi.ImageStream{ ObjectMeta: kapi.ObjectMeta{ Name: "test", Namespace: "", }, Spec: imageapi.ImageStreamSpec{ Tags: map[string]imageapi.TagReference{ "v1": { From: &kapi.ObjectReference{ Kind: "DockerImage", Name: "foo/bar:v1", }, Annotations: map[string]string{"an": "annotation"}, }, }, }, Status: imageapi.ImageStreamStatus{ Tags: map[string]imageapi.TagEventList{}, }, }, expectedErr: nil, }, { name: "remove unexportable SA secrets", object: &kapi.ServiceAccount{ ObjectMeta: kapi.ObjectMeta{ Name: baseSA.Name, }, ImagePullSecrets: []kapi.LocalObjectReference{ {Name: osautil.GetDockercfgSecretNamePrefix(baseSA) + "-foo"}, {Name: "another-pull-secret"}, }, Secrets: []kapi.ObjectReference{ {Name: osautil.GetDockercfgSecretNamePrefix(baseSA) + "-foo"}, {Name: osautil.GetTokenSecretNamePrefix(baseSA) + "-foo"}, {Name: "another-mountable-secret"}, }, }, expectedObj: &kapi.ServiceAccount{ ObjectMeta: kapi.ObjectMeta{ Name: baseSA.Name, }, ImagePullSecrets: []kapi.LocalObjectReference{ {Name: "another-pull-secret"}, }, Secrets: []kapi.ObjectReference{ {Name: "another-mountable-secret"}, }, }, expectedErr: nil, }, { name: "do not remove unexportable SA secrets with exact", object: &kapi.ServiceAccount{ ObjectMeta: kapi.ObjectMeta{ Name: baseSA.Name, }, ImagePullSecrets: []kapi.LocalObjectReference{ {Name: osautil.GetDockercfgSecretNamePrefix(baseSA) + "-foo"}, {Name: "another-pull-secret"}, }, Secrets: []kapi.ObjectReference{ {Name: osautil.GetDockercfgSecretNamePrefix(baseSA) + "-foo"}, {Name: osautil.GetTokenSecretNamePrefix(baseSA) + "-foo"}, {Name: "another-mountable-secret"}, }, }, expectedObj: &kapi.ServiceAccount{ ObjectMeta: kapi.ObjectMeta{ Name: baseSA.Name, }, ImagePullSecrets: []kapi.LocalObjectReference{ {Name: osautil.GetDockercfgSecretNamePrefix(baseSA) + "-foo"}, {Name: "another-pull-secret"}, }, Secrets: []kapi.ObjectReference{ {Name: osautil.GetDockercfgSecretNamePrefix(baseSA) + "-foo"}, {Name: osautil.GetTokenSecretNamePrefix(baseSA) + "-foo"}, {Name: "another-mountable-secret"}, }, }, exact: true, expectedErr: nil, }, } for _, test := range tests { if err := exporter.Export(test.object, test.exact); err != test.expectedErr { t.Errorf("error mismatch: expected %v, got %v", test.expectedErr, err) } if !reflect.DeepEqual(test.object, test.expectedObj) { t.Errorf("object mismatch: expected \n%v\ngot \n%v\n", test.expectedObj, test.object) } } }