// TestProcess_changeForUnregisteredTag ensures that an image update for which // there is a matching trigger results in a no-op due to the tag specified on // the trigger not matching the tags defined on the image stream. func TestProcess_changeForUnregisteredTag(t *testing.T) { config := deploytest.OkDeploymentConfig(0) stream := deploytest.OkStreamForConfig(config) // The image has been resolved at least once before. config.Spec.Triggers[0].ImageChangeParams.From.Name = imageapi.JoinImageStreamTag(stream.Name, "unrelatedtag") fake := &testclient.Fake{} fake.AddReactor("get", "imagestreams", func(action core.Action) (handled bool, ret runtime.Object, err error) { return true, stream, nil }) image := config.Spec.Template.Spec.Containers[0].Image // verify no-op; should be the same for force=true and force=false if err := processTriggers(config, fake, false); err != nil { t.Fatalf("unexpected error: %v", err) } if image != config.Spec.Template.Spec.Containers[0].Image { t.Fatalf("unexpected image update: %#v", config.Spec.Template.Spec.Containers[0].Image) } if err := processTriggers(config, fake, true); err != nil { t.Fatalf("unexpected error when forced: %v", err) } if image != config.Spec.Template.Spec.Containers[0].Image { t.Fatalf("unexpected image update when forced: %#v", config.Spec.Template.Spec.Containers[0].Image) } }
func TestInstall_canary(t *testing.T) { fake := fake.NewSimpleClientset() fake.AddReactor("create", "deployments", func(action testcore.Action) (bool, runtime.Object, error) { obj := action.(testcore.CreateAction).GetObject().(*extensions.Deployment) i := obj.Spec.Template.Spec.Containers[0].Image if i != "gcr.io/kubernetes-helm/tiller:canary" { t.Errorf("expected canary image, got '%s'", i) } return true, obj, nil }) err := Install(fake.Extensions(), api.NamespaceDefault, "", true, false) if err != nil { t.Errorf("unexpected error: %#+v", err) } }
func TestDeploymentNotFoundError(t *testing.T) { name := "foo" ns := "default" deployment := &extensions.Deployment{ ObjectMeta: api.ObjectMeta{ Name: name, Namespace: ns, }, Spec: extensions.DeploymentSpec{ Replicas: 0, Selector: &unversioned.LabelSelector{MatchLabels: map[string]string{"k1": "v1"}}, }, Status: extensions.DeploymentStatus{ Replicas: 0, }, } template := deploymentutil.GetNewReplicaSetTemplateInternal(deployment) fake := fake.NewSimpleClientset( deployment, &extensions.ReplicaSetList{Items: []extensions.ReplicaSet{ { ObjectMeta: api.ObjectMeta{ Name: name, Namespace: ns, }, Spec: extensions.ReplicaSetSpec{ Template: template, }, }, }, }, ) fake.AddReactor("get", "replicasets", func(action testcore.Action) (handled bool, ret runtime.Object, err error) { return true, nil, ScaleError{ActualError: errors.NewNotFound(api.Resource("replicaset"), "doesn't-matter")} }) reaper := DeploymentReaper{fake.Extensions(), fake.Extensions(), time.Millisecond, time.Millisecond} if err := reaper.Stop(ns, name, 0, nil); err != nil { t.Fatalf("unexpected error: %#v", err) } }
// TestHandle_imageChangeTrigger ensures that a config with an image change // trigger will be reconciled. func TestHandle_imageChangeTrigger(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, rcInformer, streamInformer, fake, codec) config := testapi.OkDeploymentConfig(0) config.Namespace = kapi.NamespaceDefault config.Spec.Triggers = []deployapi.DeploymentTriggerPolicy{testapi.OkImageChangeTrigger()} if err := controller.Handle(config); err != nil { t.Fatalf("unexpected error: %v", err) } if !updated { t.Fatalf("expected config to be instantiated") } }
func TestInstall(t *testing.T) { image := "gcr.io/kubernetes-helm/tiller:v2.0.0" fake := fake.NewSimpleClientset() fake.AddReactor("create", "deployments", func(action testcore.Action) (bool, runtime.Object, error) { obj := action.(testcore.CreateAction).GetObject().(*extensions.Deployment) l := obj.GetLabels() if reflect.DeepEqual(l, map[string]string{"app": "helm"}) { t.Errorf("expected labels = '', got '%s'", l) } i := obj.Spec.Template.Spec.Containers[0].Image if i != image { t.Errorf("expected image = '%s', got '%s'", image, i) } return true, obj, nil }) err := Install(fake.Extensions(), api.NamespaceDefault, image, false, false) if err != nil { t.Errorf("unexpected error: %#+v", err) } }
// TestProcess_changeForNonAutomaticTag ensures that an image update for which // there is a matching trigger results in a no-op due to the trigger's // automatic flag being set to false or updates the config if forced. func TestProcess_changeForNonAutomaticTag(t *testing.T) { tests := []struct { name string force bool expected bool expectedErr bool }{ { name: "normal update", force: false, expected: false, expectedErr: false, }, { name: "forced update", force: true, expected: true, expectedErr: false, }, } for _, test := range tests { config := deploytest.OkDeploymentConfig(1) config.Namespace = kapi.NamespaceDefault config.Spec.Triggers[0].ImageChangeParams.Automatic = false // The image has been resolved at least once before. config.Spec.Triggers[0].ImageChangeParams.LastTriggeredImage = deploytest.DockerImageReference stream := deploytest.OkStreamForConfig(config) config.Spec.Triggers[0].ImageChangeParams.LastTriggeredImage = "someotherresolveddockerimagereference" fake := &testclient.Fake{} fake.AddReactor("get", "imagestreams", func(action core.Action) (handled bool, ret runtime.Object, err error) { if !test.expected { t.Errorf("unexpected imagestream call") } return true, stream, nil }) image := config.Spec.Template.Spec.Containers[0].Image // Force equals to false; we shouldn't update the config anyway err := processTriggers(config, fake, test.force) if err == nil && test.expectedErr { t.Errorf("%s: expected an error", test.name) continue } if err != nil && !test.expectedErr { t.Errorf("%s: unexpected error: %v", test.name, err) continue } if test.expected && config.Spec.Template.Spec.Containers[0].Image == image { t.Errorf("%s: expected an image update but got none", test.name) } else if !test.expected && config.Spec.Template.Spec.Containers[0].Image != image { t.Errorf("%s: didn't expect an image update but got %s", test.name, image) } } }
// TestProcess_matchScenarios comprehensively tests trigger definitions against // image stream updates to ensure that the image change triggers match (or don't // match) properly. func TestProcess_matchScenarios(t *testing.T) { tests := []struct { name string param *deployapi.DeploymentTriggerImageChangeParams notFound bool expected bool }{ { name: "automatic=true, initial trigger, explicit namespace", param: &deployapi.DeploymentTriggerImageChangeParams{ Automatic: true, ContainerNames: []string{"container1"}, From: kapi.ObjectReference{Namespace: kapi.NamespaceDefault, Name: imageapi.JoinImageStreamTag(deploytest.ImageStreamName, imageapi.DefaultImageTag)}, LastTriggeredImage: "", }, expected: true, }, { name: "automatic=true, initial trigger, implicit namespace", param: &deployapi.DeploymentTriggerImageChangeParams{ Automatic: true, ContainerNames: []string{"container1"}, From: kapi.ObjectReference{Name: imageapi.JoinImageStreamTag(deploytest.ImageStreamName, imageapi.DefaultImageTag)}, LastTriggeredImage: "", }, expected: true, }, { name: "automatic=false, initial trigger", param: &deployapi.DeploymentTriggerImageChangeParams{ Automatic: false, ContainerNames: []string{"container1"}, From: kapi.ObjectReference{Namespace: kapi.NamespaceDefault, Name: imageapi.JoinImageStreamTag(deploytest.ImageStreamName, imageapi.DefaultImageTag)}, LastTriggeredImage: "", }, expected: false, }, { name: "(no-op) automatic=false, already triggered", param: &deployapi.DeploymentTriggerImageChangeParams{ Automatic: false, ContainerNames: []string{"container1"}, From: kapi.ObjectReference{Namespace: kapi.NamespaceDefault, Name: imageapi.JoinImageStreamTag(deploytest.ImageStreamName, imageapi.DefaultImageTag)}, LastTriggeredImage: deploytest.DockerImageReference, }, expected: false, }, { name: "(no-op) automatic=true, image is already deployed", param: &deployapi.DeploymentTriggerImageChangeParams{ Automatic: true, ContainerNames: []string{"container1"}, From: kapi.ObjectReference{Name: imageapi.JoinImageStreamTag(deploytest.ImageStreamName, imageapi.DefaultImageTag)}, LastTriggeredImage: deploytest.DockerImageReference, }, expected: false, }, { name: "(no-op) trigger doesn't match the stream", param: &deployapi.DeploymentTriggerImageChangeParams{ Automatic: true, ContainerNames: []string{"container1"}, From: kapi.ObjectReference{Namespace: kapi.NamespaceDefault, Name: imageapi.JoinImageStreamTag("other-stream", imageapi.DefaultImageTag)}, LastTriggeredImage: "", }, notFound: true, expected: false, }, } for i := range tests { test := tests[i] t.Logf("running test %q", test.name) fake := &testclient.Fake{} fake.AddReactor("get", "imagestreams", func(action core.Action) (handled bool, ret runtime.Object, err error) { if test.notFound { name := action.(core.GetAction).GetName() return true, nil, errors.NewNotFound(imageapi.Resource("ImageStream"), name) } stream := fakeStream(deploytest.ImageStreamName, imageapi.DefaultImageTag, deploytest.DockerImageReference, deploytest.ImageID) return true, stream, nil }) config := deploytest.OkDeploymentConfig(1) config.Namespace = kapi.NamespaceDefault config.Spec.Triggers = []deployapi.DeploymentTriggerPolicy{ { Type: deployapi.DeploymentTriggerOnImageChange, ImageChangeParams: test.param, }, } image := config.Spec.Template.Spec.Containers[0].Image err := processTriggers(config, fake, false) if err != nil { t.Errorf("unexpected error: %v", err) continue } if test.expected && config.Spec.Template.Spec.Containers[0].Image == image { t.Errorf("%s: expected an image update but got none", test.name) } else if !test.expected && config.Spec.Template.Spec.Containers[0].Image != image { t.Errorf("%s: didn't expect an image update but got %s", test.name, image) } } }