package deploymentconfig
import (
"errors"
"fmt"
"reflect"
"sort"
"testing"
kapi "k8s.io/kubernetes/pkg/api"
kerrors "k8s.io/kubernetes/pkg/api/errors"
ktestclient "k8s.io/kubernetes/pkg/client/unversioned/testclient"
"k8s.io/kubernetes/pkg/runtime"
api "github.com/openshift/origin/pkg/api/latest"
buildapi "github.com/openshift/origin/pkg/build/api"
"github.com/openshift/origin/pkg/client/testclient"
deployapi "github.com/openshift/origin/pkg/deploy/api"
deploytest "github.com/openshift/origin/pkg/deploy/api/test"
deployutil "github.com/openshift/origin/pkg/deploy/util"
imageapi "github.com/openshift/origin/pkg/image/api"
)
// TestHandle_initialOk ensures that an initial config (version 0) doesn't result
// in a new deployment.
func TestHandle_initialOk(t *testing.T) {
controller := &DeploymentConfigController{
makeDeployment: func(config *deployapi.DeploymentConfig) (*kapi.ReplicationController, error) {
return deployutil.MakeDeployment(config, api.Codec)
},
deploymentClient: &deploymentClientImpl{
createDeploymentFunc: func(namespace string, deployment *kapi.ReplicationController) (*kapi.ReplicationController, error) {
t.Fatalf("unexpected call with deployment %v", deployment)
return nil, nil
},
listDeploymentsForConfigFunc: func(namespace, configName string) (*kapi.ReplicationControllerList, error) {
return &kapi.ReplicationControllerList{}, nil
},
updateDeploymentFunc: func(namespace string, deployment *kapi.ReplicationController) (*kapi.ReplicationController, error) {
t.Fatalf("unexpected update call with deployment %v", deployment)
return nil, nil
},
},
osClient: testclient.NewSimpleFake(deploytest.OkDeploymentConfig(0)),
}
err := controller.Handle(deploytest.OkDeploymentConfig(0))
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
}
// TestHandle_updateOk ensures that an updated config (version >0) results in
// a new deployment with the appropriate replica count based on a variety of
// existing prior deployments.
func TestHandle_updateOk(t *testing.T) {
var (
config *deployapi.DeploymentConfig
deployed *kapi.ReplicationController
existingDeployments *kapi.ReplicationControllerList
)
controller := &DeploymentConfigController{
makeDeployment: func(config *deployapi.DeploymentConfig) (*kapi.ReplicationController, error) {
return deployutil.MakeDeployment(config, api.Codec)
},
deploymentClient: &deploymentClientImpl{
createDeploymentFunc: func(namespace string, deployment *kapi.ReplicationController) (*kapi.ReplicationController, error) {
deployed = deployment
return deployment, nil
},
listDeploymentsForConfigFunc: func(namespace, configName string) (*kapi.ReplicationControllerList, error) {
return existingDeployments, nil
},
updateDeploymentFunc: func(namespace string, deployment *kapi.ReplicationController) (*kapi.ReplicationController, error) {
t.Fatalf("unexpected update call with deployment %v", deployment)
return nil, nil
},
},
osClient: testclient.NewSimpleFake(),
}
type existing struct {
version int
replicas int
status deployapi.DeploymentStatus
}
type scenario struct {
version int
expectedReplicas int
existing []existing
}
scenarios := []scenario{
{1, 1, []existing{}},
{2, 1, []existing{
{1, 1, deployapi.DeploymentStatusComplete},
}},
{3, 4, []existing{
{1, 0, deployapi.DeploymentStatusComplete},
{2, 4, deployapi.DeploymentStatusComplete},
}},
{3, 4, []existing{
{1, 4, deployapi.DeploymentStatusComplete},
{2, 1, deployapi.DeploymentStatusFailed},
}},
{4, 2, []existing{
{1, 0, deployapi.DeploymentStatusComplete},
{2, 0, deployapi.DeploymentStatusFailed},
{3, 2, deployapi.DeploymentStatusComplete},
}},
// Scramble the order of the previous to ensure we still get it right.
{4, 2, []existing{
{2, 0, deployapi.DeploymentStatusFailed},
{3, 2, deployapi.DeploymentStatusComplete},
{1, 0, deployapi.DeploymentStatusComplete},
}},
}
for _, scenario := range scenarios {
deployed = nil
config = deploytest.OkDeploymentConfig(scenario.version)
config.Triggers = []deployapi.DeploymentTriggerPolicy{}
existingDeployments = &kapi.ReplicationControllerList{}
for _, e := range scenario.existing {
d, _ := deployutil.MakeDeployment(deploytest.OkDeploymentConfig(e.version), api.Codec)
d.Spec.Replicas = e.replicas
d.Annotations[deployapi.DeploymentStatusAnnotation] = string(e.status)
existingDeployments.Items = append(existingDeployments.Items, *d)
}
err := controller.Handle(config)
if deployed == nil {
t.Fatalf("expected a deployment")
}
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
desired, hasDesired := deployutil.DeploymentDesiredReplicas(deployed)
if !hasDesired {
t.Fatalf("expected desired replicas")
}
if e, a := scenario.expectedReplicas, desired; e != a {
t.Errorf("expected desired replicas %d, got %d", e, a)
}
}
}
// TestHandle_nonfatalLookupError ensures that an API failure to look up the
// existing deployment for an updated config results in a nonfatal error.
func TestHandle_nonfatalLookupError(t *testing.T) {
configController := &DeploymentConfigController{
makeDeployment: func(config *deployapi.DeploymentConfig) (*kapi.ReplicationController, error) {
return deployutil.MakeDeployment(config, api.Codec)
},
deploymentClient: &deploymentClientImpl{
createDeploymentFunc: func(namespace string, deployment *kapi.ReplicationController) (*kapi.ReplicationController, error) {
t.Fatalf("unexpected call with deployment %v", deployment)
return nil, nil
},
listDeploymentsForConfigFunc: func(namespace, configName string) (*kapi.ReplicationControllerList, error) {
return nil, kerrors.NewInternalError(fmt.Errorf("fatal test error"))
},
updateDeploymentFunc: func(namespace string, deployment *kapi.ReplicationController) (*kapi.ReplicationController, error) {
t.Fatalf("unexpected update call with deployment %v", deployment)
return nil, nil
},
},
osClient: testclient.NewSimpleFake(),
}
err := configController.Handle(deploytest.OkDeploymentConfig(1))
if err == nil {
t.Fatalf("expected error")
}
if _, isFatal := err.(fatalError); isFatal {
t.Fatalf("expected a retryable error, got a fatal error: %v", err)
}
}
// TestHandle_configAlreadyDeployed ensures that an attempt to create a
// deployment for an updated config for which the deployment was already
// created results in a no-op.
func TestHandle_configAlreadyDeployed(t *testing.T) {
deploymentConfig := deploytest.OkDeploymentConfig(0)
controller := &DeploymentConfigController{
makeDeployment: func(config *deployapi.DeploymentConfig) (*kapi.ReplicationController, error) {
return deployutil.MakeDeployment(config, api.Codec)
},
deploymentClient: &deploymentClientImpl{
createDeploymentFunc: func(namespace string, deployment *kapi.ReplicationController) (*kapi.ReplicationController, error) {
t.Fatalf("unexpected call to to create deployment: %v", deployment)
return nil, nil
},
listDeploymentsForConfigFunc: func(namespace, configName string) (*kapi.ReplicationControllerList, error) {
existingDeployments := []kapi.ReplicationController{}
deployment, _ := deployutil.MakeDeployment(deploymentConfig, kapi.Codec)
existingDeployments = append(existingDeployments, *deployment)
return &kapi.ReplicationControllerList{Items: existingDeployments}, nil
},
updateDeploymentFunc: func(namespace string, deployment *kapi.ReplicationController) (*kapi.ReplicationController, error) {
t.Fatalf("unexpected update call with deployment %v", deployment)
return nil, nil
},
},
osClient: testclient.NewSimpleFake(deploymentConfig),
}
err := controller.Handle(deploymentConfig)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
}
// TestHandle_nonfatalCreateError ensures that a failed API attempt to create
// a new deployment for an updated config results in a nonfatal error.
func TestHandle_nonfatalCreateError(t *testing.T) {
configController := &DeploymentConfigController{
makeDeployment: func(config *deployapi.DeploymentConfig) (*kapi.ReplicationController, error) {
return deployutil.MakeDeployment(config, api.Codec)
},
deploymentClient: &deploymentClientImpl{
createDeploymentFunc: func(namespace string, deployment *kapi.ReplicationController) (*kapi.ReplicationController, error) {
return nil, kerrors.NewInternalError(fmt.Errorf("test error"))
},
listDeploymentsForConfigFunc: func(namespace, configName string) (*kapi.ReplicationControllerList, error) {
return &kapi.ReplicationControllerList{}, nil
},
updateDeploymentFunc: func(namespace string, deployment *kapi.ReplicationController) (*kapi.ReplicationController, error) {
t.Fatalf("unexpected update call with deployment %v", deployment)
return nil, nil
},
},
osClient: testclient.NewSimpleFake(),
}
err := configController.Handle(deploytest.OkDeploymentConfig(1))
if err == nil {
t.Fatalf("expected error")
}
if _, isFatal := err.(fatalError); isFatal {
t.Fatalf("expected a nonfatal error, got a fatal error: %v", err)
}
}
// TestHandle_fatalError ensures that in internal (not API) failure to make a
// deployment from an updated config results in a fatal error.
func TestHandle_fatalError(t *testing.T) {
configController := &DeploymentConfigController{
makeDeployment: func(config *deployapi.DeploymentConfig) (*kapi.ReplicationController, error) {
return nil, fmt.Errorf("couldn't make deployment")
},
deploymentClient: &deploymentClientImpl{
createDeploymentFunc: func(namespace string, deployment *kapi.ReplicationController) (*kapi.ReplicationController, error) {
t.Fatalf("unexpected call to create")
return nil, kerrors.NewInternalError(fmt.Errorf("test error"))
},
listDeploymentsForConfigFunc: func(namespace, configName string) (*kapi.ReplicationControllerList, error) {
return &kapi.ReplicationControllerList{}, nil
},
updateDeploymentFunc: func(namespace string, deployment *kapi.ReplicationController) (*kapi.ReplicationController, error) {
t.Fatalf("unexpected update call with deployment %v", deployment)
return nil, nil
},
},
osClient: testclient.NewSimpleFake(deploytest.OkDeploymentConfig(1)),
}
err := configController.Handle(deploytest.OkDeploymentConfig(1))
if err == nil {
t.Fatalf("expected error")
}
if _, isFatal := err.(fatalError); !isFatal {
t.Fatalf("expected a fatal error, got: %v", err)
}
}
// TestHandle_existingDeployments ensures that an attempt to create a
// new deployment for a config that has existing deployments succeeds of fails
// depending upon the state of the existing deployments
func TestHandle_existingDeployments(t *testing.T) {
var (
config *deployapi.DeploymentConfig
deployed *kapi.ReplicationController
existingDeployments *kapi.ReplicationControllerList
updatedDeployments []kapi.ReplicationController
)
controller := &DeploymentConfigController{
makeDeployment: func(cfg *deployapi.DeploymentConfig) (*kapi.ReplicationController, error) {
return deployutil.MakeDeployment(cfg, api.Codec)
},
deploymentClient: &deploymentClientImpl{
createDeploymentFunc: func(namespace string, deployment *kapi.ReplicationController) (*kapi.ReplicationController, error) {
deployed = deployment
return deployment, nil
},
listDeploymentsForConfigFunc: func(namespace, configName string) (*kapi.ReplicationControllerList, error) {
return existingDeployments, nil
},
updateDeploymentFunc: func(namespace string, deployment *kapi.ReplicationController) (*kapi.ReplicationController, error) {
updatedDeployments = append(updatedDeployments, *deployment)
return deployment, nil
},
},
osClient: testclient.NewSimpleFake(),
}
type existing struct {
version int
status deployapi.DeploymentStatus
shouldCancel bool
}
type scenario struct {
version int
existing []existing
errorType reflect.Type
expectDeployment bool
}
transientErrorType := reflect.TypeOf(transientError(""))
scenarios := []scenario{
// No existing deployments
{1, []existing{}, nil, true},
// A single existing completed deployment
{2, []existing{{1, deployapi.DeploymentStatusComplete, false}}, nil, true},
// A single existing failed deployment
{2, []existing{{1, deployapi.DeploymentStatusFailed, false}}, nil, true},
// Multiple existing completed/failed deployments
{3, []existing{{2, deployapi.DeploymentStatusFailed, false}, {1, deployapi.DeploymentStatusComplete, false}}, nil, true},
// A single existing deployment in the default state
{2, []existing{{1, "", false}}, transientErrorType, false},
// A single existing new deployment
{2, []existing{{1, deployapi.DeploymentStatusNew, false}}, transientErrorType, false},
// A single existing pending deployment
{2, []existing{{1, deployapi.DeploymentStatusPending, false}}, transientErrorType, false},
// A single existing running deployment
{2, []existing{{1, deployapi.DeploymentStatusRunning, false}}, transientErrorType, false},
// Multiple existing deployments with one in new/pending/running
{4, []existing{{3, deployapi.DeploymentStatusRunning, false}, {2, deployapi.DeploymentStatusComplete, false}, {1, deployapi.DeploymentStatusFailed, false}}, transientErrorType, false},
// Latest deployment exists and has already failed/completed
{2, []existing{{2, deployapi.DeploymentStatusFailed, false}, {1, deployapi.DeploymentStatusComplete, false}}, nil, false},
// Latest deployment exists and is in new/pending/running state
{2, []existing{{2, deployapi.DeploymentStatusRunning, false}, {1, deployapi.DeploymentStatusComplete, false}}, nil, false},
// Multiple existing deployments with more than one in new/pending/running
{4, []existing{{3, deployapi.DeploymentStatusNew, false}, {2, deployapi.DeploymentStatusRunning, true}, {1, deployapi.DeploymentStatusFailed, false}}, transientErrorType, false},
// Multiple existing deployments with more than one in new/pending/running
// Latest deployment has already failed
{6, []existing{{5, deployapi.DeploymentStatusFailed, false}, {4, deployapi.DeploymentStatusRunning, false}, {3, deployapi.DeploymentStatusNew, true}, {2, deployapi.DeploymentStatusComplete, false}, {1, deployapi.DeploymentStatusNew, true}}, transientErrorType, false},
}
for _, scenario := range scenarios {
updatedDeployments = []kapi.ReplicationController{}
deployed = nil
config = deploytest.OkDeploymentConfig(scenario.version)
existingDeployments = &kapi.ReplicationControllerList{}
for _, e := range scenario.existing {
d, _ := deployutil.MakeDeployment(deploytest.OkDeploymentConfig(e.version), api.Codec)
if e.status != "" {
d.Annotations[deployapi.DeploymentStatusAnnotation] = string(e.status)
}
existingDeployments.Items = append(existingDeployments.Items, *d)
}
controller.osClient = testclient.NewSimpleFake(config)
err := controller.Handle(config)
if scenario.expectDeployment && deployed == nil {
t.Fatalf("expected a deployment")
}
if scenario.errorType == nil {
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
} else {
if err == nil {
t.Fatalf("expected error")
}
if reflect.TypeOf(err) != scenario.errorType {
t.Fatalf("error expected: %s, got: %s", scenario.errorType, reflect.TypeOf(err))
}
}
expectedCancellations := []int{}
actualCancellations := []int{}
for _, e := range scenario.existing {
if e.shouldCancel {
expectedCancellations = append(expectedCancellations, e.version)
}
}
for _, d := range updatedDeployments {
actualCancellations = append(actualCancellations, deployutil.DeploymentVersionFor(&d))
}
sort.Ints(actualCancellations)
sort.Ints(expectedCancellations)
if !reflect.DeepEqual(actualCancellations, expectedCancellations) {
t.Fatalf("expected cancellations: %v, actual: %v", expectedCancellations, actualCancellations)
}
}
}
func TestFindDetails(t *testing.T) {
existingDeployments := &kapi.ReplicationControllerList{}
controller := &DeploymentConfigController{
deploymentClient: &deploymentClientImpl{
listDeploymentsForConfigFunc: func(namespace, configName string) (*kapi.ReplicationControllerList, error) {
return existingDeployments, nil
},
},
osClient: testclient.NewSimpleFake(),
}
type reaction struct {
verb, resource string
fn ktestclient.ReactionFunc
}
tests := []struct {
name string
controller *DeploymentConfigController
version int
hasDeployments bool
hasNoImageChange bool
hasMultipleErrors bool
status deployapi.DeploymentStatus
reactions []reaction
expectedDetails string
expectedLatest bool
expectedErr bool
}{
{
name: "cannot get existing deployments",
controller: &DeploymentConfigController{
deploymentClient: &deploymentClientImpl{
listDeploymentsForConfigFunc: func(namespace, configName string) (*kapi.ReplicationControllerList, error) {
return nil, errors.New("cannot return these deployments")
},
},
},
version: 0,
hasDeployments: false,
expectedDetails: "",
expectedLatest: false,
expectedErr: true,
},
{
name: "complete latest",
controller: controller,
version: 1,
hasDeployments: true,
status: deployapi.DeploymentStatusComplete,
expectedDetails: "",
expectedLatest: true,
expectedErr: false,
},
{
name: "no image change triggers",
controller: controller,
version: 1,
hasDeployments: true,
hasNoImageChange: true,
status: deployapi.DeploymentStatusFailed,
expectedDetails: "",
expectedLatest: true,
expectedErr: false,
},
{
name: "cannot retrieve istag",
controller: controller,
version: 1,
hasDeployments: true,
status: deployapi.DeploymentStatusFailed,
reactions: []reaction{
{
verb: "get",
resource: "imagestreamtags",
fn: func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) {
return true, nil, errors.New("unknown error while retrieving an istag")
},
},
},
expectedDetails: "",
expectedLatest: true,
expectedErr: false,
},
{
name: "found istag",
controller: controller,
version: 1,
hasDeployments: true,
status: deployapi.DeploymentStatusFailed,
reactions: []reaction{
{
verb: "get",
resource: "imagestreamtags",
fn: func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) {
return true, &imageapi.ImageStreamTag{}, nil
},
},
},
expectedDetails: "",
expectedLatest: true,
expectedErr: false,
},
{
name: "not found istag",
controller: controller,
version: 1,
hasDeployments: true,
status: deployapi.DeploymentStatusFailed,
reactions: []reaction{
{
verb: "get",
resource: "imagestreamtags",
fn: func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) {
return true, nil, kerrors.NewNotFound("imagestreamtag", "test-image-stream:latest")
},
},
{
verb: "list",
resource: "buildconfigs",
fn: func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) {
return true, &buildapi.BuildConfigList{}, nil
},
},
{
verb: "get",
resource: "imagestreams",
fn: func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) {
return true, nil, nil
},
},
},
expectedDetails: "The image trigger for image stream tag \"test-image-stream:latest\" will have no effect because image stream tag \"test-image-stream:latest\" does not exist.",
expectedLatest: true,
expectedErr: false,
},
{
name: "synthetic istag",
controller: controller,
version: 1,
hasDeployments: true,
status: deployapi.DeploymentStatusFailed,
reactions: []reaction{
{
verb: "get",
resource: "imagestreamtags",
fn: func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) {
return true, nil, kerrors.NewNotFound("imagestreamtag", "test-image-stream:"+imageapi.DefaultImageTag)
},
},
{
verb: "list",
resource: "buildconfigs",
fn: func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) {
return true, mkBuildConfigList(), nil
},
},
{
verb: "get",
resource: "imagestreams",
fn: func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) {
return true, nil, nil
},
},
},
expectedDetails: "The image trigger for image stream tag \"test-image-stream:latest\" will have no effect because image stream tag \"test-image-stream:latest\" does not exist.\n\tIf image stream tag \"test-image-stream:latest\" is expected, check build config \"mybc\" which produces image stream tag \"test-image-stream:latest\".",
expectedLatest: true,
expectedErr: false,
},
{
name: "not found image stream",
controller: controller,
version: 1,
hasDeployments: true,
status: deployapi.DeploymentStatusFailed,
reactions: []reaction{
{
verb: "get",
resource: "imagestreamtags",
fn: func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) {
return true, nil, kerrors.NewNotFound("imagestreamtag", "test-image-stream:latest")
},
},
{
verb: "get",
resource: "imagestreams",
fn: func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) {
return true, nil, kerrors.NewNotFound("imagestream", "test-image-stream")
},
},
},
expectedDetails: "The image trigger for image stream tag \"test-image-stream:latest\" will have no effect because image stream \"test-image-stream\" does not exist.",
expectedLatest: true,
expectedErr: false,
},
{
name: "no deployments - not found istag",
controller: controller,
version: 0,
status: deployapi.DeploymentStatusFailed,
reactions: []reaction{
{
verb: "get",
resource: "imagestreamtags",
fn: func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) {
return true, nil, kerrors.NewNotFound("imagestreamtag", "test-image-stream:latest")
},
},
{
verb: "list",
resource: "buildconfigs",
fn: func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) {
return true, &buildapi.BuildConfigList{}, nil
},
},
{
verb: "get",
resource: "imagestreams",
fn: func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) {
return true, nil, nil
},
},
},
expectedDetails: "The image trigger for image stream tag \"test-image-stream:latest\" will have no effect because image stream tag \"test-image-stream:latest\" does not exist.",
expectedErr: false,
},
{
name: "no deployments - synthetic istag",
controller: controller,
version: 0,
status: deployapi.DeploymentStatusFailed,
reactions: []reaction{
{
verb: "get",
resource: "imagestreamtags",
fn: func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) {
return true, nil, kerrors.NewNotFound("imagestreamtag", "test-image-stream:"+imageapi.DefaultImageTag)
},
},
{
verb: "list",
resource: "buildconfigs",
fn: func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) {
return true, mkBuildConfigList(), nil
},
},
{
verb: "get",
resource: "imagestreams",
fn: func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) {
return true, nil, nil
},
},
},
expectedDetails: "The image trigger for image stream tag \"test-image-stream:latest\" will have no effect because image stream tag \"test-image-stream:latest\" does not exist.\n\tIf image stream tag \"test-image-stream:latest\" is expected, check build config \"mybc\" which produces image stream tag \"test-image-stream:latest\".",
expectedErr: false,
},
{
name: "no deployments - not found image stream",
controller: controller,
version: 1,
hasDeployments: true,
status: deployapi.DeploymentStatusFailed,
reactions: []reaction{
{
verb: "get",
resource: "imagestreamtags",
fn: func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) {
return true, nil, kerrors.NewNotFound("imagestreamtag", "test-image-stream:latest")
},
},
{
verb: "get",
resource: "imagestreams",
fn: func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) {
return true, nil, kerrors.NewNotFound("imagestream", "test-image-stream")
},
},
{
verb: "get",
resource: "imagestreams",
fn: func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) {
return true, nil, kerrors.NewNotFound("imagestream", "test-image-stream")
},
},
},
expectedDetails: "The image trigger for image stream tag \"test-image-stream:latest\" will have no effect because image stream \"test-image-stream\" does not exist.",
expectedLatest: true,
expectedErr: false,
},
{
name: "multiple errors",
controller: controller,
version: 0,
hasMultipleErrors: true,
status: deployapi.DeploymentStatusFailed,
reactions: []reaction{
{
verb: "get",
resource: "imagestreamtags",
fn: func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) {
return true, nil, kerrors.NewNotFound("imagestreamtag", "test-image-stream:latest")
},
},
{
verb: "get",
resource: "imagestreamtags",
fn: func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) {
return true, nil, kerrors.NewNotFound("imagestreamtag", "second-is:latest")
},
},
{
verb: "list",
resource: "buildconfigs",
fn: func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) {
return true, &buildapi.BuildConfigList{}, nil
},
},
{
verb: "get",
resource: "imagestreams",
fn: func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) {
return true, nil, nil
},
},
},
expectedDetails: "Deployment config \"config\" blocked by multiple errors:\n\n\t* The image trigger for image stream tag \"test-image-stream:latest\" will have no effect because image stream tag \"test-image-stream:latest\" does not exist.\n\t* The image trigger for image stream tag \"second-is:latest\" will have no effect because image stream tag \"second-is:latest\" does not exist.",
expectedErr: false,
},
}
for _, test := range tests {
// Need to setup a couple of things before passing the config in findDetails
// Namely, initalize the config, its triggers and its deployments
config := deploytest.OkDeploymentConfig(test.version)
if test.hasNoImageChange {
config.Triggers = []deployapi.DeploymentTriggerPolicy{}
} else if test.hasMultipleErrors {
config.Triggers = append(config.Triggers, deployapi.DeploymentTriggerPolicy{
Type: deployapi.DeploymentTriggerOnImageChange,
ImageChangeParams: &deployapi.DeploymentTriggerImageChangeParams{
Automatic: true,
ContainerNames: []string{
"container2",
},
From: kapi.ObjectReference{
Kind: "ImageStream",
Name: "second-is",
},
Tag: imageapi.DefaultImageTag,
},
})
}
if test.hasDeployments {
existingDeployments.Items = []kapi.ReplicationController{}
d := mkdeployment(test.version)
d.Annotations[deployapi.DeploymentStatusAnnotation] = string(test.status)
existingDeployments.Items = append(mkDeploymentList(test.version-1).Items, d)
}
// We also have to setup fake client reactions for imagestreamtags and buildconfigs
for _, act := range test.reactions {
test.controller.osClient.(*testclient.Fake).PrependReactor(act.verb, act.resource, act.fn)
}
details, _, latest, err := test.controller.findDetails(config)
// Check errors
if err != nil && !test.expectedErr {
t.Errorf("%s: didn't expect an error but got %v", test.name, err)
continue
}
if err == nil && test.expectedErr {
t.Errorf("%s: expected an error but got none", test.name)
continue
}
// Check details
if details != test.expectedDetails {
t.Errorf("%s: details mismatch!\nExpected:\n%s\ngot:\n%s\n\n", test.name, test.expectedDetails, details)
continue
}
// Check latest
if latest != test.expectedLatest {
t.Errorf("%s: latest mismatch! Expected %t but got %t", test.name, test.expectedLatest, latest)
continue
}
}
}
func mkdeployment(version int) kapi.ReplicationController {
deployment, _ := deployutil.MakeDeployment(deploytest.OkDeploymentConfig(version), kapi.Codec)
return *deployment
}
func mkDeploymentList(versions int) *kapi.ReplicationControllerList {
list := &kapi.ReplicationControllerList{}
for v := 1; v <= versions; v++ {
list.Items = append(list.Items, mkdeployment(v))
}
return list
}
func mkBuildConfigList() *buildapi.BuildConfigList {
return &buildapi.BuildConfigList{
Items: []buildapi.BuildConfig{
{
ObjectMeta: kapi.ObjectMeta{Name: "mybc"},
Spec: buildapi.BuildConfigSpec{
BuildSpec: buildapi.BuildSpec{
Output: buildapi.BuildOutput{
To: &kapi.ObjectReference{
Name: "test-image-stream:" + imageapi.DefaultImageTag,
Kind: "ImageStreamTag",
},
},
},
},
},
},
}
}