func TestCreateGeneratorError(t *testing.T) { rest := REST{ generator: Client{ GRFn: func(from, to *deployapi.DeploymentConfig, spec *deployapi.DeploymentConfigRollbackSpec) (*deployapi.DeploymentConfig, error) { return nil, kerrors.NewInternalError(fmt.Errorf("something terrible happened")) }, RCFn: func(ctx kapi.Context, name string) (*kapi.ReplicationController, error) { deployment, _ := deployutil.MakeDeployment(deploytest.OkDeploymentConfig(1), kapi.Codec) return deployment, nil }, DCFn: func(ctx kapi.Context, name string) (*deployapi.DeploymentConfig, error) { return deploytest.OkDeploymentConfig(1), nil }, }, codec: api.Codec, } _, err := rest.Create(kapi.NewDefaultContext(), &deployapi.DeploymentConfigRollback{ Spec: deployapi.DeploymentConfigRollbackSpec{ From: kapi.ObjectReference{ Name: "deployment", Namespace: kapi.NamespaceDefault, }, }, }) if err == nil || !strings.Contains(err.Error(), "something terrible happened") { t.Errorf("Unexpected error: %v", err) } }
func TestGenerate_fromConfigWithoutTagChange(t *testing.T) { generator := &DeploymentConfigGenerator{ Client: Client{ DCFn: func(ctx kapi.Context, id string) (*deployapi.DeploymentConfig, error) { return deploytest.OkDeploymentConfig(1), nil }, ISFn: func(ctx kapi.Context, name string) (*imageapi.ImageStream, error) { stream := makeStream( "test-image-stream", imageapi.DefaultImageTag, "registry:8080/repo1:ref1", "00000000000000000000000000000001", ) return stream, nil }, }, } config, err := generator.Generate(kapi.NewDefaultContext(), "deploy1") if err != nil { t.Fatalf("Unexpected error: %v", err) } if config == nil { t.Fatalf("Expected non-nil config") } if config.LatestVersion != 1 { t.Fatalf("Expected config LatestVersion=1, got %d", config.LatestVersion) } }
// TestHandle_newConfigNoTriggers ensures that a change to a config with no // triggers doesn't result in a new config version bump. func TestHandle_newConfigNoTriggers(t *testing.T) { controller := &DeploymentConfigChangeController{ decodeConfig: func(deployment *kapi.ReplicationController) (*deployapi.DeploymentConfig, error) { return deployutil.DecodeDeploymentConfig(deployment, api.Codec) }, changeStrategy: &changeStrategyImpl{ generateDeploymentConfigFunc: func(namespace, name string) (*deployapi.DeploymentConfig, error) { t.Fatalf("unexpected generation of deploymentConfig") return nil, nil }, updateDeploymentConfigFunc: func(namespace string, config *deployapi.DeploymentConfig) (*deployapi.DeploymentConfig, error) { t.Fatalf("unexpected update of deploymentConfig") return config, nil }, }, } config := deployapitest.OkDeploymentConfig(1) config.Triggers = []deployapi.DeploymentTriggerPolicy{} err := controller.Handle(config) if err != nil { t.Fatalf("unexpected 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 }, }, } 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_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 }, }, recorder: &record.FakeRecorder{}, } 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_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) { t.Fatalf("unexpected call to list deployments") return nil, nil }, updateDeploymentFunc: func(namespace string, deployment *kapi.ReplicationController) (*kapi.ReplicationController, error) { t.Fatalf("unexpected update call with deployment %v", deployment) return nil, nil }, }, recorder: &record.FakeRecorder{}, } err := controller.Handle(deploytest.OkDeploymentConfig(0)) if err != nil { t.Fatalf("unexpected 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 }, }, } err := controller.Handle(deploymentConfig) if err != nil { t.Fatalf("unexpected error: %v", err) } }
func TestCreateMissingDeploymentConfig(t *testing.T) { rest := REST{ generator: Client{ GRFn: func(from, to *deployapi.DeploymentConfig, spec *deployapi.DeploymentConfigRollbackSpec) (*deployapi.DeploymentConfig, error) { t.Fatal("unexpected call to generator") return nil, errors.New("something terrible happened") }, RCFn: func(ctx kapi.Context, name string) (*kapi.ReplicationController, error) { deployment, _ := deployutil.MakeDeployment(deploytest.OkDeploymentConfig(1), kapi.Codec) return deployment, nil }, DCFn: func(ctx kapi.Context, name string) (*deployapi.DeploymentConfig, error) { return nil, kerrors.NewNotFound("deploymentConfig", name) }, }, codec: api.Codec, } obj, err := rest.Create(kapi.NewDefaultContext(), &deployapi.DeploymentConfigRollback{ Spec: deployapi.DeploymentConfigRollbackSpec{ From: kapi.ObjectReference{ Name: "deployment", Namespace: kapi.NamespaceDefault, }, }, }) if err == nil { t.Errorf("Expected an error") } if obj != nil { t.Error("Unexpected result obj") } }
// TestHandle_runningPod ensures that a running deployer pod results in a // transition of the deployment's status to running. func TestHandle_runningPod(t *testing.T) { deployment, _ := deployutil.MakeDeployment(deploytest.OkDeploymentConfig(1), kapi.Codec) deployment.Annotations[deployapi.DeploymentStatusAnnotation] = string(deployapi.DeploymentStatusPending) var updatedDeployment *kapi.ReplicationController controller := &DeployerPodController{ deploymentClient: &deploymentClientImpl{ getDeploymentFunc: func(namespace, name string) (*kapi.ReplicationController, error) { return deployment, nil }, updateDeploymentFunc: func(namespace string, deployment *kapi.ReplicationController) (*kapi.ReplicationController, error) { updatedDeployment = deployment return deployment, nil }, }, } err := controller.Handle(runningPod(deployment)) if err != nil { t.Fatalf("unexpected error: %v", err) } if updatedDeployment == nil { t.Fatalf("expected deployment update") } if e, a := deployapi.DeploymentStatusRunning, deployutil.DeploymentStatusFor(updatedDeployment); e != a { t.Fatalf("expected updated deployment status %s, got %s", e, a) } }
func TestHookExecutor_executeExecNewPodFailed(t *testing.T) { hook := &deployapi.LifecycleHook{ FailurePolicy: deployapi.LifecycleHookFailurePolicyAbort, ExecNewPod: &deployapi.ExecNewPodHook{ ContainerName: "container1", }, } deployment, _ := deployutil.MakeDeployment(deploytest.OkDeploymentConfig(1), kapi.Codec) var createdPod *kapi.Pod executor := &HookExecutor{ PodClient: &HookExecutorPodClientImpl{ CreatePodFunc: func(namespace string, pod *kapi.Pod) (*kapi.Pod, error) { createdPod = pod return createdPod, nil }, PodWatchFunc: func(namespace, name, resourceVersion string, stopChannel chan struct{}) func() *kapi.Pod { createdPod.Status.Phase = kapi.PodFailed return func() *kapi.Pod { return createdPod } }, }, } err := executor.executeExecNewPod(hook, deployment, "hook") if err == nil { t.Fatalf("expected an error", err) } t.Logf("got expected error: %s", err) }
// TestCmdDeploy_latestConcurrentRejection ensures that attempts to start a // deployment concurrent with a running deployment are rejected. func TestCmdDeploy_latestConcurrentRejection(t *testing.T) { var existingDeployment *kapi.ReplicationController commandClient := &deployCommandClientImpl{ GetDeploymentFn: func(namespace, name string) (*kapi.ReplicationController, error) { return existingDeployment, nil }, UpdateDeploymentConfigFn: func(config *deployapi.DeploymentConfig) (*deployapi.DeploymentConfig, error) { t.Fatalf("unexpected call to UpdateDeploymentConfig") return nil, nil }, UpdateDeploymentFn: func(deployment *kapi.ReplicationController) (*kapi.ReplicationController, error) { t.Fatalf("unexpected call to UpdateDeployment for %s/%s", deployment.Namespace, deployment.Name) return nil, nil }, } c := &deployLatestCommand{client: commandClient} invalidStatusList := []deployapi.DeploymentStatus{ deployapi.DeploymentStatusNew, deployapi.DeploymentStatusPending, deployapi.DeploymentStatusRunning, } for _, status := range invalidStatusList { config := deploytest.OkDeploymentConfig(1) existingDeployment = deploymentFor(config, status) err := c.deploy(config, ioutil.Discard) if err == nil { t.Errorf("expected an error starting deployment with existing status %s", status) } } }
func TestRolling_deployInitial(t *testing.T) { initialStrategyInvoked := false strategy := &RollingDeploymentStrategy{ codec: api.Codec, client: &rollingUpdaterClient{ GetReplicationControllerFn: func(namespace, name string) (*kapi.ReplicationController, error) { t.Fatalf("unexpected call to GetReplicationController") return nil, nil }, }, initialStrategy: &testStrategy{ deployFn: func(from *kapi.ReplicationController, to *kapi.ReplicationController, desiredReplicas int, updateAcceptor kubectl.UpdateAcceptor) error { initialStrategyInvoked = true return nil }, }, rollingUpdate: func(config *kubectl.RollingUpdaterConfig) error { t.Fatalf("unexpected call to rollingUpdate") return nil }, getUpdateAcceptor: getUpdateAcceptor, } config := deploytest.OkDeploymentConfig(1) config.Template.Strategy = deploytest.OkRollingStrategy() deployment, _ := deployutil.MakeDeployment(config, kapi.Codec) err := strategy.Deploy(nil, deployment, 2) if err != nil { t.Fatalf("unexpected error: %v", err) } if !initialStrategyInvoked { t.Fatalf("expected initial strategy to be invoked") } }
// TestHandle_changeWithTemplateDiff ensures that a pod template change to a // config with a config change trigger results in a version bump and cause // update. func TestHandle_changeWithTemplateDiff(t *testing.T) { var updated *deployapi.DeploymentConfig controller := &DeploymentConfigChangeController{ decodeConfig: func(deployment *kapi.ReplicationController) (*deployapi.DeploymentConfig, error) { return deployutil.DecodeDeploymentConfig(deployment, api.Codec) }, changeStrategy: &changeStrategyImpl{ generateDeploymentConfigFunc: func(namespace, name string) (*deployapi.DeploymentConfig, error) { return deployapitest.OkDeploymentConfig(2), nil }, updateDeploymentConfigFunc: func(namespace string, config *deployapi.DeploymentConfig) (*deployapi.DeploymentConfig, error) { updated = config return config, nil }, getDeploymentFunc: func(namespace, name string) (*kapi.ReplicationController, error) { deployment, _ := deployutil.MakeDeployment(deployapitest.OkDeploymentConfig(1), kapi.Codec) return deployment, nil }, }, } config := deployapitest.OkDeploymentConfig(1) config.Triggers = []deployapi.DeploymentTriggerPolicy{deployapitest.OkConfigChangeTrigger()} config.Template.ControllerTemplate.Template.Spec.Containers[1].Name = "modified" err := controller.Handle(config) if err != nil { t.Fatalf("unexpected error: %v", err) } if updated == nil { t.Fatalf("expected config to be updated") } if e, a := 2, updated.LatestVersion; e != a { t.Fatalf("expected update to latestversion=%d, got %d", e, a) } if updated.Details == nil { t.Fatalf("expected config change details to be set") } else if updated.Details.Causes == nil { t.Fatalf("expected config change causes to be set") } else if updated.Details.Causes[0].Type != deployapi.DeploymentTriggerOnConfigChange { t.Fatalf("expected config change cause to be set to config change trigger, got %s", updated.Details.Causes[0].Type) } }
// TestHandle_orphanedPod ensures that deployer pods associated with a non- // existent deployment results in all deployer pods being deleted. func TestHandle_orphanedPod(t *testing.T) { deleted := kutil.NewStringSet() controller := &DeployerPodController{ deploymentClient: &deploymentClientImpl{ updateDeploymentFunc: func(namespace string, deployment *kapi.ReplicationController) (*kapi.ReplicationController, error) { t.Fatalf("Unexpected deployment update") return nil, nil }, getDeploymentFunc: func(namespace, name string) (*kapi.ReplicationController, error) { return nil, kerrors.NewNotFound("ReplicationController", name) }, }, deployerPodsFor: func(namespace, name string) (*kapi.PodList, error) { mkpod := func(suffix string) kapi.Pod { deployment, _ := deployutil.MakeDeployment(deploytest.OkDeploymentConfig(1), kapi.Codec) p := okPod(deployment) p.Name = p.Name + suffix return *p } return &kapi.PodList{ Items: []kapi.Pod{ mkpod(""), mkpod("-prehook"), mkpod("-posthook"), }, }, nil }, deletePod: func(namespace, name string) error { deleted.Insert(name) return nil }, } deployment, _ := deployutil.MakeDeployment(deploytest.OkDeploymentConfig(1), kapi.Codec) err := controller.Handle(runningPod(deployment)) if err != nil { t.Fatalf("unexpected error: %v", err) } deployerName := deployutil.DeployerPodNameForDeployment(deployment.Name) if !deleted.HasAll(deployerName, deployerName+"-prehook", deployerName+"-posthook") { t.Fatalf("unexpected deleted names: %v", deleted.List()) } }
func TestTriggers_manual(t *testing.T) { testutil.DeleteAllEtcdKeys() openshift := NewTestDeployOpenshift(t) defer openshift.Close() config := deploytest.OkDeploymentConfig(0) config.Namespace = testutil.Namespace() config.Triggers = []deployapi.DeploymentTriggerPolicy{ { Type: deployapi.DeploymentTriggerManual, }, } var err error dc, err := openshift.Client.DeploymentConfigs(testutil.Namespace()).Create(config) if err != nil { t.Fatalf("Couldn't create DeploymentConfig: %v %#v", err, config) } watch, err := openshift.KubeClient.ReplicationControllers(testutil.Namespace()).Watch(labels.Everything(), fields.Everything(), dc.ResourceVersion) if err != nil { t.Fatalf("Couldn't subscribe to Deployments: %v", err) } defer watch.Stop() config, err = openshift.Client.DeploymentConfigs(testutil.Namespace()).Generate(config.Name) if err != nil { t.Fatalf("Error generating config: %v", err) } if config.LatestVersion != 1 { t.Fatalf("Generated deployment should have version 1: %#v", config) } glog.Infof("config(1): %#v", config) new, err := openshift.Client.DeploymentConfigs(testutil.Namespace()).Update(config) if err != nil { t.Fatalf("Couldn't create updated DeploymentConfig: %v %#v", err, config) } glog.Infof("config(2): %#v", new) event := <-watch.ResultChan() if e, a := watchapi.Added, event.Type; e != a { t.Fatalf("expected watch event type %s, got %s", e, a) } deployment := event.Object.(*kapi.ReplicationController) if e, a := config.Name, deployutil.DeploymentConfigNameFor(deployment); e != a { t.Fatalf("Expected deployment annotated with deploymentConfig '%s', got '%s'", e, a) } if e, a := 1, deployutil.DeploymentVersionFor(deployment); e != a { t.Fatalf("Deployment annotation version does not match: %#v", deployment) } }
// TestHandle_changeWithoutTemplateDiff ensures that an updated config with no // pod template diff results in the config version remaining the same. func TestHandle_changeWithoutTemplateDiff(t *testing.T) { config := deployapitest.OkDeploymentConfig(1) config.Triggers = []deployapi.DeploymentTriggerPolicy{deployapitest.OkConfigChangeTrigger()} generated := false updated := false controller := &DeploymentConfigChangeController{ decodeConfig: func(deployment *kapi.ReplicationController) (*deployapi.DeploymentConfig, error) { return deployutil.DecodeDeploymentConfig(deployment, api.Codec) }, changeStrategy: &changeStrategyImpl{ generateDeploymentConfigFunc: func(namespace, name string) (*deployapi.DeploymentConfig, error) { generated = true return config, nil }, updateDeploymentConfigFunc: func(namespace string, config *deployapi.DeploymentConfig) (*deployapi.DeploymentConfig, error) { updated = true return config, nil }, getDeploymentFunc: func(namespace, name string) (*kapi.ReplicationController, error) { deployment, _ := deployutil.MakeDeployment(deployapitest.OkDeploymentConfig(1), kapi.Codec) return deployment, nil }, }, } err := controller.Handle(config) if err != nil { t.Fatalf("unexpected error: %v", err) } if generated { t.Error("Unexpected generation of deploymentConfig") } if updated { t.Error("Unexpected update of deploymentConfig") } }
// TestHandle_deploymentCleanupTransientError ensures that a failure // to clean up a failed deployment results in a transient error // and the deployment status is not set to Failed. func TestHandle_deploymentCleanupTransientError(t *testing.T) { completedDeployment, _ := deployutil.MakeDeployment(deploytest.OkDeploymentConfig(1), kapi.Codec) completedDeployment.Annotations[deployapi.DeploymentStatusAnnotation] = string(deployapi.DeploymentStatusComplete) currentDeployment, _ := deployutil.MakeDeployment(deploytest.OkDeploymentConfig(2), kapi.Codec) currentDeployment.Annotations[deployapi.DeploymentStatusAnnotation] = string(deployapi.DeploymentStatusRunning) currentDeployment.Annotations[deployapi.DesiredReplicasAnnotation] = "2" controller := &DeployerPodController{ deploymentClient: &deploymentClientImpl{ getDeploymentFunc: func(namespace, name string) (*kapi.ReplicationController, error) { return currentDeployment, nil }, updateDeploymentFunc: func(namespace string, deployment *kapi.ReplicationController) (*kapi.ReplicationController, error) { // simulate failure ONLY for the completed deployment if deployutil.DeploymentStatusFor(deployment) == deployapi.DeploymentStatusComplete { return nil, fmt.Errorf("test failure in updating completed deployment") } return deployment, nil }, listDeploymentsForConfigFunc: func(namespace, configName string) (*kapi.ReplicationControllerList, error) { return &kapi.ReplicationControllerList{Items: []kapi.ReplicationController{*currentDeployment, *completedDeployment}}, nil }, }, } err := controller.Handle(terminatedPod(currentDeployment)) if err == nil { t.Fatalf("unexpected error: %v", err) } if _, isTransient := err.(transientError); !isTransient { t.Fatalf("expected transientError on failure to update deployment") } if e, a := deployapi.DeploymentStatusRunning, deployutil.DeploymentStatusFor(currentDeployment); e != a { t.Fatalf("expected updated deployment status to remain %s, got %s", e, a) } }
func TestGenerate_fromConfigWithUpdatedImageRef(t *testing.T) { newRepoName := "registry:8080/openshift/test-image@sha256:00000000000000000000000000000002" newImageID := "00000000000000000000000000000002" generator := &DeploymentConfigGenerator{ Client: Client{ DCFn: func(ctx kapi.Context, id string) (*deployapi.DeploymentConfig, error) { return deploytest.OkDeploymentConfig(1), nil }, ISFn: func(ctx kapi.Context, name string) (*imageapi.ImageStream, error) { stream := makeStream( "test-image-stream", imageapi.DefaultImageTag, newRepoName, newImageID, ) return stream, nil }, }, } config, err := generator.Generate(kapi.NewDefaultContext(), "deploy1") if err != nil { t.Fatalf("Unexpected error: %v", err) } if config == nil { t.Fatalf("Expected non-nil config") } if config.LatestVersion != 2 { t.Fatalf("Expected config LatestVersion=2, got %d", config.LatestVersion) } if e, a := newRepoName, config.Template.ControllerTemplate.Template.Spec.Containers[0].Image; e != a { t.Fatalf("Expected container image %s, got %s", e, a) } if e, a := newRepoName, config.Triggers[0].ImageChangeParams.LastTriggeredImage; e != a { t.Fatalf("Expected LastTriggeredImage %s, got %s", e, a) } if e, a := config.Details.Causes[0].ImageTrigger.Tag, imageapi.DefaultImageTag; e != a { t.Fatalf("Expected cause tag %s, got %s", e, a) } if e, a := config.Details.Causes[0].ImageTrigger.RepositoryName, newRepoName; e != a { t.Fatalf("Expected cause stream %s, got %s", e, a) } }
func TestCreateOk(t *testing.T) { rest := REST{ generator: Client{ GRFn: func(from, to *deployapi.DeploymentConfig, spec *deployapi.DeploymentConfigRollbackSpec) (*deployapi.DeploymentConfig, error) { return &deployapi.DeploymentConfig{}, nil }, RCFn: func(ctx kapi.Context, name string) (*kapi.ReplicationController, error) { deployment, _ := deployutil.MakeDeployment(deploytest.OkDeploymentConfig(1), kapi.Codec) return deployment, nil }, DCFn: func(ctx kapi.Context, name string) (*deployapi.DeploymentConfig, error) { return deploytest.OkDeploymentConfig(1), nil }, }, codec: api.Codec, } obj, err := rest.Create(kapi.NewDefaultContext(), &deployapi.DeploymentConfigRollback{ Spec: deployapi.DeploymentConfigRollbackSpec{ From: kapi.ObjectReference{ Name: "deployment", Namespace: kapi.NamespaceDefault, }, }, }) if err != nil { t.Errorf("Unexpected error: %v", err) } if obj == nil { t.Errorf("Expected a result obj") } if _, ok := obj.(*deployapi.DeploymentConfig); !ok { t.Errorf("expected a DeploymentConfig, got a %#v", obj) } }
func TestHookExecutor_makeHookPodInvalidContainerRef(t *testing.T) { hook := &deployapi.LifecycleHook{ FailurePolicy: deployapi.LifecycleHookFailurePolicyAbort, ExecNewPod: &deployapi.ExecNewPodHook{ ContainerName: "undefined", }, } deployment, _ := deployutil.MakeDeployment(deploytest.OkDeploymentConfig(1), kapi.Codec) _, err := makeHookPod(hook, deployment, "hook") if err == nil { t.Fatalf("expected an error") } t.Logf("got expected error: %s", err) }
func TestHookExecutor_executeExecNewPodSucceeded(t *testing.T) { hook := &deployapi.LifecycleHook{ FailurePolicy: deployapi.LifecycleHookFailurePolicyAbort, ExecNewPod: &deployapi.ExecNewPodHook{ ContainerName: "container1", }, } config := deploytest.OkDeploymentConfig(1) deployment, _ := deployutil.MakeDeployment(config, kapi.Codec) deployment.Spec.Template.Spec.NodeSelector = map[string]string{"labelKey1": "labelValue1", "labelKey2": "labelValue2"} var createdPod *kapi.Pod executor := &HookExecutor{ PodClient: &HookExecutorPodClientImpl{ CreatePodFunc: func(namespace string, pod *kapi.Pod) (*kapi.Pod, error) { createdPod = pod return createdPod, nil }, PodWatchFunc: func(namespace, name, resourceVersion string, stopChannel chan struct{}) func() *kapi.Pod { createdPod.Status.Phase = kapi.PodSucceeded return func() *kapi.Pod { return createdPod } }, }, } err := executor.executeExecNewPod(hook, deployment, "hook") if err != nil { t.Fatalf("unexpected error: %s", err) } if e, a := deployment.Spec.Template.Spec.NodeSelector, createdPod.Spec.NodeSelector; !reflect.DeepEqual(e, a) { t.Fatalf("expected pod NodeSelector %v, got %v", e, a) } if createdPod.Spec.ActiveDeadlineSeconds == nil { t.Fatalf("expected ActiveDeadlineSeconds to be set on the deployment hook executor pod") } if *createdPod.Spec.ActiveDeadlineSeconds != deployapi.MaxDeploymentDurationSeconds { t.Fatalf("expected ActiveDeadlineSeconds to be set to %d; found: %d", deployapi.MaxDeploymentDurationSeconds, *createdPod.Spec.ActiveDeadlineSeconds) } }
// TestCmdDeploy_retryRejectNonFailed ensures that attempts to retry a non- // failed deployment are rejected. func TestCmdDeploy_retryRejectNonFailed(t *testing.T) { var existingDeployment *kapi.ReplicationController commandClient := &deployCommandClientImpl{ GetDeploymentFn: func(namespace, name string) (*kapi.ReplicationController, error) { return existingDeployment, nil }, UpdateDeploymentConfigFn: func(config *deployapi.DeploymentConfig) (*deployapi.DeploymentConfig, error) { t.Fatalf("unexpected call to UpdateDeploymentConfig") return nil, nil }, UpdateDeploymentFn: func(deployment *kapi.ReplicationController) (*kapi.ReplicationController, error) { t.Fatalf("unexpected call to UpdateDeployment") return nil, nil }, ListDeployerPodsForFn: func(namespace, deploymentName string) (*kapi.PodList, error) { t.Fatalf("unexpected call to ListDeployerPodsFor") return nil, nil }, DeletePodFn: func(pod *kapi.Pod) error { t.Fatalf("unexpected call to DeletePod") return nil }, } c := &retryDeploymentCommand{client: commandClient} invalidStatusList := []deployapi.DeploymentStatus{ deployapi.DeploymentStatusNew, deployapi.DeploymentStatusPending, deployapi.DeploymentStatusRunning, deployapi.DeploymentStatusComplete, } for _, status := range invalidStatusList { config := deploytest.OkDeploymentConfig(1) existingDeployment = deploymentFor(config, status) err := c.retry(config, ioutil.Discard) if err == nil { t.Errorf("expected an error retrying deployment with status %s", status) } } }
func TestHookExecutor_makeHookPodRestart(t *testing.T) { hook := &deployapi.LifecycleHook{ FailurePolicy: deployapi.LifecycleHookFailurePolicyRetry, ExecNewPod: &deployapi.ExecNewPodHook{ ContainerName: "container1", }, } deployment, _ := deployutil.MakeDeployment(deploytest.OkDeploymentConfig(1), kapi.Codec) pod, err := makeHookPod(hook, deployment, "hook") if err != nil { t.Fatalf("unexpected error: %s", err) } if e, a := kapi.RestartPolicyOnFailure, pod.Spec.RestartPolicy; e != a { t.Errorf("expected pod restart policy %s, got %s", e, a) } }
func TestGenerate_reportsInvalidErrorWhenMissingRepo(t *testing.T) { generator := &DeploymentConfigGenerator{ Client: Client{ DCFn: func(ctx kapi.Context, name string) (*deployapi.DeploymentConfig, error) { return deploytest.OkDeploymentConfig(1), nil }, ISFn: func(ctx kapi.Context, name string) (*imageapi.ImageStream, error) { return nil, kerrors.NewNotFound("ImageStream", name) }, }, } _, err := generator.Generate(kapi.NewDefaultContext(), "deploy1") if err == nil || !kerrors.IsInvalid(err) { t.Fatalf("Unexpected error type: %v", err) } if !strings.Contains(err.Error(), "not found") { t.Errorf("unexpected error message: %v", err) } }
// TestCmdDeploy_latestOk ensures that attempts to start a new deployment // succeeds given an existing deployment in a terminal state. func TestCmdDeploy_latestOk(t *testing.T) { var existingDeployment *kapi.ReplicationController var updatedConfig *deployapi.DeploymentConfig commandClient := &deployCommandClientImpl{ GetDeploymentFn: func(namespace, name string) (*kapi.ReplicationController, error) { return existingDeployment, nil }, UpdateDeploymentConfigFn: func(config *deployapi.DeploymentConfig) (*deployapi.DeploymentConfig, error) { updatedConfig = config return config, nil }, UpdateDeploymentFn: func(deployment *kapi.ReplicationController) (*kapi.ReplicationController, error) { t.Fatalf("unexpected call to UpdateDeployment for %s/%s", deployment.Namespace, deployment.Name) return nil, nil }, } c := &deployLatestCommand{client: commandClient} validStatusList := []deployapi.DeploymentStatus{ deployapi.DeploymentStatusComplete, deployapi.DeploymentStatusFailed, } for _, status := range validStatusList { config := deploytest.OkDeploymentConfig(1) existingDeployment = deploymentFor(config, status) err := c.deploy(config, ioutil.Discard) if err != nil { t.Fatalf("unexpected error: %v", err) } if updatedConfig == nil { t.Fatalf("expected updated config") } if e, a := 2, updatedConfig.LatestVersion; e != a { t.Fatalf("expected updated config version %d, got %d", e, a) } } }
// TestHandle_uncorrelatedPod ensures that pods uncorrelated with a deployment // are ignored. func TestHandle_uncorrelatedPod(t *testing.T) { controller := &DeployerPodController{ deploymentClient: &deploymentClientImpl{ updateDeploymentFunc: func(namespace string, deployment *kapi.ReplicationController) (*kapi.ReplicationController, error) { t.Fatalf("unexpected deployment update") return nil, nil }, }, } // Verify no-op deployment, _ := deployutil.MakeDeployment(deploytest.OkDeploymentConfig(1), kapi.Codec) pod := runningPod(deployment) pod.Annotations = make(map[string]string) err := controller.Handle(pod) if err != nil { t.Fatalf("unexpected err: %v", err) } }
func TestDeploy_triggerEnable(t *testing.T) { var updated *deployapi.DeploymentConfig triggerEnabler := &triggerEnabler{ updateConfig: func(namespace string, config *deployapi.DeploymentConfig) (*deployapi.DeploymentConfig, error) { updated = config return config, nil }, } mktrigger := func() deployapi.DeploymentTriggerPolicy { t := deploytest.OkImageChangeTrigger() t.ImageChangeParams.Automatic = false return t } count := 3 config := deploytest.OkDeploymentConfig(1) config.Triggers = []deployapi.DeploymentTriggerPolicy{} for i := 0; i < count; i++ { config.Triggers = append(config.Triggers, mktrigger()) } err := triggerEnabler.enableTriggers(config, ioutil.Discard) if err != nil { t.Fatalf("unexpected error: %v", err) } if updated == nil { t.Fatalf("expected an updated config") } if e, a := count, len(config.Triggers); e != a { t.Fatalf("expected %d triggers, got %d", e, a) } for _, trigger := range config.Triggers { if !trigger.ImageChangeParams.Automatic { t.Errorf("expected trigger to be enabled: %#v", trigger.ImageChangeParams) } } }
// TestCmdDeploy_latestLookupError ensures that an error is thrown when // existing deployments can't be looked up due to some fatal server error. func TestCmdDeploy_latestLookupError(t *testing.T) { commandClient := &deployCommandClientImpl{ GetDeploymentFn: func(namespace, name string) (*kapi.ReplicationController, error) { return nil, fmt.Errorf("fatal GetDeployment error") }, UpdateDeploymentConfigFn: func(config *deployapi.DeploymentConfig) (*deployapi.DeploymentConfig, error) { t.Fatalf("unexpected call to UpdateDeploymentConfig") return nil, nil }, UpdateDeploymentFn: func(deployment *kapi.ReplicationController) (*kapi.ReplicationController, error) { t.Fatalf("unexpected call to UpdateDeployment for %s/%s", deployment.Namespace, deployment.Name) return nil, nil }, } config := deploytest.OkDeploymentConfig(1) c := &deployLatestCommand{client: commandClient} err := c.deploy(config, ioutil.Discard) if err == nil { t.Fatal("expected an error error") } }
func TestGenerate_deprecatedFromConfigWithoutTagChange(t *testing.T) { generator := &DeploymentConfigGenerator{ Client: Client{ DCFn: func(ctx kapi.Context, id string) (*deployapi.DeploymentConfig, error) { config := deploytest.OkDeploymentConfig(1) config.Triggers[0] = deploytest.OkImageChangeTriggerDeprecated() return config, nil }, LISFn: func(ctx kapi.Context) (*imageapi.ImageStreamList, error) { stream := makeStream( "test-image-stream", imageapi.DefaultImageTag, "registry:8080/repo1:ref1", "00000000000000000000000000000001", ) stream.Status.DockerImageRepository = "registry:8080/repo1:ref1" return &imageapi.ImageStreamList{ Items: []imageapi.ImageStream{*stream}, }, nil }, }, } config, err := generator.Generate(kapi.NewDefaultContext(), "deploy1") if err != nil { t.Fatalf("Unexpected error: %v", err) } if config == nil { t.Fatalf("Expected non-nil config") } if config.LatestVersion != 1 { t.Fatalf("Expected config LatestVersion=1, got %d", config.LatestVersion) } }
// TestHandle_podTerminatedFailNoContainerStatus ensures that a failed // deployer pod with no container status results in a transition of the // deployment's status to failed. func TestHandle_podTerminatedFailNoContainerStatus(t *testing.T) { var updatedDeployment *kapi.ReplicationController deployment, _ := deployutil.MakeDeployment(deploytest.OkDeploymentConfig(1), kapi.Codec) // since we do not set the desired replicas annotation, // this also tests that the error is just logged and not result in a failure deployment.Annotations[deployapi.DeploymentStatusAnnotation] = string(deployapi.DeploymentStatusRunning) controller := &DeployerPodController{ deploymentClient: &deploymentClientImpl{ getDeploymentFunc: func(namespace, name string) (*kapi.ReplicationController, error) { return deployment, nil }, updateDeploymentFunc: func(namespace string, deployment *kapi.ReplicationController) (*kapi.ReplicationController, error) { updatedDeployment = deployment return deployment, nil }, listDeploymentsForConfigFunc: func(namespace, configName string) (*kapi.ReplicationControllerList, error) { return &kapi.ReplicationControllerList{Items: []kapi.ReplicationController{*deployment}}, nil }, }, } err := controller.Handle(terminatedPod(deployment)) if err != nil { t.Fatalf("unexpected error: %v", err) } if updatedDeployment == nil { t.Fatalf("expected deployment update") } if e, a := deployapi.DeploymentStatusFailed, deployutil.DeploymentStatusFor(updatedDeployment); e != a { t.Fatalf("expected updated deployment status %s, got %s", e, a) } }