func TestValidateSelectorMatchesPodTemplateLabels(t *testing.T) { tests := map[string]struct { spec api.DeploymentConfigSpec expectedErr bool errorType field.ErrorType field string }{ "valid template labels": { spec: api.DeploymentConfigSpec{ Selector: test.OkSelector(), Strategy: test.OkStrategy(), Template: test.OkPodTemplate(), }, }, "invalid template labels": { spec: api.DeploymentConfigSpec{ Selector: test.OkSelector(), Strategy: test.OkStrategy(), Template: test.OkPodTemplate(), }, expectedErr: true, errorType: field.ErrorTypeInvalid, field: "spec.template.metadata.labels", }, } for name, test := range tests { if test.expectedErr { test.spec.Template.Labels["a"] = "c" } errs := ValidateDeploymentConfigSpec(test.spec) if len(errs) == 0 && test.expectedErr { t.Errorf("%s: expected failure", name) continue } if !test.expectedErr { continue } if len(errs) != 1 { t.Errorf("%s: expected one error, got %d", name, len(errs)) continue } err := errs[0] if err.Type != test.errorType { t.Errorf("%s: expected error to have type %q, got %q", name, test.errorType, err.Type) } if err.Field != test.field { t.Errorf("%s: expected error to have field %q, got %q", name, test.field, err.Field) } } }
func TestValidateDeploymentConfigDefaultImageStreamKind(t *testing.T) { config := &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: "name:v1", }, ContainerNames: []string{"foo"}, }, }, }, Selector: test.OkSelector(), Template: test.OkPodTemplate(), Strategy: test.OkStrategy(), }, } if errs := ValidateDeploymentConfig(config); len(errs) > 0 { t.Errorf("Unxpected non-empty error list: %v", errs) } }
func podTemplateA() *kapi.PodTemplateSpec { t := deploytest.OkPodTemplate() t.Spec.Containers = append(t.Spec.Containers, kapi.Container{ Name: "container1", Image: "registry:8080/repo1:ref1", }) return t }
func TestDCPodTemplateSpecNode(t *testing.T) { g := osgraph.New() dc := &deployapi.DeploymentConfig{} dc.Namespace = "ns" dc.Name = "foo" dc.Spec.Template = test.OkPodTemplate() _ = EnsureDeploymentConfigNode(g, dc) edges := g.Edges() if len(edges) != 2 { t.Errorf("expected 2 edges, got %d", len(edges)) return } for i := range edges { if !g.EdgeKinds(edges[i]).Has(osgraph.ContainsEdgeKind) { t.Errorf("expected %v, got %v", osgraph.ContainsEdgeKind, g.EdgeKinds(edges[i])) return } } nodes := g.Nodes() if len(nodes) != 3 { t.Errorf("expected 3 nodes, got %d", len(nodes)) return } sorted, err := topo.Sort(g) if err != nil { t.Errorf("unexpected error: %v", err) return } // Just to be sure if len(sorted) != 3 { t.Errorf("expected 3 nodes, got %d", len(sorted)) return } if _, ok := sorted[0].(*DeploymentConfigNode); !ok { t.Errorf("expected first node to be a DeploymentConfigNode") return } if _, ok := sorted[1].(*kubetypes.PodTemplateSpecNode); !ok { t.Errorf("expected second node to be a PodTemplateSpecNode") return } if _, ok := sorted[2].(*kubetypes.PodSpecNode); !ok { t.Errorf("expected third node to be a PodSpecNode") } }
func TestValidateDeploymentConfigOK(t *testing.T) { errs := ValidateDeploymentConfig(&api.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{Name: "foo", Namespace: "bar"}, Spec: api.DeploymentConfigSpec{ Replicas: 1, Triggers: manualTrigger(), Selector: test.OkSelector(), Strategy: test.OkStrategy(), Template: test.OkPodTemplate(), }, }) if len(errs) > 0 { t.Errorf("Unxpected non-empty error list: %#v", errs) } }
func rollingConfig(interval, updatePeriod, timeout int) api.DeploymentConfig { return api.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{Name: "foo", Namespace: "bar"}, Spec: api.DeploymentConfigSpec{ Triggers: manualTrigger(), Strategy: api.DeploymentStrategy{ Type: api.DeploymentStrategyTypeRolling, RollingParams: &api.RollingDeploymentStrategyParams{ IntervalSeconds: mkint64p(interval), UpdatePeriodSeconds: mkint64p(updatePeriod), TimeoutSeconds: mkint64p(timeout), MaxSurge: intstr.FromInt(1), }, }, Template: test.OkPodTemplate(), Selector: test.OkSelector(), }, } }
func rollingConfigMax(maxSurge, maxUnavailable intstr.IntOrString) api.DeploymentConfig { return api.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{Name: "foo", Namespace: "bar"}, Spec: api.DeploymentConfigSpec{ Triggers: manualTrigger(), Strategy: api.DeploymentStrategy{ Type: api.DeploymentStrategyTypeRolling, RollingParams: &api.RollingDeploymentStrategyParams{ IntervalSeconds: mkint64p(1), UpdatePeriodSeconds: mkint64p(1), TimeoutSeconds: mkint64p(1), MaxSurge: maxSurge, MaxUnavailable: maxUnavailable, }, }, Template: test.OkPodTemplate(), Selector: test.OkSelector(), }, } }
func TestCanTrigger(t *testing.T) { tests := []struct { name string config *deployapi.DeploymentConfig decoded *deployapi.DeploymentConfig force bool expected bool expectedCauses []deployapi.DeploymentCause expectedErr bool }{ { name: "no trigger [w/ podtemplate change]", config: &deployapi.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{Name: "config"}, Spec: deployapi.DeploymentConfigSpec{ Triggers: []deployapi.DeploymentTriggerPolicy{}, Template: deploytest.OkPodTemplateChanged(), }, Status: deploytest.OkDeploymentConfigStatus(1), }, decoded: &deployapi.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{Name: "config"}, Spec: deployapi.DeploymentConfigSpec{ Triggers: []deployapi.DeploymentTriggerPolicy{}, Template: deploytest.OkPodTemplate(), }, Status: deploytest.OkDeploymentConfigStatus(1), }, force: false, expected: false, expectedCauses: nil, }, { name: "forced updated", config: &deployapi.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{Name: "config"}, Spec: deployapi.DeploymentConfigSpec{ Template: deploytest.OkPodTemplateChanged(), }, Status: deploytest.OkDeploymentConfigStatus(1), }, decoded: &deployapi.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{Name: "config"}, Spec: deployapi.DeploymentConfigSpec{ Template: deploytest.OkPodTemplate(), }, Status: deploytest.OkDeploymentConfigStatus(1), }, force: true, expected: true, expectedCauses: []deployapi.DeploymentCause{{Type: deployapi.DeploymentTriggerManual}}, }, { name: "config change trigger only [w/ podtemplate change]", config: &deployapi.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{Name: "config"}, Spec: deployapi.DeploymentConfigSpec{ Template: deploytest.OkPodTemplateChanged(), Triggers: []deployapi.DeploymentTriggerPolicy{ deploytest.OkConfigChangeTrigger(), }, }, Status: deploytest.OkDeploymentConfigStatus(1), }, decoded: &deployapi.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{Name: "config"}, Spec: deployapi.DeploymentConfigSpec{ Template: deploytest.OkPodTemplate(), Triggers: []deployapi.DeploymentTriggerPolicy{ deploytest.OkConfigChangeTrigger(), }, }, Status: deploytest.OkDeploymentConfigStatus(1), }, force: false, expected: true, expectedCauses: deploytest.OkConfigChangeDetails().Causes, }, { name: "config change trigger only [no change][initial]", config: &deployapi.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{Name: "config"}, Spec: deployapi.DeploymentConfigSpec{ Template: deploytest.OkPodTemplate(), Triggers: []deployapi.DeploymentTriggerPolicy{ deploytest.OkConfigChangeTrigger(), }, }, Status: deploytest.OkDeploymentConfigStatus(0), }, decoded: &deployapi.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{Name: "config"}, Spec: deployapi.DeploymentConfigSpec{ Template: deploytest.OkPodTemplate(), Triggers: []deployapi.DeploymentTriggerPolicy{ deploytest.OkConfigChangeTrigger(), }, }, Status: deploytest.OkDeploymentConfigStatus(0), }, force: false, expected: true, expectedCauses: deploytest.OkConfigChangeDetails().Causes, }, { name: "config change trigger only [no change]", config: &deployapi.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{Name: "config"}, Spec: deployapi.DeploymentConfigSpec{ Template: deploytest.OkPodTemplate(), Triggers: []deployapi.DeploymentTriggerPolicy{ deploytest.OkConfigChangeTrigger(), }, }, Status: deploytest.OkDeploymentConfigStatus(1), }, decoded: &deployapi.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{Name: "config"}, Spec: deployapi.DeploymentConfigSpec{ Template: deploytest.OkPodTemplate(), Triggers: []deployapi.DeploymentTriggerPolicy{ deploytest.OkConfigChangeTrigger(), }, }, Status: deploytest.OkDeploymentConfigStatus(1), }, force: false, expected: false, expectedCauses: nil, }, { name: "image change trigger only [automatic=false][w/ podtemplate change]", config: &deployapi.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{Name: "config"}, Spec: deployapi.DeploymentConfigSpec{ Template: deploytest.OkPodTemplateChanged(), // Irrelevant change Triggers: []deployapi.DeploymentTriggerPolicy{ deploytest.OkNonAutomaticICT(), // Image still to be resolved but it's false anyway }, }, Status: deploytest.OkDeploymentConfigStatus(1), }, decoded: &deployapi.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{Name: "config"}, Spec: deployapi.DeploymentConfigSpec{ Template: deploytest.OkPodTemplate(), Triggers: []deployapi.DeploymentTriggerPolicy{ deploytest.OkNonAutomaticICT(), }, }, Status: deploytest.OkDeploymentConfigStatus(1), }, force: false, expected: false, expectedCauses: nil, expectedErr: true, }, { name: "image change trigger only [automatic=false][w/ image change]", config: &deployapi.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{Name: "config"}, Spec: deployapi.DeploymentConfigSpec{ Template: deploytest.OkPodTemplateChanged(), // Image has been updated in the template but automatic=false Triggers: []deployapi.DeploymentTriggerPolicy{ deploytest.OkTriggeredNonAutomatic(), }, }, Status: deploytest.OkDeploymentConfigStatus(1), }, decoded: &deployapi.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{Name: "config"}, Spec: deployapi.DeploymentConfigSpec{ Template: deploytest.OkPodTemplate(), Triggers: []deployapi.DeploymentTriggerPolicy{ deploytest.OkNonAutomaticICT(), }, }, Status: deploytest.OkDeploymentConfigStatus(1), }, force: false, expected: false, expectedCauses: nil, }, { name: "image change trigger only [automatic=true][w/ image change]", config: &deployapi.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{Name: "config"}, Spec: deployapi.DeploymentConfigSpec{ Template: deploytest.OkPodTemplateChanged(), Triggers: []deployapi.DeploymentTriggerPolicy{ deploytest.OkTriggeredImageChange(), }, }, Status: deploytest.OkDeploymentConfigStatus(1), }, decoded: &deployapi.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{Name: "config"}, Spec: deployapi.DeploymentConfigSpec{ Template: deploytest.OkPodTemplate(), Triggers: []deployapi.DeploymentTriggerPolicy{ deploytest.OkImageChangeTrigger(), }, }, Status: deploytest.OkDeploymentConfigStatus(1), }, force: false, expected: true, expectedCauses: deploytest.OkImageChangeDetails().Causes, }, { name: "image change trigger only [automatic=true][no change]", config: &deployapi.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{Name: "config"}, Spec: deployapi.DeploymentConfigSpec{ Template: deploytest.OkPodTemplateChanged(), Triggers: []deployapi.DeploymentTriggerPolicy{ deploytest.OkTriggeredImageChange(), }, }, Status: deploytest.OkDeploymentConfigStatus(1), }, decoded: &deployapi.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{Name: "config"}, Spec: deployapi.DeploymentConfigSpec{ Template: deploytest.OkPodTemplateChanged(), Triggers: []deployapi.DeploymentTriggerPolicy{ deploytest.OkTriggeredImageChange(), }, }, Status: deploytest.OkDeploymentConfigStatus(1), }, force: false, expected: false, expectedCauses: nil, }, { name: "config change and image change trigger [automatic=false][initial][w/ image change]", config: &deployapi.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{Name: "config"}, Spec: deployapi.DeploymentConfigSpec{ Template: deploytest.OkPodTemplateChanged(), Triggers: []deployapi.DeploymentTriggerPolicy{ deploytest.OkConfigChangeTrigger(), deploytest.OkTriggeredNonAutomatic(), }, }, Status: deploytest.OkDeploymentConfigStatus(0), }, decoded: &deployapi.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{Name: "config"}, Spec: deployapi.DeploymentConfigSpec{ Template: deploytest.OkPodTemplate(), Triggers: []deployapi.DeploymentTriggerPolicy{ deploytest.OkConfigChangeTrigger(), deploytest.OkNonAutomaticICT(), }, }, Status: deploytest.OkDeploymentConfigStatus(0), }, force: false, expected: true, expectedCauses: deploytest.OkConfigChangeDetails().Causes, }, { name: "config change and image change trigger [automatic=false][initial][no change]", config: &deployapi.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{Name: "config"}, Spec: deployapi.DeploymentConfigSpec{ Template: deploytest.OkPodTemplate(), Triggers: []deployapi.DeploymentTriggerPolicy{ deploytest.OkConfigChangeTrigger(), deploytest.OkNonAutomaticICT(), // Image is not resolved yet }, }, Status: deploytest.OkDeploymentConfigStatus(0), }, decoded: &deployapi.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{Name: "config"}, Spec: deployapi.DeploymentConfigSpec{ Template: deploytest.OkPodTemplate(), Triggers: []deployapi.DeploymentTriggerPolicy{ deploytest.OkConfigChangeTrigger(), deploytest.OkNonAutomaticICT(), }, }, Status: deploytest.OkDeploymentConfigStatus(0), }, force: false, expected: false, expectedCauses: nil, expectedErr: true, }, { name: "config change and image change trigger [automatic=true][initial][w/ podtemplate change]", config: &deployapi.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{Name: "config"}, Spec: deployapi.DeploymentConfigSpec{ Template: deploytest.OkPodTemplateChanged(), // Pod template has changed but the image in the template is yet to be updated Triggers: []deployapi.DeploymentTriggerPolicy{ deploytest.OkConfigChangeTrigger(), deploytest.OkImageChangeTrigger(), }, }, Status: deploytest.OkDeploymentConfigStatus(0), }, decoded: &deployapi.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{Name: "config"}, Spec: deployapi.DeploymentConfigSpec{ Template: deploytest.OkPodTemplate(), Triggers: []deployapi.DeploymentTriggerPolicy{ deploytest.OkConfigChangeTrigger(), deploytest.OkImageChangeTrigger(), }, }, Status: deploytest.OkDeploymentConfigStatus(0), }, force: false, expected: false, expectedCauses: nil, expectedErr: true, }, { name: "config change and image change trigger [automatic=true][initial][w/ image change]", config: &deployapi.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{Name: "config"}, Spec: deployapi.DeploymentConfigSpec{ Template: deploytest.OkPodTemplateChanged(), Triggers: []deployapi.DeploymentTriggerPolicy{ deploytest.OkConfigChangeTrigger(), deploytest.OkTriggeredImageChange(), }, }, Status: deploytest.OkDeploymentConfigStatus(0), }, decoded: &deployapi.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{Name: "config"}, Spec: deployapi.DeploymentConfigSpec{ Template: deploytest.OkPodTemplate(), Triggers: []deployapi.DeploymentTriggerPolicy{ deploytest.OkConfigChangeTrigger(), deploytest.OkImageChangeTrigger(), }, }, Status: deploytest.OkDeploymentConfigStatus(0), }, force: false, expected: true, expectedCauses: deploytest.OkImageChangeDetails().Causes, }, { name: "config change and image change trigger [automatic=true][no change]", config: &deployapi.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{Name: "config"}, Spec: deployapi.DeploymentConfigSpec{ Template: deploytest.OkPodTemplateChanged(), Triggers: []deployapi.DeploymentTriggerPolicy{ deploytest.OkConfigChangeTrigger(), deploytest.OkTriggeredImageChange(), }, }, Status: deploytest.OkDeploymentConfigStatus(1), }, force: false, expected: false, expectedCauses: nil, }, } for _, test := range tests { t.Logf("running scenario %q", test.name) fake := &ktestclient.Fake{} fake.AddReactor("get", "replicationcontrollers", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) { config := test.decoded if config == nil { config = test.config } config = deploytest.RoundTripConfig(t, config) deployment, _ := deployutil.MakeDeployment(config, codec) return true, deployment, nil }) test.config = deploytest.RoundTripConfig(t, test.config) got, gotCauses, err := canTrigger(test.config, fake, codec, test.force) if err != nil && !test.expectedErr { t.Errorf("unexpected error: %v", err) continue } if err == nil && test.expectedErr { t.Errorf("expected an error") continue } if test.expected != got { t.Errorf("expected to trigger: %t, got: %t", test.expected, got) } if !kapi.Semantic.DeepEqual(test.expectedCauses, gotCauses) { t.Errorf("expected causes:\n%#v\ngot:\n%#v", test.expectedCauses, gotCauses) } } }
func TestCanTrigger(t *testing.T) { tests := []struct { name string config *deployapi.DeploymentConfig decoded *deployapi.DeploymentConfig expected bool expectedCauses []deployapi.DeploymentCause }{ { name: "nil decoded config", config: testapi.OkDeploymentConfig(1), decoded: nil, expected: false, expectedCauses: nil, }, { name: "no trigger", config: &deployapi.DeploymentConfig{ Spec: deployapi.DeploymentConfigSpec{ Template: testapi.OkPodTemplateChanged(), }, Status: testapi.OkDeploymentConfigStatus(1), }, decoded: &deployapi.DeploymentConfig{ Spec: deployapi.DeploymentConfigSpec{ Template: testapi.OkPodTemplate(), }, Status: testapi.OkDeploymentConfigStatus(1), }, expected: false, expectedCauses: nil, }, { name: "config change trigger only", config: &deployapi.DeploymentConfig{ Spec: deployapi.DeploymentConfigSpec{ Template: testapi.OkPodTemplateChanged(), Triggers: []deployapi.DeploymentTriggerPolicy{ testapi.OkConfigChangeTrigger(), }, }, Status: testapi.OkDeploymentConfigStatus(1), }, decoded: &deployapi.DeploymentConfig{ Spec: deployapi.DeploymentConfigSpec{ Template: testapi.OkPodTemplate(), Triggers: []deployapi.DeploymentTriggerPolicy{ testapi.OkConfigChangeTrigger(), }, }, Status: testapi.OkDeploymentConfigStatus(1), }, expected: true, expectedCauses: testapi.OkConfigChangeDetails().Causes, }, { name: "config change trigger only [no change][initial]", config: &deployapi.DeploymentConfig{ Spec: deployapi.DeploymentConfigSpec{ Template: testapi.OkPodTemplate(), Triggers: []deployapi.DeploymentTriggerPolicy{ testapi.OkConfigChangeTrigger(), }, }, Status: testapi.OkDeploymentConfigStatus(0), }, decoded: &deployapi.DeploymentConfig{ Spec: deployapi.DeploymentConfigSpec{ Template: testapi.OkPodTemplate(), Triggers: []deployapi.DeploymentTriggerPolicy{ testapi.OkConfigChangeTrigger(), }, }, Status: testapi.OkDeploymentConfigStatus(0), }, expected: true, expectedCauses: testapi.OkConfigChangeDetails().Causes, }, { name: "config change trigger only [no change]", config: &deployapi.DeploymentConfig{ Spec: deployapi.DeploymentConfigSpec{ Template: testapi.OkPodTemplate(), Triggers: []deployapi.DeploymentTriggerPolicy{ testapi.OkConfigChangeTrigger(), }, }, Status: testapi.OkDeploymentConfigStatus(1), }, decoded: &deployapi.DeploymentConfig{ Spec: deployapi.DeploymentConfigSpec{ Template: testapi.OkPodTemplate(), Triggers: []deployapi.DeploymentTriggerPolicy{ testapi.OkConfigChangeTrigger(), }, }, Status: testapi.OkDeploymentConfigStatus(1), }, expected: false, expectedCauses: nil, }, { name: "image change trigger only [automatic=false]", config: &deployapi.DeploymentConfig{ Spec: deployapi.DeploymentConfigSpec{ Template: testapi.OkPodTemplateChanged(), // Irrelevant change Triggers: []deployapi.DeploymentTriggerPolicy{ testapi.OkNonAutomaticICT(), // Image still to be resolved but it's false anyway }, }, }, decoded: &deployapi.DeploymentConfig{ Spec: deployapi.DeploymentConfigSpec{ Template: testapi.OkPodTemplate(), Triggers: []deployapi.DeploymentTriggerPolicy{ testapi.OkNonAutomaticICT(), }, }, }, expected: false, expectedCauses: nil, }, { name: "image change trigger only [automatic=false][image triggered]", config: &deployapi.DeploymentConfig{ Spec: deployapi.DeploymentConfigSpec{ Template: testapi.OkPodTemplateChanged(), // Image has been updated in the template but automatic=false Triggers: []deployapi.DeploymentTriggerPolicy{ testapi.OkTriggeredNonAutomatic(), }, }, }, decoded: &deployapi.DeploymentConfig{ Spec: deployapi.DeploymentConfigSpec{ Template: testapi.OkPodTemplate(), Triggers: []deployapi.DeploymentTriggerPolicy{ testapi.OkNonAutomaticICT(), }, }, }, expected: false, expectedCauses: nil, }, { name: "image change trigger only [automatic=true]", config: &deployapi.DeploymentConfig{ Spec: deployapi.DeploymentConfigSpec{ Template: testapi.OkPodTemplateChanged(), Triggers: []deployapi.DeploymentTriggerPolicy{ testapi.OkTriggeredImageChange(), }, }, }, decoded: &deployapi.DeploymentConfig{ Spec: deployapi.DeploymentConfigSpec{ Template: testapi.OkPodTemplate(), Triggers: []deployapi.DeploymentTriggerPolicy{ testapi.OkImageChangeTrigger(), }, }, }, expected: true, expectedCauses: testapi.OkImageChangeDetails().Causes, }, { name: "image change trigger only [automatic=true][no change]", config: &deployapi.DeploymentConfig{ Spec: deployapi.DeploymentConfigSpec{ Template: testapi.OkPodTemplate(), Triggers: []deployapi.DeploymentTriggerPolicy{ testapi.OkImageChangeTrigger(), }, }, }, decoded: &deployapi.DeploymentConfig{ Spec: deployapi.DeploymentConfigSpec{ Template: testapi.OkPodTemplate(), Triggers: []deployapi.DeploymentTriggerPolicy{ testapi.OkImageChangeTrigger(), }, }, }, expected: false, expectedCauses: nil, }, { name: "config change and image change trigger [automatic=false][initial][image resolved]", config: &deployapi.DeploymentConfig{ Spec: deployapi.DeploymentConfigSpec{ Template: testapi.OkPodTemplateChanged(), Triggers: []deployapi.DeploymentTriggerPolicy{ testapi.OkConfigChangeTrigger(), testapi.OkTriggeredNonAutomatic(), }, }, Status: testapi.OkDeploymentConfigStatus(0), }, decoded: &deployapi.DeploymentConfig{ Spec: deployapi.DeploymentConfigSpec{ Template: testapi.OkPodTemplate(), Triggers: []deployapi.DeploymentTriggerPolicy{ testapi.OkConfigChangeTrigger(), testapi.OkNonAutomaticICT(), }, }, Status: testapi.OkDeploymentConfigStatus(0), }, expected: true, expectedCauses: testapi.OkConfigChangeDetails().Causes, }, { name: "config change and image change trigger [automatic=false][initial]", config: &deployapi.DeploymentConfig{ Spec: deployapi.DeploymentConfigSpec{ Template: testapi.OkPodTemplate(), Triggers: []deployapi.DeploymentTriggerPolicy{ testapi.OkConfigChangeTrigger(), testapi.OkNonAutomaticICT(), // Image is not resolved yet }, }, Status: testapi.OkDeploymentConfigStatus(0), }, decoded: &deployapi.DeploymentConfig{ Spec: deployapi.DeploymentConfigSpec{ Template: testapi.OkPodTemplate(), Triggers: []deployapi.DeploymentTriggerPolicy{ testapi.OkConfigChangeTrigger(), testapi.OkNonAutomaticICT(), }, }, Status: testapi.OkDeploymentConfigStatus(0), }, expected: false, expectedCauses: nil, }, { name: "config change and image change trigger [automatic=true][initial]", config: &deployapi.DeploymentConfig{ Spec: deployapi.DeploymentConfigSpec{ Template: testapi.OkPodTemplateChanged(), // Pod template has changed but the image in the template is yet to be updated Triggers: []deployapi.DeploymentTriggerPolicy{ testapi.OkConfigChangeTrigger(), testapi.OkImageChangeTrigger(), }, }, Status: testapi.OkDeploymentConfigStatus(0), }, decoded: &deployapi.DeploymentConfig{ Spec: deployapi.DeploymentConfigSpec{ Template: testapi.OkPodTemplate(), Triggers: []deployapi.DeploymentTriggerPolicy{ testapi.OkConfigChangeTrigger(), testapi.OkImageChangeTrigger(), }, }, Status: testapi.OkDeploymentConfigStatus(0), }, expected: false, expectedCauses: nil, }, { name: "config change and image change trigger [automatic=true][initial][image triggered]", config: &deployapi.DeploymentConfig{ Spec: deployapi.DeploymentConfigSpec{ Template: testapi.OkPodTemplateChanged(), Triggers: []deployapi.DeploymentTriggerPolicy{ testapi.OkConfigChangeTrigger(), testapi.OkTriggeredImageChange(), }, }, Status: testapi.OkDeploymentConfigStatus(0), }, decoded: &deployapi.DeploymentConfig{ Spec: deployapi.DeploymentConfigSpec{ Template: testapi.OkPodTemplate(), Triggers: []deployapi.DeploymentTriggerPolicy{ testapi.OkConfigChangeTrigger(), testapi.OkImageChangeTrigger(), }, }, Status: testapi.OkDeploymentConfigStatus(0), }, expected: true, expectedCauses: testapi.OkImageChangeDetails().Causes, }, { name: "config change and image change trigger [automatic=true][no change]", config: &deployapi.DeploymentConfig{ Spec: deployapi.DeploymentConfigSpec{ Template: testapi.OkPodTemplate(), Triggers: []deployapi.DeploymentTriggerPolicy{ testapi.OkConfigChangeTrigger(), testapi.OkImageChangeTrigger(), }, }, Status: testapi.OkDeploymentConfigStatus(1), }, decoded: &deployapi.DeploymentConfig{ Spec: deployapi.DeploymentConfigSpec{ Template: testapi.OkPodTemplate(), Triggers: []deployapi.DeploymentTriggerPolicy{ testapi.OkConfigChangeTrigger(), testapi.OkImageChangeTrigger(), }, }, Status: testapi.OkDeploymentConfigStatus(1), }, expected: false, expectedCauses: nil, }, } for _, test := range tests { got, gotCauses := canTrigger(test.config, test.decoded) if test.expected != got { t.Errorf("%s: expected to trigger: %t, got: %t", test.name, test.expected, got) continue } if !kapi.Semantic.DeepEqual(test.expectedCauses, gotCauses) { t.Errorf("%s: expected causes:\n%#v\ngot:\n%#v", test.name, test.expectedCauses, gotCauses) } } }
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 TestValidateDeploymentConfigUpdate(t *testing.T) { oldConfig := &api.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{Name: "foo", Namespace: "bar", ResourceVersion: "1"}, Spec: api.DeploymentConfigSpec{ Replicas: 1, Triggers: manualTrigger(), Selector: test.OkSelector(), Strategy: test.OkStrategy(), Template: test.OkPodTemplate(), }, Status: api.DeploymentConfigStatus{ LatestVersion: 5, }, } newConfig := &api.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{Name: "foo", Namespace: "bar", ResourceVersion: "1"}, Spec: api.DeploymentConfigSpec{ Replicas: 1, Triggers: manualTrigger(), Selector: test.OkSelector(), Strategy: test.OkStrategy(), Template: test.OkPodTemplate(), }, Status: api.DeploymentConfigStatus{ LatestVersion: 3, }, } scenarios := []struct { oldLatestVersion int newLatestVersion int }{ {5, 3}, {5, 7}, {0, -1}, } for _, values := range scenarios { oldConfig.Status.LatestVersion = values.oldLatestVersion newConfig.Status.LatestVersion = values.newLatestVersion errs := ValidateDeploymentConfigUpdate(newConfig, oldConfig) if len(errs) == 0 { t.Errorf("Expected update failure") } for i := range errs { if errs[i].Type != field.ErrorTypeInvalid { t.Errorf("expected update error to have type %s: %v", field.ErrorTypeInvalid, errs[i]) } if errs[i].Field != "status.latestVersion" { t.Errorf("expected update error to have field %s: %v", "latestVersion", errs[i]) } } } // testing for a successful update oldConfig.Status.LatestVersion = 5 newConfig.Status.LatestVersion = 6 errs := ValidateDeploymentConfigUpdate(newConfig, oldConfig) if len(errs) > 0 { t.Errorf("Unexpected update failure") } }