// TestHandle_newConfigTriggers ensures that the creation of a new config // (with version 0) with a config change trigger results in a version bump and // cause update for initial deployment. func TestHandle_newConfigTriggers(t *testing.T) { var updated *deployapi.DeploymentConfig fake := &testclient.Fake{} fake.AddReactor("update", "deploymentconfigs/status", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) { updated = action.(ktestclient.UpdateAction).GetObject().(*deployapi.DeploymentConfig) return true, updated, nil }) kFake := &ktestclient.Fake{} controller := NewDeploymentTriggerController(fake, kFake, codec) config := testapi.OkDeploymentConfig(0) config.Namespace = kapi.NamespaceDefault config.Spec.Triggers = []deployapi.DeploymentTriggerPolicy{testapi.OkConfigChangeTrigger()} if err := controller.Handle(config); err != nil { t.Fatalf("unexpected error: %v", err) } if updated == nil { t.Fatalf("expected config to be updated") } if e, a := int64(1), updated.Status.LatestVersion; e != a { t.Fatalf("expected update to latestversion=%d, got %d", e, a) } if updated.Status.Details == nil { t.Fatalf("expected config change details to be set") } else if updated.Status.Details.Causes == nil { t.Fatalf("expected config change causes to be set") } else if updated.Status.Details.Causes[0].Type != deployapi.DeploymentTriggerOnConfigChange { t.Fatalf("expected config change cause to be set to config change trigger, got %s", updated.Status.Details.Causes[0].Type) } }
// TestHandle_waitForImageController tests an initial deployment with unresolved image. The config // change controller should never increment latestVersion, thus trigger a deployment for this config. func TestHandle_waitForImageController(t *testing.T) { fake := &testclient.Fake{} kFake := &ktestclient.Fake{} fake.PrependReactor("update", "deploymentconfigs/status", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) { t.Fatalf("an update should never run before the template image is resolved") return true, nil, nil }) controller := &DeploymentConfigChangeController{ client: fake, kClient: kFake, decodeConfig: func(deployment *kapi.ReplicationController) (*deployapi.DeploymentConfig, error) { return deployutil.DecodeDeploymentConfig(deployment, kapi.Codecs.LegacyCodec(deployapi.SchemeGroupVersion)) }, } config := testapi.OkDeploymentConfig(0) config.Namespace = kapi.NamespaceDefault config.Spec.Triggers = []deployapi.DeploymentTriggerPolicy{testapi.OkConfigChangeTrigger(), testapi.OkImageChangeTrigger()} if err := controller.Handle(config); err != nil { t.Fatalf("unexpected error: %v", err) } }
// TestHandle_changeWithTemplateDiff ensures that a pod template change to a // config with a config change trigger results in a version bump and cause // update. func TestHandle_changeWithTemplateDiff(t *testing.T) { var updated *deployapi.DeploymentConfig controller := &DeploymentConfigChangeController{ decodeConfig: func(deployment *kapi.ReplicationController) (*deployapi.DeploymentConfig, error) { return deployutil.DecodeDeploymentConfig(deployment, api.Codec) }, changeStrategy: &changeStrategyImpl{ generateDeploymentConfigFunc: func(namespace, name string) (*deployapi.DeploymentConfig, error) { return deployapitest.OkDeploymentConfig(2), nil }, updateDeploymentConfigFunc: func(namespace string, config *deployapi.DeploymentConfig) (*deployapi.DeploymentConfig, error) { updated = config return config, nil }, getDeploymentFunc: func(namespace, name string) (*kapi.ReplicationController, error) { deployment, _ := deployutil.MakeDeployment(deployapitest.OkDeploymentConfig(1), kapi.Codec) return deployment, nil }, }, } config := deployapitest.OkDeploymentConfig(1) config.Triggers = []deployapi.DeploymentTriggerPolicy{deployapitest.OkConfigChangeTrigger()} config.Template.ControllerTemplate.Template.Spec.Containers[1].Name = "modified" err := controller.Handle(config) if err != nil { t.Fatalf("unexpected error: %v", err) } if updated == nil { t.Fatalf("expected config to be updated") } if e, a := 2, updated.LatestVersion; e != a { t.Fatalf("expected update to latestversion=%d, got %d", e, a) } if updated.Details == nil { t.Fatalf("expected config change details to be set") } else if updated.Details.Causes == nil { t.Fatalf("expected config change causes to be set") } else if updated.Details.Causes[0].Type != deployapi.DeploymentTriggerOnConfigChange { t.Fatalf("expected config change cause to be set to config change trigger, got %s", updated.Details.Causes[0].Type) } }
func TestHandle_nonAutomaticImageUpdates(t *testing.T) { var updated *deployapi.DeploymentConfig controller := &DeploymentConfigChangeController{ decodeConfig: func(deployment *kapi.ReplicationController) (*deployapi.DeploymentConfig, error) { return deployutil.DecodeDeploymentConfig(deployment, kapi.Codecs.LegacyCodec(deployapi.SchemeGroupVersion)) }, changeStrategy: &changeStrategyImpl{ generateDeploymentConfigFunc: func(namespace, name string) (*deployapi.DeploymentConfig, error) { generated := deployapitest.OkDeploymentConfig(1) // The generator doesn't change automatic so it's ok to fake it here. generated.Spec.Triggers[0].ImageChangeParams.Automatic = false generated.Status.Details = deployapitest.OkImageChangeDetails() updated = generated return generated, nil }, updateDeploymentConfigFunc: func(namespace string, config *deployapi.DeploymentConfig) (*deployapi.DeploymentConfig, error) { updated.Status.Details = deployapitest.OkConfigChangeDetails() return updated, nil }, }, } config := deployapitest.OkDeploymentConfig(0) ict := deployapitest.OkImageChangeTrigger() ict.ImageChangeParams.Automatic = false config.Spec.Triggers = []deployapi.DeploymentTriggerPolicy{deployapitest.OkConfigChangeTrigger(), ict} if err := controller.Handle(config); err != nil { t.Fatalf("unexpected error: %v", err) } if e, a := 1, updated.Status.LatestVersion; e != a { t.Fatalf("expected update to latestversion=%d, got %d", e, a) } if updated.Status.Details == nil { t.Fatalf("expected config change details to be set") } else if updated.Status.Details.Causes == nil { t.Fatalf("expected config change causes to be set") } else if updated.Status.Details.Causes[0].Type != deployapi.DeploymentTriggerOnConfigChange { t.Fatalf("expected config change cause to be set to config change trigger, got %s", updated.Status.Details.Causes[0].Type) } }
// TestHandle_waitForImageController tests an initial deployment with unresolved image. The config // change controller should never increment latestVersion, thus trigger a deployment for this config. func TestHandle_waitForImageController(t *testing.T) { fake := &testclient.Fake{} kFake := &ktestclient.Fake{} fake.PrependReactor("update", "deploymentconfigs/status", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) { t.Fatalf("an update should never run before the template image is resolved") return true, nil, nil }) controller := NewDeploymentTriggerController(fake, kFake, codec) config := testapi.OkDeploymentConfig(0) config.Namespace = kapi.NamespaceDefault config.Spec.Triggers = []deployapi.DeploymentTriggerPolicy{testapi.OkConfigChangeTrigger(), testapi.OkImageChangeTrigger()} if err := controller.Handle(config); err != nil { t.Fatalf("unexpected error: %v", err) } }
// TestHandle_newConfigTriggers ensures that the creation of a new config // (with version 0) with a config change trigger results in a version bump and // cause update for initial deployment. func TestHandle_newConfigTriggers(t *testing.T) { var updated *deployapi.DeploymentConfig controller := &DeploymentConfigChangeController{ decodeConfig: func(deployment *kapi.ReplicationController) (*deployapi.DeploymentConfig, error) { return deployutil.DecodeDeploymentConfig(deployment, kapi.Codecs.LegacyCodec(deployapi.SchemeGroupVersion)) }, changeStrategy: &changeStrategyImpl{ generateDeploymentConfigFunc: func(namespace, name string) (*deployapi.DeploymentConfig, error) { return deployapitest.OkDeploymentConfig(1), nil }, updateDeploymentConfigFunc: func(namespace string, config *deployapi.DeploymentConfig) (*deployapi.DeploymentConfig, error) { updated = config return config, nil }, }, } config := deployapitest.OkDeploymentConfig(0) config.Spec.Triggers = []deployapi.DeploymentTriggerPolicy{deployapitest.OkConfigChangeTrigger()} err := controller.Handle(config) if err != nil { t.Fatalf("unexpected error: %v", err) } if updated == nil { t.Fatalf("expected config to be updated") } if e, a := 1, updated.Status.LatestVersion; e != a { t.Fatalf("expected update to latestversion=%d, got %d", e, a) } if updated.Status.Details == nil { t.Fatalf("expected config change details to be set") } else if updated.Status.Details.Causes == nil { t.Fatalf("expected config change causes to be set") } else if updated.Status.Details.Causes[0].Type != deployapi.DeploymentTriggerOnConfigChange { t.Fatalf("expected config change cause to be set to config change trigger, got %s", updated.Status.Details.Causes[0].Type) } }
func TestHandle_raceWithTheImageController(t *testing.T) { var updated *deployapi.DeploymentConfig controller := &DeploymentConfigChangeController{ decodeConfig: func(deployment *kapi.ReplicationController) (*deployapi.DeploymentConfig, error) { return deployutil.DecodeDeploymentConfig(deployment, kapi.Codecs.LegacyCodec(deployapi.SchemeGroupVersion)) }, changeStrategy: &changeStrategyImpl{ generateDeploymentConfigFunc: func(namespace, name string) (*deployapi.DeploymentConfig, error) { generated := deployapitest.OkDeploymentConfig(1) generated.Status.Details = deployapitest.OkImageChangeDetails() updated = generated return generated, nil }, updateDeploymentConfigFunc: func(namespace string, config *deployapi.DeploymentConfig) (*deployapi.DeploymentConfig, error) { t.Errorf("an update should never run in the presence of races") updated.Status.Details = deployapitest.OkConfigChangeDetails() return updated, nil }, }, } config := deployapitest.OkDeploymentConfig(0) config.Spec.Triggers = []deployapi.DeploymentTriggerPolicy{deployapitest.OkConfigChangeTrigger(), deployapitest.OkImageChangeTrigger()} if err := controller.Handle(config); err != nil { t.Fatalf("unexpected error: %v", err) } if e, a := 1, updated.Status.LatestVersion; e != a { t.Fatalf("expected update to latestversion=%d, got %d", e, a) } if updated.Status.Details == nil { t.Fatalf("expected config change details to be set") } else if updated.Status.Details.Causes == nil { t.Fatalf("expected config change causes to be set") } else if updated.Status.Details.Causes[0].Type != deployapi.DeploymentTriggerOnImageChange { t.Fatalf("expected config change cause to be set to image change trigger, got %s", updated.Status.Details.Causes[0].Type) } }
// TestHandle_changeWithoutTemplateDiff ensures that an updated config with no // pod template diff results in the config version remaining the same. func TestHandle_changeWithoutTemplateDiff(t *testing.T) { config := deployapitest.OkDeploymentConfig(1) config.Triggers = []deployapi.DeploymentTriggerPolicy{deployapitest.OkConfigChangeTrigger()} generated := false updated := false controller := &DeploymentConfigChangeController{ decodeConfig: func(deployment *kapi.ReplicationController) (*deployapi.DeploymentConfig, error) { return deployutil.DecodeDeploymentConfig(deployment, api.Codec) }, changeStrategy: &changeStrategyImpl{ generateDeploymentConfigFunc: func(namespace, name string) (*deployapi.DeploymentConfig, error) { generated = true return config, nil }, updateDeploymentConfigFunc: func(namespace string, config *deployapi.DeploymentConfig) (*deployapi.DeploymentConfig, error) { updated = true return config, nil }, getDeploymentFunc: func(namespace, name string) (*kapi.ReplicationController, error) { deployment, _ := deployutil.MakeDeployment(deployapitest.OkDeploymentConfig(1), kapi.Codec) return deployment, nil }, }, } err := controller.Handle(config) if err != nil { t.Fatalf("unexpected error: %v", err) } if generated { t.Error("Unexpected generation of deploymentConfig") } if updated { t.Error("Unexpected update of deploymentConfig") } }
// TestHandle_configChangeTrigger ensures that a config with a config change // trigger will be reconciled. func TestHandle_configChangeTrigger(t *testing.T) { updated := false fake := &testclient.Fake{} fake.AddReactor("update", "deploymentconfigs/instantiate", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) { updated = true return true, nil, nil }) controller := NewDeploymentTriggerController(dcInformer, streamInformer, fake, codec) config := testapi.OkDeploymentConfig(0) config.Namespace = kapi.NamespaceDefault config.Spec.Triggers = []deployapi.DeploymentTriggerPolicy{testapi.OkConfigChangeTrigger()} if err := controller.Handle(config); err != nil { t.Fatalf("unexpected error: %v", err) } if !updated { t.Fatalf("expected config to be instantiated") } }
// TestHandle_changeWithTemplateDiff ensures that a pod template change to a // config with a config change trigger results in a version bump and cause // update. func TestHandle_changeWithTemplateDiff(t *testing.T) { scenarios := []struct { name string modify func(*deployapi.DeploymentConfig) changeExpected bool }{ { name: "container name change", changeExpected: true, modify: func(config *deployapi.DeploymentConfig) { config.Spec.Template.Spec.Containers[1].Name = "modified" }, }, { name: "template label change", changeExpected: true, modify: func(config *deployapi.DeploymentConfig) { config.Spec.Template.Labels["newkey"] = "value" }, }, { name: "no diff", changeExpected: false, modify: func(config *deployapi.DeploymentConfig) {}, }, } for _, s := range scenarios { t.Logf("running scenario: %s", s.name) config := deployapitest.OkDeploymentConfig(1) config.Spec.Triggers = []deployapi.DeploymentTriggerPolicy{deployapitest.OkConfigChangeTrigger()} deployment, _ := deployutil.MakeDeployment(config, kapi.Codec) var updated *deployapi.DeploymentConfig controller := &DeploymentConfigChangeController{ decodeConfig: func(deployment *kapi.ReplicationController) (*deployapi.DeploymentConfig, error) { return deployutil.DecodeDeploymentConfig(deployment, api.Codec) }, changeStrategy: &changeStrategyImpl{ generateDeploymentConfigFunc: func(namespace, name string) (*deployapi.DeploymentConfig, error) { return deployapitest.OkDeploymentConfig(2), nil }, updateDeploymentConfigFunc: func(namespace string, config *deployapi.DeploymentConfig) (*deployapi.DeploymentConfig, error) { updated = config return config, nil }, getDeploymentFunc: func(namespace, name string) (*kapi.ReplicationController, error) { return deployment, nil }, }, } s.modify(config) err := controller.Handle(config) if err != nil { t.Errorf("unexpected error: %v", err) } if s.changeExpected { if updated == nil { t.Errorf("expected config to be updated") continue } if e, a := 2, updated.Status.LatestVersion; e != a { t.Errorf("expected update to latestversion=%d, got %d", e, a) } if updated.Status.Details == nil { t.Errorf("expected config change details to be set") } else if updated.Status.Details.Causes == nil { t.Errorf("expected config change causes to be set") } else if updated.Status.Details.Causes[0].Type != deployapi.DeploymentTriggerOnConfigChange { t.Errorf("expected config change cause to be set to config change trigger, got %s", updated.Status.Details.Causes[0].Type) } } else { if updated != nil { t.Errorf("unexpected update to version %d", updated.Status.LatestVersion) } } } }
func TestTriggers_configChange(t *testing.T) { const namespace = "test-triggers-configchange" _, clusterAdminKubeConfig, err := testserver.StartTestMaster() checkErr(t, err) clusterAdminClientConfig, err := testutil.GetClusterAdminClientConfig(clusterAdminKubeConfig) checkErr(t, err) clusterAdminClient, err := testutil.GetClusterAdminClient(clusterAdminKubeConfig) checkErr(t, err) _, err = testserver.CreateNewProject(clusterAdminClient, *clusterAdminClientConfig, namespace, "my-test-user") checkErr(t, err) osClient, kubeClient, _, err := testutil.GetClientForUser(*clusterAdminClientConfig, "my-test-user") checkErr(t, err) config := deploytest.OkDeploymentConfig(0) config.Namespace = namespace config.Spec.Triggers[0] = deploytest.OkConfigChangeTrigger() rcWatch, err := kubeClient.ReplicationControllers(namespace).Watch(labels.Everything(), fields.Everything(), "0") if err != nil { t.Fatalf("Couldn't subscribe to Deployments %v", err) } defer rcWatch.Stop() // submit the initial deployment config if _, err := osClient.DeploymentConfigs(namespace).Create(config); err != nil { t.Fatalf("Couldn't create DeploymentConfig: %v", err) } // verify the initial deployment exists event := <-rcWatch.ResultChan() if e, a := watchapi.Added, event.Type; e != a { t.Fatalf("expected watch event type %s, got %s", e, a) } deployment := event.Object.(*kapi.ReplicationController) if e, a := config.Name, deployutil.DeploymentConfigNameFor(deployment); e != a { t.Fatalf("Expected deployment annotated with deploymentConfig '%s', got '%s'", e, a) } assertEnvVarEquals("ENV1", "VAL1", deployment, t) retryErr := kclient.RetryOnConflict(wait.Backoff{Steps: maxUpdateRetries}, func() error { // submit a new config with an updated environment variable config, err := osClient.DeploymentConfigs(namespace).Generate(config.Name) if err != nil { return err } config.Spec.Template.Spec.Containers[0].Env[0].Value = "UPDATED" // before we update the config, we need to update the state of the existing deployment // this is required to be done manually since the deployment and deployer pod controllers are not run in this test // get this live or conflicts will never end up resolved liveDeployment, err := kubeClient.ReplicationControllers(deployment.Namespace).Get(deployment.Name) if err != nil { return err } liveDeployment.Annotations[deployapi.DeploymentStatusAnnotation] = string(deployapi.DeploymentStatusComplete) // update the deployment if _, err := kubeClient.ReplicationControllers(namespace).Update(liveDeployment); err != nil { return err } event = <-rcWatch.ResultChan() if e, a := watchapi.Modified, event.Type; e != a { t.Fatalf("expected watch event type %s, got %s", e, a) } if _, err := osClient.DeploymentConfigs(namespace).Update(config); err != nil { return err } return nil }) if retryErr != nil { t.Fatal(retryErr) } var newDeployment *kapi.ReplicationController for { event = <-rcWatch.ResultChan() if event.Type != watchapi.Added { // Discard modifications which could be applied to the original RC, etc. continue } newDeployment = event.Object.(*kapi.ReplicationController) break } assertEnvVarEquals("ENV1", "UPDATED", newDeployment, t) if newDeployment.Name == deployment.Name { t.Fatalf("expected new deployment; old=%s, new=%s", deployment.Name, newDeployment.Name) } }
func TestDeploymentConfigDescriber(t *testing.T) { config := deployapitest.OkDeploymentConfig(1) deployment, _ := deployutil.MakeDeployment(config, kapi.Codecs.LegacyCodec(deployapi.SchemeGroupVersion)) podList := &kapi.PodList{} fake := &testclient.Fake{} fake.PrependReactor("get", "deploymentconfigs", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) { return true, config, nil }) kFake := &ktestclient.Fake{} kFake.PrependReactor("list", "horizontalpodautoscalers", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) { return true, &extensions.HorizontalPodAutoscalerList{ Items: []extensions.HorizontalPodAutoscaler{ *deployapitest.OkHPAForDeploymentConfig(config, 1, 3), }}, nil }) kFake.PrependReactor("get", "replicationcontrollers", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) { return true, deployment, nil }) kFake.PrependReactor("list", "replicationcontrollers", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) { return true, &kapi.ReplicationControllerList{}, nil }) kFake.PrependReactor("list", "pods", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) { return true, podList, nil }) kFake.PrependReactor("list", "events", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) { return true, &kapi.EventList{}, nil }) d := &DeploymentConfigDescriber{ osClient: fake, kubeClient: kFake, } describe := func() string { output, err := d.Describe("test", "deployment", kubectl.DescriberSettings{}) if err != nil { t.Fatalf("unexpected error: %v", err) return "" } t.Logf("describer output:\n%s\n", output) return output } podList.Items = []kapi.Pod{*mkPod(kapi.PodRunning, 0)} out := describe() substr := "Autoscaling:\tbetween 1 and 3 replicas" if !strings.Contains(out, substr) { t.Fatalf("expected %q in output:\n%s", substr, out) } config.Spec.Triggers = append(config.Spec.Triggers, deployapitest.OkConfigChangeTrigger()) describe() config.Spec.Strategy = deployapitest.OkCustomStrategy() describe() config.Spec.Triggers[0].ImageChangeParams.From = kapi.ObjectReference{Name: "imagestream"} describe() config.Spec.Strategy = deployapitest.OkStrategy() config.Spec.Strategy.RecreateParams = &deployapi.RecreateDeploymentStrategyParams{ Pre: &deployapi.LifecycleHook{ FailurePolicy: deployapi.LifecycleHookFailurePolicyAbort, ExecNewPod: &deployapi.ExecNewPodHook{ ContainerName: "container", Command: []string{"/command1", "args"}, Env: []kapi.EnvVar{ { Name: "KEY1", Value: "value1", }, }, }, }, Post: &deployapi.LifecycleHook{ FailurePolicy: deployapi.LifecycleHookFailurePolicyIgnore, ExecNewPod: &deployapi.ExecNewPodHook{ ContainerName: "container", Command: []string{"/command2", "args"}, Env: []kapi.EnvVar{ { Name: "KEY2", Value: "value2", }, }, }, }, } describe() }
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) } } }
// TestHandle_changeWithTemplateDiff ensures that a pod template change to a // config with a config change trigger results in a version bump and cause // update. func TestHandle_changeWithTemplateDiff(t *testing.T) { scenarios := []struct { name string modify func(*deployapi.DeploymentConfig) changeExpected bool }{ { name: "container name change", changeExpected: true, modify: func(config *deployapi.DeploymentConfig) { config.Spec.Template.Spec.Containers[1].Name = "modified" }, }, { name: "template label change", changeExpected: true, modify: func(config *deployapi.DeploymentConfig) { config.Spec.Template.Labels["newkey"] = "value" }, }, { name: "no diff", changeExpected: false, modify: func(config *deployapi.DeploymentConfig) {}, }, } for _, s := range scenarios { t.Logf("running scenario: %s", s.name) fake := &testclient.Fake{} kFake := &ktestclient.Fake{} config := testapi.OkDeploymentConfig(1) config.Namespace = kapi.NamespaceDefault config.Spec.Triggers = []deployapi.DeploymentTriggerPolicy{testapi.OkConfigChangeTrigger()} deployment, _ := deployutil.MakeDeployment(config, kapi.Codecs.LegacyCodec(deployapi.SchemeGroupVersion)) var updated *deployapi.DeploymentConfig fake.PrependReactor("update", "deploymentconfigs/status", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) { updated = action.(ktestclient.UpdateAction).GetObject().(*deployapi.DeploymentConfig) return true, updated, nil }) kFake.PrependReactor("get", "replicationcontrollers", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) { return true, deployment, nil }) controller := NewDeploymentTriggerController(fake, kFake, codec) s.modify(config) if err := controller.Handle(config); err != nil { t.Errorf("unexpected error: %v", err) continue } if !s.changeExpected { if updated != nil { t.Errorf("unexpected update to version %d", updated.Status.LatestVersion) } continue } // changeExpected == true if updated == nil { t.Errorf("expected config to be updated") continue } if e, a := int64(2), updated.Status.LatestVersion; e != a { t.Errorf("expected update to latestversion=%d, got %d", e, a) continue } if updated.Status.Details == nil { t.Errorf("expected config change details to be set") } else if updated.Status.Details.Causes == nil { t.Errorf("expected config change causes to be set") } else if updated.Status.Details.Causes[0].Type != deployapi.DeploymentTriggerOnConfigChange { t.Errorf("expected config change cause to be set to config change trigger, got %s", updated.Status.Details.Causes[0].Type) } } }
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 }{ "empty container field": { api.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{Name: "foo", Namespace: "bar"}, Spec: api.DeploymentConfigSpec{ Replicas: 1, Triggers: []api.DeploymentTriggerPolicy{test.OkConfigChangeTrigger()}, Selector: test.OkSelector(), Strategy: test.OkStrategy(), Template: test.OkPodTemplateMissingImage("container1"), }, }, field.ErrorTypeRequired, "spec.template.spec.containers[0].image", }, "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", }, "invalid spec.strategy.customParams.environment": { 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{ Environment: []kapi.EnvVar{ {Name: "A=B"}, }, }, }, Template: test.OkPodTemplate(), }, }, field.ErrorTypeInvalid, "spec.strategy.customParams.environment[0].name", }, "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.ErrorTypeInvalid, "spec.strategy.recreateParams.pre", }, "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]", }, "missing spec.strategy.recreateParams.mid.execNewPod": { api.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{Name: "foo", Namespace: "bar"}, Spec: api.DeploymentConfigSpec{ Replicas: 1, Strategy: api.DeploymentStrategy{ Type: api.DeploymentStrategyTypeRecreate, RecreateParams: &api.RecreateDeploymentStrategyParams{ Mid: &api.LifecycleHook{ FailurePolicy: api.LifecycleHookFailurePolicyRetry, }, }, }, Template: test.OkPodTemplate(), Selector: test.OkSelector(), }, }, field.ErrorTypeInvalid, "spec.strategy.recreateParams.mid", }, "missing spec.strategy.recreateParams.post.execNewPod": { api.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{Name: "foo", Namespace: "bar"}, Spec: api.DeploymentConfigSpec{ Replicas: 1, Strategy: api.DeploymentStrategy{ Type: api.DeploymentStrategyTypeRecreate, RecreateParams: &api.RecreateDeploymentStrategyParams{ Post: &api.LifecycleHook{ FailurePolicy: api.LifecycleHookFailurePolicyRetry, }, }, }, Template: test.OkPodTemplate(), Selector: test.OkSelector(), }, }, field.ErrorTypeInvalid, "spec.strategy.recreateParams.post", }, "missing spec.strategy.after.tagImages": { api.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{Name: "foo", Namespace: "bar"}, Spec: api.DeploymentConfigSpec{ Replicas: 1, Strategy: api.DeploymentStrategy{ Type: api.DeploymentStrategyTypeRecreate, RecreateParams: &api.RecreateDeploymentStrategyParams{ Post: &api.LifecycleHook{ FailurePolicy: api.LifecycleHookFailurePolicyRetry, TagImages: []api.TagImageHook{ { ContainerName: "missing", To: kapi.ObjectReference{Kind: "ImageStreamTag", Name: "stream:tag"}, }, }, }, }, }, Template: test.OkPodTemplate(), Selector: test.OkSelector(), }, }, field.ErrorTypeInvalid, "spec.strategy.recreateParams.post.tagImages[0].containerName", }, "missing spec.strategy.after.tagImages.to.kind": { api.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{Name: "foo", Namespace: "bar"}, Spec: api.DeploymentConfigSpec{ Replicas: 1, Strategy: api.DeploymentStrategy{ Type: api.DeploymentStrategyTypeRecreate, RecreateParams: &api.RecreateDeploymentStrategyParams{ Post: &api.LifecycleHook{ FailurePolicy: api.LifecycleHookFailurePolicyRetry, TagImages: []api.TagImageHook{ { ContainerName: "container1", To: kapi.ObjectReference{Name: "stream:tag"}, }, }, }, }, }, Template: test.OkPodTemplate(), Selector: test.OkSelector(), }, }, field.ErrorTypeInvalid, "spec.strategy.recreateParams.post.tagImages[0].to.kind", }, "missing spec.strategy.after.tagImages.to.name": { api.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{Name: "foo", Namespace: "bar"}, Spec: api.DeploymentConfigSpec{ Replicas: 1, Strategy: api.DeploymentStrategy{ Type: api.DeploymentStrategyTypeRecreate, RecreateParams: &api.RecreateDeploymentStrategyParams{ Post: &api.LifecycleHook{ FailurePolicy: api.LifecycleHookFailurePolicyRetry, TagImages: []api.TagImageHook{ { ContainerName: "container1", To: kapi.ObjectReference{Kind: "ImageStreamTag"}, }, }, }, }, }, Template: test.OkPodTemplate(), Selector: test.OkSelector(), }, }, field.ErrorTypeRequired, "spec.strategy.recreateParams.post.tagImages[0].to.name", }, "can't have both tag and execNewPod": { api.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{Name: "foo", Namespace: "bar"}, Spec: api.DeploymentConfigSpec{ Replicas: 1, Strategy: api.DeploymentStrategy{ Type: api.DeploymentStrategyTypeRecreate, RecreateParams: &api.RecreateDeploymentStrategyParams{ Post: &api.LifecycleHook{ FailurePolicy: api.LifecycleHookFailurePolicyRetry, ExecNewPod: &api.ExecNewPodHook{}, TagImages: []api.TagImageHook{{}}, }, }, }, Template: test.OkPodTemplate(), Selector: test.OkSelector(), }, }, field.ErrorTypeInvalid, "spec.strategy.recreateParams.post", }, "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 TestDeploymentConfigDescriber(t *testing.T) { config := deployapitest.OkDeploymentConfig(1) deployment, _ := deployutil.MakeDeployment(config, kapi.Codec) podList := &kapi.PodList{} eventList := &kapi.EventList{} deploymentList := &kapi.ReplicationControllerList{} d := &DeploymentConfigDescriber{ client: &genericDeploymentDescriberClient{ getDeploymentConfigFunc: func(namespace, name string) (*deployapi.DeploymentConfig, error) { return config, nil }, getDeploymentFunc: func(namespace, name string) (*kapi.ReplicationController, error) { return deployment, nil }, listDeploymentsFunc: func(namespace string, selector labels.Selector) (*kapi.ReplicationControllerList, error) { return deploymentList, nil }, listPodsFunc: func(namespace string, selector labels.Selector) (*kapi.PodList, error) { return podList, nil }, listEventsFunc: func(deploymentConfig *deployapi.DeploymentConfig) (*kapi.EventList, error) { return eventList, nil }, }, } describe := func() { if output, err := d.Describe("test", "deployment"); err != nil { t.Fatalf("unexpected error: %v", err) } else { t.Logf("describer output:\n%s\n", output) } } podList.Items = []kapi.Pod{*mkPod(kapi.PodRunning, 0)} describe() config.Triggers = append(config.Triggers, deployapitest.OkConfigChangeTrigger()) describe() config.Template.Strategy = deployapitest.OkCustomStrategy() describe() config.Triggers[0].ImageChangeParams.RepositoryName = "" config.Triggers[0].ImageChangeParams.From = kapi.ObjectReference{Name: "imageRepo"} describe() config.Template.Strategy = deployapitest.OkStrategy() config.Template.Strategy.RecreateParams = &deployapi.RecreateDeploymentStrategyParams{ Pre: &deployapi.LifecycleHook{ FailurePolicy: deployapi.LifecycleHookFailurePolicyAbort, ExecNewPod: &deployapi.ExecNewPodHook{ ContainerName: "container", Command: []string{"/command1", "args"}, Env: []kapi.EnvVar{ { Name: "KEY1", Value: "value1", }, }, }, }, Post: &deployapi.LifecycleHook{ FailurePolicy: deployapi.LifecycleHookFailurePolicyIgnore, ExecNewPod: &deployapi.ExecNewPodHook{ ContainerName: "container", Command: []string{"/command2", "args"}, Env: []kapi.EnvVar{ { Name: "KEY2", Value: "value2", }, }, }, }, } describe() }
func TestTriggers_configChange(t *testing.T) { testutil.DeleteAllEtcdKeys() openshift := NewTestDeployOpenshift(t) defer openshift.Close() config := deploytest.OkDeploymentConfig(0) config.Namespace = testutil.Namespace() config.Triggers[0] = deploytest.OkConfigChangeTrigger() var err error watch, err := openshift.KubeClient.ReplicationControllers(testutil.Namespace()).Watch(labels.Everything(), fields.Everything(), "0") if err != nil { t.Fatalf("Couldn't subscribe to Deployments %v", err) } defer watch.Stop() // submit the initial deployment config if _, err := openshift.Client.DeploymentConfigs(testutil.Namespace()).Create(config); err != nil { t.Fatalf("Couldn't create DeploymentConfig: %v", err) } // verify the initial deployment exists event := <-watch.ResultChan() if e, a := watchapi.Added, event.Type; e != a { t.Fatalf("expected watch event type %s, got %s", e, a) } deployment := event.Object.(*kapi.ReplicationController) if e, a := config.Name, deployutil.DeploymentConfigNameFor(deployment); e != a { t.Fatalf("Expected deployment annotated with deploymentConfig '%s', got '%s'", e, a) } assertEnvVarEquals("ENV1", "VAL1", deployment, t) // submit a new config with an updated environment variable if config, err = openshift.Client.DeploymentConfigs(testutil.Namespace()).Generate(config.Name); err != nil { t.Fatalf("Error generating config: %v", err) } config.Template.ControllerTemplate.Template.Spec.Containers[0].Env[0].Value = "UPDATED" // before we update the config, we need to update the state of the existing deployment // this is required to be done manually since the deployment and deployer pod controllers are not run in this test deployment.Annotations[deployapi.DeploymentStatusAnnotation] = string(deployapi.DeploymentStatusComplete) // update the deployment if _, err = openshift.KubeClient.ReplicationControllers(testutil.Namespace()).Update(deployment); err != nil { t.Fatalf("Error updating existing deployment: %v", err) } event = <-watch.ResultChan() if e, a := watchapi.Modified, event.Type; e != a { t.Fatalf("expected watch event type %s, got %s", e, a) } if _, err := openshift.Client.DeploymentConfigs(testutil.Namespace()).Update(config); err != nil { t.Fatalf("Couldn't create updated DeploymentConfig: %v", err) } event = <-watch.ResultChan() if e, a := watchapi.Added, event.Type; e != a { t.Fatalf("expected watch event type %s, got %s", e, a) } newDeployment := event.Object.(*kapi.ReplicationController) assertEnvVarEquals("ENV1", "UPDATED", newDeployment, t) if newDeployment.Name == deployment.Name { t.Fatalf("expected new deployment; old=%s, new=%s", deployment.Name, newDeployment.Name) } }
// TestHandle_automaticImageUpdates tests automatic and non-automatic updates // from image change triggers. func TestHandle_automaticImageUpdates(t *testing.T) { tests := []struct { name string auto bool canTrigger bool version int64 expectedUpdate bool }{ { name: "initial deployment with unresolved image (auto: true)", auto: true, canTrigger: false, version: 0, expectedUpdate: false, }, { name: "initial deployment with unresolved image (auto: false)", auto: false, canTrigger: false, version: 0, expectedUpdate: false, }, { name: "initial deployment with resolved image (auto: true)", auto: true, canTrigger: true, version: 0, expectedUpdate: true, }, { name: "initial deployment with resolved image (auto: false)", auto: false, canTrigger: true, version: 0, expectedUpdate: true, }, } for _, test := range tests { updated := false fake := &testclient.Fake{} kFake := &ktestclient.Fake{} fake.PrependReactor("update", "deploymentconfigs/status", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) { updated = true return true, nil, nil }) kFake.PrependReactor("get", "replicationcontrollers", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) { // This will always return no template difference. We test template differences in TestHandle_changeWithTemplateDiff config := testapi.OkDeploymentConfig(0) deployment, _ := deployutil.MakeDeployment(config, kapi.Codecs.LegacyCodec(deployapi.SchemeGroupVersion)) return true, deployment, nil }) controller := NewDeploymentTriggerController(fake, kFake, codec) config := testapi.OkDeploymentConfig(test.version) config.Namespace = kapi.NamespaceDefault ict := testapi.OkImageChangeTrigger() ict.ImageChangeParams.Automatic = test.auto if test.canTrigger { ict.ImageChangeParams.LastTriggeredImage = testapi.DockerImageReference } config.Spec.Triggers = []deployapi.DeploymentTriggerPolicy{testapi.OkConfigChangeTrigger(), ict} if err := controller.Handle(config); err != nil { t.Errorf("%s: unexpected error: %v", test.name, err) continue } if test.expectedUpdate != updated { t.Errorf("%s: expected update: %t, got update: %t", test.name, test.expectedUpdate, updated) } } }