package imagechange
import (
"flag"
"testing"
kapi "k8s.io/kubernetes/pkg/api"
deployapi "github.com/openshift/origin/pkg/deploy/api"
deployapitest "github.com/openshift/origin/pkg/deploy/api/test"
imageapi "github.com/openshift/origin/pkg/image/api"
)
func init() {
flag.Set("v", "5")
}
// TestHandle_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.
func TestHandle_changeForNonAutomaticTag(t *testing.T) {
controller := &ImageChangeController{
deploymentConfigClient: &deploymentConfigClientImpl{
updateDeploymentConfigFunc: func(namespace string, config *deployapi.DeploymentConfig) (*deployapi.DeploymentConfig, error) {
t.Fatalf("unexpected DeploymentConfig update")
return nil, nil
},
generateDeploymentConfigFunc: func(namespace, name string) (*deployapi.DeploymentConfig, error) {
t.Fatalf("unexpected generator call")
return nil, nil
},
listDeploymentConfigsFunc: func() ([]*deployapi.DeploymentConfig, error) {
config := deployapitest.OkDeploymentConfig(1)
config.Spec.Triggers[0].ImageChangeParams.Automatic = false
return []*deployapi.DeploymentConfig{config}, nil
},
},
}
// verify no-op
tagUpdate := makeRepo(
"test-image-repo",
imageapi.DefaultImageTag,
"registry:8080/openshift/test-image@sha256:00000000000000000000000000000001",
"00000000000000000000000000000001",
)
err := controller.Handle(tagUpdate)
if err != nil {
t.Fatalf("unexpected err: %v", err)
}
}
// TestHandle_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 repo.
func TestHandle_changeForUnregisteredTag(t *testing.T) {
controller := &ImageChangeController{
deploymentConfigClient: &deploymentConfigClientImpl{
updateDeploymentConfigFunc: func(namespace string, config *deployapi.DeploymentConfig) (*deployapi.DeploymentConfig, error) {
t.Fatalf("unexpected DeploymentConfig update")
return nil, nil
},
generateDeploymentConfigFunc: func(namespace, name string) (*deployapi.DeploymentConfig, error) {
t.Fatalf("unexpected generator call")
return nil, nil
},
listDeploymentConfigsFunc: func() ([]*deployapi.DeploymentConfig, error) {
return []*deployapi.DeploymentConfig{deployapitest.OkDeploymentConfig(0)}, nil
},
},
}
// verify no-op
imageRepo := makeRepo(
"test-image-repo",
"unrecognized",
"registry:8080/openshift/test-image@sha256:00000000000000000000000000000001",
"00000000000000000000000000000001",
)
err := controller.Handle(imageRepo)
if err != nil {
t.Fatalf("unexpected err: %v", err)
}
}
// TestHandle_matchScenarios comprehensively tests trigger definitions against
// image repo updates to ensure that the image change triggers match (or don't
// match) properly.
func TestHandle_matchScenarios(t *testing.T) {
params := map[string]*deployapi.DeploymentTriggerImageChangeParams{
"params.1": {
Automatic: true,
ContainerNames: []string{"container-1"},
From: kapi.ObjectReference{Namespace: kapi.NamespaceDefault, Name: imageapi.JoinImageStreamTag("repoA", imageapi.DefaultImageTag)},
LastTriggeredImage: "",
},
"params.2": {
Automatic: true,
ContainerNames: []string{"container-1"},
From: kapi.ObjectReference{Name: imageapi.JoinImageStreamTag("repoA", imageapi.DefaultImageTag)},
LastTriggeredImage: "",
},
"params.3": {
Automatic: false,
ContainerNames: []string{"container-1"},
From: kapi.ObjectReference{Namespace: kapi.NamespaceDefault, Name: imageapi.JoinImageStreamTag("repoA", imageapi.DefaultImageTag)},
LastTriggeredImage: "",
},
"params.4": {
Automatic: true,
ContainerNames: []string{"container-1"},
From: kapi.ObjectReference{Name: imageapi.JoinImageStreamTag("repoA", imageapi.DefaultImageTag)},
LastTriggeredImage: "registry:8080/openshift/test-image@sha256:00000000000000000000000000000001",
},
"params.5": {
Automatic: true,
ContainerNames: []string{"container-1"},
From: kapi.ObjectReference{Namespace: kapi.NamespaceDefault, Name: imageapi.JoinImageStreamTag("repoC", imageapi.DefaultImageTag)},
LastTriggeredImage: "",
},
}
tagHistoryFor := func(tag, dir, image string) map[string]imageapi.TagEventList {
return map[string]imageapi.TagEventList{
tag: {
Items: []imageapi.TagEvent{
{
DockerImageReference: dir,
Image: image,
},
},
},
}
}
updates := map[string]*imageapi.ImageStream{
"update.1": {
ObjectMeta: kapi.ObjectMeta{Name: "repoA", Namespace: kapi.NamespaceDefault},
Status: imageapi.ImageStreamStatus{
Tags: tagHistoryFor(
imageapi.DefaultImageTag,
"registry:8080/openshift/test-image@sha256:00000000000000000000000000000001",
"00000000000000000000000000000001",
),
},
},
}
scenarios := []struct {
param string
repo string
matches bool
}{
// Update from empty last image ID to a new one with explicit namespaces
{"params.1", "update.1", true},
// Update from empty last image ID to a new one with implicit namespaces
{"params.2", "update.1", true},
// Update from empty last image ID to a new one, but not marked automatic
{"params.3", "update.1", false},
// Updated image ID is equal to the last triggered ID
{"params.4", "update.1", false},
// Trigger repo reference doesn't match
{"params.5", "update.1", false},
}
for _, s := range scenarios {
config := deployapitest.OkDeploymentConfig(0)
config.Namespace = kapi.NamespaceDefault
config.Spec.Triggers = []deployapi.DeploymentTriggerPolicy{
{
Type: deployapi.DeploymentTriggerOnImageChange,
ImageChangeParams: params[s.param],
},
}
updated := false
generated := false
controller := &ImageChangeController{
deploymentConfigClient: &deploymentConfigClientImpl{
updateDeploymentConfigFunc: func(namespace string, config *deployapi.DeploymentConfig) (*deployapi.DeploymentConfig, error) {
if !s.matches {
t.Fatalf("unexpected DeploymentConfig update for scenario: %v", s)
}
updated = true
return config, nil
},
generateDeploymentConfigFunc: func(namespace, name string) (*deployapi.DeploymentConfig, error) {
if !s.matches {
t.Fatalf("unexpected generator call for scenario: %v", s)
}
generated = true
// simulate a generation
newConfig := deployapitest.OkDeploymentConfig(config.Status.LatestVersion + 1)
newConfig.Namespace = config.Namespace
newConfig.Spec.Triggers = config.Spec.Triggers
return newConfig, nil
},
listDeploymentConfigsFunc: func() ([]*deployapi.DeploymentConfig, error) {
return []*deployapi.DeploymentConfig{config}, nil
},
},
}
t.Logf("running scenario: %v", s)
err := controller.Handle(updates[s.repo])
if err != nil {
t.Fatalf("unexpected error for scenario %v: %v", s, err)
}
// assert updates/generations occurred
if s.matches && !updated {
t.Fatalf("expected update for scenario: %v", s)
}
if s.matches && !generated {
t.Fatalf("expected generation for scenario: %v", s)
}
}
}
func makeRepo(name, tag, dir, image string) *imageapi.ImageStream {
return &imageapi.ImageStream{
ObjectMeta: kapi.ObjectMeta{Name: name},
Status: imageapi.ImageStreamStatus{
Tags: map[string]imageapi.TagEventList{
tag: {
Items: []imageapi.TagEvent{
{
DockerImageReference: dir,
Image: image,
},
},
},
},
},
}
}