// 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) } }
func TestCreateOk(t *testing.T) { oc := &testclient.Fake{} oc.AddReactor("get", "deploymentconfigs", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) { return true, deploytest.OkDeploymentConfig(2), nil }) kc := &ktestclient.Fake{} kc.AddReactor("get", "replicationcontrollers", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) { deployment, _ := deployutil.MakeDeployment(deploytest.OkDeploymentConfig(1), codec) return true, deployment, nil }) obj, err := NewREST(oc, kc, codec).Create(kapi.NewDefaultContext(), &deployapi.DeploymentConfigRollback{ Name: "config", Spec: deployapi.DeploymentConfigRollbackSpec{ Revision: 1, }, }) 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 deployment config, got a %#v", obj) } }
func TestCreateGeneratorError(t *testing.T) { oc := &testclient.Fake{} oc.AddReactor("get", "deploymentconfigs", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) { return true, deploytest.OkDeploymentConfig(2), nil }) kc := &ktestclient.Fake{} kc.AddReactor("get", "replicationcontrollers", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) { deployment, _ := deployutil.MakeDeployment(deploytest.OkDeploymentConfig(1), codec) return true, deployment, nil }) rest := REST{ generator: &terribleGenerator{}, dn: oc, rn: kc, codec: kapi.Codecs.LegacyCodec(deployv1.SchemeGroupVersion), } _, err := rest.Create(kapi.NewDefaultContext(), &deployapi.DeploymentConfigRollback{ Name: "config", Spec: deployapi.DeploymentConfigRollbackSpec{ Revision: 1, }, }) if err == nil || !strings.Contains(err.Error(), "something terrible happened") { t.Errorf("Unexpected error: %v", err) } }
func TestCreateMissingDeploymentConfig(t *testing.T) { oc := &testclient.Fake{} oc.AddReactor("get", "deploymentconfigs", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) { dc := deploytest.OkDeploymentConfig(2) return true, nil, kerrors.NewNotFound(deployapi.Resource("deploymentConfig"), dc.Name) }) kc := &ktestclient.Fake{} kc.AddReactor("get", "replicationcontrollers", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) { deployment, _ := deployutil.MakeDeployment(deploytest.OkDeploymentConfig(1), codec) return true, deployment, nil }) obj, err := NewREST(oc, kc, codec).Create(kapi.NewDefaultContext(), &deployapi.DeploymentConfigRollback{ Name: "config", Spec: deployapi.DeploymentConfigRollbackSpec{ Revision: 1, }, }) if err == nil { t.Errorf("Expected an error") } if obj != nil { t.Error("Unexpected result obj") } }
func TestCreateInvalidDeployment(t *testing.T) { oc := &testclient.Fake{} oc.AddReactor("get", "deploymentconfigs", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) { return true, deploytest.OkDeploymentConfig(2), nil }) kc := &ktestclient.Fake{} kc.AddReactor("get", "replicationcontrollers", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) { // invalidate the encoded config deployment, _ := deployutil.MakeDeployment(deploytest.OkDeploymentConfig(1), codec) deployment.Annotations[deployapi.DeploymentEncodedConfigAnnotation] = "" return true, deployment, nil }) obj, err := NewREST(oc, kc, codec).Create(kapi.NewDefaultContext(), &deployapi.DeploymentConfigRollback{ Name: "config", Spec: deployapi.DeploymentConfigRollbackSpec{ Revision: 1, }, }) if err == nil { t.Errorf("Expected an error") } if obj != nil { t.Error("Unexpected result obj") } }
// 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) } }
func TestCreateGeneratorErrorDepr(t *testing.T) { rest := DeprecatedREST{ 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.Codecs.LegacyCodec(deployapi.SchemeGroupVersion)) return deployment, nil }, DCFn: func(ctx kapi.Context, name string) (*deployapi.DeploymentConfig, error) { return deploytest.OkDeploymentConfig(1), nil }, }, codec: kapi.Codecs.LegacyCodec(deployapi.SchemeGroupVersion), } _, 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) } }
// TestHandle_cleanupDesiredReplicasAnnotation ensures that the desired replicas annotation // will be cleaned up in a complete deployment and stay around in a failed deployment func TestHandle_cleanupDesiredReplicasAnnotation(t *testing.T) { // shared fixtures shouldn't be used in unit tests shared, _ := deployutil.MakeDeployment(deploytest.OkDeploymentConfig(1), kapi.Codecs.LegacyCodec(deployapi.SchemeGroupVersion)) tests := []struct { name string pod *kapi.Pod expected bool }{ { name: "complete deployment - cleaned up annotation", pod: succeededPod(shared), expected: false, }, { name: "failed deployment - annotation stays", pod: terminatedPod(shared), expected: true, }, } for _, test := range tests { deployment, _ := deployutil.MakeDeployment(deploytest.OkDeploymentConfig(1), kapi.Codecs.LegacyCodec(deployapi.SchemeGroupVersion)) var updatedDeployment *kapi.ReplicationController deployment.Annotations[deployapi.DesiredReplicasAnnotation] = "1" kFake := &ktestclient.Fake{} kFake.PrependReactor("get", "replicationcontrollers", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) { return true, deployment, nil }) kFake.PrependReactor("update", "replicationcontrollers", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) { updatedDeployment = deployment return true, deployment, nil }) controller := &DeployerPodController{ decodeConfig: func(deployment *kapi.ReplicationController) (*deployapi.DeploymentConfig, error) { return deployutil.DecodeDeploymentConfig(deployment, kapi.Codecs.UniversalDecoder()) }, store: cache.NewStore(cache.MetaNamespaceKeyFunc), kClient: kFake, } if err := controller.Handle(test.pod); err != nil { t.Errorf("%s: unexpected error: %v", test.name, err) continue } if updatedDeployment == nil { t.Errorf("%s: expected deployment update", test.name) continue } if _, got := updatedDeployment.Annotations[deployapi.DesiredReplicasAnnotation]; got != test.expected { t.Errorf("%s: expected annotation: %t, got %t", test.name, test.expected, got) } } }
// TestHandle_cleanupPendingRunning ensures that deployer pods are deleted // for deployments in post-New phases. func TestHandle_cleanupPendingRunning(t *testing.T) { hookPods := []string{"pre", "post"} deletedPods := 0 deployment, _ := deployutil.MakeDeployment(deploytest.OkDeploymentConfig(1), codec) deployment.Annotations[deployapi.DeploymentCancelledAnnotation] = deployapi.DeploymentCancelledAnnotationValue fake := &ktestclient.Fake{} fake.AddReactor("delete", "pods", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) { deletedPods++ return true, nil, nil }) fake.AddReactor("update", "replicationcontrollers", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) { // None of these tests should transition the phase. t.Errorf("unexpected call to update a deployment") return true, nil, nil }) controller := okDeploymentController(fake, deployment, hookPods, true) for _, status := range []deployapi.DeploymentStatus{deployapi.DeploymentStatusPending, deployapi.DeploymentStatusRunning} { deletedPods = 0 deployment.Annotations[deployapi.DeploymentStatusAnnotation] = string(status) if err := controller.Handle(deployment); err != nil { t.Fatalf("unexpected error: %v", err) } if e, a := len(hookPods)+1, deletedPods; e != a { t.Fatalf("expected %d deleted pods, got %d", e, a) } } }
// TestHandle_cleanupPodFail ensures that a failed attempt to clean up the // deployer pod for a completed deployment results in an actionable error. func TestHandle_cleanupPodFail(t *testing.T) { fake := &ktestclient.Fake{} fake.AddReactor("delete", "pods", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) { return true, nil, kerrors.NewInternalError(fmt.Errorf("deployer pod internal error")) }) fake.AddReactor("create", "pods", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) { t.Fatalf("unexpected call to create pod") return true, nil, nil }) fake.AddReactor("update", "replicationcontrollers", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) { t.Fatalf("unexpected deployment update") return true, nil, nil }) // Verify error config := deploytest.OkDeploymentConfig(1) deployment, _ := deployutil.MakeDeployment(config, codec) deployment.Annotations[deployapi.DeploymentStatusAnnotation] = string(deployapi.DeploymentStatusComplete) controller := okDeploymentController(fake, deployment, nil, true) err := controller.Handle(deployment) if err == nil { t.Fatal("expected an actionable error") } if _, isActionable := err.(actionableError); !isActionable { t.Fatalf("expected an actionable error, got %#v", err) } }
// TestHandle_failedTest ensures that failed test deployments have their // replicas set to zero. func TestHandle_failedTest(t *testing.T) { var updatedDeployment *kapi.ReplicationController fake := &ktestclient.Fake{} fake.AddReactor("create", "pods", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) { t.Fatalf("unexpected call to create pod") return true, nil, nil }) fake.AddReactor("update", "replicationcontrollers", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) { rc := action.(ktestclient.UpdateAction).GetObject().(*kapi.ReplicationController) updatedDeployment = rc return true, rc, nil }) // Verify successful cleanup config := deploytest.TestDeploymentConfig(deploytest.OkDeploymentConfig(1)) deployment, _ := deployutil.MakeDeployment(config, codec) deployment.Spec.Replicas = 1 deployment.Annotations[deployapi.DeploymentStatusAnnotation] = string(deployapi.DeploymentStatusFailed) controller := okDeploymentController(fake, deployment, nil, true) if err := controller.Handle(deployment); err != nil { t.Fatalf("unexpected error: %v", err) } if updatedDeployment == nil { t.Fatal("deployment not updated") } if e, a := int32(0), updatedDeployment.Spec.Replicas; e != a { t.Fatalf("expected updated deployment replicas to be %d, got %d", e, a) } }
// TestHandle_deployerPodAlreadyExists ensures that attempts to create a // deployer pod which was already created don't result in an error // (effectively skipping the handling as redundant). func TestHandle_deployerPodAlreadyExists(t *testing.T) { var updatedDeployment *kapi.ReplicationController config := deploytest.OkDeploymentConfig(1) deployment, _ := deployutil.MakeDeployment(config, codec) deployment.Annotations[deployapi.DeploymentStatusAnnotation] = string(deployapi.DeploymentStatusNew) deployerPodName := deployutil.DeployerPodNameForDeployment(deployment.Name) fake := &ktestclient.Fake{} fake.AddReactor("create", "pods", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) { name := action.(ktestclient.CreateAction).GetObject().(*kapi.Pod).Name return true, nil, kerrors.NewAlreadyExists(kapi.Resource("Pod"), name) }) fake.AddReactor("update", "replicationcontrollers", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) { rc := action.(ktestclient.UpdateAction).GetObject().(*kapi.ReplicationController) updatedDeployment = rc return true, rc, nil }) controller := okDeploymentController(fake, deployment, nil, true) if err := controller.Handle(deployment); err != nil { t.Fatalf("unexpected error: %v", err) } if updatedDeployment.Annotations[deployapi.DeploymentPodAnnotation] != deployerPodName { t.Fatalf("deployment not updated with pod name annotation") } if updatedDeployment.Annotations[deployapi.DeploymentStatusAnnotation] != string(deployapi.DeploymentStatusPending) { t.Fatalf("deployment status not updated to pending") } }
// 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.Spec.Triggers = []deployapi.DeploymentTriggerPolicy{} err := controller.Handle(config) if err != nil { t.Fatalf("unexpected error: %v", err) } }
func TestRecreate_deploymentPreHookSuccess(t *testing.T) { config := deploytest.OkDeploymentConfig(1) config.Spec.Strategy = recreateParams(30, deployapi.LifecycleHookFailurePolicyAbort, "", "") deployment, _ := deployutil.MakeDeployment(config, kapi.Codecs.LegacyCodec(registered.GroupOrDie(kapi.GroupName).GroupVersions[0])) scaler := &cmdtest.FakeScaler{} hookExecuted := false strategy := &RecreateDeploymentStrategy{ out: &bytes.Buffer{}, errOut: &bytes.Buffer{}, decoder: kapi.Codecs.UniversalDecoder(), retryTimeout: 1 * time.Second, retryPeriod: 1 * time.Millisecond, getUpdateAcceptor: getUpdateAcceptor, eventClient: fake.NewSimpleClientset().Core(), rcClient: &fakeControllerClient{deployment: deployment}, hookExecutor: &hookExecutorImpl{ executeFunc: func(hook *deployapi.LifecycleHook, deployment *kapi.ReplicationController, suffix, label string) error { hookExecuted = true return nil }, }, scaler: scaler, } err := strategy.Deploy(nil, deployment, 2) if err != nil { t.Fatalf("unexpected deploy error: %#v", err) } if !hookExecuted { t.Fatalf("expected hook execution") } }
// 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) { fake := &testclient.Fake{} fake.AddReactor("update", "deploymentconfigs", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) { t.Fatalf("unexpected deploymentconfig update") return true, nil, nil }) controller := NewImageChangeController(dcInformer, streamInformer, fake) config := testapi.OkDeploymentConfig(1) config.Namespace = kapi.NamespaceDefault config.Spec.Triggers[0].ImageChangeParams.Automatic = false // The image has been resolved at least once before. config.Spec.Triggers[0].ImageChangeParams.LastTriggeredImage = testapi.DockerImageReference controller.dcLister.Add(config) // verify no-op tagUpdate := makeStream(testapi.ImageStreamName, imageapi.DefaultImageTag, testapi.DockerImageReference, testapi.ImageID) if err := controller.Handle(tagUpdate); err != nil { t.Fatalf("unexpected err: %v", err) } if len(fake.Actions()) > 0 { t.Fatalf("unexpected actions: %v", fake.Actions()) } }
func TestRecreate_deploymentMidHookFail(t *testing.T) { config := deploytest.OkDeploymentConfig(1) config.Spec.Strategy = recreateParams(30, "", deployapi.LifecycleHookFailurePolicyAbort, "") deployment, _ := deployutil.MakeDeployment(config, kapi.Codecs.LegacyCodec(deployv1.SchemeGroupVersion)) scaler := &cmdtest.FakeScaler{} strategy := &RecreateDeploymentStrategy{ out: &bytes.Buffer{}, errOut: &bytes.Buffer{}, decoder: kapi.Codecs.UniversalDecoder(), retryTimeout: 1 * time.Second, retryPeriod: 1 * time.Millisecond, rcClient: &fakeControllerClient{deployment: deployment}, eventClient: fake.NewSimpleClientset().Core(), getUpdateAcceptor: getUpdateAcceptor, hookExecutor: &hookExecutorImpl{ executeFunc: func(hook *deployapi.LifecycleHook, deployment *kapi.ReplicationController, suffix, label string) error { return fmt.Errorf("hook execution failure") }, }, scaler: scaler, } err := strategy.Deploy(nil, deployment, 2) if err == nil { t.Fatalf("expected a deploy error") } if len(scaler.Events) > 0 { t.Fatalf("unexpected scaling events: %v", scaler.Events) } }
func TestRecreate_initialDeployment(t *testing.T) { var deployment *kapi.ReplicationController scaler := &cmdtest.FakeScaler{} strategy := &RecreateDeploymentStrategy{ out: &bytes.Buffer{}, errOut: &bytes.Buffer{}, decoder: kapi.Codecs.UniversalDecoder(), retryTimeout: 1 * time.Second, retryPeriod: 1 * time.Millisecond, getUpdateAcceptor: getUpdateAcceptor, scaler: scaler, eventClient: fake.NewSimpleClientset().Core(), } config := deploytest.OkDeploymentConfig(1) config.Spec.Strategy = recreateParams(30, "", "", "") deployment, _ = deployutil.MakeDeployment(config, kapi.Codecs.LegacyCodec(registered.GroupOrDie(kapi.GroupName).GroupVersions[0])) strategy.rcClient = &fakeControllerClient{deployment: deployment} err := strategy.Deploy(nil, deployment, 3) if err != nil { t.Fatalf("unexpected deploy error: %#v", err) } if e, a := 1, len(scaler.Events); e != a { t.Fatalf("expected %d scale calls, got %d", e, a) } if e, a := uint(3), scaler.Events[0].Size; e != a { t.Errorf("expected scale up to %d, got %d", e, a) } }
// TestHandle_changeForInitialNonAutomaticDeployment ensures that an image update for which // there is a matching trigger will actually update the deployment config if it hasn't been // deployed before. func TestHandle_changeForInitialNonAutomaticDeployment(t *testing.T) { fake := &testclient.Fake{} controller := NewImageChangeController(dcInformer, streamInformer, fake) config := testapi.OkDeploymentConfig(0) config.Namespace = kapi.NamespaceDefault config.Spec.Triggers[0].ImageChangeParams.Automatic = false config.Spec.Triggers[0].ImageChangeParams.From.Namespace = kapi.NamespaceDefault controller.dcLister.Indexer.Add(config) tagUpdate := makeStream(testapi.ImageStreamName, imageapi.DefaultImageTag, testapi.DockerImageReference, testapi.ImageID) if err := controller.Handle(tagUpdate); err != nil { t.Fatalf("unexpected err: %v", err) } actions := fake.Actions() if len(actions) != 1 { t.Fatalf("unexpected amount of actions: expected 1, got %d (%v)", len(actions), actions) } if !actions[0].Matches("update", "deploymentconfigs") { t.Fatalf("unexpected action: %v", actions[0]) } }
// 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 } }, }, podLogDestination: ioutil.Discard, podLogStream: func(namespace, name string, opts *kapi.PodLogOptions) (io.ReadCloser, error) { return nil, fmt.Errorf("can't access logs") }, } err := executor.executeExecNewPod(hook, deployment, "hook") if err == nil { t.Fatalf("expected an error, got none") } t.Logf("got expected error: %s", err) }
// TestHandle_createPodFail ensures that an an API failure while creating a // deployer pod results in a nonfatal error. func TestHandle_createPodFail(t *testing.T) { var updatedDeployment *kapi.ReplicationController fake := &ktestclient.Fake{} fake.AddReactor("create", "pods", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) { name := action.(ktestclient.CreateAction).GetObject().(*kapi.Pod).Name return true, nil, fmt.Errorf("failed to create pod %q", name) }) fake.AddReactor("update", "replicationcontrollers", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) { rc := action.(ktestclient.UpdateAction).GetObject().(*kapi.ReplicationController) updatedDeployment = rc return true, rc, nil }) config := deploytest.OkDeploymentConfig(1) deployment, _ := deployutil.MakeDeployment(config, codec) deployment.Annotations[deployapi.DeploymentStatusAnnotation] = string(deployapi.DeploymentStatusNew) controller := okDeploymentController(fake, nil, nil, true) err := controller.Handle(deployment) if err == nil { t.Fatalf("expected an error") } if _, isFatal := err.(fatalError); isFatal { t.Fatalf("expected a nonfatal error, got a %#v", err) } }
// 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.Codecs.LegacyCodec(deployapi.SchemeGroupVersion)) deployment.Annotations[deployapi.DeploymentStatusAnnotation] = string(deployapi.DeploymentStatusPending) var updatedDeployment *kapi.ReplicationController kFake := &ktestclient.Fake{} kFake.PrependReactor("get", "replicationcontrollers", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) { return true, deployment, nil }) kFake.PrependReactor("update", "replicationcontrollers", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) { updatedDeployment = deployment return true, deployment, nil }) controller := &DeployerPodController{ store: cache.NewStore(cache.MetaNamespaceKeyFunc), kClient: kFake, } 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) } }
// TestHandle_noop ensures that pending, running, and failed states result in // no action by the controller (as these represent in-progress or terminal // states). func TestHandle_noop(t *testing.T) { fake := &ktestclient.Fake{} fake.AddReactor("create", "pods", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) { t.Fatalf("unexpected call to create pod") return true, nil, nil }) fake.AddReactor("update", "replicationcontrollers", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) { t.Fatalf("unexpected deployment update") return true, nil, nil }) // Verify no-op config := deploytest.OkDeploymentConfig(1) deployment, _ := deployutil.MakeDeployment(config, codec) noopStatus := []deployapi.DeploymentStatus{ deployapi.DeploymentStatusPending, deployapi.DeploymentStatusRunning, deployapi.DeploymentStatusFailed, } for _, status := range noopStatus { deployment.Annotations[deployapi.DeploymentStatusAnnotation] = string(status) controller := okDeploymentController(fake, deployment, nil, true) if err := controller.Handle(deployment); err != nil { t.Fatalf("unexpected error: %v", err) } } }
func TestRolling_deployInitial(t *testing.T) { initialStrategyInvoked := false strategy := &RollingDeploymentStrategy{ codec: api.Codec, client: ktestclient.NewSimpleFake(), initialStrategy: &testStrategy{ deployFn: func(from *kapi.ReplicationController, to *kapi.ReplicationController, desiredReplicas int, updateAcceptor strat.UpdateAcceptor) error { initialStrategyInvoked = true return nil }, }, rollingUpdate: func(config *kubectl.RollingUpdaterConfig) error { t.Fatalf("unexpected call to rollingUpdate") return nil }, getUpdateAcceptor: getUpdateAcceptor, apiRetryPeriod: 1 * time.Millisecond, apiRetryTimeout: 10 * time.Millisecond, } 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_cleanupPodNoop ensures that an attempt to delete pods are not made // if the deployer pods are not listed based on a label query func TestHandle_cleanupPodNoop(t *testing.T) { fake := &ktestclient.Fake{} fake.AddReactor("delete", "pods", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) { t.Fatalf("unexpected call to delete pod") return true, nil, nil }) fake.AddReactor("create", "pods", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) { t.Fatalf("unexpected call to create pod") return true, nil, nil }) fake.AddReactor("update", "replicationcontrollers", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) { t.Fatalf("unexpected deployment update") return true, nil, nil }) // Verify no-op config := deploytest.OkDeploymentConfig(1) deployment, _ := deployutil.MakeDeployment(config, codec) deployment.Annotations[deployapi.DeploymentStatusAnnotation] = string(deployapi.DeploymentStatusComplete) controller := okDeploymentController(fake, deployment, nil, true) pod := deployerPod(deployment, "", true) pod.Labels[deployapi.DeployerPodForDeploymentLabel] = "unrelated" controller.podStore.Update(pod) if err := controller.Handle(deployment); err != nil { t.Fatalf("unexpected error: %v", err) } }
func TestHookExecutor_executeExecNewCreatePodFailure(t *testing.T) { hook := &deployapi.LifecycleHook{ FailurePolicy: deployapi.LifecycleHookFailurePolicyAbort, ExecNewPod: &deployapi.ExecNewPodHook{ ContainerName: "container1", }, } deployment, _ := deployutil.MakeDeployment(deploytest.OkDeploymentConfig(1), kapi.Codecs.LegacyCodec(deployapi.SchemeGroupVersion)) executor := &HookExecutor{ podClient: &HookExecutorPodClientImpl{ CreatePodFunc: func(namespace string, pod *kapi.Pod) (*kapi.Pod, error) { return nil, fmt.Errorf("couldn't create pod") }, PodWatchFunc: func(namespace, name, resourceVersion string, stopChannel chan struct{}) func() *kapi.Pod { return func() *kapi.Pod { return nil } }, }, decoder: kapi.Codecs.UniversalDecoder(), } err := executor.executeExecNewPod(hook, deployment, "hook", "test") if err == nil { t.Fatalf("expected an error") } t.Logf("got expected error: %s", err) }
func TestHandle_cancelNew(t *testing.T) { var updatedDeployment *kapi.ReplicationController fake := &ktestclient.Fake{} fake.AddReactor("create", "pods", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) { t.Fatalf("unexpected call to create pod") return true, nil, nil }) fake.AddReactor("update", "replicationcontrollers", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) { rc := action.(ktestclient.UpdateAction).GetObject().(*kapi.ReplicationController) updatedDeployment = rc return true, rc, nil }) deployment, _ := deployutil.MakeDeployment(deploytest.OkDeploymentConfig(1), codec) deployment.Annotations[deployapi.DeploymentStatusAnnotation] = string(deployapi.DeploymentStatusNew) deployment.Annotations[deployapi.DeploymentCancelledAnnotation] = deployapi.DeploymentCancelledAnnotationValue controller := okDeploymentController(fake, deployment, nil, true) if err := controller.Handle(deployment); err != nil { t.Fatalf("unexpected error: %v", err) } if e, a := deployapi.DeploymentStatusPending, deployutil.DeploymentStatusFor(updatedDeployment); e != a { t.Fatalf("expected deployment status %s, got %s", e, a) } }
// 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_deployerPodDisappeared ensures that a pending/running deployment // is failed when its deployer pod vanishes. func TestHandle_deployerPodDisappeared(t *testing.T) { var updatedDeployment *kapi.ReplicationController updateCalled := false fake := &ktestclient.Fake{} fake.AddReactor("update", "replicationcontrollers", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) { rc := action.(ktestclient.UpdateAction).GetObject().(*kapi.ReplicationController) updatedDeployment = rc updateCalled = true return true, nil, nil }) deployment, _ := deployutil.MakeDeployment(deploytest.OkDeploymentConfig(1), codec) deployment.Annotations[deployapi.DeploymentStatusAnnotation] = string(deployapi.DeploymentStatusRunning) controller := okDeploymentController(fake, nil, nil, true) if err := controller.Handle(deployment); err != nil { t.Fatalf("unexpected error: %v", err) } if !updateCalled { t.Fatalf("expected update") } if e, a := deployapi.DeploymentStatusFailed, deployutil.DeploymentStatusFor(updatedDeployment); e != a { t.Fatalf("expected deployment status %s, got %s", e, a) } }
// 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) } }