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