diff --git a/pkg/build/api/types.go b/pkg/build/api/types.go index 2909e95e4a59..83497e6711d5 100644 --- a/pkg/build/api/types.go +++ b/pkg/build/api/types.go @@ -245,6 +245,9 @@ type ImageChangeTrigger struct { ImageRepositoryRef *kapi.ObjectReference `json:"imageRepositoryRef" yaml:"imageRepositoryRef"` // Tag is the name of an image repository tag to watch for changes. Tag string `json:"tag,omitempty" yaml:"tag,omitempty"` + // LastTriggeredImageID is used internally by the ImageChangeController to save last + // used image ID for build + LastTriggeredImageID string `json:"lastTriggeredImageID,omitempty" yaml:"lastTriggeredImageID,omitempty"` } // BuildTriggerPolicy describes a policy for a single trigger that results in a new Build. diff --git a/pkg/build/api/v1beta1/types.go b/pkg/build/api/v1beta1/types.go index 8259f2d08870..3f222fd0c8c4 100644 --- a/pkg/build/api/v1beta1/types.go +++ b/pkg/build/api/v1beta1/types.go @@ -240,6 +240,9 @@ type ImageChangeTrigger struct { ImageRepositoryRef *kapi.ObjectReference `json:"imageRepositoryRef" yaml:"imageRepositoryRef"` // Tag is the name of an image repository tag to watch for changes. Tag string `json:"tag,omitempty" yaml:"tag,omitempty"` + // LastTriggeredImageID is used internally by the ImageChangeController to save last + // used image ID for build + LastTriggeredImageID string `json:"lastTriggeredImageID,omitempty" yaml:"lastTriggeredImageID,omitempty"` } // BuildTriggerPolicy describes a policy for a single trigger that results in a new Build. diff --git a/pkg/build/controller/factory/factory.go b/pkg/build/controller/factory/factory.go index 276c245354d9..9b8c5ea20154 100644 --- a/pkg/build/controller/factory/factory.go +++ b/pkg/build/controller/factory/factory.go @@ -85,8 +85,9 @@ func (factory *ImageChangeControllerFactory) Create() *controller.ImageChangeCon cache.NewReflector(&buildConfigLW{client: factory.Client}, &buildapi.BuildConfig{}, store).Run() return &controller.ImageChangeController{ - BuildConfigStore: store, - BuildCreator: &ClientBuildCreator{factory.Client}, + BuildConfigStore: store, + BuildConfigUpdater: &ClientBuildConfigUpdater{factory.Client}, + BuildCreator: &ClientBuildCreator{factory.Client}, NextImageRepository: func() *imageapi.ImageRepository { repo := queue.Pop().(*imageapi.ImageRepository) panicIfStopped(factory.Stop, "build image change controller stopped") @@ -219,7 +220,12 @@ func (c ClientPodManager) CreatePod(namespace string, pod *kapi.Pod) (*kapi.Pod, return c.KubeClient.Pods(namespace).Create(pod) } -// ClientBuildUpdater is a buildUpdater which delegates to the OpenShift client interfaces +// DeletePod destroys a pod using the Kubernetes client. +func (c ClientPodManager) DeletePod(namespace string, pod *kapi.Pod) error { + return c.KubeClient.Pods(namespace).Delete(pod.Name) +} + +// ClientBuildUpdater is a buildUpdater which delegates to the OpenShift client interfaces. type ClientBuildUpdater struct { Client osclient.Interface } @@ -229,7 +235,7 @@ func (c ClientBuildUpdater) UpdateBuild(namespace string, build *buildapi.Build) return c.Client.Builds(namespace).Update(build) } -// ClientBuildCreator is a buildCreator which delegates to the OpenShift client interfaces +// ClientBuildCreator is a buildCreator which delegates to the OpenShift client interfaces. type ClientBuildCreator struct { Client osclient.Interface } @@ -247,7 +253,13 @@ func (c *ClientBuildCreator) CreateBuild(config *buildapi.BuildConfig, imageSubs return nil } -// DeletePod destroys a pod using the Kubernetes client. -func (c ClientPodManager) DeletePod(namespace string, pod *kapi.Pod) error { - return c.KubeClient.Pods(namespace).Delete(pod.Name) +// ClientBuildConfigUpdater is a buildConfigUpdater which delegates to the OpenShift client interfaces. +type ClientBuildConfigUpdater struct { + Client osclient.Interface +} + +// UpdateBuildConfig updates buildConfig using the OpenShift client. +func (c *ClientBuildConfigUpdater) UpdateBuildConfig(buildConfig *buildapi.BuildConfig) error { + _, err := c.Client.BuildConfigs(buildConfig.Namespace).Update(buildConfig) + return err } diff --git a/pkg/build/controller/image_change_controller.go b/pkg/build/controller/image_change_controller.go index b87996ba0f29..42b2f17cb62b 100644 --- a/pkg/build/controller/image_change_controller.go +++ b/pkg/build/controller/image_change_controller.go @@ -16,11 +16,16 @@ import ( type ImageChangeController struct { NextImageRepository func() *imageapi.ImageRepository BuildConfigStore cache.Store + BuildConfigUpdater buildConfigUpdater BuildCreator buildCreator // Stop is an optional channel that controls when the controller exits Stop <-chan struct{} } +type buildConfigUpdater interface { + UpdateBuildConfig(buildConfig *buildapi.BuildConfig) error +} + type buildCreator interface { CreateBuild(build *buildapi.BuildConfig, imageSubstitutions map[string]string) error } @@ -42,33 +47,47 @@ func (c *ImageChangeController) HandleImageRepo() { glog.V(4).Infof("Detecting changed images for buildConfig %s", config.Name) // Extract relevant triggers for this imageRepo for this config - var triggerForConfig *buildapi.ImageChangeTrigger + shouldTriggerBuild := false for _, trigger := range config.Triggers { + if trigger.Type != buildapi.ImageChangeBuildTriggerType { + continue + } // for every ImageChange trigger, record the image it substitutes for and get the latest // image id from the imagerepository. We will substitute all images in the buildconfig // with the latest values from the imagerepositories. - if trigger.Type == buildapi.ImageChangeBuildTriggerType { - // TODO: we don't really want to create a build for a buildconfig based the "test" tag if the "prod" tag is what just got - // updated, but ImageRepository doesn't give us that granularity today, so the only way to avoid these spurious builds is - // to check if the new imageid is different from the last time we built this buildcfg. Need to add this check. - // Will be effectively identical the logic needed on startup to spin new builds only if we missed a new image event. - var tag string - if tag = trigger.ImageChange.Tag; len(tag) == 0 { - tag = buildapi.DefaultImageTag - } - if repoImageID, repoHasTag := imageRepo.Tags[tag]; repoHasTag { - imageSubstitutions[trigger.ImageChange.Image] = imageRepo.DockerImageRepository + ":" + repoImageID - } - if trigger.ImageChange.ImageRepositoryRef.Name == imageRepo.Name { - triggerForConfig = trigger.ImageChange - } + icTrigger := trigger.ImageChange + + // TODO: we don't really want to create a build for a buildconfig based the "test" tag if the "prod" tag is what just got + // updated, but ImageRepository doesn't give us that granularity today, so the only way to avoid these spurious builds is + // to check if the new imageid is different from the last time we built this buildcfg. Need to add this check. + // Will be effectively identical the logic needed on startup to spin new builds only if we missed a new image event. + tag := icTrigger.Tag + if len(tag) == 0 { + tag = buildapi.DefaultImageTag + } + imageID, hasTag := imageRepo.Tags[tag] + if !hasTag { + continue + } + + // comparison requires us to match Name of the image and LastTriggeredImageID + // (must be different) to trigger a build + if icTrigger.ImageRepositoryRef.Name == imageRepo.Name && + icTrigger.LastTriggeredImageID != imageID { + imageSubstitutions[icTrigger.Image] = imageRepo.DockerImageRepository + ":" + imageID + shouldTriggerBuild = true + icTrigger.LastTriggeredImageID = imageID } } - if triggerForConfig != nil { + if shouldTriggerBuild { glog.V(4).Infof("Running build for buildConfig %s", config.Name) if err := c.BuildCreator.CreateBuild(config, imageSubstitutions); err != nil { glog.V(2).Infof("Error starting build for buildConfig %v: %v", config.Name, err) + } else { + if err := c.BuildConfigUpdater.UpdateBuildConfig(config); err != nil { + glog.V(2).Infof("Error updating buildConfig %v: %v", config.Name, err) + } } } } diff --git a/pkg/build/controller/image_change_controller_test.go b/pkg/build/controller/image_change_controller_test.go index fe8ce7541704..1e37420ab2be 100644 --- a/pkg/build/controller/image_change_controller_test.go +++ b/pkg/build/controller/image_change_controller_test.go @@ -1,6 +1,7 @@ package controller import ( + "fmt" "testing" kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api" @@ -10,19 +11,29 @@ import ( imageapi "github.com/openshift/origin/pkg/image/api" ) +type mockBuildConfigUpdater struct { + buildcfg *buildapi.BuildConfig +} + +func (m *mockBuildConfigUpdater) UpdateBuildConfig(buildcfg *buildapi.BuildConfig) error { + m.buildcfg = buildcfg + return nil +} + type mockBuildCreator struct { buildcfg *buildapi.BuildConfig imageSubstitutions map[string]string + err error } func (m *mockBuildCreator) CreateBuild(buildcfg *buildapi.BuildConfig, imageSubstitutions map[string]string) error { m.buildcfg = buildcfg m.imageSubstitutions = imageSubstitutions - return nil + return m.err } -func mockBuildConfig(baseImage string, triggerImage string, repoName string, repoTag string) (buildcfg *buildapi.BuildConfig) { - buildcfg = &buildapi.BuildConfig{ +func mockBuildConfig(baseImage, triggerImage, repoName, repoTag string) *buildapi.BuildConfig { + return &buildapi.BuildConfig{ ObjectMeta: kapi.ObjectMeta{ Name: "testBuildCfg", }, @@ -48,11 +59,22 @@ func mockBuildConfig(baseImage string, triggerImage string, repoName string, rep }, }, } - return } -func mockImageChangeController(buildcfg *buildapi.BuildConfig, repoName string, dockerImageRepo string, tags map[string]string) (controller *ImageChangeController) { +func appendTrigger(buildcfg *buildapi.BuildConfig, triggerImage, repoName, repoTag string) { + buildcfg.Triggers = append(buildcfg.Triggers, buildapi.BuildTriggerPolicy{ + Type: buildapi.ImageChangeBuildTriggerType, + ImageChange: &buildapi.ImageChangeTrigger{ + Image: triggerImage, + ImageRepositoryRef: &kapi.ObjectReference{ + Name: repoName, + }, + Tag: repoTag, + }, + }) +} +func mockImageChangeController(buildcfg *buildapi.BuildConfig, repoName, dockerImageRepo string, tags map[string]string) *ImageChangeController { imageRepo := imageapi.ImageRepository{ ObjectMeta: kapi.ObjectMeta{ Name: repoName, @@ -61,61 +83,199 @@ func mockImageChangeController(buildcfg *buildapi.BuildConfig, repoName string, Tags: tags, } - controller = &ImageChangeController{ + return &ImageChangeController{ NextImageRepository: func() *imageapi.ImageRepository { return &imageRepo }, BuildConfigStore: buildtest.NewFakeBuildConfigStore(buildcfg), + BuildConfigUpdater: &mockBuildConfigUpdater{}, BuildCreator: &mockBuildCreator{}, } - return } -func TestHandleImageRepo(t *testing.T) { - +func TestNewImageID(t *testing.T) { // valid configuration, new build should be triggered. - buildcfg := mockBuildConfig("registry.com/namespace/imagename", "registry.com/namespace/imagename", "testImageRepo", "test") - controller := mockImageChangeController(buildcfg, "testImageRepo", "registry.com/namespace/imagename", map[string]string{"test": "newImageId123"}) + buildcfg := mockBuildConfig("registry.com/namespace/imagename", "registry.com/namespace/imagename", "testImageRepo", "testTag") + controller := mockImageChangeController(buildcfg, "testImageRepo", "registry.com/namespace/imagename", map[string]string{"testTag": "newImageID123"}) controller.HandleImageRepo() buildCreator := controller.BuildCreator.(*mockBuildCreator) + buildConfigUpdater := controller.BuildConfigUpdater.(*mockBuildConfigUpdater) + if buildCreator.buildcfg == nil { - t.Errorf("New build not created when new image was created") + t.Error("Expected new build when new image was created!") } - if buildCreator.imageSubstitutions["registry.com/namespace/imagename"] != "registry.com/namespace/imagename:newImageId123" { + if buildCreator.imageSubstitutions["registry.com/namespace/imagename"] != "registry.com/namespace/imagename:newImageID123" { t.Errorf("Image substitutions not properly setup for new build: %s |", buildCreator.imageSubstitutions["registry.com/namespace/imagename"]) } + if buildConfigUpdater.buildcfg == nil { + t.Fatal("Expected buildConfig update when new image was created!") + } + if buildConfigUpdater.buildcfg.Triggers[0].ImageChange.LastTriggeredImageID != "newImageID123" { + t.Errorf("Expected imageID newImageID123, got %s", buildConfigUpdater.buildcfg.Triggers[0].ImageChange.LastTriggeredImageID) + } +} - // valid configuration using default latest tag, new build should be triggered. - buildcfg = mockBuildConfig("registry.com/namespace/imagename", "registry.com/namespace/imagename", "testImageRepo", "") - controller = mockImageChangeController(buildcfg, "testImageRepo", "registry.com/namespace/imagename", map[string]string{"latest": "newImageId123"}) +func TestNewImageIDDefaultTag(t *testing.T) { + // valid configuration using default tag, new build should be triggered. + buildcfg := mockBuildConfig("registry.com/namespace/imagename", "registry.com/namespace/imagename", "testImageRepo", "") + controller := mockImageChangeController(buildcfg, "testImageRepo", "registry.com/namespace/imagename", map[string]string{buildapi.DefaultImageTag: "newImageID123"}) controller.HandleImageRepo() - buildCreator = controller.BuildCreator.(*mockBuildCreator) + buildCreator := controller.BuildCreator.(*mockBuildCreator) + buildConfigUpdater := controller.BuildConfigUpdater.(*mockBuildConfigUpdater) + if buildCreator.buildcfg == nil { - t.Errorf("New build not created when new image was created") + t.Error("Expected new build when new image was created!") + } + if buildCreator.imageSubstitutions["registry.com/namespace/imagename"] != "registry.com/namespace/imagename:newImageID123" { + t.Errorf("Image substitutions not properly setup for new build using default tag: %s |", buildCreator.imageSubstitutions["registry.com/namespace/imagename"]) + } + if buildConfigUpdater.buildcfg == nil { + t.Fatal("Expected buildConfig update when new image was created!") } - if buildCreator.imageSubstitutions["registry.com/namespace/imagename"] != "registry.com/namespace/imagename:newImageId123" { - t.Errorf("Image substitutions not properly setup for new build using default latest tag: %s |", buildCreator.imageSubstitutions["registry.com/namespace/imagename"]) + if buildConfigUpdater.buildcfg.Triggers[0].ImageChange.LastTriggeredImageID != "newImageID123" { + t.Errorf("Expected imageID newImageID123, got %s", buildConfigUpdater.buildcfg.Triggers[0].ImageChange.LastTriggeredImageID) } +} +func TestNonExistentImageRepository(t *testing.T) { // this buildconfig references a non-existent imagerepo, so an update to the real imagerepo should not // trigger a build here. - buildcfg = mockBuildConfig("registry.com/namespace/imagename", "registry.com/namespace/imagename", "testImageRepo2", "test") - controller = mockImageChangeController(buildcfg, "testImageRepo", "registry.com/namespace/imagename", map[string]string{"test": "newImageId123"}) + buildcfg := mockBuildConfig("registry.com/namespace/imagename", "registry.com/namespace/imagename", "testImageRepo", "testTag") + controller := mockImageChangeController(buildcfg, "otherImageRepo", "registry.com/namespace/imagename", map[string]string{"testTag": "newImageID123"}) + controller.HandleImageRepo() + buildCreator := controller.BuildCreator.(*mockBuildCreator) + buildConfigUpdater := controller.BuildConfigUpdater.(*mockBuildConfigUpdater) + + if buildCreator.buildcfg != nil { + t.Error("New build created when a different repository was updated!") + } + if len(buildCreator.imageSubstitutions) != 0 { + t.Errorf("Should not have had any image substitutions since tag does not exist in imagerepo") + } + if buildConfigUpdater.buildcfg != nil { + t.Error("BuildConfig was updated when a different repository was updated!") + } +} + +func TestNewImageDifferentTagUpdate(t *testing.T) { + // this buildconfig references a different tag than the one that will be updated + buildcfg := mockBuildConfig("registry.com/namespace/imagename", "registry.com/namespace/imagename", "testImageRepo", "testTag") + controller := mockImageChangeController(buildcfg, "testImageRepo", "registry.com/namespace/imagename", map[string]string{"otherTag": "newImageID123"}) controller.HandleImageRepo() - buildCreator = controller.BuildCreator.(*mockBuildCreator) + buildCreator := controller.BuildCreator.(*mockBuildCreator) + buildConfigUpdater := controller.BuildConfigUpdater.(*mockBuildConfigUpdater) + if buildCreator.buildcfg != nil { - t.Errorf("New build created when a different repository was updated") + t.Error("New build created when a different repository was updated!") + } + if len(buildCreator.imageSubstitutions) != 0 { + t.Errorf("Should not have had any image substitutions since tag does not exist in imagerepo") + } + if buildConfigUpdater.buildcfg != nil { + t.Error("BuildConfig was updated when a different repository was updated!") } +} - // this buildconfig references a different tag than the one that will be updated, this will (for now) result - // in a build being triggered, but there should be no image name substitution since the imagerepo does not contain - // a valid imageid for the "test2" tag, so we should use the existing image name in the buildconfig. - buildcfg = mockBuildConfig("registry.com/namespace/imagename", "registry.com/namespace/imagename", "testImageRepo", "test2") - controller = mockImageChangeController(buildcfg, "testImageRepo", "registry.com/namespace/imagename", map[string]string{"test": "newImageId123"}) +func TestNewDifferentImageUpdate(t *testing.T) { + // this buildconfig references a different tag than the one that will be updated + buildcfg := mockBuildConfig("registry.com/namespace/imagename1", "registry.com/namespace/imagename1", "testImageRepo1", "testTag1") + controller := mockImageChangeController(buildcfg, "testImageRepo2", "registry.com/namespace/imagename2", map[string]string{"testTag2": "newImageID123"}) controller.HandleImageRepo() - buildCreator = controller.BuildCreator.(*mockBuildCreator) - if buildCreator.buildcfg == nil { - t.Errorf("New build not created when a different repository tag was updated") + buildCreator := controller.BuildCreator.(*mockBuildCreator) + buildConfigUpdater := controller.BuildConfigUpdater.(*mockBuildConfigUpdater) + + if buildCreator.buildcfg != nil { + t.Error("New build created when a different repository was updated!") } if len(buildCreator.imageSubstitutions) != 0 { t.Errorf("Should not have had any image substitutions since tag does not exist in imagerepo") } + if buildConfigUpdater.buildcfg != nil { + t.Error("BuildConfig was updated when a different repository was updated!") + } +} + +func TestMultipleTriggers(t *testing.T) { + // this buildconfig references multiple images + buildcfg := mockBuildConfig("registry.com/namespace/imagename1", "registry.com/namespace/imagename1", "testImageRepo1", "testTag1") + appendTrigger(buildcfg, "registry.com/namespace/imagename2", "testImageRepo2", "testTag2") + controller := mockImageChangeController(buildcfg, "testImageRepo2", "registry.com/namespace/imagename2", map[string]string{"testTag2": "newImageID123"}) + controller.HandleImageRepo() + buildCreator := controller.BuildCreator.(*mockBuildCreator) + buildConfigUpdater := controller.BuildConfigUpdater.(*mockBuildConfigUpdater) + + if buildCreator.buildcfg == nil { + t.Error("Expected new build when new image was created!") + } + if len(buildCreator.imageSubstitutions) != 1 { + t.Errorf("Expected exactly 1 substitution, got different count: %d", len(buildCreator.imageSubstitutions)) + } + if buildCreator.imageSubstitutions["registry.com/namespace/imagename2"] != "registry.com/namespace/imagename2:newImageID123" { + t.Errorf("Image substitutions not properly setup for new build using default tag: %s |", buildCreator.imageSubstitutions["registry.com/namespace/imagename2"]) + } + if buildConfigUpdater.buildcfg == nil { + t.Fatal("Expected buildConfig update when new image was created!") + } + if buildConfigUpdater.buildcfg.Triggers[1].ImageChange.LastTriggeredImageID != "newImageID123" { + t.Errorf("Expected imageID newImageID123, got %s", buildConfigUpdater.buildcfg.Triggers[1].ImageChange.LastTriggeredImageID) + } +} + +func TestBuildConfigWithDifferentTriggerType(t *testing.T) { + // this buildconfig has different (than ImageChangeTrigger) trigger defined + buildcfg := mockBuildConfig("registry.com/namespace/imagename1", "", "", "") + buildcfg.Triggers[0].Type = buildapi.GenericWebHookBuildTriggerType + controller := mockImageChangeController(buildcfg, "testImageRepo2", "registry.com/namespace/imagename2", map[string]string{"testTag2": "newImageID123"}) + controller.HandleImageRepo() + buildCreator := controller.BuildCreator.(*mockBuildCreator) + buildConfigUpdater := controller.BuildConfigUpdater.(*mockBuildConfigUpdater) + + if buildCreator.buildcfg != nil { + t.Error("New build created when a different trigger type was defined!") + } + if len(buildCreator.imageSubstitutions) != 0 { + t.Errorf("Should not have had any image substitutions since different trigger type was defined!") + } + if buildConfigUpdater.buildcfg != nil { + t.Error("BuildConfig was updated when a different trigger was defined!") + } +} + +func TestNoImageIDChange(t *testing.T) { + // this buildConfig has up to date configuration, but is checked eg. during + // startup when we're checking all the imageRepos + buildcfg := mockBuildConfig("registry.com/namespace/imagename", "registry.com/namespace/imagename", "testImageRepo", "testTag") + buildcfg.Triggers[0].ImageChange.LastTriggeredImageID = "imageID123" + controller := mockImageChangeController(buildcfg, "testImageRepo", "registry.com/namespace/imagename", map[string]string{"testTag": "imageID123"}) + controller.HandleImageRepo() + buildCreator := controller.BuildCreator.(*mockBuildCreator) + buildConfigUpdater := controller.BuildConfigUpdater.(*mockBuildConfigUpdater) + + if buildCreator.buildcfg != nil { + t.Error("New build created when no change happened!") + } + if len(buildCreator.imageSubstitutions) != 0 { + t.Errorf("Should not have had any image substitutions since no change happened!") + } + if buildConfigUpdater.buildcfg != nil { + t.Error("BuildConfig was updated when no change happened!") + } +} + +func TestBuildCreateError(t *testing.T) { + // valid configuration, but build creation failes, in that situation the buildconfig should not be updated + buildcfg := mockBuildConfig("registry.com/namespace/imagename", "registry.com/namespace/imagename", "testImageRepo", "testTag") + controller := mockImageChangeController(buildcfg, "testImageRepo", "registry.com/namespace/imagename", map[string]string{"testTag": "newImageID123"}) + buildCreator := controller.BuildCreator.(*mockBuildCreator) + buildCreator.err = fmt.Errorf("error") + controller.HandleImageRepo() + buildConfigUpdater := controller.BuildConfigUpdater.(*mockBuildConfigUpdater) + + if buildCreator.buildcfg == nil { + t.Error("Expected new build when new image was created!") + } + if buildCreator.imageSubstitutions["registry.com/namespace/imagename"] != "registry.com/namespace/imagename:newImageID123" { + t.Errorf("Image substitutions not properly setup for new build: %s |", buildCreator.imageSubstitutions["registry.com/namespace/imagename"]) + } + if buildConfigUpdater.buildcfg != nil { + t.Fatal("Expected no buildConfig update on BuildCreate error!") + } } diff --git a/test/integration/imagechange_buildtrigger_test.go b/test/integration/imagechange_buildtrigger_test.go index 7e815663d746..90923b0088ff 100644 --- a/test/integration/imagechange_buildtrigger_test.go +++ b/test/integration/imagechange_buildtrigger_test.go @@ -20,7 +20,6 @@ func init() { func TestSimpleImageChangeBuildTrigger(t *testing.T) { t.Log("starting run") deleteAllEtcdKeys() - //openshift := NewTestOpenshift(t) openshift := NewTestOpenshift(t) defer openshift.Close() @@ -33,7 +32,6 @@ func TestSimpleImageChangeBuildTrigger(t *testing.T) { } config := imageChangeBuildConfig() - var err error watch, err := openshift.Client.Builds(testNamespace).Watch(labels.Everything(), labels.Everything(), "0") if err != nil { @@ -66,6 +64,14 @@ func TestSimpleImageChangeBuildTrigger(t *testing.T) { t.Fatalf("Expected build with base image %s, got %s", "registry:8080/openshift/test-image:ref-2", newBuild.Parameters.Strategy.DockerStrategy.BaseImage) } + updatedConfig, err := openshift.Client.BuildConfigs(testNamespace).Get(config.Name) + if err != nil { + t.Fatalf("Couldn't get BuildConfig: %v", err) + } + if updatedConfig.Triggers[0].ImageChange.LastTriggeredImageID != "ref-2" { + t.Errorf("Expected imageID ref-2, got %s", updatedConfig.Triggers[0].ImageChange.LastTriggeredImageID) + } + } func imageChangeBuildConfig() *buildapi.BuildConfig {