github.com/swisscom/cloudfoundry-cli@v7.1.0+incompatible/actor/v2action/buildpack_test.go (about) 1 package v2action_test 2 3 import ( 4 "errors" 5 "io" 6 "io/ioutil" 7 "os" 8 "path/filepath" 9 "strings" 10 11 . "github.com/onsi/ginkgo" 12 . "github.com/onsi/gomega" 13 14 "code.cloudfoundry.org/cli/actor/actionerror" 15 . "code.cloudfoundry.org/cli/actor/v2action" 16 "code.cloudfoundry.org/cli/actor/v2action/v2actionfakes" 17 "code.cloudfoundry.org/cli/api/cloudcontroller/ccerror" 18 "code.cloudfoundry.org/cli/api/cloudcontroller/ccv2" 19 "code.cloudfoundry.org/cli/api/cloudcontroller/ccv2/constant" 20 "code.cloudfoundry.org/cli/types" 21 ) 22 23 var _ = Describe("Buildpack", func() { 24 var ( 25 actor *Actor 26 fakeCloudControllerClient *v2actionfakes.FakeCloudControllerClient 27 fakeConfig *v2actionfakes.FakeConfig 28 ) 29 30 BeforeEach(func() { 31 fakeCloudControllerClient = new(v2actionfakes.FakeCloudControllerClient) 32 fakeConfig = new(v2actionfakes.FakeConfig) 33 actor = NewActor(fakeCloudControllerClient, nil, fakeConfig) 34 }) 35 36 Describe("Buildpack", func() { 37 Describe("NoStack", func() { 38 var buildpack Buildpack 39 40 When("the stack is empty", func() { 41 BeforeEach(func() { 42 buildpack.Stack = "" 43 }) 44 45 It("returns true", func() { 46 Expect(buildpack.NoStack()).To(BeTrue()) 47 }) 48 }) 49 50 When("the stack is set", func() { 51 BeforeEach(func() { 52 buildpack.Stack = "something i guess" 53 }) 54 55 It("returns false", func() { 56 Expect(buildpack.NoStack()).To(BeFalse()) 57 }) 58 }) 59 }) 60 }) 61 62 Describe("CreateBuildpack", func() { 63 var ( 64 buildpack Buildpack 65 warnings Warnings 66 executeErr error 67 ) 68 69 JustBeforeEach(func() { 70 buildpack, warnings, executeErr = actor.CreateBuildpack("some-bp-name", 42, true) 71 }) 72 73 When("creating the buildpack is successful", func() { 74 BeforeEach(func() { 75 fakeCloudControllerClient.CreateBuildpackReturns(ccv2.Buildpack{GUID: "some-guid"}, ccv2.Warnings{"some-create-warning"}, nil) 76 }) 77 78 It("returns the buildpack and all warnings", func() { 79 Expect(executeErr).ToNot(HaveOccurred()) 80 Expect(fakeCloudControllerClient.CreateBuildpackCallCount()).To(Equal(1)) 81 Expect(fakeCloudControllerClient.CreateBuildpackArgsForCall(0)).To(Equal(ccv2.Buildpack{ 82 Name: "some-bp-name", 83 Position: types.NullInt{IsSet: true, Value: 42}, 84 Enabled: types.NullBool{IsSet: true, Value: true}, 85 })) 86 87 Expect(buildpack).To(Equal(Buildpack{GUID: "some-guid"})) 88 Expect(warnings).To(ConsistOf("some-create-warning")) 89 }) 90 }) 91 92 When("the buildpack already exists with nil stack", func() { 93 BeforeEach(func() { 94 fakeCloudControllerClient.CreateBuildpackReturns(ccv2.Buildpack{}, ccv2.Warnings{"some-create-warning"}, ccerror.BuildpackInvalidError{Message: "some failure message"}) 95 }) 96 97 It("returns a BuildpackInvalidError error and all warnings", func() { 98 Expect(warnings).To(ConsistOf("some-create-warning")) 99 Expect(executeErr).To(MatchError(actionerror.BuildpackInvalidError{Message: "some failure message"})) 100 }) 101 }) 102 103 When("the buildpack name is taken", func() { 104 BeforeEach(func() { 105 fakeCloudControllerClient.CreateBuildpackReturns(ccv2.Buildpack{}, ccv2.Warnings{"some-create-warning"}, ccerror.BuildpackNameTakenError{Message: ""}) 106 }) 107 108 It("returns a BuildpackNameTaken error and all warnings", func() { 109 Expect(warnings).To(ConsistOf("some-create-warning")) 110 Expect(executeErr).To(MatchError(actionerror.BuildpackNameTakenError{Name: "some-bp-name"})) 111 }) 112 }) 113 114 When("a cc create error occurs", func() { 115 BeforeEach(func() { 116 fakeCloudControllerClient.CreateBuildpackReturns(ccv2.Buildpack{}, ccv2.Warnings{"some-create-warning"}, errors.New("kaboom")) 117 }) 118 119 It("returns an error and all warnings", func() { 120 Expect(warnings).To(ConsistOf("some-create-warning")) 121 Expect(executeErr).To(MatchError("kaboom")) 122 }) 123 }) 124 }) 125 126 Describe("PrepareBuildpackBits", func() { 127 var ( 128 inPath string 129 outPath string 130 tmpDirPath string 131 fakeDownloader *v2actionfakes.FakeDownloader 132 133 executeErr error 134 ) 135 136 BeforeEach(func() { 137 fakeDownloader = new(v2actionfakes.FakeDownloader) 138 }) 139 140 JustBeforeEach(func() { 141 outPath, executeErr = actor.PrepareBuildpackBits(inPath, tmpDirPath, fakeDownloader) 142 }) 143 144 When("the buildpack path is a url", func() { 145 BeforeEach(func() { 146 inPath = "http://buildpacks.com/a.zip" 147 fakeDownloader = new(v2actionfakes.FakeDownloader) 148 149 var err error 150 tmpDirPath, err = ioutil.TempDir("", "buildpackdir-") 151 Expect(err).ToNot(HaveOccurred()) 152 }) 153 154 AfterEach(func() { 155 Expect(os.RemoveAll(tmpDirPath)).ToNot(HaveOccurred()) 156 }) 157 158 When("downloading the file succeeds", func() { 159 BeforeEach(func() { 160 fakeDownloader.DownloadReturns("/tmp/buildpackdir-100/a.zip", nil) 161 }) 162 163 It("downloads the buildpack to a local file", func() { 164 Expect(executeErr).ToNot(HaveOccurred()) 165 Expect(fakeDownloader.DownloadCallCount()).To(Equal(1)) 166 167 inputPath, inputTmpDirPath := fakeDownloader.DownloadArgsForCall(0) 168 Expect(inputPath).To(Equal("http://buildpacks.com/a.zip")) 169 Expect(inputTmpDirPath).To(Equal(tmpDirPath)) 170 }) 171 }) 172 173 When("downloading the file fails", func() { 174 BeforeEach(func() { 175 fakeDownloader.DownloadReturns("", errors.New("some-download-error")) 176 }) 177 178 It("returns the error", func() { 179 Expect(executeErr).To(MatchError("some-download-error")) 180 }) 181 }) 182 }) 183 184 When("the buildpack path points to a directory", func() { 185 var tempFile *os.File 186 BeforeEach(func() { 187 var err error 188 inPath, err = ioutil.TempDir("", "buildpackdir-") 189 Expect(err).ToNot(HaveOccurred()) 190 191 tempFile, err = ioutil.TempFile(inPath, "foo") 192 Expect(err).ToNot(HaveOccurred()) 193 194 tmpDirPath, err = ioutil.TempDir("", "buildpackdir-") 195 Expect(err).ToNot(HaveOccurred()) 196 }) 197 198 AfterEach(func() { 199 tempFile.Close() 200 Expect(os.RemoveAll(inPath)).ToNot(HaveOccurred()) 201 Expect(os.RemoveAll(tmpDirPath)).ToNot(HaveOccurred()) 202 }) 203 204 It("returns a path to the zipped directory", func() { 205 Expect(executeErr).ToNot(HaveOccurred()) 206 Expect(fakeDownloader.DownloadCallCount()).To(Equal(0)) 207 208 Expect(filepath.Base(outPath)).To(Equal(filepath.Base(inPath) + ".zip")) 209 }) 210 }) 211 212 When("the buildpack path points to an empty directory", func() { 213 BeforeEach(func() { 214 var err error 215 inPath, err = ioutil.TempDir("", "some-empty-dir") 216 Expect(err).ToNot(HaveOccurred()) 217 218 tmpDirPath, err = ioutil.TempDir("", "buildpackdir-") 219 Expect(err).ToNot(HaveOccurred()) 220 }) 221 222 AfterEach(func() { 223 Expect(os.RemoveAll(inPath)).ToNot(HaveOccurred()) 224 Expect(os.RemoveAll(tmpDirPath)).ToNot(HaveOccurred()) 225 }) 226 227 It("returns an error", func() { 228 Expect(executeErr).To(MatchError(actionerror.EmptyBuildpackDirectoryError{Path: inPath})) 229 }) 230 }) 231 232 When("the buildpack path points to a zip file", func() { 233 BeforeEach(func() { 234 inPath = "/foo/buildpacks/a.zip" 235 }) 236 237 It("returns the local filepath", func() { 238 Expect(executeErr).ToNot(HaveOccurred()) 239 Expect(fakeDownloader.DownloadCallCount()).To(Equal(0)) 240 Expect(outPath).To(Equal("/foo/buildpacks/a.zip")) 241 }) 242 }) 243 }) 244 245 Describe("RenameBuildpack", func() { 246 var ( 247 oldName string 248 newName string 249 stackName string 250 warnings Warnings 251 executeErr error 252 ) 253 254 BeforeEach(func() { 255 oldName = "some-old-name" 256 newName = "some-new-name" 257 stackName = "" 258 }) 259 260 JustBeforeEach(func() { 261 warnings, executeErr = actor.RenameBuildpack(oldName, newName, stackName) 262 }) 263 264 When("lookup is based on only name of buildpack", func() { 265 When("the lookup returns one buildpack", func() { 266 BeforeEach(func() { 267 fakeCloudControllerClient.GetBuildpacksReturns( 268 []ccv2.Buildpack{{Name: newName}}, 269 ccv2.Warnings{"warning-1", "warning-2"}, 270 nil) 271 }) 272 273 When("the update succeeds", func() { 274 BeforeEach(func() { 275 fakeCloudControllerClient.UpdateBuildpackReturns(ccv2.Buildpack{}, 276 ccv2.Warnings{"warning-3", "warning-4"}, 277 nil) 278 }) 279 280 It("returns warnings", func() { 281 Expect(executeErr).ToNot(HaveOccurred()) 282 Expect(warnings).To(ConsistOf("warning-1", "warning-2", "warning-3", "warning-4")) 283 }) 284 }) 285 286 When("the update errors", func() { 287 BeforeEach(func() { 288 fakeCloudControllerClient.UpdateBuildpackReturns(ccv2.Buildpack{}, 289 ccv2.Warnings{"warning-3", "warning-4"}, 290 errors.New("some-error")) 291 }) 292 293 It("returns the error and warnings", func() { 294 Expect(executeErr).To(MatchError("some-error")) 295 Expect(warnings).To(ConsistOf("warning-1", "warning-2", "warning-3", "warning-4")) 296 }) 297 }) 298 }) 299 300 When("lookup returns multiple buildpacks", func() { 301 When("one buildpack does not have a stack", func() { 302 BeforeEach(func() { 303 fakeCloudControllerClient.GetBuildpacksReturns( 304 []ccv2.Buildpack{ 305 {Name: oldName, GUID: "guid-1"}, 306 {Name: oldName, Stack: "some-stack", GUID: "guid-2"}, 307 }, 308 ccv2.Warnings{"warning-1", "warning-2"}, 309 nil) 310 }) 311 312 It("uses that buildpack", func() { 313 Expect(executeErr).ToNot(HaveOccurred()) 314 actualBp := fakeCloudControllerClient.UpdateBuildpackArgsForCall(0) 315 Expect(actualBp).To(Equal(ccv2.Buildpack{Name: newName, GUID: "guid-1"})) 316 Expect(warnings).To(ConsistOf("warning-1", "warning-2")) 317 }) 318 }) 319 320 When("all the buildpacks have stacks", func() { 321 BeforeEach(func() { 322 fakeCloudControllerClient.GetBuildpacksReturns( 323 []ccv2.Buildpack{ 324 {Name: oldName, Stack: "a-stack"}, 325 {Name: oldName, Stack: "some-stack"}, 326 }, 327 ccv2.Warnings{"warning-1", "warning-2"}, 328 nil) 329 }) 330 331 It("returns an error", func() { 332 Expect(executeErr).To(MatchError(actionerror.MultipleBuildpacksFoundError{BuildpackName: oldName})) 333 Expect(warnings).To(ConsistOf("warning-1", "warning-2")) 334 }) 335 }) 336 }) 337 }) 338 339 When("lookup is based on name and stack name of buildpack", func() { 340 BeforeEach(func() { 341 oldName = "some-old-name" 342 stackName = "cflinuxfs2" 343 }) 344 345 When("the lookup succeeds", func() { 346 BeforeEach(func() { 347 fakeCloudControllerClient.GetBuildpacksReturns( 348 []ccv2.Buildpack{{Name: newName}}, 349 ccv2.Warnings{"warning-1", "warning-2"}, 350 nil, 351 ) 352 }) 353 354 It("uses the stack filter when looking up buildpacks", func() { 355 filters := fakeCloudControllerClient.GetBuildpacksArgsForCall(0) 356 Expect(filters).To(ContainElement(ccv2.Filter{Type: constant.StackFilter, Operator: constant.EqualOperator, Values: []string{stackName}})) 357 Expect(executeErr).ToNot(HaveOccurred()) 358 Expect(warnings).To(ConsistOf("warning-1", "warning-2")) 359 }) 360 }) 361 362 When("lookup returns multiple buildpacks", func() { 363 BeforeEach(func() { 364 fakeCloudControllerClient.GetBuildpacksReturns( 365 []ccv2.Buildpack{ 366 {Name: oldName, Stack: "a-stack"}, 367 {Name: oldName, Stack: "some-stack"}, 368 }, 369 ccv2.Warnings{"warning-1", "warning-2"}, 370 nil) 371 }) 372 373 It("returns an error", func() { 374 Expect(executeErr).To(MatchError(actionerror.MultipleBuildpacksFoundError{BuildpackName: oldName})) 375 Expect(warnings).To(ConsistOf("warning-1", "warning-2")) 376 }) 377 }) 378 }) 379 380 When("the lookup errors", func() { 381 BeforeEach(func() { 382 fakeCloudControllerClient.GetBuildpacksReturns(nil, 383 ccv2.Warnings{"warning-1", "warning-2"}, 384 errors.New("some-lookup-error")) 385 }) 386 It("returns the error and warnings", func() { 387 Expect(executeErr).To(MatchError("some-lookup-error")) 388 Expect(warnings).To(ConsistOf("warning-1", "warning-2")) 389 }) 390 }) 391 }) 392 393 Describe("UpdateBuildpack", func() { 394 var ( 395 buildpack Buildpack 396 updatedBuildpack Buildpack 397 warnings Warnings 398 executeErr error 399 ) 400 401 JustBeforeEach(func() { 402 buildpack = Buildpack{ 403 Name: "some-bp-name", 404 GUID: "some-bp-guid", 405 Stack: "some-stack", 406 } 407 updatedBuildpack, warnings, executeErr = actor.UpdateBuildpack(buildpack) 408 }) 409 410 When("there are no errors", func() { 411 BeforeEach(func() { 412 fakeCloudControllerClient.UpdateBuildpackReturns(ccv2.Buildpack{ 413 Name: "some-bp-name", 414 GUID: "some-bp-guid", 415 Stack: "some-stack", 416 }, ccv2.Warnings{"some-warning"}, nil) 417 }) 418 419 It("returns the updated buildpack", func() { 420 Expect(executeErr).ToNot(HaveOccurred()) 421 Expect(warnings).To(ConsistOf(Warnings{"some-warning"})) 422 Expect(fakeCloudControllerClient.UpdateBuildpackCallCount()).To(Equal(1)) 423 424 Expect(updatedBuildpack).To(Equal(buildpack)) 425 }) 426 }) 427 428 When("the client errors", func() { 429 When("the buildpack is not found", func() { 430 BeforeEach(func() { 431 fakeCloudControllerClient.UpdateBuildpackReturns(ccv2.Buildpack{}, ccv2.Warnings{"some-warning"}, ccerror.ResourceNotFoundError{}) 432 }) 433 434 It("returns a buildpack not found error", func() { 435 Expect(executeErr).To(MatchError(actionerror.BuildpackNotFoundError{BuildpackName: "some-bp-name"})) 436 Expect(warnings).To(ConsistOf(Warnings{"some-warning"})) 437 Expect(fakeCloudControllerClient.UpdateBuildpackCallCount()).To(Equal(1)) 438 }) 439 }) 440 441 When("the buildpack already exists without a stack association", func() { 442 BeforeEach(func() { 443 fakeCloudControllerClient.UpdateBuildpackReturns(ccv2.Buildpack{}, ccv2.Warnings{"some-warning"}, ccerror.BuildpackInvalidError{Message: "some failure message"}) 444 }) 445 446 It("returns a buildpack already exists without stack error", func() { 447 Expect(executeErr).To(MatchError(actionerror.BuildpackInvalidError{Message: "some failure message"})) 448 Expect(warnings).To(ConsistOf(Warnings{"some-warning"})) 449 Expect(fakeCloudControllerClient.UpdateBuildpackCallCount()).To(Equal(1)) 450 }) 451 }) 452 453 When("the buildpack already exists with a stack association", func() { 454 BeforeEach(func() { 455 fakeCloudControllerClient.UpdateBuildpackReturns(ccv2.Buildpack{}, ccv2.Warnings{"some-warning"}, ccerror.BuildpackAlreadyExistsForStackError{Message: "some-message"}) 456 }) 457 458 It("returns a buildpack already exists for stack error", func() { 459 Expect(executeErr).To(MatchError(actionerror.BuildpackAlreadyExistsForStackError{Message: "some-message"})) 460 Expect(warnings).To(ConsistOf(Warnings{"some-warning"})) 461 Expect(fakeCloudControllerClient.UpdateBuildpackCallCount()).To(Equal(1)) 462 }) 463 }) 464 465 When("the client returns a generic error", func() { 466 BeforeEach(func() { 467 fakeCloudControllerClient.UpdateBuildpackReturns(ccv2.Buildpack{}, ccv2.Warnings{"some-warning"}, errors.New("some-error")) 468 }) 469 470 It("returns the error", func() { 471 Expect(executeErr).To(MatchError("some-error")) 472 Expect(warnings).To(ConsistOf(Warnings{"some-warning"})) 473 Expect(fakeCloudControllerClient.UpdateBuildpackCallCount()).To(Equal(1)) 474 }) 475 }) 476 }) 477 }) 478 479 Describe("UpdateBuildpackByNameAndStack", func() { 480 var ( 481 newPosition types.NullInt 482 newLocked types.NullBool 483 newEnabled types.NullBool 484 currentStack string 485 newStack string 486 487 buildpackGUID string 488 warnings Warnings 489 executeErr error 490 ) 491 492 BeforeEach(func() { 493 newPosition = types.NullInt{} 494 newLocked = types.NullBool{} 495 newEnabled = types.NullBool{} 496 currentStack = "" 497 newStack = "" 498 }) 499 500 JustBeforeEach(func() { 501 buildpackGUID, warnings, executeErr = actor.UpdateBuildpackByNameAndStack("some-bp-name", currentStack, newPosition, newLocked, newEnabled, newStack) 502 }) 503 504 When("current stack is an empty string", func() { 505 It("gets the buildpack by name only", func() { 506 args := fakeCloudControllerClient.GetBuildpacksArgsForCall(0) 507 Expect(len(args)).To(Equal(1)) 508 Expect(args[0].Values[0]).To(Equal("some-bp-name")) 509 }) 510 }) 511 512 When("a non-empty current stack name is passed", func() { 513 BeforeEach(func() { 514 currentStack = "some-stack" 515 }) 516 517 It("gets the buildpack by name and current stack", func() { 518 Expect(fakeCloudControllerClient.GetBuildpacksCallCount()).To(Equal(1)) 519 args := fakeCloudControllerClient.GetBuildpacksArgsForCall(0) 520 Expect(len(args)).To(Equal(2)) 521 Expect(args[0].Values[0]).To(Equal("some-bp-name")) 522 Expect(args[1].Values[0]).To(Equal(currentStack)) 523 }) 524 525 When("the cc responds successfully", func() { 526 BeforeEach(func() { 527 fakeCloudControllerClient.GetBuildpacksReturns([]ccv2.Buildpack{{GUID: "some-guid"}}, ccv2.Warnings{"warning-1", "warning-2"}, nil) 528 }) 529 530 It("returns the buildpack GUID", func() { 531 Expect(fakeCloudControllerClient.GetBuildpacksCallCount()).To(Equal(1)) 532 Expect(executeErr).ToNot(HaveOccurred()) 533 Expect(buildpackGUID).To(Equal("some-guid")) 534 }) 535 }) 536 537 When("the cc responds with an error", func() { 538 BeforeEach(func() { 539 fakeCloudControllerClient.GetBuildpacksReturns([]ccv2.Buildpack{}, ccv2.Warnings{"warning-1", "warning-2"}, errors.New("boom!")) 540 }) 541 542 It("returns an error and all warnings", func() { 543 Expect(executeErr).To(MatchError("boom!")) 544 Expect(warnings).To(ConsistOf("warning-1", "warning-2")) 545 }) 546 }) 547 }) 548 549 When("getting the buildpack fails", func() { 550 var expectedError error 551 552 BeforeEach(func() { 553 expectedError = errors.New("some-error") 554 fakeCloudControllerClient.GetBuildpacksReturns(nil, nil, expectedError) 555 }) 556 557 It("returns the error", func() { 558 Expect(executeErr).To(MatchError(expectedError)) 559 }) 560 }) 561 562 When("getting the buildpack returns an empty list", func() { 563 BeforeEach(func() { 564 fakeCloudControllerClient.GetBuildpacksReturns([]ccv2.Buildpack{}, ccv2.Warnings{"warning-1", "warning-2"}, nil) 565 }) 566 567 It("returns a BuildpackNotFoundError and all warnings", func() { 568 Expect(executeErr).To(MatchError(actionerror.BuildpackNotFoundError{BuildpackName: "some-bp-name"})) 569 Expect(warnings).To(ConsistOf("warning-1", "warning-2")) 570 }) 571 }) 572 573 When("getting the buildpack returns multiple buildpacks with stacks", func() { 574 BeforeEach(func() { 575 fakeCloudControllerClient.GetBuildpacksReturns( 576 []ccv2.Buildpack{ 577 {GUID: "some guid", Name: "some-bp-name", Stack: "some-stack"}, 578 {GUID: "some other guid", Name: "some-bp-name", Stack: "some-stack-2"}, 579 }, 580 ccv2.Warnings{"warning-1", "warning-2"}, 581 nil) 582 }) 583 584 It("returns an error that multiple buildpacks were found and returns all warnings", func() { 585 Expect(executeErr).To(MatchError(actionerror.MultipleBuildpacksFoundError{BuildpackName: "some-bp-name"})) 586 Expect(warnings).To(ConsistOf("warning-1", "warning-2")) 587 }) 588 }) 589 590 When("getting the buildpack successfully returns a single buildpack", func() { 591 BeforeEach(func() { 592 fakeCloudControllerClient.GetBuildpacksReturns([]ccv2.Buildpack{ 593 ccv2.Buildpack{GUID: "some guid", Name: "some-bp-name"}}, ccv2.Warnings{"get warning"}, nil) 594 }) 595 596 It("does not return an error", func() { 597 Expect(executeErr).ToNot(HaveOccurred()) 598 }) 599 600 It("returns any warnings", func() { 601 Expect(warnings).To(ConsistOf("get warning")) 602 }) 603 604 When("no changes to the buildpack record are specified", func() { 605 It("doesn't call the CC API", func() { 606 Expect(fakeCloudControllerClient.UpdateBuildpackCallCount()).To(Equal(0)) 607 }) 608 }) 609 610 When("a new position is specified", func() { 611 BeforeEach(func() { 612 newPosition = types.NullInt{IsSet: true, Value: 3} 613 }) 614 615 It("makes an API call to update the position", func() { 616 Expect(fakeCloudControllerClient.UpdateBuildpackCallCount()).To(Equal(1)) 617 passedBuildpack := fakeCloudControllerClient.UpdateBuildpackArgsForCall(0) 618 Expect(passedBuildpack.Position).To(Equal(newPosition)) 619 }) 620 }) 621 622 When("a new locked state is specified", func() { 623 BeforeEach(func() { 624 newLocked = types.NullBool{IsSet: true, Value: true} 625 }) 626 627 It("makes an API call to update the locked state", func() { 628 Expect(fakeCloudControllerClient.UpdateBuildpackCallCount()).To(Equal(1)) 629 passedBuildpack := fakeCloudControllerClient.UpdateBuildpackArgsForCall(0) 630 Expect(passedBuildpack.Locked).To(Equal(newLocked)) 631 }) 632 }) 633 634 When("a new enabled state is specified", func() { 635 BeforeEach(func() { 636 newEnabled = types.NullBool{IsSet: true, Value: true} 637 }) 638 639 It("makes an API call to update the enabled state", func() { 640 Expect(fakeCloudControllerClient.UpdateBuildpackCallCount()).To(Equal(1)) 641 passedBuildpack := fakeCloudControllerClient.UpdateBuildpackArgsForCall(0) 642 Expect(passedBuildpack.Enabled).To(Equal(newEnabled)) 643 }) 644 }) 645 646 When("a new stack is specified", func() { 647 BeforeEach(func() { 648 newStack = "some-new-stack" 649 fakeCloudControllerClient.GetStacksReturns( 650 []ccv2.Stack{{Name: newStack}}, 651 nil, 652 nil, 653 ) 654 }) 655 656 When("new stack exists", func() { 657 It("makes an API call to update the stack", func() { 658 Expect(fakeCloudControllerClient.UpdateBuildpackCallCount()).To(Equal(1)) 659 passedBuildpack := fakeCloudControllerClient.UpdateBuildpackArgsForCall(0) 660 Expect(passedBuildpack.Stack).To(Equal(newStack)) 661 }) 662 663 When("the buildpack already has a stack association", func() { 664 BeforeEach(func() { 665 fakeConfig.BinaryNameReturns("faceman") 666 fakeCloudControllerClient.GetBuildpacksReturns([]ccv2.Buildpack{ 667 ccv2.Buildpack{Stack: "some-old-stack-name", Name: "some-bp-name"}}, ccv2.Warnings{"get warning"}, nil) 668 }) 669 670 It("return the error and warnings", func() { 671 Expect(executeErr).To(MatchError(actionerror.BuildpackStackChangeError{BuildpackName: "some-bp-name", BinaryName: "faceman"})) 672 Expect(warnings).To(ConsistOf("get warning")) 673 }) 674 675 When("there are multiple buildpacks with the same name with stack associations", func() { 676 BeforeEach(func() { 677 fakeCloudControllerClient.GetBuildpacksReturns([]ccv2.Buildpack{ 678 ccv2.Buildpack{ 679 Stack: "some-stack-name", 680 Name: "some-bp-name", 681 }, 682 ccv2.Buildpack{ 683 Stack: "some-other-stack-name", 684 Name: "some-bp-name", 685 }}, ccv2.Warnings{"warning-1", "warning-2"}, nil) 686 }) 687 688 It("returns a BuildpackStackChangeError and warnings", func() { 689 Expect(executeErr).To(MatchError(actionerror.BuildpackStackChangeError{BuildpackName: "some-bp-name", BinaryName: "faceman"})) 690 Expect(warnings).To(ConsistOf("warning-1", "warning-2")) 691 }) 692 }) 693 694 When("there are multiple buildpacks with the same name and one has no stack association", func() { 695 BeforeEach(func() { 696 currentStack = "" 697 newStack = "some-new-stack" 698 fakeCloudControllerClient.GetBuildpacksReturns([]ccv2.Buildpack{ 699 ccv2.Buildpack{ 700 Stack: "some-stack-name", 701 Name: "some-bp-name", 702 GUID: "wrong-id", 703 }, 704 ccv2.Buildpack{ 705 Name: "some-bp-name", 706 GUID: "right-id", 707 }}, ccv2.Warnings{"warning-1", "warning-2"}, nil) 708 }) 709 710 It("succeeds and returns all warnings", func() { 711 Expect(executeErr).NotTo(HaveOccurred()) 712 Expect(warnings).To(ConsistOf("warning-1", "warning-2")) 713 }) 714 715 It("updates the buildpack that had no stack association", func() { 716 Expect(fakeCloudControllerClient.UpdateBuildpackCallCount()).To(Equal(1)) 717 ccv2Buildpack := fakeCloudControllerClient.UpdateBuildpackArgsForCall(0) 718 Expect(ccv2Buildpack.GUID).To(Equal("right-id")) 719 }) 720 }) 721 }) 722 }) 723 724 When("new stack does not exists", func() { 725 BeforeEach(func() { 726 newStack = "some-non-existing-stack" 727 fakeCloudControllerClient.GetStacksReturns( 728 []ccv2.Stack{}, 729 ccv2.Warnings{"get-stack-warning"}, 730 nil, 731 ) 732 }) 733 734 It("returns the error and warnings", func() { 735 Expect(executeErr).To(MatchError(actionerror.StackNotFoundError{Name: newStack})) 736 Expect(warnings).To(ConsistOf("get-stack-warning")) 737 }) 738 }) 739 }) 740 741 When("some arguments are specified and buildpack record update is needed", func() { 742 BeforeEach(func() { 743 newPosition = types.NullInt{IsSet: true, Value: 3} 744 newLocked = types.NullBool{IsSet: true, Value: true} 745 newEnabled = types.NullBool{IsSet: true, Value: true} 746 }) 747 748 It("updates the buildpack using the correct buildpack values", func() { 749 Expect(fakeCloudControllerClient.UpdateBuildpackCallCount()).To(Equal(1)) 750 Expect(fakeCloudControllerClient.UpdateBuildpackArgsForCall(0)).To(Equal(ccv2.Buildpack{ 751 GUID: "some guid", 752 Name: "some-bp-name", 753 Position: types.NullInt{IsSet: true, Value: 3}, 754 Locked: types.NullBool{IsSet: true, Value: true}, 755 Enabled: types.NullBool{IsSet: true, Value: true}, 756 })) 757 }) 758 759 When("updating the buildpack record returns an error", func() { 760 BeforeEach(func() { 761 fakeCloudControllerClient.UpdateBuildpackReturns(ccv2.Buildpack{}, nil, errors.New("failed")) 762 }) 763 764 It("returns the error", func() { 765 Expect(executeErr).To(MatchError("failed")) 766 }) 767 }) 768 769 When("updating the buildpack record succeeds", func() { 770 BeforeEach(func() { 771 fakeCloudControllerClient.UpdateBuildpackReturns(ccv2.Buildpack{GUID: "some guid"}, ccv2.Warnings{"update warning"}, nil) 772 }) 773 774 It("does not return an error", func() { 775 Expect(executeErr).ToNot(HaveOccurred()) 776 }) 777 778 It("returns any warnings", func() { 779 Expect(warnings).To(ConsistOf("get warning", "update warning")) 780 }) 781 }) 782 }) 783 }) 784 }) 785 786 Describe("UploadBuildpack", func() { 787 var ( 788 bpFile io.Reader 789 bpFilePath string 790 fakePb *v2actionfakes.FakeSimpleProgressBar 791 792 warnings Warnings 793 executeErr error 794 ) 795 796 BeforeEach(func() { 797 bpFile = strings.NewReader("") 798 }) 799 800 JustBeforeEach(func() { 801 fakePb = new(v2actionfakes.FakeSimpleProgressBar) 802 fakePb.InitializeReturns(bpFile, 0, nil) 803 bpFilePath = "tmp/buildpack.zip" 804 warnings, executeErr = actor.UploadBuildpack("some-bp-guid", bpFilePath, fakePb) 805 }) 806 807 It("tracks the progress of the upload", func() { 808 Expect(executeErr).ToNot(HaveOccurred()) 809 Expect(fakePb.InitializeCallCount()).To(Equal(1)) 810 Expect(fakePb.InitializeArgsForCall(0)).To(Equal(bpFilePath)) 811 Expect(fakePb.TerminateCallCount()).To(Equal(1)) 812 }) 813 814 When("the upload errors", func() { 815 BeforeEach(func() { 816 fakeCloudControllerClient.UploadBuildpackReturns(ccv2.Warnings{"some-upload-warning"}, errors.New("some-upload-error")) 817 }) 818 819 It("returns warnings and errors", func() { 820 Expect(warnings).To(ConsistOf("some-upload-warning")) 821 Expect(executeErr).To(MatchError("some-upload-error")) 822 }) 823 }) 824 825 When("the cc returns an error because the buildpack and stack combo already exists", func() { 826 BeforeEach(func() { 827 fakeCloudControllerClient.UploadBuildpackReturns(ccv2.Warnings{"some-upload-warning"}, ccerror.BuildpackAlreadyExistsForStackError{Message: "ya blew it"}) 828 }) 829 830 It("returns warnings and a BuildpackAlreadyExistsForStackError", func() { 831 Expect(warnings).To(ConsistOf("some-upload-warning")) 832 Expect(executeErr).To(MatchError(actionerror.BuildpackAlreadyExistsForStackError{Message: "ya blew it"})) 833 }) 834 }) 835 836 When("the upload is successful", func() { 837 BeforeEach(func() { 838 fakeCloudControllerClient.UploadBuildpackReturns(ccv2.Warnings{"some-create-warning"}, nil) 839 }) 840 841 It("uploads the buildpack and returns any warnings", func() { 842 Expect(executeErr).ToNot(HaveOccurred()) 843 Expect(fakeCloudControllerClient.UploadBuildpackCallCount()).To(Equal(1)) 844 guid, path, pbReader, size := fakeCloudControllerClient.UploadBuildpackArgsForCall(0) 845 Expect(guid).To(Equal("some-bp-guid")) 846 Expect(size).To(Equal(int64(0))) 847 Expect(path).To(Equal(bpFilePath)) 848 Expect(pbReader).To(Equal(bpFile)) 849 Expect(warnings).To(ConsistOf("some-create-warning")) 850 }) 851 }) 852 }) 853 854 Describe("Zipit", func() { 855 //tested in buildpack_linux_test.go and buildpack_windows_test.go 856 var ( 857 source string 858 target string 859 860 executeErr error 861 ) 862 863 JustBeforeEach(func() { 864 executeErr = Zipit(source, target, "testzip-") 865 }) 866 867 When("the source directory does not exist", func() { 868 BeforeEach(func() { 869 source = "" 870 target = "" 871 }) 872 873 It("returns an error", func() { 874 Expect(os.IsNotExist(executeErr)).To(BeTrue()) 875 }) 876 }) 877 }) 878 })