github.com/mook-as/cf-cli@v7.0.0-beta.28.0.20200120190804-b91c115fae48+incompatible/command/v7/create_buildpack_command_test.go (about) 1 package v7_test 2 3 import ( 4 "errors" 5 6 "code.cloudfoundry.org/cli/actor/actionerror" 7 "code.cloudfoundry.org/cli/actor/v7action" 8 "code.cloudfoundry.org/cli/api/cloudcontroller/ccerror" 9 "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3" 10 "code.cloudfoundry.org/cli/command/commandfakes" 11 "code.cloudfoundry.org/cli/command/flag" 12 "code.cloudfoundry.org/cli/command/translatableerror" 13 . "code.cloudfoundry.org/cli/command/v7" 14 "code.cloudfoundry.org/cli/command/v7/v7fakes" 15 "code.cloudfoundry.org/cli/types" 16 "code.cloudfoundry.org/cli/util/configv3" 17 "code.cloudfoundry.org/cli/util/ui" 18 19 . "github.com/onsi/ginkgo" 20 . "github.com/onsi/gomega" 21 . "github.com/onsi/gomega/gbytes" 22 ) 23 24 var _ = Describe("create buildpack Command", func() { 25 var ( 26 cmd CreateBuildpackCommand 27 testUI *ui.UI 28 fakeConfig *commandfakes.FakeConfig 29 fakeSharedActor *commandfakes.FakeSharedActor 30 fakeActor *v7fakes.FakeCreateBuildpackActor 31 executeErr error 32 args []string 33 binaryName string 34 buildpackName string 35 buildpackPath string 36 ) 37 38 BeforeEach(func() { 39 testUI = ui.NewTestUI(nil, NewBuffer(), NewBuffer()) 40 fakeConfig = new(commandfakes.FakeConfig) 41 fakeSharedActor = new(commandfakes.FakeSharedActor) 42 fakeActor = new(v7fakes.FakeCreateBuildpackActor) 43 args = nil 44 buildpackName = "some-buildpack" 45 buildpackPath = "/path/to/buildpack.zip" 46 47 cmd = CreateBuildpackCommand{ 48 RequiredArgs: flag.CreateBuildpackArgs{ 49 Buildpack: buildpackName, 50 Path: flag.PathWithExistenceCheckOrURL(buildpackPath), 51 Position: 7, 52 }, 53 UI: testUI, 54 Config: fakeConfig, 55 SharedActor: fakeSharedActor, 56 Actor: fakeActor, 57 } 58 59 binaryName = "faceman" 60 fakeConfig.BinaryNameReturns(binaryName) 61 }) 62 63 JustBeforeEach(func() { 64 executeErr = cmd.Execute(args) 65 }) 66 67 When("the environment is not set up correctly", func() { 68 BeforeEach(func() { 69 fakeSharedActor.CheckTargetReturns(actionerror.NotLoggedInError{BinaryName: binaryName}) 70 }) 71 72 It("returns an error", func() { 73 Expect(executeErr).To(MatchError(actionerror.NotLoggedInError{BinaryName: binaryName})) 74 75 Expect(fakeSharedActor.CheckTargetCallCount()).To(Equal(1)) 76 checkTargetedOrg, checkTargetedSpace := fakeSharedActor.CheckTargetArgsForCall(0) 77 Expect(checkTargetedOrg).To(BeFalse()) 78 Expect(checkTargetedSpace).To(BeFalse()) 79 }) 80 }) 81 82 When("the environment is setup correctly", func() { 83 BeforeEach(func() { 84 fakeConfig.CurrentUserReturns(configv3.User{Name: "the-user"}, nil) 85 }) 86 87 It("should print text indicating it is creating a buildpack", func() { 88 Expect(executeErr).NotTo(HaveOccurred()) 89 Expect(testUI.Out).To(Say(`Creating buildpack %s as the-user\.\.\.`, buildpackName)) 90 }) 91 92 When("preparing the buildpack bits fails", func() { 93 BeforeEach(func() { 94 fakeActor.PrepareBuildpackBitsReturns("some/invalid/path", errors.New("some-prepare-bp-error")) 95 }) 96 97 It("returns an error", func() { 98 Expect(executeErr).To(MatchError("some-prepare-bp-error")) 99 Expect(fakeActor.PrepareBuildpackBitsCallCount()).To(Equal(1)) 100 }) 101 }) 102 103 When("Preparing the buildpack bits succeeds", func() { 104 105 BeforeEach(func() { 106 fakeActor.PrepareBuildpackBitsReturns("buildpack.zip", nil) 107 }) 108 109 When("creating the buildpack fails", func() { 110 BeforeEach(func() { 111 fakeActor.CreateBuildpackReturns( 112 v7action.Buildpack{}, 113 v7action.Warnings{"warning-1"}, 114 actionerror.BuildpackNameTakenError{Name: "this-error-occurred"}, 115 ) 116 }) 117 It("errors and prints all warnings", func() { 118 Expect(executeErr).To(Equal(actionerror.BuildpackNameTakenError{Name: "this-error-occurred"})) 119 Expect(testUI.Err).To(Say("warning-1")) 120 }) 121 }) 122 123 When("The disabled flag is set", func() { 124 BeforeEach(func() { 125 cmd.Disable = true 126 buildpack := v7action.Buildpack{ 127 Name: buildpackName, 128 Enabled: types.NullBool{Value: false, IsSet: true}, 129 } 130 fakeActor.CreateBuildpackReturns(buildpack, v7action.Warnings{"some-create-warning-1"}, nil) 131 }) 132 133 It("correctly creates a disabled buildpack", func() { 134 buildpack := fakeActor.CreateBuildpackArgsForCall(0) 135 Expect(buildpack.Name).To(Equal(buildpackName)) 136 Expect(buildpack.Enabled.Value).To(BeFalse()) 137 }) 138 }) 139 140 When("creating buildpack succeeds", func() { 141 BeforeEach(func() { 142 buildpack := v7action.Buildpack{ 143 Name: buildpackName, 144 Position: types.NullInt{Value: 1, IsSet: true}, 145 Enabled: types.NullBool{Value: true, IsSet: true}, 146 Locked: types.NullBool{Value: false, IsSet: true}, 147 Filename: "buildpack-1.file", 148 Stack: "buildpack-1-stack", 149 GUID: "some-guid", 150 } 151 fakeActor.CreateBuildpackReturns(buildpack, v7action.Warnings{"some-create-warning-1"}, nil) 152 }) 153 154 It("correctly created the buildpack", func() { 155 buildpack := fakeActor.CreateBuildpackArgsForCall(0) 156 Expect(buildpack.Name).To(Equal(buildpackName)) 157 Expect(buildpack.Position.Value).To(Equal(7)) 158 }) 159 160 It("prints any warnings and uploads the bits", func() { 161 Expect(executeErr).NotTo(HaveOccurred()) 162 Expect(testUI.Out).To(Say("OK")) 163 Expect(testUI.Err).To(Say("some-create-warning-1")) 164 Expect(testUI.Out).To(Say(`Uploading buildpack %s as the-user\.\.\.`, buildpackName)) 165 }) 166 167 It("Displays it is starting the upload", func() { 168 Expect(executeErr).ToNot(HaveOccurred()) 169 Expect(testUI.Out).To(Say("Uploading buildpack %s as the-user", buildpackName)) 170 171 Expect(fakeActor.PrepareBuildpackBitsCallCount()).To(Equal(1)) 172 path, _, _ := fakeActor.PrepareBuildpackBitsArgsForCall(0) 173 Expect(path).To(Equal(buildpackPath)) 174 }) 175 176 When("uploading the buildpack fails due to an auth token expired error", func() { 177 BeforeEach(func() { 178 fakeActor.UploadBuildpackReturns( 179 ccv3.JobURL(""), 180 v7action.Warnings{"some-create-bp-with-auth-warning"}, 181 ccerror.InvalidAuthTokenError{Message: "token expired"}, 182 ) 183 }) 184 185 It("alerts the user and retries the upload", func() { 186 Expect(testUI.Err).To(Say("Failed to upload buildpack due to auth token expiration, retrying...")) 187 Expect(fakeActor.UploadBuildpackCallCount()).To(Equal(2)) 188 }) 189 }) 190 191 When("Uploading the buildpack fails due to a generic error", func() { 192 BeforeEach(func() { 193 fakeActor.UploadBuildpackReturns( 194 ccv3.JobURL(""), 195 v7action.Warnings{"warning-2"}, 196 errors.New("some-error"), 197 ) 198 }) 199 200 It("errors, prints a tip and all warnings", func() { 201 Expect(executeErr).To(MatchError(translatableerror.TipDecoratorError{ 202 BaseError: errors.New("some-error"), 203 Tip: "A buildpack with name '{{.BuildpackName}}' and nil stack has been created. Use '{{.CfDeleteBuildpackCommand}}' to delete it or '{{.CfUpdateBuildpackCommand}}' to try again.", 204 TipKeys: map[string]interface{}{ 205 "BuildpackName": cmd.RequiredArgs.Buildpack, 206 "CfDeleteBuildpackCommand": cmd.Config.BinaryName() + " delete-buildpack", 207 "CfUpdateBuildpackCommand": cmd.Config.BinaryName() + " update-buildpack", 208 }, 209 })) 210 Expect(testUI.Err).To(Say("warning-2")) 211 Expect(testUI.Out).To(Say("Uploading buildpack %s", buildpackName)) 212 Consistently(testUI.Out).ShouldNot(Say("OK")) 213 }) 214 215 }) 216 217 When("Uploading the buildpack succeeds", func() { 218 BeforeEach(func() { 219 fakeActor.UploadBuildpackReturns( 220 ccv3.JobURL("http://example.com/some-job-url"), 221 v7action.Warnings{"some-upload-warning-1"}, 222 nil, 223 ) 224 }) 225 226 It("prints all warnings", func() { 227 Expect(executeErr).NotTo(HaveOccurred()) 228 Expect(testUI.Out).To(Say("Uploading buildpack %s", buildpackName)) 229 Expect(testUI.Out).To(Say("OK")) 230 Expect(testUI.Err).To(Say("some-upload-warning-1")) 231 232 Expect(fakeActor.UploadBuildpackCallCount()).To(Equal(1)) 233 guid, path, _ := fakeActor.UploadBuildpackArgsForCall(0) 234 Expect(guid).To(Equal("some-guid")) 235 Expect(path).To(Equal("buildpack.zip")) 236 }) 237 238 Describe("polling the upload-to-blobstore job", func() { 239 It("polls for job completion/failure", func() { 240 Expect(executeErr).NotTo(HaveOccurred()) 241 Expect(testUI.Out).To(Say("Uploading buildpack %s", buildpackName)) 242 Expect(testUI.Out).To(Say("OK")) 243 244 Expect(fakeActor.PollUploadBuildpackJobCallCount()).To(Equal(1)) 245 url := fakeActor.PollUploadBuildpackJobArgsForCall(0) 246 247 Expect(url).To(Equal(ccv3.JobURL("http://example.com/some-job-url"))) 248 }) 249 250 When("the job completes successfully", func() { 251 BeforeEach(func() { 252 fakeActor.PollUploadBuildpackJobReturns(v7action.Warnings{"poll-warning"}, nil) 253 }) 254 255 It("prints all warnings and exits successfully", func() { 256 Expect(executeErr).NotTo(HaveOccurred()) 257 Expect(testUI.Out).To(Say(`Processing uploaded buildpack %s\.\.\.`, buildpackName)) 258 Expect(testUI.Out).To(Say("OK")) 259 Expect(testUI.Err).To(Say("poll-warning")) 260 }) 261 }) 262 263 When("the job fails with an error", func() { 264 BeforeEach(func() { 265 fakeActor.PollUploadBuildpackJobReturns( 266 v7action.Warnings{"poll-warning"}, 267 errors.New("some-error"), 268 ) 269 }) 270 271 It("prints all warnings and a tip, then returns the error", func() { 272 Expect(executeErr).To(MatchError(translatableerror.TipDecoratorError{ 273 BaseError: errors.New("some-error"), 274 Tip: "A buildpack with name '{{.BuildpackName}}' and nil stack has been created. Use '{{.CfDeleteBuildpackCommand}}' to delete it or '{{.CfUpdateBuildpackCommand}}' to try again.", 275 TipKeys: map[string]interface{}{ 276 "BuildpackName": cmd.RequiredArgs.Buildpack, 277 "CfDeleteBuildpackCommand": cmd.Config.BinaryName() + " delete-buildpack", 278 "CfUpdateBuildpackCommand": cmd.Config.BinaryName() + " update-buildpack", 279 }, 280 })) 281 Expect(testUI.Err).To(Say("poll-warning")) 282 Expect(testUI.Out).To(Say(`Processing uploaded buildpack %s\.\.\.`, buildpackName)) 283 Consistently(testUI.Out).ShouldNot(Say("OK")) 284 }) 285 }) 286 }) 287 }) 288 }) 289 }) 290 }) 291 })