github.com/mook-as/cf-cli@v7.0.0-beta.28.0.20200120190804-b91c115fae48+incompatible/actor/pushaction/apply_test.go (about) 1 package pushaction_test 2 3 import ( 4 "errors" 5 "io/ioutil" 6 "os" 7 8 "code.cloudfoundry.org/cli/actor/actionerror" 9 . "code.cloudfoundry.org/cli/actor/pushaction" 10 "code.cloudfoundry.org/cli/actor/pushaction/pushactionfakes" 11 "code.cloudfoundry.org/cli/actor/v2action" 12 "code.cloudfoundry.org/cli/api/cloudcontroller/ccerror" 13 "code.cloudfoundry.org/cli/cf/util/testhelpers/matchers" 14 . "github.com/onsi/ginkgo" 15 . "github.com/onsi/gomega" 16 ) 17 18 func collectAllEvents(configStream <-chan ApplicationConfig, eventStream <-chan Event, warningsStream <-chan Warnings, errorStream <-chan error) ([]ApplicationConfig, []Event, Warnings, []error) { 19 var ( 20 configStreamClosed, eventStreamClosed, warningsStreamClosed, errorStreamClosed bool 21 22 allConfigs []ApplicationConfig 23 allEvents []Event 24 allWarnings Warnings 25 allErrors []error 26 ) 27 28 for { 29 select { 30 case config, ok := <-configStream: 31 if !ok { 32 configStreamClosed = true 33 } 34 35 allConfigs = append(allConfigs, config) 36 case event, ok := <-eventStream: 37 if !ok { 38 eventStreamClosed = true 39 } 40 41 allEvents = append(allEvents, event) 42 case warning, ok := <-warningsStream: 43 if !ok { 44 warningsStreamClosed = true 45 } 46 47 allWarnings = append(allWarnings, warning...) 48 case err, ok := <-errorStream: 49 if !ok { 50 errorStreamClosed = true 51 } 52 53 if err != nil { 54 allErrors = append(allErrors, err) 55 } 56 } 57 58 if configStreamClosed && eventStreamClosed && warningsStreamClosed && errorStreamClosed { 59 break 60 } 61 } 62 63 return allConfigs, allEvents, allWarnings, allErrors 64 } 65 66 var _ = Describe("Apply", func() { 67 var ( 68 actor *Actor 69 fakeV2Actor *pushactionfakes.FakeV2Actor 70 fakeSharedActor *pushactionfakes.FakeSharedActor 71 72 config ApplicationConfig 73 fakeProgressBar *pushactionfakes.FakeProgressBar 74 75 eventStream <-chan Event 76 warningsStream <-chan Warnings 77 errorStream <-chan error 78 configStream <-chan ApplicationConfig 79 80 allConfigs []ApplicationConfig 81 allEvents []Event 82 allWarnings Warnings 83 allErrors []error 84 ) 85 86 BeforeEach(func() { 87 actor, fakeV2Actor, _, fakeSharedActor = getTestPushActor() 88 config = ApplicationConfig{ 89 DesiredApplication: Application{ 90 Application: v2action.Application{ 91 Name: "some-app-name", 92 SpaceGUID: "some-space-guid", 93 }}, 94 DesiredRoutes: []v2action.Route{{Host: "banana"}}, 95 } 96 fakeProgressBar = new(pushactionfakes.FakeProgressBar) 97 }) 98 99 JustBeforeEach(func() { 100 configStream, eventStream, warningsStream, errorStream = actor.Apply(config, fakeProgressBar) 101 102 allConfigs, allEvents, allWarnings, allErrors = collectAllEvents(configStream, eventStream, warningsStream, errorStream) 103 }) 104 105 When("creating/updating the application is successful", func() { 106 var createdApp v2action.Application 107 108 BeforeEach(func() { 109 fakeV2Actor.CreateApplicationStub = func(application v2action.Application) (v2action.Application, v2action.Warnings, error) { 110 createdApp = application 111 createdApp.GUID = "some-app-guid" 112 113 return createdApp, v2action.Warnings{"create-application-warnings-1", "create-application-warnings-2"}, nil 114 } 115 }) 116 117 JustBeforeEach(func() { 118 Expect(allEvents).To(matchers.ContainElementsInOrder(SettingUpApplication, CreatedApplication)) 119 Expect(allWarnings).To(matchers.ContainElementsInOrder("create-application-warnings-1", "create-application-warnings-2")) 120 }) 121 122 When("the route creation is successful", func() { 123 var createdRoutes []v2action.Route 124 125 BeforeEach(func() { 126 createdRoutes = []v2action.Route{{Host: "banana", GUID: "some-route-guid"}} 127 fakeV2Actor.CreateRouteReturns(createdRoutes[0], v2action.Warnings{"create-route-warnings-1", "create-route-warnings-2"}, nil) 128 }) 129 130 JustBeforeEach(func() { 131 Expect(allEvents).To(matchers.ContainElementsInOrder(CreatingAndMappingRoutes)) 132 Expect(allWarnings).To(matchers.ContainElementsInOrder("create-route-warnings-1", "create-route-warnings-2")) 133 Expect(allEvents).To(matchers.ContainElementsInOrder(CreatedRoutes)) 134 }) 135 136 When("mapping the routes is successful", func() { 137 var desiredServices map[string]v2action.ServiceInstance 138 139 BeforeEach(func() { 140 desiredServices = map[string]v2action.ServiceInstance{ 141 "service_1": {Name: "service_1", GUID: "service_guid"}, 142 } 143 config.DesiredServices = desiredServices 144 fakeV2Actor.MapRouteToApplicationReturns(v2action.Warnings{"map-route-warnings-1", "map-route-warnings-2"}, nil) 145 }) 146 147 JustBeforeEach(func() { 148 Expect(allWarnings).To(matchers.ContainElementsInOrder("map-route-warnings-1", "map-route-warnings-2")) 149 Expect(allEvents).To(matchers.ContainElementsInOrder(BoundRoutes)) 150 }) 151 152 When("service binding is successful", func() { 153 BeforeEach(func() { 154 fakeV2Actor.BindServiceByApplicationAndServiceInstanceReturns(v2action.Warnings{"bind-service-warnings-1", "bind-service-warnings-2"}, nil) 155 }) 156 157 JustBeforeEach(func() { 158 Expect(allEvents).To(matchers.ContainElementsInOrder(ConfiguringServices)) 159 Expect(allWarnings).To(matchers.ContainElementsInOrder("bind-service-warnings-1", "bind-service-warnings-2")) 160 Expect(allEvents).To(matchers.ContainElementsInOrder(BoundServices)) 161 }) 162 163 When("resource matching happens", func() { 164 BeforeEach(func() { 165 config.Path = "some-path" 166 }) 167 168 JustBeforeEach(func() { 169 Expect(allEvents).To(matchers.ContainElementsInOrder(ResourceMatching)) 170 Expect(allWarnings).To(matchers.ContainElementsInOrder("resource-warnings-1", "resource-warnings-2")) 171 }) 172 173 When("there is at least one resource that has not been matched", func() { 174 BeforeEach(func() { 175 fakeV2Actor.ResourceMatchReturns(nil, []v2action.Resource{{}}, v2action.Warnings{"resource-warnings-1", "resource-warnings-2"}, nil) 176 }) 177 178 When("the archive creation is successful", func() { 179 var archivePath string 180 181 BeforeEach(func() { 182 tmpfile, err := ioutil.TempFile("", "fake-archive") 183 Expect(err).ToNot(HaveOccurred()) 184 _, err = tmpfile.Write([]byte("123456")) 185 Expect(err).ToNot(HaveOccurred()) 186 Expect(tmpfile.Close()).ToNot(HaveOccurred()) 187 188 archivePath = tmpfile.Name() 189 fakeSharedActor.ZipDirectoryResourcesReturns(archivePath, nil) 190 }) 191 192 JustBeforeEach(func() { 193 Expect(allEvents).To(matchers.ContainElementsInOrder(CreatingArchive)) 194 }) 195 196 When("the upload is successful", func() { 197 BeforeEach(func() { 198 fakeV2Actor.UploadApplicationPackageReturns(v2action.Job{}, v2action.Warnings{"upload-warnings-1", "upload-warnings-2"}, nil) 199 }) 200 201 JustBeforeEach(func() { 202 Expect(allEvents).To(matchers.ContainElementsInOrder(UploadingApplicationWithArchive, UploadWithArchiveComplete)) 203 Expect(allWarnings).To(matchers.ContainElementsInOrder("upload-warnings-1", "upload-warnings-2")) 204 }) 205 206 It("sends the updated config and a complete event", func() { 207 Expect(allConfigs).To(matchers.ContainElementsInOrder(ApplicationConfig{ 208 CurrentApplication: Application{Application: createdApp}, 209 CurrentRoutes: createdRoutes, 210 CurrentServices: desiredServices, 211 DesiredApplication: Application{Application: createdApp}, 212 DesiredRoutes: createdRoutes, 213 DesiredServices: desiredServices, 214 UnmatchedResources: []v2action.Resource{{}}, 215 Path: "some-path", 216 })) 217 Expect(allEvents).To(matchers.ContainElementsInOrder(Complete)) 218 219 Expect(fakeV2Actor.UploadApplicationPackageCallCount()).To(Equal(1)) 220 }) 221 }) 222 }) 223 }) 224 225 When("all the resources have been matched", func() { 226 BeforeEach(func() { 227 fakeV2Actor.ResourceMatchReturns(nil, nil, v2action.Warnings{"resource-warnings-1", "resource-warnings-2"}, nil) 228 }) 229 230 JustBeforeEach(func() { 231 Expect(allEvents).To(matchers.ContainElementsInOrder(UploadingApplication)) 232 Expect(allWarnings).To(matchers.ContainElementsInOrder("upload-warnings-1", "upload-warnings-2")) 233 }) 234 235 When("the upload is successful", func() { 236 BeforeEach(func() { 237 fakeV2Actor.UploadApplicationPackageReturns(v2action.Job{}, v2action.Warnings{"upload-warnings-1", "upload-warnings-2"}, nil) 238 }) 239 240 It("sends the updated config and a complete event", func() { 241 Expect(allConfigs).To(matchers.ContainElementsInOrder(ApplicationConfig{ 242 CurrentApplication: Application{Application: createdApp}, 243 CurrentRoutes: createdRoutes, 244 CurrentServices: desiredServices, 245 DesiredApplication: Application{Application: createdApp}, 246 DesiredRoutes: createdRoutes, 247 DesiredServices: desiredServices, 248 Path: "some-path", 249 })) 250 Expect(allEvents).To(matchers.ContainElementsInOrder(Complete)) 251 252 Expect(fakeV2Actor.UploadApplicationPackageCallCount()).To(Equal(1)) 253 _, _, reader, readerLength := fakeV2Actor.UploadApplicationPackageArgsForCall(0) 254 Expect(reader).To(BeNil()) 255 Expect(readerLength).To(BeNumerically("==", 0)) 256 }) 257 }) 258 }) 259 }) 260 261 When("a droplet is provided", func() { 262 var dropletPath string 263 264 BeforeEach(func() { 265 tmpfile, err := ioutil.TempFile("", "fake-droplet") 266 Expect(err).ToNot(HaveOccurred()) 267 _, err = tmpfile.Write([]byte("123456")) 268 Expect(err).ToNot(HaveOccurred()) 269 Expect(tmpfile.Close()).ToNot(HaveOccurred()) 270 271 dropletPath = tmpfile.Name() 272 config.DropletPath = dropletPath 273 }) 274 275 AfterEach(func() { 276 Expect(os.RemoveAll(dropletPath)).ToNot(HaveOccurred()) 277 }) 278 279 When("the upload is successful", func() { 280 BeforeEach(func() { 281 fakeV2Actor.UploadDropletReturns(v2action.Job{}, v2action.Warnings{"upload-warnings-1", "upload-warnings-2"}, nil) 282 }) 283 284 It("sends an updated config and a complete event", func() { 285 Expect(allEvents).To(matchers.ContainElementsInOrder(UploadDropletComplete)) 286 Expect(allWarnings).To(matchers.ContainElementsInOrder("upload-warnings-1", "upload-warnings-2")) 287 Expect(allConfigs).To(matchers.ContainElementsInOrder(ApplicationConfig{ 288 CurrentApplication: Application{Application: createdApp}, 289 CurrentRoutes: createdRoutes, 290 CurrentServices: desiredServices, 291 DesiredApplication: Application{Application: createdApp}, 292 DesiredRoutes: createdRoutes, 293 DesiredServices: desiredServices, 294 DropletPath: dropletPath, 295 })) 296 297 Expect(fakeV2Actor.UploadDropletCallCount()).To(Equal(1)) 298 _, droplet, dropletLength := fakeV2Actor.UploadDropletArgsForCall(0) 299 Expect(droplet).To(BeNil()) 300 Expect(dropletLength).To(BeNumerically("==", 6)) 301 Expect(fakeSharedActor.ZipDirectoryResourcesCallCount()).To(Equal(0)) 302 }) 303 }) 304 }) 305 }) 306 }) 307 }) 308 }) 309 310 When("creating/updating errors", func() { 311 var expectedErr error 312 313 BeforeEach(func() { 314 expectedErr = errors.New("dios mio") 315 fakeV2Actor.CreateApplicationReturns(v2action.Application{}, v2action.Warnings{"create-application-warnings-1", "create-application-warnings-2"}, expectedErr) 316 }) 317 318 It("sends warnings and errors, then stops", func() { 319 Expect(allEvents).To(matchers.ContainElementsInOrder(SettingUpApplication)) 320 Expect(allWarnings).To(matchers.ContainElementsInOrder("create-application-warnings-1", "create-application-warnings-2")) 321 Expect(allErrors).To(ContainElement(MatchError(expectedErr))) 322 }) 323 }) 324 325 Describe("Routes", func() { 326 BeforeEach(func() { 327 config.DesiredRoutes = v2action.Routes{{GUID: "some-route-guid"}} 328 }) 329 330 When("NoRoutes is set", func() { 331 BeforeEach(func() { 332 config.NoRoute = true 333 }) 334 335 When("config has at least one route", func() { 336 BeforeEach(func() { 337 config.CurrentRoutes = []v2action.Route{{GUID: "some-route-guid-1"}} 338 }) 339 340 When("unmapping routes succeeds", func() { 341 BeforeEach(func() { 342 fakeV2Actor.UnmapRouteFromApplicationReturns(v2action.Warnings{"unmapping-route-warnings"}, nil) 343 }) 344 345 It("sends the UnmappingRoutes event and does not raise an error", func() { 346 Expect(allEvents).To(matchers.ContainElementsInOrder(UnmappingRoutes, Complete)) 347 Expect(allWarnings).To(ContainElement("unmapping-route-warnings")) 348 }) 349 }) 350 351 When("unmapping routes fails", func() { 352 BeforeEach(func() { 353 fakeV2Actor.UnmapRouteFromApplicationReturns(v2action.Warnings{"unmapping-route-warnings"}, errors.New("ohno")) 354 }) 355 356 It("sends the UnmappingRoutes event and raise an error", func() { 357 Expect(allEvents).To(matchers.ContainElementsInOrder(UnmappingRoutes)) 358 Expect(allEvents).NotTo(ContainElement(Complete)) 359 Expect(allWarnings).To(matchers.ContainElementsInOrder("unmapping-route-warnings")) 360 Expect(allErrors).To(ContainElement(MatchError("ohno"))) 361 }) 362 }) 363 }) 364 365 When("config has no routes", func() { 366 BeforeEach(func() { 367 config.CurrentRoutes = nil 368 }) 369 370 It("should not send the UnmappingRoutes event", func() { 371 Expect(allEvents).NotTo(ContainElement(UnmappingRoutes)) 372 Expect(allErrors).To(BeEmpty()) 373 374 Expect(fakeV2Actor.UnmapRouteFromApplicationCallCount()).To(Equal(0)) 375 }) 376 }) 377 }) 378 379 When("NoRoutes is NOT set", func() { 380 BeforeEach(func() { 381 config.NoRoute = false 382 }) 383 384 It("should send the CreatingAndMappingRoutes event", func() { 385 Expect(allEvents).To(ContainElement(CreatingAndMappingRoutes)) 386 }) 387 388 When("no new routes are provided", func() { 389 BeforeEach(func() { 390 config.DesiredRoutes = nil 391 }) 392 393 It("should not send the CreatedRoutes event", func() { 394 Expect(allEvents).To(ContainElement(CreatingAndMappingRoutes)) 395 Expect(allEvents).NotTo(ContainElement(CreatedRoutes)) 396 Expect(allWarnings).To(BeEmpty()) 397 }) 398 }) 399 400 When("new routes are provided", func() { 401 BeforeEach(func() { 402 config.DesiredRoutes = []v2action.Route{{}} 403 }) 404 405 When("route creation fails", func() { 406 BeforeEach(func() { 407 fakeV2Actor.CreateRouteReturns(v2action.Route{}, v2action.Warnings{"create-route-warning"}, errors.New("ohno")) 408 }) 409 410 It("raise an error", func() { 411 Expect(allEvents).To(ContainElement(CreatingAndMappingRoutes)) 412 Expect(allEvents).NotTo(ContainElement(CreatedRoutes)) 413 Expect(allEvents).NotTo(ContainElement(Complete)) 414 Expect(allWarnings).To(matchers.ContainElementsInOrder("create-route-warning")) 415 Expect(allErrors).To(ContainElement(MatchError("ohno"))) 416 }) 417 }) 418 419 When("route creation succeeds", func() { 420 BeforeEach(func() { 421 fakeV2Actor.CreateRouteReturns(v2action.Route{}, v2action.Warnings{"create-route-warning"}, nil) 422 }) 423 424 It("should send the CreatedRoutes event", func() { 425 Expect(allEvents).To(matchers.ContainElementsInOrder(CreatingAndMappingRoutes, CreatedRoutes)) 426 Expect(allWarnings).To(matchers.ContainElementsInOrder("create-route-warning")) 427 }) 428 }) 429 }) 430 431 When("there are no routes to map", func() { 432 BeforeEach(func() { 433 config.CurrentRoutes = config.DesiredRoutes 434 }) 435 436 It("should not send the BoundRoutes event", func() { 437 Expect(allEvents).To(ContainElement(CreatingAndMappingRoutes)) 438 439 Expect(allEvents).NotTo(ContainElement(BoundRoutes)) 440 }) 441 }) 442 443 When("there are routes to map", func() { 444 BeforeEach(func() { 445 config.DesiredRoutes = []v2action.Route{{GUID: "new-guid"}} 446 }) 447 448 When("binding the route fails", func() { 449 BeforeEach(func() { 450 fakeV2Actor.MapRouteToApplicationReturns(v2action.Warnings{"bind-route-warning"}, errors.New("ohno")) 451 }) 452 453 It("raise an error", func() { 454 Expect(allEvents).To(ContainElement(CreatingAndMappingRoutes)) 455 Expect(allEvents).NotTo(ContainElement(BoundRoutes)) 456 Expect(allEvents).NotTo(ContainElement(Complete)) 457 Expect(allWarnings).To(matchers.ContainElementsInOrder("bind-route-warning")) 458 Expect(allErrors).To(ContainElement(MatchError("ohno"))) 459 }) 460 }) 461 462 When("binding the route succeeds", func() { 463 BeforeEach(func() { 464 fakeV2Actor.MapRouteToApplicationReturns(v2action.Warnings{"bind-route-warning"}, nil) 465 }) 466 467 It("should send the BoundRoutes event", func() { 468 Expect(allEvents).To(matchers.ContainElementsInOrder(CreatingAndMappingRoutes, BoundRoutes)) 469 Expect(allWarnings).To(matchers.ContainElementsInOrder("bind-route-warning")) 470 }) 471 }) 472 }) 473 }) 474 }) 475 476 Describe("Services", func() { 477 var ( 478 service1 v2action.ServiceInstance 479 service2 v2action.ServiceInstance 480 ) 481 482 BeforeEach(func() { 483 service1 = v2action.ServiceInstance{Name: "service_1", GUID: "service_1_guid"} 484 service2 = v2action.ServiceInstance{Name: "service_2", GUID: "service_2_guid"} 485 }) 486 487 When("there are no new services", func() { 488 BeforeEach(func() { 489 config.CurrentServices = map[string]v2action.ServiceInstance{"service1": service1} 490 config.DesiredServices = map[string]v2action.ServiceInstance{"service1": service1} 491 }) 492 493 It("should not send the ConfiguringServices or BoundServices event", func() { 494 Expect(allEvents).NotTo(ContainElement(ConfiguringServices)) 495 Expect(allEvents).NotTo(ContainElement(BoundServices)) 496 }) 497 }) 498 499 When("are new services", func() { 500 BeforeEach(func() { 501 config.CurrentServices = map[string]v2action.ServiceInstance{"service1": service1} 502 config.DesiredServices = map[string]v2action.ServiceInstance{"service1": service1, "service2": service2} 503 }) 504 505 When("binding services fails", func() { 506 BeforeEach(func() { 507 fakeV2Actor.BindServiceByApplicationAndServiceInstanceReturns(v2action.Warnings{"bind-service-warning"}, errors.New("ohno")) 508 }) 509 510 It("raises an error", func() { 511 Expect(allEvents).To(matchers.ContainElementsInOrder(BoundRoutes, ConfiguringServices)) 512 Expect(allEvents).NotTo(ContainElement(BoundServices)) 513 Expect(allEvents).NotTo(ContainElement(Complete)) 514 Expect(allWarnings).To(matchers.ContainElementsInOrder("bind-service-warning")) 515 Expect(allErrors).To(ContainElement(MatchError("ohno"))) 516 }) 517 }) 518 519 When("binding services suceeds", func() { 520 BeforeEach(func() { 521 fakeV2Actor.BindServiceByApplicationAndServiceInstanceReturns(v2action.Warnings{"bind-service-warning"}, nil) 522 }) 523 524 It("sends the ConfiguringServices and BoundServices events", func() { 525 Expect(allEvents).To(matchers.ContainElementsInOrder(ConfiguringServices, BoundServices)) 526 Expect(allWarnings).To(matchers.ContainElementsInOrder("bind-service-warning")) 527 }) 528 }) 529 }) 530 }) 531 532 Describe("Upload", func() { 533 When("a droplet is provided", func() { 534 var dropletPath string 535 536 BeforeEach(func() { 537 tmpfile, err := ioutil.TempFile("", "fake-droplet") 538 Expect(err).ToNot(HaveOccurred()) 539 _, err = tmpfile.Write([]byte("123456")) 540 Expect(err).ToNot(HaveOccurred()) 541 Expect(tmpfile.Close()).ToNot(HaveOccurred()) 542 543 dropletPath = tmpfile.Name() 544 config.DropletPath = dropletPath 545 }) 546 547 AfterEach(func() { 548 Expect(os.RemoveAll(dropletPath)).ToNot(HaveOccurred()) 549 }) 550 551 When("uploading the droplet fails", func() { 552 When("the error is a retryable error", func() { 553 var someErr error 554 BeforeEach(func() { 555 someErr = errors.New("I AM A BANANA") 556 fakeV2Actor.UploadDropletReturns(v2action.Job{}, v2action.Warnings{"droplet-upload-warning"}, ccerror.PipeSeekError{Err: someErr}) 557 }) 558 559 It("should send a RetryUpload event and retry uploading up to 3x", func() { 560 Expect(allEvents).To(matchers.ContainElementsInOrder( 561 UploadingDroplet, 562 RetryUpload, 563 UploadingDroplet, 564 RetryUpload, 565 UploadingDroplet, 566 RetryUpload, 567 )) 568 569 Expect(allEvents).To(matchers.ContainElementTimes(RetryUpload, 3)) 570 Expect(allEvents).NotTo(ContainElement(UploadDropletComplete)) 571 Expect(allEvents).NotTo(ContainElement(Complete)) 572 573 Expect(allWarnings).To(matchers.ContainElementsInOrder( 574 "droplet-upload-warning", 575 "droplet-upload-warning", 576 "droplet-upload-warning", 577 )) 578 579 Expect(fakeV2Actor.UploadDropletCallCount()).To(Equal(3)) 580 Expect(allErrors).To(ContainElement(MatchError(actionerror.UploadFailedError{Err: someErr}))) 581 }) 582 }) 583 584 When("the error is not a retryable error", func() { 585 BeforeEach(func() { 586 fakeV2Actor.UploadDropletReturns(v2action.Job{}, v2action.Warnings{"droplet-upload-warning"}, errors.New("ohno")) 587 }) 588 589 It("raises an error", func() { 590 Expect(allEvents).To(matchers.ContainElementsInOrder(UploadingDroplet)) 591 Expect(allWarnings).To(matchers.ContainElementsInOrder("droplet-upload-warning")) 592 Expect(allErrors).To(ContainElement(MatchError("ohno"))) 593 594 Expect(allEvents).NotTo(ContainElement(EqualEither(RetryUpload, UploadDropletComplete, Complete))) 595 }) 596 }) 597 }) 598 599 When("uploading the droplet is successful", func() { 600 BeforeEach(func() { 601 fakeV2Actor.UploadDropletReturns(v2action.Job{}, v2action.Warnings{"droplet-upload-warning"}, nil) 602 }) 603 604 It("sends the UploadingDroplet event", func() { 605 Expect(allEvents).To(matchers.ContainElementsInOrder(UploadingDroplet, UploadDropletComplete)) 606 Expect(allWarnings).To(matchers.ContainElementsInOrder("droplet-upload-warning")) 607 }) 608 }) 609 }) 610 611 When("app bits are provided", func() { 612 When("there is at least one unmatched resource", func() { 613 BeforeEach(func() { 614 fakeV2Actor.ResourceMatchReturns(nil, []v2action.Resource{{}}, v2action.Warnings{"resource-warnings-1", "resource-warnings-2"}, nil) 615 }) 616 617 It("returns resource match warnings", func() { 618 Expect(allEvents).To(matchers.ContainElementsInOrder(ResourceMatching)) 619 Expect(allWarnings).To(matchers.ContainElementsInOrder("resource-warnings-1", "resource-warnings-2")) 620 }) 621 622 When("creating the archive is successful", func() { 623 var archivePath string 624 625 BeforeEach(func() { 626 tmpfile, err := ioutil.TempFile("", "fake-archive") 627 Expect(err).ToNot(HaveOccurred()) 628 _, err = tmpfile.Write([]byte("123456")) 629 Expect(err).ToNot(HaveOccurred()) 630 Expect(tmpfile.Close()).ToNot(HaveOccurred()) 631 632 archivePath = tmpfile.Name() 633 fakeSharedActor.ZipDirectoryResourcesReturns(archivePath, nil) 634 }) 635 636 It("sends a CreatingArchive event", func() { 637 Expect(allEvents).To(matchers.ContainElementsInOrder(CreatingArchive)) 638 }) 639 640 When("the upload is successful", func() { 641 BeforeEach(func() { 642 fakeV2Actor.UploadApplicationPackageReturns(v2action.Job{}, v2action.Warnings{"upload-warnings-1", "upload-warnings-2"}, nil) 643 }) 644 645 It("sends a UploadingApplicationWithArchive event", func() { 646 Expect(allEvents).To(matchers.ContainElementsInOrder(UploadingApplicationWithArchive)) 647 Expect(allEvents).To(matchers.ContainElementsInOrder(UploadWithArchiveComplete)) 648 Expect(allWarnings).To(matchers.ContainElementsInOrder("upload-warnings-1", "upload-warnings-2")) 649 }) 650 }) 651 652 When("the upload fails", func() { 653 When("the upload error is a retryable error", func() { 654 var someErr error 655 656 BeforeEach(func() { 657 someErr = errors.New("I AM A BANANA") 658 fakeV2Actor.UploadApplicationPackageReturns(v2action.Job{}, v2action.Warnings{"upload-warnings-1", "upload-warnings-2"}, ccerror.PipeSeekError{Err: someErr}) 659 }) 660 661 It("should send a RetryUpload event and retry uploading", func() { 662 Expect(allEvents).To(matchers.ContainElementsInOrder( 663 UploadingApplicationWithArchive, 664 RetryUpload, 665 UploadingApplicationWithArchive, 666 RetryUpload, 667 UploadingApplicationWithArchive, 668 RetryUpload, 669 )) 670 671 Expect(allEvents).To(matchers.ContainElementTimes(RetryUpload, 3)) 672 Expect(allEvents).NotTo(ContainElement(EqualEither(UploadWithArchiveComplete, Complete))) 673 674 Expect(allWarnings).To(matchers.ContainElementsInOrder( 675 "upload-warnings-1", "upload-warnings-2", 676 "upload-warnings-1", "upload-warnings-2", 677 "upload-warnings-1", "upload-warnings-2", 678 )) 679 680 Expect(fakeV2Actor.UploadApplicationPackageCallCount()).Should(Equal(3)) 681 Expect(allErrors).To(ContainElement(MatchError(actionerror.UploadFailedError{Err: someErr}))) 682 }) 683 684 }) 685 686 When("the upload error is not a retryable error", func() { 687 BeforeEach(func() { 688 fakeV2Actor.UploadApplicationPackageReturns(v2action.Job{}, v2action.Warnings{"upload-warnings-1", "upload-warnings-2"}, errors.New("dios mio")) 689 }) 690 691 It("sends warnings and errors, then stops", func() { 692 693 Expect(allEvents).To(matchers.ContainElementsInOrder(UploadingApplicationWithArchive)) 694 Expect(allWarnings).To(matchers.ContainElementsInOrder("upload-warnings-1", "upload-warnings-2")) 695 Expect(allEvents).NotTo(ContainElement(EqualEither(RetryUpload, UploadWithArchiveComplete, Complete))) 696 Expect(allErrors).To(ContainElement(MatchError("dios mio"))) 697 }) 698 }) 699 }) 700 }) 701 702 When("creating the archive fails", func() { 703 BeforeEach(func() { 704 fakeSharedActor.ZipDirectoryResourcesReturns("", errors.New("some-error")) 705 }) 706 707 It("raises an error", func() { 708 Expect(allEvents).To(matchers.ContainElementsInOrder(ResourceMatching)) 709 Expect(allEvents).NotTo(ContainElement(Complete)) 710 Expect(allWarnings).To(matchers.ContainElementsInOrder("resource-warnings-1", "resource-warnings-2")) 711 Expect(allErrors).To(ContainElement(MatchError("some-error"))) 712 713 }) 714 }) 715 }) 716 717 When("all resources have been matched", func() { 718 BeforeEach(func() { 719 fakeV2Actor.ResourceMatchReturns(nil, nil, v2action.Warnings{"resource-warnings-1", "resource-warnings-2"}, nil) 720 }) 721 722 It("sends the UploadingApplication event", func() { 723 Expect(allEvents).To(matchers.ContainElementsInOrder(ResourceMatching)) 724 Expect(allWarnings).To(matchers.ContainElementsInOrder("resource-warnings-1", "resource-warnings-2")) 725 Expect(allEvents).To(matchers.ContainElementsInOrder(UploadingApplication)) 726 }) 727 728 When("the upload is successful", func() { 729 BeforeEach(func() { 730 fakeV2Actor.UploadApplicationPackageReturns(v2action.Job{}, v2action.Warnings{"upload-warnings-1", "upload-warnings-2"}, nil) 731 }) 732 733 It("uploads the application and completes", func() { 734 Expect(allEvents).To(matchers.ContainElementsInOrder(UploadingApplication)) 735 Expect(allWarnings).To(matchers.ContainElementsInOrder("upload-warnings-1", "upload-warnings-2")) 736 Expect(allEvents).To(matchers.ContainElementsInOrder(Complete)) 737 }) 738 }) 739 740 When("the upload fails", func() { 741 BeforeEach(func() { 742 fakeV2Actor.UploadApplicationPackageReturns(v2action.Job{}, v2action.Warnings{"upload-warnings-1", "upload-warnings-2"}, errors.New("some-upload-error")) 743 }) 744 745 It("returns an error", func() { 746 Expect(allEvents).To(matchers.ContainElementsInOrder(UploadingApplication)) 747 Expect(allWarnings).To(matchers.ContainElementsInOrder("upload-warnings-1", "upload-warnings-2")) 748 Expect(allErrors).To(ContainElement(MatchError("some-upload-error"))) 749 Expect(allEvents).NotTo(ContainElement(Complete)) 750 }) 751 }) 752 }) 753 }) 754 755 When("a docker image is provided", func() { 756 BeforeEach(func() { 757 config.DesiredApplication.DockerImage = "hi-im-a-ge" 758 759 fakeV2Actor.CreateApplicationReturns(config.DesiredApplication.Application, nil, nil) 760 }) 761 762 It("should skip uploading anything", func() { 763 Expect(allEvents).NotTo(ContainElement(EqualEither(UploadingDroplet, UploadingApplication))) 764 }) 765 }) 766 }) 767 })