github.com/sleungcy/cli@v7.1.0+incompatible/command/v7/update_buildpack_command_test.go (about)

     1  package v7_test
     2  
     3  import (
     4  	"errors"
     5  
     6  	"code.cloudfoundry.org/cli/actor/v7action"
     7  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccerror"
     8  	"code.cloudfoundry.org/cli/command/v7/v7fakes"
     9  	"code.cloudfoundry.org/cli/types"
    10  
    11  	"code.cloudfoundry.org/cli/command/translatableerror"
    12  
    13  	"code.cloudfoundry.org/cli/actor/actionerror"
    14  	"code.cloudfoundry.org/cli/command/commandfakes"
    15  	"code.cloudfoundry.org/cli/command/flag"
    16  	. "code.cloudfoundry.org/cli/command/v7"
    17  	"code.cloudfoundry.org/cli/util/configv3"
    18  	"code.cloudfoundry.org/cli/util/ui"
    19  	. "github.com/onsi/ginkgo"
    20  	. "github.com/onsi/gomega"
    21  	. "github.com/onsi/gomega/gbytes"
    22  )
    23  
    24  var _ = Describe("UpdateBuildpackCommand", func() {
    25  	var (
    26  		cmd             UpdateBuildpackCommand
    27  		fakeSharedActor *commandfakes.FakeSharedActor
    28  		testUI          *ui.UI
    29  		input           *Buffer
    30  		fakeActor       *v7fakes.FakeActor
    31  		fakeConfig      *commandfakes.FakeConfig
    32  		buildpackGUID   = "buildpack-guid"
    33  		buildpackName   = "some-bp"
    34  		binaryName      = "faceman"
    35  
    36  		executeErr  error
    37  		expectedErr error
    38  	)
    39  
    40  	BeforeEach(func() {
    41  		fakeSharedActor = new(commandfakes.FakeSharedActor)
    42  		input = NewBuffer()
    43  		testUI = ui.NewTestUI(input, NewBuffer(), NewBuffer())
    44  		fakeActor = new(v7fakes.FakeActor)
    45  		fakeConfig = new(commandfakes.FakeConfig)
    46  		buildpackGUID = "some guid"
    47  
    48  		cmd = UpdateBuildpackCommand{
    49  			RequiredArgs: flag.BuildpackName{Buildpack: buildpackName},
    50  			BaseCommand: BaseCommand{
    51  				UI:          testUI,
    52  				SharedActor: fakeSharedActor,
    53  				Actor:       fakeActor,
    54  				Config:      fakeConfig,
    55  			},
    56  		}
    57  	})
    58  
    59  	JustBeforeEach(func() {
    60  		executeErr = cmd.Execute(nil)
    61  	})
    62  
    63  	Describe("invalid flag combinations", func() {
    64  		When("the --lock and --unlock flags are provided", func() {
    65  			BeforeEach(func() {
    66  				cmd.Lock = true
    67  				cmd.Unlock = true
    68  			})
    69  
    70  			It("returns an ArgumentCombinationError", func() {
    71  				Expect(executeErr).To(MatchError(translatableerror.ArgumentCombinationError{
    72  					Args: []string{"--lock", "--unlock"},
    73  				}))
    74  			})
    75  		})
    76  
    77  		When("the --enable and --disable flags are provided", func() {
    78  			BeforeEach(func() {
    79  				cmd.Enable = true
    80  				cmd.Disable = true
    81  			})
    82  
    83  			It("returns an ArgumentCombinationError", func() {
    84  				Expect(executeErr).To(MatchError(translatableerror.ArgumentCombinationError{
    85  					Args: []string{"--enable", "--disable"},
    86  				}))
    87  			})
    88  		})
    89  
    90  		When("the --path and --lock flags are provided", func() {
    91  			BeforeEach(func() {
    92  				cmd.Lock = true
    93  				cmd.Path = "asdf"
    94  			})
    95  
    96  			It("returns an ArgumentCombinationError", func() {
    97  				Expect(executeErr).To(MatchError(translatableerror.ArgumentCombinationError{
    98  					Args: []string{"--path", "--lock"},
    99  				}))
   100  			})
   101  		})
   102  
   103  		When("the --path and --assign-stack flags are provided", func() {
   104  			BeforeEach(func() {
   105  				cmd.Path = "asdf"
   106  				cmd.NewStack = "some-new-stack"
   107  			})
   108  
   109  			It("returns an ArgumentCombinationError", func() {
   110  				Expect(executeErr).To(MatchError(translatableerror.ArgumentCombinationError{
   111  					Args: []string{"--path", "--assign-stack"},
   112  				}))
   113  			})
   114  		})
   115  
   116  		When("the --stack and --assign-stack flags are provided", func() {
   117  			BeforeEach(func() {
   118  				cmd.CurrentStack = "current-stack"
   119  				cmd.NewStack = "some-new-stack"
   120  			})
   121  
   122  			It("returns an ArgumentCombinationError", func() {
   123  				Expect(executeErr).To(MatchError(translatableerror.ArgumentCombinationError{
   124  					Args: []string{"--stack", "--assign-stack"},
   125  				}))
   126  			})
   127  		})
   128  	})
   129  
   130  	When("the environment is not set up correctly", func() {
   131  		BeforeEach(func() {
   132  			fakeSharedActor.CheckTargetReturns(actionerror.NotLoggedInError{BinaryName: binaryName})
   133  		})
   134  
   135  		It("returns an error", func() {
   136  			Expect(executeErr).To(MatchError(actionerror.NotLoggedInError{BinaryName: binaryName}))
   137  
   138  			Expect(fakeSharedActor.CheckTargetCallCount()).To(Equal(1))
   139  			checkTargetedOrg, checkTargetedSpace := fakeSharedActor.CheckTargetArgsForCall(0)
   140  			Expect(checkTargetedOrg).To(BeFalse())
   141  			Expect(checkTargetedSpace).To(BeFalse())
   142  		})
   143  	})
   144  
   145  	When("the environment is setup correctly", func() {
   146  		When("getting the current user fails", func() {
   147  			BeforeEach(func() {
   148  				expectedErr = errors.New("some-error that happened")
   149  				fakeConfig.CurrentUserReturns(configv3.User{}, expectedErr)
   150  			})
   151  
   152  			It("returns the error", func() {
   153  				Expect(executeErr).To(MatchError(expectedErr))
   154  			})
   155  		})
   156  
   157  		When("getting the current user succeeds", func() {
   158  			var userName string
   159  
   160  			BeforeEach(func() {
   161  				userName = "some-user"
   162  				fakeConfig.CurrentUserReturns(configv3.User{Name: userName}, nil)
   163  			})
   164  
   165  			When("preparing buildpack bits causes an error", func() {
   166  				var emptyDirectoryError error
   167  				BeforeEach(func() {
   168  					emptyDirectoryError = actionerror.EmptyBuildpackDirectoryError{Path: "some-directory"}
   169  					fakeActor.PrepareBuildpackBitsReturns("", emptyDirectoryError)
   170  					cmd.Path = "some empty directory"
   171  				})
   172  
   173  				It("exits without updating if the path points to an empty directory", func() {
   174  					Expect(executeErr).To(MatchError(emptyDirectoryError))
   175  					Expect(fakeActor.UpdateBuildpackByNameAndStackCallCount()).To(Equal(0))
   176  				})
   177  			})
   178  
   179  			When("updating the buildpack fails", func() {
   180  				BeforeEach(func() {
   181  					cmd.Path = "path/to/buildpack"
   182  					fakeActor.PrepareBuildpackBitsReturns("path/to/prepared/bits", nil)
   183  					expectedErr = errors.New("update-error")
   184  					fakeActor.UpdateBuildpackByNameAndStackReturns(
   185  						v7action.Buildpack{},
   186  						v7action.Warnings{"update-bp-warning1", "update-bp-warning2"},
   187  						expectedErr,
   188  					)
   189  				})
   190  
   191  				It("returns the error and prints any warnings", func() {
   192  					Expect(testUI.Err).To(Say("update-bp-warning1"))
   193  					Expect(testUI.Err).To(Say("update-bp-warning2"))
   194  					Expect(executeErr).To(MatchError(expectedErr))
   195  					Expect(fakeActor.UploadBuildpackCallCount()).To(Equal(0))
   196  				})
   197  			})
   198  
   199  			When("the --lock flag is provided", func() {
   200  				BeforeEach(func() {
   201  					cmd.Lock = true
   202  				})
   203  
   204  				It("sets the locked value to true when updating the buildpack", func() {
   205  					Expect(executeErr).ToNot(HaveOccurred())
   206  					_, _, buildpack := fakeActor.UpdateBuildpackByNameAndStackArgsForCall(0)
   207  					Expect(buildpack.Locked.IsSet).To(Equal(true))
   208  					Expect(buildpack.Locked.Value).To(Equal(true))
   209  				})
   210  			})
   211  
   212  			When("the --unlock flag is provided", func() {
   213  				BeforeEach(func() {
   214  					cmd.Unlock = true
   215  				})
   216  
   217  				It("sets the locked value to false when updating the buildpack", func() {
   218  					Expect(executeErr).ToNot(HaveOccurred())
   219  					_, _, buildpack := fakeActor.UpdateBuildpackByNameAndStackArgsForCall(0)
   220  					Expect(buildpack.Locked.IsSet).To(Equal(true))
   221  					Expect(buildpack.Locked.Value).To(Equal(false))
   222  				})
   223  			})
   224  
   225  			When("the --enable flag is provided", func() {
   226  				BeforeEach(func() {
   227  					cmd.Enable = true
   228  				})
   229  
   230  				It("sets the enabled value to true when updating the buildpack", func() {
   231  					Expect(executeErr).ToNot(HaveOccurred())
   232  					_, _, buildpack := fakeActor.UpdateBuildpackByNameAndStackArgsForCall(0)
   233  					Expect(buildpack.Enabled.IsSet).To(Equal(true))
   234  					Expect(buildpack.Enabled.Value).To(Equal(true))
   235  				})
   236  			})
   237  
   238  			When("the --disable flag is provided", func() {
   239  				BeforeEach(func() {
   240  					cmd.Disable = true
   241  				})
   242  
   243  				It("sets the enabled value to false when updating the buildpack", func() {
   244  					Expect(executeErr).ToNot(HaveOccurred())
   245  					_, _, buildpack := fakeActor.UpdateBuildpackByNameAndStackArgsForCall(0)
   246  					Expect(buildpack.Enabled.IsSet).To(Equal(true))
   247  					Expect(buildpack.Enabled.Value).To(Equal(false))
   248  				})
   249  			})
   250  
   251  			When("the --index flag is provided", func() {
   252  				BeforeEach(func() {
   253  					cmd.Position = types.NullInt{IsSet: true, Value: 99}
   254  				})
   255  
   256  				It("sets the new buildpack order when updating the buildpack", func() {
   257  					Expect(executeErr).ToNot(HaveOccurred())
   258  					_, _, buildpack := fakeActor.UpdateBuildpackByNameAndStackArgsForCall(0)
   259  					Expect(buildpack.Position.IsSet).To(Equal(true))
   260  					Expect(buildpack.Position.Value).To(Equal(99))
   261  				})
   262  			})
   263  
   264  			When("the --assign-stack flag is provided", func() {
   265  				BeforeEach(func() {
   266  					cmd.NewStack = "some-new-stack"
   267  				})
   268  
   269  				It("sets the new stack on the buildpack", func() {
   270  					Expect(executeErr).ToNot(HaveOccurred())
   271  					_, _, buildpack := fakeActor.UpdateBuildpackByNameAndStackArgsForCall(0)
   272  					Expect(testUI.Out).ToNot(Say("Updating buildpack %s", buildpackName))
   273  					Expect(testUI.Out).To(Say("Assigning stack %s to %s as %s...", cmd.NewStack, buildpackName, userName))
   274  					Expect(buildpack.Stack).To(Equal("some-new-stack"))
   275  				})
   276  
   277  				Context("and the --index flag is provided", func() {
   278  					BeforeEach(func() {
   279  						cmd.Position = types.NullInt{IsSet: true, Value: 3}
   280  					})
   281  
   282  					It("sets the new stack and updates the priority of the buildpack", func() {
   283  						Expect(executeErr).ToNot(HaveOccurred())
   284  						Expect(testUI.Out).To(Say("Assigning stack %s to %s as %s...", cmd.NewStack, buildpackName, userName))
   285  						Expect(testUI.Out).To(Say("Updating buildpack %s with stack %s...", buildpackName, cmd.NewStack))
   286  						Expect(testUI.Out).To(Say("OK"))
   287  					})
   288  				})
   289  
   290  				Context("and the --lock flag is provided", func() {
   291  					BeforeEach(func() {
   292  						cmd.Lock = true
   293  					})
   294  
   295  					It("sets the new stack and locks the buildpack", func() {
   296  						Expect(executeErr).ToNot(HaveOccurred())
   297  						Expect(testUI.Out).To(Say("Assigning stack %s to %s as %s...", cmd.NewStack, buildpackName, userName))
   298  						Expect(testUI.Out).To(Say("Updating buildpack %s with stack %s...", buildpackName, cmd.NewStack))
   299  						Expect(testUI.Out).To(Say("OK"))
   300  					})
   301  				})
   302  
   303  				Context("and the --unlock flag is provided", func() {
   304  					BeforeEach(func() {
   305  						cmd.Unlock = true
   306  					})
   307  
   308  					It("sets the new stack and unlocks the buildpack", func() {
   309  						Expect(executeErr).ToNot(HaveOccurred())
   310  						Expect(testUI.Out).To(Say("Assigning stack %s to %s as %s...", cmd.NewStack, buildpackName, userName))
   311  						Expect(testUI.Out).To(Say("Updating buildpack %s with stack %s...", buildpackName, cmd.NewStack))
   312  						Expect(testUI.Out).To(Say("OK"))
   313  					})
   314  				})
   315  
   316  				Context("and the --enable flag is provided", func() {
   317  					BeforeEach(func() {
   318  						cmd.Enable = true
   319  					})
   320  
   321  					It("sets the new stack and enables the buildpack", func() {
   322  						Expect(executeErr).ToNot(HaveOccurred())
   323  						Expect(testUI.Out).To(Say("Assigning stack %s to %s as %s...", cmd.NewStack, buildpackName, userName))
   324  						Expect(testUI.Out).To(Say("Updating buildpack %s with stack %s...", buildpackName, cmd.NewStack))
   325  						Expect(testUI.Out).To(Say("OK"))
   326  					})
   327  				})
   328  
   329  				Context("and the --disable flag is provided", func() {
   330  					BeforeEach(func() {
   331  						cmd.Disable = true
   332  					})
   333  
   334  					It("sets the new stack and disables the buildpack", func() {
   335  						Expect(executeErr).ToNot(HaveOccurred())
   336  						Expect(testUI.Out).To(Say("Assigning stack %s to %s as %s...", cmd.NewStack, buildpackName, userName))
   337  						Expect(testUI.Out).To(Say("Updating buildpack %s with stack %s...", buildpackName, cmd.NewStack))
   338  						Expect(testUI.Out).To(Say("OK"))
   339  					})
   340  				})
   341  
   342  			})
   343  
   344  			When("the --rename flag is provided", func() {
   345  				BeforeEach(func() {
   346  					cmd.NewName = "new-buildpack-name"
   347  				})
   348  
   349  				It("sets the new name on the buildpack", func() {
   350  					Expect(executeErr).ToNot(HaveOccurred())
   351  					_, _, buildpack := fakeActor.UpdateBuildpackByNameAndStackArgsForCall(0)
   352  					Expect(buildpack.Name).To(Equal("new-buildpack-name"))
   353  
   354  					Expect(testUI.Out).ToNot(Say("Updating buildpack %s", buildpackName))
   355  					Expect(testUI.Out).To(Say(
   356  						"Renaming buildpack %s to %s as %s...", buildpackName, cmd.NewName, userName))
   357  					Expect(testUI.Out).To(Say("OK"))
   358  				})
   359  
   360  				Context("and the --assign-stack flag is provided", func() {
   361  					BeforeEach(func() {
   362  						cmd.NewStack = "new-stack"
   363  					})
   364  
   365  					It("sets the new name/stack on the buildpack and refers to the new name going forward", func() {
   366  						Expect(executeErr).ToNot(HaveOccurred())
   367  						_, _, buildpack := fakeActor.UpdateBuildpackByNameAndStackArgsForCall(0)
   368  						Expect(buildpack.Name).To(Equal("new-buildpack-name"))
   369  						Expect(buildpack.Stack).To(Equal("new-stack"))
   370  
   371  						Expect(testUI.Out).To(Say(
   372  							"Renaming buildpack %s to %s as %s...", buildpackName, cmd.NewName, userName))
   373  
   374  						Expect(testUI.Out).To(Say(
   375  							"Assigning stack %s to %s as %s", cmd.NewStack, cmd.NewName, userName))
   376  
   377  						Expect(testUI.Out).ToNot(Say("Updating buildpack %s", buildpackName))
   378  
   379  						Expect(testUI.Out).To(Say("OK"))
   380  					})
   381  				})
   382  			})
   383  
   384  			When("updating the buildpack succeeds", func() {
   385  				BeforeEach(func() {
   386  					fakeActor.UpdateBuildpackByNameAndStackReturns(
   387  						v7action.Buildpack{GUID: buildpackGUID},
   388  						v7action.Warnings{"update-bp-warning1", "update-bp-warning2"},
   389  						nil,
   390  					)
   391  				})
   392  
   393  				When("no arguments are specified", func() {
   394  					It("makes the actor call to update the buildpack", func() {
   395  						Expect(fakeActor.UpdateBuildpackByNameAndStackCallCount()).To(Equal(1))
   396  						_, newStack, buildpack := fakeActor.UpdateBuildpackByNameAndStackArgsForCall(0)
   397  						Expect(buildpack.Name).To(Equal(""))
   398  						Expect(buildpack.Stack).To(Equal(""))
   399  						Expect(buildpack.Position.IsSet).To(BeFalse())
   400  						Expect(buildpack.Locked.IsSet).To(BeFalse())
   401  						Expect(buildpack.Enabled.IsSet).To(BeFalse())
   402  						Expect(newStack).To(Equal(""))
   403  
   404  						Expect(testUI.Err).To(Say("update-bp-warning1"))
   405  						Expect(testUI.Err).To(Say("update-bp-warning2"))
   406  						Expect(testUI.Out).To(Say("Updating buildpack %s as %s...", buildpackName, userName))
   407  						Expect(testUI.Out).To(Say("OK"))
   408  					})
   409  				})
   410  
   411  				When("a path is specified", func() {
   412  					BeforeEach(func() {
   413  						cmd.Path = "some path"
   414  					})
   415  
   416  					It("makes the call to update the buildpack", func() {
   417  						Expect(fakeActor.UpdateBuildpackByNameAndStackCallCount()).To(Equal(1))
   418  						buildpackNameArg, _, _ := fakeActor.UpdateBuildpackByNameAndStackArgsForCall(0)
   419  						Expect(buildpackNameArg).To(Equal(buildpackName))
   420  
   421  						Expect(testUI.Err).To(Say("update-bp-warning1"))
   422  						Expect(testUI.Err).To(Say("update-bp-warning2"))
   423  						Expect(testUI.Out).To(Say("Updating buildpack %s as %s...", buildpackName, userName))
   424  						Expect(testUI.Out).To(Say("OK"))
   425  					})
   426  
   427  					When("preparing the bits succeeds", func() {
   428  						buildpackBitsPath := "some path on the file system"
   429  						BeforeEach(func() {
   430  							fakeActor.PrepareBuildpackBitsReturns(buildpackBitsPath, nil)
   431  						})
   432  
   433  						It("uploads the new buildpack bits", func() {
   434  							Expect(testUI.Out).To(Say("Uploading buildpack some-bp as some-user..."))
   435  							Expect(fakeActor.UploadBuildpackCallCount()).To(Equal(1))
   436  							buildpackGUIDUsed, pathUsed, _ := fakeActor.UploadBuildpackArgsForCall(0)
   437  							Expect(buildpackGUIDUsed).To(Equal(buildpackGUID))
   438  							Expect(pathUsed).To(Equal(buildpackBitsPath))
   439  						})
   440  
   441  						When("uploading the buildpack fails", func() {
   442  
   443  							When("the client returns invalid auth token", func() {
   444  								BeforeEach(func() {
   445  									fakeActor.UploadBuildpackReturns("", v7action.Warnings{"some-create-bp-with-auth-warning"}, ccerror.InvalidAuthTokenError{Message: "token expired"})
   446  								})
   447  
   448  								It("alerts the user and retries the upload", func() {
   449  									Expect(testUI.Err).To(Say("Failed to upload buildpack due to auth token expiration, retrying..."))
   450  									Expect(fakeActor.UploadBuildpackCallCount()).To(Equal(2))
   451  								})
   452  							})
   453  
   454  							When("a non token error occurs", func() {
   455  								BeforeEach(func() {
   456  									expectedErr = errors.New("upload error")
   457  									fakeActor.UploadBuildpackReturns("", v7action.Warnings{"upload-warning1", "upload-warning2"}, expectedErr)
   458  								})
   459  
   460  								It("returns all warnings and an error", func() {
   461  									Expect(testUI.Err).To(Say("update-bp-warning1"))
   462  									Expect(testUI.Err).To(Say("update-bp-warning2"))
   463  									Expect(testUI.Err).To(Say("upload-warning1"))
   464  									Expect(testUI.Err).To(Say("upload-warning2"))
   465  									Expect(executeErr).To(MatchError(expectedErr))
   466  								})
   467  							})
   468  						})
   469  
   470  						When("uploading the buildpack succeeds", func() {
   471  							BeforeEach(func() {
   472  								fakeActor.UploadBuildpackReturns(
   473  									"example.com/job/url/",
   474  									v7action.Warnings{"upload-warning1", "upload-warning2"},
   475  									nil,
   476  								)
   477  							})
   478  
   479  							When("polling the buildpack job fails", func() {
   480  								BeforeEach(func() {
   481  									expectedErr = ccerror.JobTimeoutError{JobGUID: "job-guid"}
   482  									fakeActor.PollUploadBuildpackJobReturns(
   483  										v7action.Warnings{"poll-warning1", "poll-warning2"},
   484  										expectedErr,
   485  									)
   486  								})
   487  
   488  								It("returns all warnings and an error", func() {
   489  									Expect(testUI.Err).To(Say("update-bp-warning1"))
   490  									Expect(testUI.Err).To(Say("update-bp-warning2"))
   491  									Expect(testUI.Err).To(Say("poll-warning1"))
   492  									Expect(testUI.Err).To(Say("poll-warning2"))
   493  									Expect(executeErr).To(MatchError(expectedErr))
   494  								})
   495  							})
   496  
   497  							When("polling the buildpack job succeeds", func() {
   498  								BeforeEach(func() {
   499  									fakeActor.PollUploadBuildpackJobReturns(
   500  										v7action.Warnings{"poll-warning1", "poll-warning2"},
   501  										nil,
   502  									)
   503  								})
   504  
   505  								It("displays success test and any warnings", func() {
   506  									Expect(testUI.Out).To(Say(`Uploading buildpack %s`, buildpackName))
   507  									Expect(testUI.Err).To(Say("upload-warning1"))
   508  									Expect(testUI.Err).To(Say("upload-warning2"))
   509  									Expect(testUI.Out).To(Say("OK"))
   510  
   511  									Expect(testUI.Out).To(Say(`Processing uploaded buildpack %s\.\.\.`, buildpackName))
   512  									Expect(testUI.Err).To(Say("poll-warning1"))
   513  									Expect(testUI.Err).To(Say("poll-warning2"))
   514  									Expect(testUI.Out).To(Say("OK"))
   515  								})
   516  							})
   517  						})
   518  					})
   519  				})
   520  			})
   521  		})
   522  	})
   523  })