github.com/mook-as/cf-cli@v7.0.0-beta.28.0.20200120190804-b91c115fae48+incompatible/command/v6/update_buildpack_command_test.go (about)

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