package controller
import (
"testing"
kapi "github.com/GoogleCloudPlatform/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"
)
const (
nonDefaultNamespace = "nondefaultnamespace"
)
func TestUnregisteredContainer(t *testing.T) {
controller := &ImageChangeController{
DeploymentConfigClient: &ImageChangeControllerDeploymentConfigClientImpl{
UpdateDeploymentConfigFunc: func(namespace string, config *deployapi.DeploymentConfig) (*deployapi.DeploymentConfig, error) {
t.Fatalf("unexpected deployment config 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.Triggers[0].ImageChangeParams.ContainerNames = []string{"container-3"}
return []*deployapi.DeploymentConfig{config}, nil
},
},
}
// verify no-op
err := controller.HandleImageRepo(tagUpdate())
if err != nil {
t.Fatalf("unexpected err: %v", err)
}
}
func TestImageChangeForNonAutomaticTag(t *testing.T) {
controller := &ImageChangeController{
DeploymentConfigClient: &ImageChangeControllerDeploymentConfigClientImpl{
UpdateDeploymentConfigFunc: func(namespace string, config *deployapi.DeploymentConfig) (*deployapi.DeploymentConfig, error) {
t.Fatalf("unexpected deployment config 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.Triggers[0].ImageChangeParams.Automatic = false
return []*deployapi.DeploymentConfig{config}, nil
},
},
}
// verify no-op
err := controller.HandleImageRepo(tagUpdate())
if err != nil {
t.Fatalf("unexpected err: %v", err)
}
}
func TestImageChangeForUnregisteredTag(t *testing.T) {
controller := &ImageChangeController{
DeploymentConfigClient: &ImageChangeControllerDeploymentConfigClientImpl{
UpdateDeploymentConfigFunc: func(namespace string, config *deployapi.DeploymentConfig) (*deployapi.DeploymentConfig, error) {
t.Fatalf("unexpected deployment config 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{imageChangeDeploymentConfig()}, nil
},
},
}
// verify no-op
imageRepo := tagUpdate()
imageRepo.Tags = map[string]string{
"unknown-tag": "ref-1",
}
err := controller.HandleImageRepo(imageRepo)
if err != nil {
t.Fatalf("unexpected err: %v", err)
}
}
func TestImageChangeMatchScenarios(t *testing.T) {
params := map[string]*deployapi.DeploymentTriggerImageChangeParams{
"params.1": {
Automatic: true,
ContainerNames: []string{"container-1"},
From: kapi.ObjectReference{Namespace: kapi.NamespaceDefault, Name: "repoA"},
Tag: "test-tag",
},
"params.2": {
Automatic: true,
ContainerNames: []string{"container-1"},
From: kapi.ObjectReference{Name: "repoA"},
Tag: "test-tag",
},
"params.3": {
Automatic: true,
ContainerNames: []string{"container-1"},
RepositoryName: "registry:8080/openshift/test-image",
Tag: "test-tag",
},
}
updates := map[string]*imageapi.ImageRepository{
"repo.1": {
ObjectMeta: kapi.ObjectMeta{Name: "repoA", Namespace: kapi.NamespaceDefault},
Status: imageapi.ImageRepositoryStatus{"registry:8080/openshift/test-image"},
Tags: map[string]string{"test-tag": "ref-2"},
},
"repo.2": {
ObjectMeta: kapi.ObjectMeta{Name: "repoB", Namespace: kapi.NamespaceDefault},
Status: imageapi.ImageRepositoryStatus{"registry:8080/openshift/test-image"},
Tags: map[string]string{"test-tag": "ref-3"},
},
"repo.3": {
ObjectMeta: kapi.ObjectMeta{Name: "repoC", Namespace: kapi.NamespaceDefault},
Status: imageapi.ImageRepositoryStatus{"registry:8080/openshift/test-image-B"},
Tags: map[string]string{"test-tag": "ref-2"},
},
"repo.4": {
ObjectMeta: kapi.ObjectMeta{Name: "repoA", Namespace: kapi.NamespaceDefault},
Tags: map[string]string{"test-tag": "ref-2"},
},
}
scenarios := []struct {
param string
repo string
matches bool
causes []string
}{
{"params.1", "repo.1", true, []string{"registry:8080/openshift/test-image:ref-2"}},
{"params.1", "repo.2", false, []string{}},
{"params.1", "repo.3", false, []string{}},
// This case relies on a brittle assumption that we'll sometimes has an empty
// imageRepo.Status.DockerImageRepository, but we'll still feed it through the
// generator anyway (which could return a config with no diffs).
{"params.1", "repo.4", true, []string{}},
{"params.2", "repo.1", true, []string{"registry:8080/openshift/test-image:ref-2"}},
{"params.2", "repo.2", false, []string{}},
{"params.2", "repo.3", false, []string{}},
// Same as params.1 -> repo.4, see above
{"params.2", "repo.4", true, []string{}},
{"params.3", "repo.1", true, []string{"registry:8080/openshift/test-image"}},
{"params.3", "repo.2", true, []string{"registry:8080/openshift/test-image"}},
{"params.3", "repo.3", false, []string{}},
{"params.3", "repo.4", false, []string{}},
}
for _, s := range scenarios {
config := imageChangeDeploymentConfig()
config.Namespace = kapi.NamespaceDefault
config.Triggers = []deployapi.DeploymentTriggerPolicy{
{
Type: deployapi.DeploymentTriggerOnImageChange,
ImageChangeParams: params[s.param],
},
}
updated := false
generated := false
controller := &ImageChangeController{
DeploymentConfigClient: &ImageChangeControllerDeploymentConfigClientImpl{
UpdateDeploymentConfigFunc: func(namespace string, config *deployapi.DeploymentConfig) (*deployapi.DeploymentConfig, error) {
if !s.matches {
t.Fatalf("unexpected deployment config 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
return config, nil
},
ListDeploymentConfigsFunc: func() ([]*deployapi.DeploymentConfig, error) {
return []*deployapi.DeploymentConfig{config}, nil
},
},
}
t.Logf("running scenario: %v", s)
err := controller.HandleImageRepo(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)
}
// assert causes are correct relative to expected updates
if updated {
if e, a := len(s.causes), len(config.Details.Causes); e != a {
t.Fatalf("expected cause length %d, got %d", e, a)
}
for i, cause := range config.Details.Causes {
if e, a := s.causes[i], cause.ImageTrigger.RepositoryName; e != a {
t.Fatalf("expected cause repositoryName %s, got %s", e, a)
}
}
} else {
if config.Details != nil && len(config.Details.Causes) != 0 {
t.Fatalf("expected cause length 0, got %d", len(config.Details.Causes))
}
}
}
}
// Utilities and convenience methods
func originalImageRepo() *imageapi.ImageRepository {
return &imageapi.ImageRepository{
ObjectMeta: kapi.ObjectMeta{Name: "test-image-repo", Namespace: nonDefaultNamespace},
DockerImageRepository: "registry:8080/openshift/test-image",
Tags: map[string]string{
"test-tag": "ref-1",
},
}
}
func unregisteredTagUpdate() *imageapi.ImageRepository {
return &imageapi.ImageRepository{
ObjectMeta: kapi.ObjectMeta{Name: "test-image-repo", Namespace: nonDefaultNamespace},
DockerImageRepository: "registry:8080/openshift/test-image",
Tags: map[string]string{
"test-tag": "ref-1",
"other-test-tag": "ref-x",
},
}
}
func tagUpdate() *imageapi.ImageRepository {
return &imageapi.ImageRepository{
ObjectMeta: kapi.ObjectMeta{Name: "test-image-repo", Namespace: nonDefaultNamespace},
DockerImageRepository: "registry:8080/openshift/test-image",
Tags: map[string]string{
"test-tag": "ref-2",
},
}
}
func imageChangeDeploymentConfig() *deployapi.DeploymentConfig {
return &deployapi.DeploymentConfig{
ObjectMeta: kapi.ObjectMeta{Name: "image-change-deploy-config"},
Triggers: []deployapi.DeploymentTriggerPolicy{
{
Type: deployapi.DeploymentTriggerOnImageChange,
ImageChangeParams: &deployapi.DeploymentTriggerImageChangeParams{
Automatic: true,
ContainerNames: []string{"container-1"},
RepositoryName: "registry:8080/openshift/test-image",
Tag: "test-tag",
},
},
},
Template: deployapi.DeploymentTemplate{
Strategy: deployapi.DeploymentStrategy{
Type: deployapi.DeploymentStrategyTypeRecreate,
},
ControllerTemplate: kapi.ReplicationControllerSpec{
Replicas: 1,
Selector: map[string]string{
"name": "test-pod",
},
Template: &kapi.PodTemplateSpec{
ObjectMeta: kapi.ObjectMeta{
Labels: map[string]string{
"name": "test-pod",
},
},
Spec: kapi.PodSpec{
Containers: []kapi.Container{
{
Name: "container-1",
Image: "registry:8080/openshift/test-image:ref-1",
},
},
},
},
},
},
}
}
func regeneratedConfig(namespace string) *deployapi.DeploymentConfig {
return &deployapi.DeploymentConfig{
ObjectMeta: kapi.ObjectMeta{Name: "image-change-deploy-config", Namespace: namespace},
Triggers: []deployapi.DeploymentTriggerPolicy{
{
Type: deployapi.DeploymentTriggerOnImageChange,
ImageChangeParams: &deployapi.DeploymentTriggerImageChangeParams{
Automatic: true,
ContainerNames: []string{"container-1"},
RepositoryName: "registry:8080/openshift/test-image",
Tag: "test-tag",
},
},
},
Template: deployapi.DeploymentTemplate{
Strategy: deployapi.DeploymentStrategy{
Type: deployapi.DeploymentStrategyTypeRecreate,
},
ControllerTemplate: kapi.ReplicationControllerSpec{
Replicas: 1,
Selector: map[string]string{
"name": "test-pod",
},
Template: &kapi.PodTemplateSpec{
ObjectMeta: kapi.ObjectMeta{
Labels: map[string]string{
"name": "test-pod",
},
},
Spec: kapi.PodSpec{
Containers: []kapi.Container{
{
Name: "container-1",
Image: "registry:8080/openshift/test-image:ref-2",
},
},
},
},
},
},
}
}
func unregisteredConfig() *deployapi.DeploymentConfig {
d := imageChangeDeploymentConfig()
d.Triggers[0].ImageChangeParams.ContainerNames = []string{"container-3"}
return d
}