github.com/cloudfoundry/cli@v7.1.0+incompatible/command/v6/update_service_command_test.go (about)

     1  package v6_test
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  
     7  	"code.cloudfoundry.org/cli/actor/actionerror"
     8  
     9  	"code.cloudfoundry.org/cli/actor/v2action"
    10  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccversion"
    11  	"code.cloudfoundry.org/cli/command/commandfakes"
    12  	"code.cloudfoundry.org/cli/command/flag"
    13  	"code.cloudfoundry.org/cli/command/translatableerror"
    14  	. "code.cloudfoundry.org/cli/command/v6"
    15  	"code.cloudfoundry.org/cli/command/v6/v6fakes"
    16  	"code.cloudfoundry.org/cli/util/configv3"
    17  	"code.cloudfoundry.org/cli/util/ui"
    18  	. "github.com/onsi/ginkgo"
    19  	. "github.com/onsi/gomega"
    20  	. "github.com/onsi/gomega/gbytes"
    21  )
    22  
    23  var _ = Describe("update-service Command", func() {
    24  
    25  	const (
    26  		serviceInstanceName = "my-service"
    27  		spaceGUID           = "space-guid"
    28  		instanceGUID        = "instance-guid"
    29  		planGUID            = "plan-guid"
    30  		username            = "cf-user"
    31  	)
    32  
    33  	var (
    34  		cmd             UpdateServiceCommand
    35  		fakeActor       *v6fakes.FakeUpdateServiceActor
    36  		fakeSharedActor *commandfakes.FakeSharedActor
    37  		fakeConfig      *commandfakes.FakeConfig
    38  		testUI          *ui.UI
    39  		input           *Buffer
    40  		executeErr      error
    41  		extraArgs       []string
    42  
    43  		space = configv3.Space{Name: "space-a", GUID: spaceGUID}
    44  
    45  		sayUpdatingServiceInstanceByCurrentUser = Say("Updating service instance %s as %s...", serviceInstanceName, username)
    46  	)
    47  
    48  	BeforeEach(func() {
    49  		input = NewBuffer()
    50  		testUI = ui.NewTestUI(input, NewBuffer(), NewBuffer())
    51  		fakeActor = new(v6fakes.FakeUpdateServiceActor)
    52  		fakeSharedActor = new(commandfakes.FakeSharedActor)
    53  		fakeConfig = new(commandfakes.FakeConfig)
    54  
    55  		fakeConfig.TargetedSpaceReturns(space)
    56  		fakeConfig.CurrentUserNameReturns(username, nil)
    57  
    58  		extraArgs = []string{}
    59  
    60  		cmd = UpdateServiceCommand{
    61  			UI:           testUI,
    62  			Actor:        fakeActor,
    63  			SharedActor:  fakeSharedActor,
    64  			Config:       fakeConfig,
    65  			RequiredArgs: flag.ServiceInstance{ServiceInstance: serviceInstanceName},
    66  		}
    67  	})
    68  
    69  	JustBeforeEach(func() {
    70  		executeErr = cmd.Execute(extraArgs)
    71  	})
    72  
    73  	When("not upgrading", func() {
    74  		It("returns UnrefactoredCommandError", func() {
    75  			// delegates non-upgrades to legacy code
    76  			Expect(executeErr).To(MatchError(translatableerror.UnrefactoredCommandError{}))
    77  		})
    78  	})
    79  
    80  	When("combining upgrade with other flags", func() {
    81  		BeforeEach(func() {
    82  			cmd.Upgrade = true
    83  		})
    84  
    85  		When("tags provided", func() {
    86  			BeforeEach(func() {
    87  				cmd.Tags = "tags"
    88  			})
    89  
    90  			It("returns UpgradeArgumentCombinationError", func() {
    91  				Expect(executeErr).To(MatchError(translatableerror.ArgumentCombinationError{
    92  					Args: []string{"--upgrade", "-t", "-c", "-p"},
    93  				}))
    94  			})
    95  		})
    96  
    97  		When("parameters provided", func() {
    98  			BeforeEach(func() {
    99  				cmd.ParametersAsJSON = "{\"some\": \"stuff\"}"
   100  			})
   101  
   102  			It("returns UpgradeArgumentCombinationError", func() {
   103  				Expect(executeErr).To(MatchError(translatableerror.ArgumentCombinationError{
   104  					Args: []string{"--upgrade", "-t", "-c", "-p"},
   105  				}))
   106  			})
   107  		})
   108  
   109  		When("plan provided", func() {
   110  			BeforeEach(func() {
   111  				cmd.Plan = "new-plan"
   112  			})
   113  
   114  			It("returns UpgradeArgumentCombinationError", func() {
   115  				Expect(executeErr).To(MatchError(translatableerror.ArgumentCombinationError{
   116  					Args: []string{"--upgrade", "-t", "-c", "-p"},
   117  				}))
   118  			})
   119  		})
   120  	})
   121  
   122  	When("upgrading", func() {
   123  		BeforeEach(func() {
   124  			cmd.Upgrade = true
   125  		})
   126  
   127  		When("the version of CC API is less than minimum version supporting maintenance_info updates", func() {
   128  			BeforeEach(func() {
   129  				fakeActor.CloudControllerAPIVersionReturns(ccversion.MinSupportedV2ClientVersion)
   130  			})
   131  
   132  			It("should warn the user that the version of CAPI is too low and exit with an error", func() {
   133  				Expect(executeErr).To(MatchError(translatableerror.MinimumCFAPIVersionNotMetError{
   134  					Command:        "Option '--upgrade'",
   135  					CurrentVersion: ccversion.MinSupportedV2ClientVersion,
   136  					MinimumVersion: ccversion.MinVersionUpdateServiceInstanceMaintenanceInfoV2,
   137  				}))
   138  			})
   139  		})
   140  
   141  		When("the version of CC API supports maintenance_info updates", func() {
   142  			BeforeEach(func() {
   143  				fakeActor.CloudControllerAPIVersionReturns(ccversion.MinVersionUpdateServiceInstanceMaintenanceInfoV2)
   144  			})
   145  
   146  			It("checks the user is logged in, and targeting an org and space", func() {
   147  				Expect(fakeSharedActor.CheckTargetCallCount()).To(Equal(1))
   148  				orgChecked, spaceChecked := fakeSharedActor.CheckTargetArgsForCall(0)
   149  				Expect(orgChecked).To(BeTrue())
   150  				Expect(spaceChecked).To(BeTrue())
   151  			})
   152  
   153  			When("checking the target succeeds", func() {
   154  				When("getting the service instance succeeds", func() {
   155  					var (
   156  						serviceInstance v2action.ServiceInstance
   157  					)
   158  
   159  					BeforeEach(func() {
   160  						serviceInstance = v2action.ServiceInstance{
   161  							Name:            serviceInstanceName,
   162  							GUID:            instanceGUID,
   163  							ServicePlanGUID: planGUID,
   164  						}
   165  						fakeActor.GetServiceInstanceByNameAndSpaceReturns(
   166  							serviceInstance,
   167  							v2action.Warnings{"warning"},
   168  							nil)
   169  					})
   170  
   171  					It("displays any warnings", func() {
   172  						Expect(testUI.Err).To(Say("warning"))
   173  					})
   174  
   175  					It("prompts the user about the upgrade", func() {
   176  						Expect(testUI.Out).To(Say("You are about to update %s\\.", serviceInstanceName))
   177  						Expect(testUI.Out).To(Say("Warning: This operation may be long running and will block further operations on the service until complete\\."))
   178  						Expect(testUI.Out).To(Say("Really update service %s\\? \\[yN\\]:", serviceInstanceName))
   179  					})
   180  
   181  					When("user refuses to proceed with the upgrade", func() {
   182  						BeforeEach(func() {
   183  							_, err := input.Write([]byte("n\n"))
   184  							Expect(err).NotTo(HaveOccurred())
   185  						})
   186  
   187  						It("does not send an upgrade request", func() {
   188  							Expect(fakeActor.UpgradeServiceInstanceCallCount()).To(Equal(0))
   189  						})
   190  
   191  						It("does not mention that it is updating a service", func() {
   192  							Expect(testUI.Out).ToNot(sayUpdatingServiceInstanceByCurrentUser)
   193  						})
   194  
   195  						It("cancels the update", func() {
   196  							Expect(executeErr).NotTo(HaveOccurred())
   197  							Expect(testUI.Out).To(Say("Update cancelled"))
   198  						})
   199  					})
   200  
   201  					When("user goes ahead with the upgrade", func() {
   202  						BeforeEach(func() {
   203  							_, err := input.Write([]byte("y\n"))
   204  							Expect(err).NotTo(HaveOccurred())
   205  						})
   206  
   207  						It("mentions which service instance was updated by which user", func() {
   208  							Expect(testUI.Out).To(sayUpdatingServiceInstanceByCurrentUser)
   209  						})
   210  
   211  						It("sends an upgrade request", func() {
   212  							Expect(fakeActor.UpgradeServiceInstanceCallCount()).To(Equal(1), "upgrade should be requested")
   213  
   214  							actualServiceInstance := fakeActor.UpgradeServiceInstanceArgsForCall(0)
   215  							Expect(actualServiceInstance).To(Equal(serviceInstance))
   216  						})
   217  
   218  						When("the update request succeeds", func() {
   219  							It("says that the update was successful", func() {
   220  								Expect(executeErr).NotTo(HaveOccurred())
   221  								Expect(testUI.Out).To(Say("OK"))
   222  							})
   223  						})
   224  
   225  						When("the update request fails", func() {
   226  							BeforeEach(func() {
   227  								fakeActor.UpgradeServiceInstanceReturns(
   228  									v2action.Warnings{},
   229  									fmt.Errorf("bad things happened"),
   230  								)
   231  							})
   232  
   233  							It("says that the update has failed", func() {
   234  								Expect(executeErr).To(MatchError("bad things happened"))
   235  							})
   236  						})
   237  
   238  						When("the update request fails with upgrade not available error", func() {
   239  							BeforeEach(func() {
   240  								fakeActor.UpgradeServiceInstanceReturns(
   241  									v2action.Warnings{},
   242  									actionerror.ServiceUpgradeNotAvailableError{},
   243  								)
   244  							})
   245  
   246  							It("says that the update has failed", func() {
   247  								expectedErr := translatableerror.TipDecoratorError{
   248  									BaseError: actionerror.ServiceUpgradeNotAvailableError{},
   249  									Tip:       "To find out if upgrade is available run `cf service {{.ServiceName}}`.",
   250  									TipKeys: map[string]interface{}{
   251  										"ServiceName": serviceInstanceName,
   252  									},
   253  								}
   254  								Expect(executeErr).To(MatchError(expectedErr))
   255  							})
   256  						})
   257  
   258  						When("there are warnings", func() {
   259  							BeforeEach(func() {
   260  								fakeActor.UpgradeServiceInstanceReturns(
   261  									v2action.Warnings{"fake upgrade warning 1", "fake upgrade warning 2"},
   262  									nil,
   263  								)
   264  							})
   265  
   266  							It("outputs the warnings", func() {
   267  								Expect(testUI.Err).To(Say("fake upgrade warning 1"))
   268  								Expect(testUI.Err).To(Say("fake upgrade warning 2"))
   269  							})
   270  
   271  							It("can still output OK", func() {
   272  								Expect(testUI.Out).To(Say("OK"))
   273  							})
   274  						})
   275  					})
   276  
   277  					When("user presses return", func() {
   278  						BeforeEach(func() {
   279  							_, err := input.Write([]byte("\n"))
   280  							Expect(err).NotTo(HaveOccurred())
   281  						})
   282  
   283  						It("cancels the update", func() {
   284  							Expect(testUI.Out).To(Say("Update cancelled"))
   285  							Expect(executeErr).NotTo(HaveOccurred())
   286  						})
   287  					})
   288  
   289  					When("user does not answer", func() {
   290  						It("fails", func() {
   291  							Expect(executeErr).To(MatchError("EOF"))
   292  						})
   293  					})
   294  
   295  					When("--force is provided", func() {
   296  						BeforeEach(func() {
   297  							cmd.ForceUpgrade = true
   298  						})
   299  
   300  						It("mentions which service instance was updated by which user", func() {
   301  							Expect(testUI.Out).To(sayUpdatingServiceInstanceByCurrentUser)
   302  						})
   303  
   304  						It("sends an upgrade request", func() {
   305  							Expect(fakeActor.UpgradeServiceInstanceCallCount()).To(Equal(1), "upgrade should be requested")
   306  
   307  							actualServiceInstance := fakeActor.UpgradeServiceInstanceArgsForCall(0)
   308  							Expect(actualServiceInstance).To(Equal(serviceInstance))
   309  						})
   310  					})
   311  				})
   312  
   313  				When("getting the service instance fails", func() {
   314  					BeforeEach(func() {
   315  						fakeActor.GetServiceInstanceByNameAndSpaceReturns(v2action.ServiceInstance{}, v2action.Warnings{"warning"}, errors.New("explode"))
   316  					})
   317  
   318  					It("propagates the error", func() {
   319  						Expect(executeErr).To(MatchError("explode"))
   320  					})
   321  
   322  					It("displays any warnings", func() {
   323  						Expect(testUI.Err).To(Say("warning"))
   324  					})
   325  				})
   326  			})
   327  
   328  			When("too many arguments are provided", func() {
   329  				BeforeEach(func() {
   330  					extraArgs = []string{"extra"}
   331  				})
   332  
   333  				It("returns a TooManyArgumentsError", func() {
   334  					Expect(executeErr).To(MatchError(translatableerror.TooManyArgumentsError{
   335  						ExtraArgument: "extra",
   336  					}))
   337  				})
   338  			})
   339  
   340  			When("checking the target returns an error", func() {
   341  				BeforeEach(func() {
   342  					fakeSharedActor.CheckTargetReturns(errors.New("explode"))
   343  				})
   344  
   345  				It("returns an error", func() {
   346  					Expect(executeErr).To(MatchError("explode"))
   347  				})
   348  			})
   349  		})
   350  	})
   351  })