github.com/DaAlbrecht/cf-cli@v0.0.0-20231128151943-1fe19bb400b9/actor/v7action/service_instance_test.go (about) 1 package v7action_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/actor/v7action/v7actionfakes" 9 "code.cloudfoundry.org/cli/api/cloudcontroller/ccerror" 10 "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3" 11 "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant" 12 "code.cloudfoundry.org/cli/resources" 13 "code.cloudfoundry.org/cli/types" 14 . "github.com/onsi/ginkgo" 15 . "github.com/onsi/gomega" 16 ) 17 18 var _ = Describe("Service Instance Actions", func() { 19 var ( 20 actor *Actor 21 fakeCloudControllerClient *v7actionfakes.FakeCloudControllerClient 22 ) 23 24 BeforeEach(func() { 25 fakeCloudControllerClient = new(v7actionfakes.FakeCloudControllerClient) 26 actor = NewActor(fakeCloudControllerClient, nil, nil, nil, nil, nil) 27 }) 28 29 Describe("GetServiceInstanceByNameAndSpace", func() { 30 const ( 31 serviceInstanceName = "some-service-instance" 32 spaceGUID = "some-source-space-guid" 33 ) 34 35 var ( 36 serviceInstance resources.ServiceInstance 37 warnings Warnings 38 executionError error 39 ) 40 41 JustBeforeEach(func() { 42 serviceInstance, warnings, executionError = actor.GetServiceInstanceByNameAndSpace(serviceInstanceName, spaceGUID) 43 }) 44 45 When("the cloud controller request is successful", func() { 46 BeforeEach(func() { 47 fakeCloudControllerClient.GetServiceInstanceByNameAndSpaceReturns(resources.ServiceInstance{ 48 Name: "some-service-instance", 49 GUID: "some-service-instance-guid", 50 }, ccv3.IncludedResources{}, ccv3.Warnings{"some-service-instance-warning"}, nil) 51 }) 52 53 It("returns a service instance and warnings", func() { 54 Expect(executionError).NotTo(HaveOccurred()) 55 56 Expect(serviceInstance).To(Equal(resources.ServiceInstance{Name: "some-service-instance", GUID: "some-service-instance-guid"})) 57 Expect(warnings).To(ConsistOf("some-service-instance-warning")) 58 Expect(fakeCloudControllerClient.GetServiceInstanceByNameAndSpaceCallCount()).To(Equal(1)) 59 actualName, actualSpaceGUID, actualQuery := fakeCloudControllerClient.GetServiceInstanceByNameAndSpaceArgsForCall(0) 60 Expect(actualName).To(Equal(serviceInstanceName)) 61 Expect(actualSpaceGUID).To(Equal(spaceGUID)) 62 Expect(actualQuery).To(BeEmpty()) 63 }) 64 }) 65 66 When("the service instance cannot be found", func() { 67 BeforeEach(func() { 68 fakeCloudControllerClient.GetServiceInstanceByNameAndSpaceReturns( 69 resources.ServiceInstance{}, 70 ccv3.IncludedResources{}, 71 ccv3.Warnings{"some-service-instance-warning"}, 72 ccerror.ServiceInstanceNotFoundError{Name: serviceInstanceName, SpaceGUID: spaceGUID}, 73 ) 74 }) 75 76 It("returns an actor error and warnings", func() { 77 Expect(executionError).To(MatchError(actionerror.ServiceInstanceNotFoundError{Name: serviceInstanceName})) 78 Expect(warnings).To(ConsistOf("some-service-instance-warning")) 79 }) 80 }) 81 82 When("the cloud controller returns an error", func() { 83 BeforeEach(func() { 84 fakeCloudControllerClient.GetServiceInstanceByNameAndSpaceReturns( 85 resources.ServiceInstance{}, 86 ccv3.IncludedResources{}, 87 ccv3.Warnings{"some-service-instance-warning"}, 88 errors.New("no service instance"), 89 ) 90 }) 91 92 It("returns an error and warnings", func() { 93 Expect(executionError).To(MatchError("no service instance")) 94 Expect(warnings).To(ConsistOf("some-service-instance-warning")) 95 }) 96 }) 97 }) 98 99 Describe("CreateUserProvidedServiceInstance", func() { 100 When("the service instance is created successfully", func() { 101 It("returns warnings", func() { 102 fakeCloudControllerClient.CreateServiceInstanceReturns("", ccv3.Warnings{"fake-warning"}, nil) 103 104 warnings, err := actor.CreateUserProvidedServiceInstance(resources.ServiceInstance{ 105 Name: "fake-upsi-name", 106 SpaceGUID: "fake-space-guid", 107 Tags: types.NewOptionalStringSlice("foo", "bar"), 108 RouteServiceURL: types.NewOptionalString("https://fake-route.com"), 109 SyslogDrainURL: types.NewOptionalString("https://fake-sylogg.com"), 110 Credentials: types.NewOptionalObject(map[string]interface{}{ 111 "foo": "bar", 112 "baz": 42, 113 }), 114 }) 115 Expect(warnings).To(ConsistOf("fake-warning")) 116 Expect(err).NotTo(HaveOccurred()) 117 118 Expect(fakeCloudControllerClient.CreateServiceInstanceCallCount()).To(Equal(1)) 119 Expect(fakeCloudControllerClient.CreateServiceInstanceArgsForCall(0)).To(Equal(resources.ServiceInstance{ 120 Type: "user-provided", 121 Name: "fake-upsi-name", 122 SpaceGUID: "fake-space-guid", 123 Tags: types.NewOptionalStringSlice("foo", "bar"), 124 RouteServiceURL: types.NewOptionalString("https://fake-route.com"), 125 SyslogDrainURL: types.NewOptionalString("https://fake-sylogg.com"), 126 Credentials: types.NewOptionalObject(map[string]interface{}{ 127 "foo": "bar", 128 "baz": 42, 129 }), 130 })) 131 }) 132 }) 133 134 When("there is an error creating the service instance", func() { 135 It("returns warnings and an error", func() { 136 fakeCloudControllerClient.CreateServiceInstanceReturns("", ccv3.Warnings{"fake-warning"}, errors.New("bang")) 137 138 warnings, err := actor.CreateUserProvidedServiceInstance(resources.ServiceInstance{ 139 Name: "fake-upsi-name", 140 SpaceGUID: "fake-space-guid", 141 }) 142 Expect(warnings).To(ConsistOf("fake-warning")) 143 Expect(err).To(MatchError("bang")) 144 }) 145 }) 146 }) 147 148 Describe("UpdateUserProvidedServiceInstance", func() { 149 const ( 150 serviceInstanceName = "fake-service-instance-name" 151 guid = "fake-service-instance-guid" 152 spaceGUID = "fake-space-guid" 153 ) 154 155 When("the service instance is updated successfully", func() { 156 BeforeEach(func() { 157 fakeCloudControllerClient.GetServiceInstanceByNameAndSpaceReturns( 158 resources.ServiceInstance{ 159 Type: resources.UserProvidedServiceInstance, 160 GUID: guid, 161 }, 162 ccv3.IncludedResources{}, 163 ccv3.Warnings{"warning from get"}, 164 nil, 165 ) 166 fakeCloudControllerClient.UpdateServiceInstanceReturns( 167 "", 168 ccv3.Warnings{"warning from update"}, 169 nil, 170 ) 171 }) 172 173 It("makes the right calls and returns all warnings", func() { 174 warnings, err := actor.UpdateUserProvidedServiceInstance( 175 serviceInstanceName, 176 spaceGUID, 177 resources.ServiceInstance{ 178 Tags: types.NewOptionalStringSlice("foo", "bar"), 179 RouteServiceURL: types.NewOptionalString("https://fake-route.com"), 180 SyslogDrainURL: types.NewOptionalString("https://fake-sylogg.com"), 181 Credentials: types.NewOptionalObject(map[string]interface{}{ 182 "foo": "bar", 183 "baz": 42, 184 }), 185 }, 186 ) 187 Expect(warnings).To(ConsistOf("warning from get", "warning from update")) 188 Expect(err).NotTo(HaveOccurred()) 189 190 Expect(fakeCloudControllerClient.GetServiceInstanceByNameAndSpaceCallCount()).To(Equal(1)) 191 actualName, actualSpaceGUID, actualQuery := fakeCloudControllerClient.GetServiceInstanceByNameAndSpaceArgsForCall(0) 192 Expect(actualName).To(Equal(serviceInstanceName)) 193 Expect(actualSpaceGUID).To(Equal(spaceGUID)) 194 Expect(actualQuery).To(BeEmpty()) 195 196 Expect(fakeCloudControllerClient.UpdateServiceInstanceCallCount()).To(Equal(1)) 197 actualGUID, actualServiceInstance := fakeCloudControllerClient.UpdateServiceInstanceArgsForCall(0) 198 Expect(actualGUID).To(Equal(guid)) 199 Expect(actualServiceInstance).To(Equal(resources.ServiceInstance{ 200 Tags: types.NewOptionalStringSlice("foo", "bar"), 201 RouteServiceURL: types.NewOptionalString("https://fake-route.com"), 202 SyslogDrainURL: types.NewOptionalString("https://fake-sylogg.com"), 203 Credentials: types.NewOptionalObject(map[string]interface{}{ 204 "foo": "bar", 205 "baz": 42, 206 }), 207 })) 208 }) 209 }) 210 211 When("the service instance is not user-provided", func() { 212 BeforeEach(func() { 213 fakeCloudControllerClient.GetServiceInstanceByNameAndSpaceReturns( 214 resources.ServiceInstance{ 215 Type: resources.ManagedServiceInstance, 216 Name: serviceInstanceName, 217 GUID: guid, 218 }, 219 ccv3.IncludedResources{}, 220 ccv3.Warnings{"warning from get"}, 221 nil, 222 ) 223 }) 224 225 It("fails with warnings", func() { 226 warnings, err := actor.UpdateUserProvidedServiceInstance( 227 serviceInstanceName, 228 spaceGUID, 229 resources.ServiceInstance{ 230 Tags: types.NewOptionalStringSlice("foo", "bar"), 231 RouteServiceURL: types.NewOptionalString("https://fake-route.com"), 232 SyslogDrainURL: types.NewOptionalString("https://fake-sylogg.com"), 233 Credentials: types.NewOptionalObject(map[string]interface{}{ 234 "foo": "bar", 235 "baz": 42, 236 }), 237 }, 238 ) 239 Expect(warnings).To(ConsistOf("warning from get")) 240 241 Expect(err).To(MatchError(actionerror.ServiceInstanceTypeError{ 242 Name: serviceInstanceName, 243 RequiredType: resources.UserProvidedServiceInstance, 244 })) 245 }) 246 }) 247 248 When("there is an error getting the service instance", func() { 249 BeforeEach(func() { 250 fakeCloudControllerClient.GetServiceInstanceByNameAndSpaceReturns( 251 resources.ServiceInstance{}, 252 ccv3.IncludedResources{}, 253 ccv3.Warnings{"warning from get"}, 254 errors.New("bang"), 255 ) 256 }) 257 258 It("returns warnings and an error", func() { 259 warnings, err := actor.UpdateUserProvidedServiceInstance( 260 serviceInstanceName, 261 spaceGUID, 262 resources.ServiceInstance{ 263 Tags: types.NewOptionalStringSlice("foo", "bar"), 264 RouteServiceURL: types.NewOptionalString("https://fake-route.com"), 265 SyslogDrainURL: types.NewOptionalString("https://fake-sylogg.com"), 266 Credentials: types.NewOptionalObject(map[string]interface{}{ 267 "foo": "bar", 268 "baz": 42, 269 }), 270 }, 271 ) 272 Expect(warnings).To(ConsistOf("warning from get")) 273 Expect(err).To(MatchError("bang")) 274 }) 275 }) 276 277 When("there is an error updating the service instance", func() { 278 BeforeEach(func() { 279 fakeCloudControllerClient.GetServiceInstanceByNameAndSpaceReturns( 280 resources.ServiceInstance{ 281 Type: resources.UserProvidedServiceInstance, 282 GUID: guid, 283 }, 284 ccv3.IncludedResources{}, 285 ccv3.Warnings{"warning from get"}, 286 nil, 287 ) 288 fakeCloudControllerClient.UpdateServiceInstanceReturns( 289 "", 290 ccv3.Warnings{"warning from update"}, 291 errors.New("boom"), 292 ) 293 }) 294 295 It("returns warnings and an error", func() { 296 warnings, err := actor.UpdateUserProvidedServiceInstance( 297 serviceInstanceName, 298 spaceGUID, 299 resources.ServiceInstance{ 300 Tags: types.NewOptionalStringSlice("foo", "bar"), 301 RouteServiceURL: types.NewOptionalString("https://fake-route.com"), 302 SyslogDrainURL: types.NewOptionalString("https://fake-sylogg.com"), 303 Credentials: types.NewOptionalObject(map[string]interface{}{ 304 "foo": "bar", 305 "baz": 42, 306 }), 307 }, 308 ) 309 Expect(warnings).To(ConsistOf("warning from get", "warning from update")) 310 Expect(err).To(MatchError("boom")) 311 }) 312 }) 313 }) 314 315 Describe("UpdateManagedServiceInstance", func() { 316 const ( 317 serviceInstanceName = "fake-service-instance-name" 318 serviceInstanceGUID = "fake-service-instance-guid" 319 servicePlanGUID = "fake-service-plan-guid" 320 serviceOfferingName = "fake-service-offering-name" 321 serviceOfferingGUID = "fake-service-offering-guid" 322 serviceBrokerName = "fake-service-broker-name" 323 spaceGUID = "fake-space-guid" 324 newServicePlanGUID = "fake-new-service-plan-guid" 325 newServicePlanName = "fake-new-service-plan-name" 326 fakeJobURL = ccv3.JobURL("fake-job-url") 327 ) 328 329 var ( 330 warnings Warnings 331 executeErr error 332 stream chan PollJobEvent 333 params UpdateManagedServiceInstanceParams 334 newTags types.OptionalStringSlice 335 newParameters types.OptionalObject 336 ) 337 338 BeforeEach(func() { 339 newTags = types.NewOptionalStringSlice("foo") 340 newParameters = types.NewOptionalObject(map[string]interface{}{"foo": "bar"}) 341 params = UpdateManagedServiceInstanceParams{ 342 ServiceInstanceName: serviceInstanceName, 343 SpaceGUID: spaceGUID, 344 ServicePlanName: newServicePlanName, 345 Tags: newTags, 346 Parameters: newParameters, 347 } 348 349 fakeCloudControllerClient.GetServiceInstanceByNameAndSpaceReturns( 350 resources.ServiceInstance{ 351 Type: resources.ManagedServiceInstance, 352 GUID: serviceInstanceGUID, 353 Name: serviceInstanceName, 354 ServicePlanGUID: servicePlanGUID, 355 }, 356 ccv3.IncludedResources{ 357 ServiceBrokers: []resources.ServiceBroker{{ 358 Name: serviceBrokerName, 359 }}, 360 ServiceOfferings: []resources.ServiceOffering{{ 361 Name: serviceOfferingName, 362 GUID: serviceOfferingGUID, 363 }}, 364 }, 365 ccv3.Warnings{"fake get service instance warning"}, 366 nil, 367 ) 368 369 fakeCloudControllerClient.GetServicePlansReturns( 370 []resources.ServicePlan{{ 371 GUID: newServicePlanGUID, 372 Name: newServicePlanName, 373 }}, 374 ccv3.Warnings{"fake get service plan warning"}, 375 nil, 376 ) 377 378 fakeCloudControllerClient.UpdateServiceInstanceReturns( 379 fakeJobURL, 380 ccv3.Warnings{"fake update service instance warning"}, 381 nil, 382 ) 383 384 fakeStream := make(chan ccv3.PollJobEvent) 385 go func() { 386 fakeStream <- ccv3.PollJobEvent{ 387 State: constant.JobProcessing, 388 Warnings: ccv3.Warnings{"stream warning"}, 389 } 390 }() 391 fakeCloudControllerClient.PollJobToEventStreamReturns(fakeStream) 392 }) 393 394 JustBeforeEach(func() { 395 stream, warnings, executeErr = actor.UpdateManagedServiceInstance(params) 396 }) 397 398 It("returns a stream, warnings, and no error", func() { 399 Expect(executeErr).NotTo(HaveOccurred()) 400 Expect(warnings).To(ConsistOf( 401 "fake get service instance warning", 402 "fake get service plan warning", 403 "fake update service instance warning", 404 )) 405 Eventually(stream).Should(Receive(Equal(PollJobEvent{ 406 State: JobProcessing, 407 Warnings: Warnings{"stream warning"}, 408 }))) 409 }) 410 411 Describe("getting the service instance", func() { 412 It("makes the right call", func() { 413 Expect(fakeCloudControllerClient.GetServiceInstanceByNameAndSpaceCallCount()).To(Equal(1)) 414 actualName, actualSpaceGUID, actualQuery := fakeCloudControllerClient.GetServiceInstanceByNameAndSpaceArgsForCall(0) 415 Expect(actualName).To(Equal(serviceInstanceName)) 416 Expect(actualSpaceGUID).To(Equal(spaceGUID)) 417 Expect(actualQuery).To(ConsistOf( 418 []ccv3.Query{ 419 { 420 Key: ccv3.FieldsServicePlanServiceOffering, 421 Values: []string{"name", "guid"}, 422 }, 423 { 424 Key: ccv3.FieldsServicePlanServiceOfferingServiceBroker, 425 Values: []string{"name"}, 426 }, 427 }, 428 )) 429 }) 430 431 When("not updating the plan", func() { 432 BeforeEach(func() { 433 params.ServicePlanName = "" 434 }) 435 436 It("does not include the offering and broker", func() { 437 Expect(fakeCloudControllerClient.GetServiceInstanceByNameAndSpaceCallCount()).To(Equal(1)) 438 _, _, actualQuery := fakeCloudControllerClient.GetServiceInstanceByNameAndSpaceArgsForCall(0) 439 440 Expect(actualQuery).To(BeEmpty()) 441 }) 442 }) 443 444 When("not a managed service instance", func() { 445 BeforeEach(func() { 446 fakeCloudControllerClient.GetServiceInstanceByNameAndSpaceReturns( 447 resources.ServiceInstance{ 448 Type: resources.UserProvidedServiceInstance, 449 Name: serviceInstanceName, 450 GUID: serviceInstanceGUID, 451 }, 452 ccv3.IncludedResources{}, 453 ccv3.Warnings{"warning from get"}, 454 nil, 455 ) 456 }) 457 458 It("returns an error and warnings", func() { 459 Expect(warnings).To(ConsistOf("warning from get")) 460 Expect(executeErr).To(MatchError(actionerror.ServiceInstanceTypeError{ 461 Name: serviceInstanceName, 462 RequiredType: resources.ManagedServiceInstance, 463 })) 464 }) 465 }) 466 467 When("not found", func() { 468 BeforeEach(func() { 469 fakeCloudControllerClient.GetServiceInstanceByNameAndSpaceReturns( 470 resources.ServiceInstance{}, 471 ccv3.IncludedResources{}, 472 ccv3.Warnings{"warning from get"}, 473 ccerror.ServiceInstanceNotFoundError{Name: serviceInstanceName}, 474 ) 475 }) 476 477 It("returns warnings and an actionerror", func() { 478 Expect(warnings).To(ConsistOf("warning from get")) 479 Expect(executeErr).To(MatchError(actionerror.ServiceInstanceNotFoundError{ 480 Name: serviceInstanceName, 481 })) 482 }) 483 }) 484 485 When("fails", func() { 486 BeforeEach(func() { 487 fakeCloudControllerClient.GetServiceInstanceByNameAndSpaceReturns( 488 resources.ServiceInstance{}, 489 ccv3.IncludedResources{}, 490 ccv3.Warnings{"warning from get"}, 491 errors.New("bang"), 492 ) 493 }) 494 495 It("returns warnings and an error", func() { 496 Expect(warnings).To(ContainElement("warning from get")) 497 Expect(executeErr).To(MatchError("bang")) 498 }) 499 }) 500 }) 501 502 Describe("checking the new plan", func() { 503 It("gets the plan", func() { 504 Expect(fakeCloudControllerClient.GetServicePlansCallCount()).To(Equal(1)) 505 Expect(fakeCloudControllerClient.GetServicePlansArgsForCall(0)).To(ConsistOf( 506 ccv3.Query{Key: ccv3.ServiceOfferingGUIDsFilter, Values: []string{serviceOfferingGUID}}, 507 ccv3.Query{Key: ccv3.NameFilter, Values: []string{newServicePlanName}}, 508 )) 509 }) 510 511 When("no plan change requested", func() { 512 BeforeEach(func() { 513 params.ServicePlanName = "" 514 }) 515 516 It("does not get the plan", func() { 517 Expect(fakeCloudControllerClient.GetServicePlansCallCount()).To(BeZero()) 518 }) 519 }) 520 521 When("no plan found", func() { 522 BeforeEach(func() { 523 fakeCloudControllerClient.GetServicePlansReturns( 524 []resources.ServicePlan{}, 525 ccv3.Warnings{"fake get service plan warning"}, 526 nil, 527 ) 528 }) 529 530 It("returns an error and warnings", func() { 531 Expect(executeErr).To(MatchError(actionerror.ServicePlanNotFoundError{ 532 PlanName: newServicePlanName, 533 OfferingName: serviceOfferingName, 534 ServiceBrokerName: serviceBrokerName, 535 })) 536 537 Expect(warnings).To(ConsistOf( 538 "fake get service instance warning", 539 "fake get service plan warning", 540 )) 541 }) 542 }) 543 544 When("fails", func() { 545 BeforeEach(func() { 546 fakeCloudControllerClient.GetServicePlansReturns( 547 []resources.ServicePlan{}, 548 ccv3.Warnings{"fake get service plan warning"}, 549 errors.New("bang"), 550 ) 551 }) 552 553 It("returns the error and warnings", func() { 554 Expect(executeErr).To(MatchError("bang")) 555 556 Expect(warnings).To(ConsistOf( 557 "fake get service instance warning", 558 "fake get service plan warning", 559 )) 560 }) 561 }) 562 563 }) 564 565 Describe("detecting no-op updates", func() { 566 When("no updates are requested", func() { 567 BeforeEach(func() { 568 params.ServicePlanName = "" 569 params.Tags = types.OptionalStringSlice{} 570 params.Parameters = types.OptionalObject{} 571 }) 572 573 It("returns a no-op error", func() { 574 Expect(executeErr).To(MatchError(actionerror.ServiceInstanceUpdateIsNoop{})) 575 }) 576 }) 577 578 When("the new plan is the same as the old plan", func() { 579 BeforeEach(func() { 580 fakeCloudControllerClient.GetServicePlansReturns( 581 []resources.ServicePlan{{ 582 GUID: servicePlanGUID, 583 }}, 584 ccv3.Warnings{"fake get service plan warning"}, 585 nil, 586 ) 587 }) 588 589 Context("and no other updates are requested", func() { 590 BeforeEach(func() { 591 params.Tags = types.OptionalStringSlice{} 592 params.Parameters = types.OptionalObject{} 593 }) 594 595 It("returns a no-op error", func() { 596 Expect(executeErr).To(MatchError(actionerror.ServiceInstanceUpdateIsNoop{})) 597 }) 598 }) 599 600 Context("and a tag change is requested", func() { 601 BeforeEach(func() { 602 params.Parameters = types.OptionalObject{} 603 }) 604 605 It("does not return a no-op error", func() { 606 Expect(executeErr).NotTo(HaveOccurred()) 607 }) 608 }) 609 610 Context("and a parameter change is requested", func() { 611 BeforeEach(func() { 612 params.Tags = types.OptionalStringSlice{} 613 }) 614 615 It("does not return a no-op error", func() { 616 Expect(executeErr).NotTo(HaveOccurred()) 617 }) 618 }) 619 }) 620 }) 621 622 Describe("initiating the update", func() { 623 It("makes the right call", func() { 624 Expect(fakeCloudControllerClient.UpdateServiceInstanceCallCount()).To(Equal(1)) 625 actualServiceInstanceGUID, actualUpdateResource := fakeCloudControllerClient.UpdateServiceInstanceArgsForCall(0) 626 Expect(actualServiceInstanceGUID).To(Equal(serviceInstanceGUID)) 627 Expect(actualUpdateResource).To(Equal(resources.ServiceInstance{ 628 ServicePlanGUID: newServicePlanGUID, 629 Tags: newTags, 630 Parameters: newParameters, 631 })) 632 }) 633 634 When("just changing tags", func() { 635 BeforeEach(func() { 636 params.ServicePlanName = "" 637 params.Parameters = types.OptionalObject{} 638 }) 639 640 It("makes the right call", func() { 641 Expect(fakeCloudControllerClient.UpdateServiceInstanceCallCount()).To(Equal(1)) 642 actualServiceInstanceGUID, actualUpdateResource := fakeCloudControllerClient.UpdateServiceInstanceArgsForCall(0) 643 Expect(actualServiceInstanceGUID).To(Equal(serviceInstanceGUID)) 644 Expect(actualUpdateResource).To(Equal(resources.ServiceInstance{ 645 Tags: newTags, 646 })) 647 }) 648 }) 649 650 When("just changing parameters", func() { 651 BeforeEach(func() { 652 params.ServicePlanName = "" 653 params.Tags = types.OptionalStringSlice{} 654 }) 655 656 It("makes the right call", func() { 657 Expect(fakeCloudControllerClient.UpdateServiceInstanceCallCount()).To(Equal(1)) 658 actualServiceInstanceGUID, actualUpdateResource := fakeCloudControllerClient.UpdateServiceInstanceArgsForCall(0) 659 Expect(actualServiceInstanceGUID).To(Equal(serviceInstanceGUID)) 660 Expect(actualUpdateResource).To(Equal(resources.ServiceInstance{ 661 Parameters: newParameters, 662 })) 663 }) 664 665 When("just changing plan", func() { 666 667 }) 668 }) 669 670 When("fails", func() { 671 BeforeEach(func() { 672 fakeCloudControllerClient.UpdateServiceInstanceReturns( 673 "", 674 ccv3.Warnings{"fake update service instance warning"}, 675 errors.New("boom"), 676 ) 677 }) 678 679 It("returns the error and warnings", func() { 680 Expect(stream).To(BeNil()) 681 Expect(warnings).To(ConsistOf( 682 "fake get service instance warning", 683 "fake get service plan warning", 684 "fake update service instance warning", 685 )) 686 Expect(executeErr).To(MatchError("boom")) 687 }) 688 }) 689 }) 690 691 Describe("polling the job", func() { 692 It("polls the job", func() { 693 Expect(fakeCloudControllerClient.PollJobToEventStreamCallCount()).To(Equal(1)) 694 Expect(fakeCloudControllerClient.PollJobToEventStreamArgsForCall(0)).To(Equal(fakeJobURL)) 695 }) 696 }) 697 }) 698 699 Describe("RenameServiceInstance", func() { 700 const ( 701 currentServiceInstanceName = "current-service-instance-name" 702 currentServiceInstanceGUID = "current-service-instance-guid" 703 newServiceInstanceName = "new-service-instance-name" 704 spaceGUID = "some-source-space-guid" 705 ) 706 707 var ( 708 warnings Warnings 709 executionError error 710 ) 711 712 BeforeEach(func() { 713 fakeCloudControllerClient.GetServiceInstanceByNameAndSpaceReturns( 714 resources.ServiceInstance{ 715 Name: currentServiceInstanceName, 716 GUID: currentServiceInstanceGUID, 717 }, 718 ccv3.IncludedResources{}, 719 ccv3.Warnings{"some-get-service-instance-warning"}, 720 nil, 721 ) 722 723 fakeCloudControllerClient.UpdateServiceInstanceReturns( 724 "", 725 ccv3.Warnings{"some-update-service-instance-warning"}, 726 nil, 727 ) 728 }) 729 730 JustBeforeEach(func() { 731 warnings, executionError = actor.RenameServiceInstance(currentServiceInstanceName, spaceGUID, newServiceInstanceName) 732 }) 733 734 It("gets the service instance", func() { 735 Expect(fakeCloudControllerClient.GetServiceInstanceByNameAndSpaceCallCount()).To(Equal(1)) 736 actualName, actualSpaceGUID, actualQuery := fakeCloudControllerClient.GetServiceInstanceByNameAndSpaceArgsForCall(0) 737 Expect(actualName).To(Equal(currentServiceInstanceName)) 738 Expect(actualSpaceGUID).To(Equal(spaceGUID)) 739 Expect(actualQuery).To(BeEmpty()) 740 }) 741 742 It("updates the service instance", func() { 743 Expect(fakeCloudControllerClient.UpdateServiceInstanceCallCount()).To(Equal(1)) 744 actualGUID, actualUpdates := fakeCloudControllerClient.UpdateServiceInstanceArgsForCall(0) 745 Expect(actualGUID).To(Equal(currentServiceInstanceGUID)) 746 Expect(actualUpdates).To(Equal(resources.ServiceInstance{Name: newServiceInstanceName})) 747 }) 748 749 It("returns warnings and no errors", func() { 750 Expect(executionError).NotTo(HaveOccurred()) 751 Expect(warnings).To(ConsistOf("some-get-service-instance-warning", "some-update-service-instance-warning")) 752 }) 753 754 When("the update is synchronous", func() { 755 It("does not wait on the job", func() { 756 Expect(fakeCloudControllerClient.PollJobCallCount()).To(Equal(0)) 757 }) 758 }) 759 760 When("the update is asynchronous", func() { 761 const job = "fake-job-url" 762 763 BeforeEach(func() { 764 fakeCloudControllerClient.UpdateServiceInstanceReturns( 765 job, 766 ccv3.Warnings{"some-update-service-instance-warning"}, 767 nil, 768 ) 769 770 fakeCloudControllerClient.PollJobForStateReturns( 771 ccv3.Warnings{"some-poll-job-warning"}, 772 nil, 773 ) 774 }) 775 776 It("waits on the job", func() { 777 Expect(fakeCloudControllerClient.PollJobForStateCallCount()).To(Equal(1)) 778 actualURL, actualState := fakeCloudControllerClient.PollJobForStateArgsForCall(0) 779 Expect(actualURL).To(Equal(actualURL)) 780 Expect(actualState).To(Equal(constant.JobPolling)) 781 Expect(warnings).To(ContainElement("some-poll-job-warning")) 782 }) 783 784 When("polling the job returns an error", func() { 785 BeforeEach(func() { 786 fakeCloudControllerClient.PollJobForStateReturns( 787 ccv3.Warnings{"some-poll-job-warning"}, 788 errors.New("bad polling issue"), 789 ) 790 }) 791 792 It("returns an error and warnings", func() { 793 Expect(executionError).To(MatchError("bad polling issue")) 794 Expect(warnings).To(ContainElement("some-poll-job-warning")) 795 }) 796 }) 797 }) 798 799 When("the service instance cannot be found", func() { 800 BeforeEach(func() { 801 fakeCloudControllerClient.GetServiceInstanceByNameAndSpaceReturns( 802 resources.ServiceInstance{}, 803 ccv3.IncludedResources{}, 804 ccv3.Warnings{"some-service-instance-warning"}, 805 ccerror.ServiceInstanceNotFoundError{Name: currentServiceInstanceName, SpaceGUID: spaceGUID}, 806 ) 807 }) 808 809 It("returns an actor error and warnings", func() { 810 Expect(executionError).To(MatchError(actionerror.ServiceInstanceNotFoundError{Name: currentServiceInstanceName})) 811 Expect(warnings).To(ConsistOf("some-service-instance-warning")) 812 }) 813 }) 814 815 When("getting the service instance returns an error", func() { 816 BeforeEach(func() { 817 fakeCloudControllerClient.GetServiceInstanceByNameAndSpaceReturns( 818 resources.ServiceInstance{}, 819 ccv3.IncludedResources{}, 820 ccv3.Warnings{"some-service-instance-warning"}, 821 errors.New("no service instance"), 822 ) 823 }) 824 825 It("returns an error and warnings", func() { 826 Expect(executionError).To(MatchError("no service instance")) 827 Expect(warnings).To(ConsistOf("some-service-instance-warning")) 828 }) 829 830 It("does not attempt to update the service instance", func() { 831 Expect(fakeCloudControllerClient.UpdateServiceInstanceCallCount()).To(Equal(0)) 832 }) 833 }) 834 835 When("updating the service instance returns an error", func() { 836 BeforeEach(func() { 837 fakeCloudControllerClient.UpdateServiceInstanceReturns( 838 "", 839 ccv3.Warnings{"some-update-service-instance-warning"}, 840 errors.New("something awful"), 841 ) 842 }) 843 844 It("returns an error and warnings", func() { 845 Expect(executionError).To(MatchError("something awful")) 846 Expect(warnings).To(ContainElement("some-update-service-instance-warning")) 847 }) 848 }) 849 }) 850 851 Describe("CreateManagedServiceInstance", func() { 852 const ( 853 fakeServiceOfferingName = "fake-offering-name" 854 fakeServicePlanName = "fake-plan-name" 855 fakeServiceInstanceName = "fake-service-instance-name" 856 fakeSpaceGUID = "fake-space-GUID" 857 ) 858 859 var ( 860 fakeServiceBrokerName string 861 fakeTags types.OptionalStringSlice 862 warnings Warnings 863 err error 864 stream chan PollJobEvent 865 fakeJobURL ccv3.JobURL 866 fakeParams types.OptionalObject 867 ) 868 869 BeforeEach(func() { 870 fakeServiceBrokerName = "fake-broker-name" 871 fakeTags = types.NewOptionalStringSlice("tag1", "tag2") 872 fakeJobURL = "http://some-cc-api/v3/jobs/job-guid" 873 fakeParams = types.NewOptionalObject(map[string]interface{}{"param1": "some-value", "param-2": "cool service"}) 874 875 fakeCloudControllerClient.GetServicePlansReturns( 876 []resources.ServicePlan{{GUID: "fake-plan-guid"}}, 877 ccv3.Warnings{"plan-warning"}, 878 nil, 879 ) 880 fakeCloudControllerClient.CreateServiceInstanceReturns(fakeJobURL, ccv3.Warnings{"fake-warning"}, nil) 881 882 fakeStream := make(chan ccv3.PollJobEvent) 883 go func() { 884 fakeStream <- ccv3.PollJobEvent{ 885 State: constant.JobPolling, 886 Err: errors.New("fake error"), 887 Warnings: ccv3.Warnings{"fake warning"}, 888 } 889 }() 890 fakeCloudControllerClient.PollJobToEventStreamReturns(fakeStream) 891 }) 892 893 JustBeforeEach(func() { 894 params := CreateManagedServiceInstanceParams{ 895 ServiceOfferingName: fakeServiceOfferingName, 896 ServicePlanName: fakeServicePlanName, 897 ServiceInstanceName: fakeServiceInstanceName, 898 ServiceBrokerName: fakeServiceBrokerName, 899 SpaceGUID: fakeSpaceGUID, 900 Tags: fakeTags, 901 Parameters: fakeParams, 902 } 903 stream, warnings, err = actor.CreateManagedServiceInstance(params) 904 }) 905 906 It("gets the service plan", func() { 907 Expect(fakeCloudControllerClient.GetServicePlansCallCount()).To(Equal(1)) 908 query := fakeCloudControllerClient.GetServicePlansArgsForCall(0) 909 Expect(query[0].Values).To(ConsistOf(fakeServicePlanName)) 910 Expect(query[0].Key).To(Equal(ccv3.NameFilter)) 911 Expect(query[1].Values).To(ConsistOf(fakeServiceBrokerName)) 912 Expect(query[1].Key).To(Equal(ccv3.ServiceBrokerNamesFilter)) 913 Expect(query[2].Values).To(ConsistOf(fakeServiceOfferingName)) 914 Expect(query[2].Key).To(Equal(ccv3.ServiceOfferingNamesFilter)) 915 }) 916 917 It("calls the client to create the instance", func() { 918 Expect(fakeCloudControllerClient.CreateServiceInstanceCallCount()).To(Equal(1)) 919 Expect(fakeCloudControllerClient.CreateServiceInstanceArgsForCall(0)).To(Equal(resources.ServiceInstance{ 920 Type: "managed", 921 Name: fakeServiceInstanceName, 922 ServicePlanGUID: "fake-plan-guid", 923 SpaceGUID: fakeSpaceGUID, 924 Tags: fakeTags, 925 Parameters: fakeParams, 926 })) 927 }) 928 929 It("polls the job", func() { 930 Expect(fakeCloudControllerClient.PollJobToEventStreamCallCount()).To(Equal(1)) 931 jobUrl := fakeCloudControllerClient.PollJobToEventStreamArgsForCall(0) 932 Expect(jobUrl).To(Equal(fakeJobURL)) 933 }) 934 935 It("returns an event stream and warnings", func() { 936 Expect(err).NotTo(HaveOccurred()) 937 Expect(warnings).To(ConsistOf("plan-warning", "fake-warning")) 938 Eventually(stream).Should(Receive(Equal(PollJobEvent{ 939 State: JobPolling, 940 Err: errors.New("fake error"), 941 Warnings: Warnings{"fake warning"}, 942 }))) 943 }) 944 945 Context("error scenarios", func() { 946 When("no plan found", func() { 947 BeforeEach(func() { 948 fakeCloudControllerClient.GetServicePlansReturns([]resources.ServicePlan{}, ccv3.Warnings{"be warned"}, nil) 949 }) 950 951 It("returns with warnings and an error", func() { 952 Expect(fakeCloudControllerClient.CreateServiceInstanceCallCount()).To(Equal(0)) 953 Expect(fakeCloudControllerClient.PollJobForStateCallCount()).To(Equal(0)) 954 955 Expect(warnings).To(ConsistOf("be warned")) 956 Expect(err).To(MatchError(actionerror.ServicePlanNotFoundError{PlanName: fakeServicePlanName, OfferingName: fakeServiceOfferingName, ServiceBrokerName: fakeServiceBrokerName})) 957 Expect(stream).To(BeNil()) 958 }) 959 }) 960 961 When("more than one plan found", func() { 962 BeforeEach(func() { 963 fakeCloudControllerClient.GetServicePlansReturns( 964 []resources.ServicePlan{{GUID: "a-guid"}, {GUID: "another-guid"}}, 965 ccv3.Warnings{"be warned"}, 966 nil, 967 ) 968 fakeServiceBrokerName = "" 969 }) 970 971 It("returns warnings and an error", func() { 972 Expect(fakeCloudControllerClient.CreateServiceInstanceCallCount()).To(Equal(0)) 973 Expect(fakeCloudControllerClient.PollJobForStateCallCount()).To(Equal(0)) 974 975 Expect(warnings).To(ConsistOf("be warned")) 976 Expect(err).To(MatchError(actionerror.ServiceBrokerNameRequiredError{ 977 ServiceOfferingName: fakeServiceOfferingName, 978 })) 979 Expect(stream).To(BeNil()) 980 }) 981 }) 982 983 When("client error when getting the plan", func() { 984 BeforeEach(func() { 985 fakeCloudControllerClient.GetServicePlansReturns([]resources.ServicePlan{}, ccv3.Warnings{"be warned"}, errors.New("boom")) 986 fakeServiceBrokerName = "" 987 }) 988 989 It("returns warnings and an error", func() { 990 Expect(fakeCloudControllerClient.CreateServiceInstanceCallCount()).To(Equal(0)) 991 Expect(fakeCloudControllerClient.PollJobForStateCallCount()).To(Equal(0)) 992 993 Expect(warnings).To(ConsistOf("be warned")) 994 Expect(err).To(MatchError("boom")) 995 Expect(stream).To(BeNil()) 996 }) 997 }) 998 999 When("there is an error creating the service instance", func() { 1000 BeforeEach(func() { 1001 fakeCloudControllerClient.CreateServiceInstanceReturns("", ccv3.Warnings{"fake-warning"}, errors.New("bang")) 1002 }) 1003 1004 It("returns warnings and an error", func() { 1005 Expect(fakeCloudControllerClient.PollJobForStateCallCount()).To(Equal(0)) 1006 1007 Expect(warnings).To(ConsistOf("plan-warning", "fake-warning")) 1008 Expect(err).To(MatchError("bang")) 1009 Expect(stream).To(BeNil()) 1010 }) 1011 }) 1012 }) 1013 }) 1014 1015 Describe("DeleteServiceInstance", func() { 1016 const ( 1017 fakeServiceInstanceName = "fake-service-instance-name" 1018 fakeSpaceGUID = "fake-space-GUID" 1019 ) 1020 1021 var ( 1022 warnings Warnings 1023 err error 1024 stream chan PollJobEvent 1025 ) 1026 1027 JustBeforeEach(func() { 1028 stream, warnings, err = actor.DeleteServiceInstance(fakeServiceInstanceName, fakeSpaceGUID) 1029 }) 1030 1031 It("makes a request to get the service instance", func() { 1032 Expect(fakeCloudControllerClient.GetServiceInstanceByNameAndSpaceCallCount()).To(Equal(1)) 1033 actualName, actualSpace, actualQuery := fakeCloudControllerClient.GetServiceInstanceByNameAndSpaceArgsForCall(0) 1034 Expect(actualName).To(Equal(fakeServiceInstanceName)) 1035 Expect(actualSpace).To(Equal(fakeSpaceGUID)) 1036 Expect(actualQuery).To(BeEmpty()) 1037 }) 1038 1039 When("the service instance exists", func() { 1040 const fakeServiceInstanceGUID = "fake-si-guid" 1041 1042 BeforeEach(func() { 1043 fakeCloudControllerClient.GetServiceInstanceByNameAndSpaceReturns( 1044 resources.ServiceInstance{GUID: fakeServiceInstanceGUID}, 1045 ccv3.IncludedResources{}, 1046 ccv3.Warnings{"get warning"}, 1047 nil, 1048 ) 1049 }) 1050 1051 It("makes the right call to delete the service instance", func() { 1052 Expect(fakeCloudControllerClient.DeleteServiceInstanceCallCount()).To(Equal(1)) 1053 Expect(fakeCloudControllerClient.DeleteServiceInstanceArgsForCall(0)).To(Equal(fakeServiceInstanceGUID)) 1054 }) 1055 1056 When("the delete response is synchronous", func() { 1057 BeforeEach(func() { 1058 fakeCloudControllerClient.DeleteServiceInstanceReturns( 1059 "", 1060 ccv3.Warnings{"delete warning"}, 1061 nil, 1062 ) 1063 }) 1064 1065 It("returns a nil channel", func() { 1066 Expect(err).NotTo(HaveOccurred()) 1067 Expect(warnings).To(ConsistOf("get warning", "delete warning")) 1068 Expect(stream).To(BeNil()) 1069 }) 1070 1071 It("does not try to poll a job", func() { 1072 Expect(fakeCloudControllerClient.PollJobToEventStreamCallCount()).To(BeZero()) 1073 }) 1074 }) 1075 1076 When("the delete response is asynchronous", func() { 1077 BeforeEach(func() { 1078 fakeCloudControllerClient.DeleteServiceInstanceReturns( 1079 "a fake job url", 1080 ccv3.Warnings{"delete warning"}, 1081 nil, 1082 ) 1083 1084 fakeStream := make(chan ccv3.PollJobEvent) 1085 go func() { 1086 fakeStream <- ccv3.PollJobEvent{ 1087 State: constant.JobPolling, 1088 Err: errors.New("fake error"), 1089 Warnings: ccv3.Warnings{"fake warning"}, 1090 } 1091 }() 1092 fakeCloudControllerClient.PollJobToEventStreamReturns(fakeStream) 1093 }) 1094 1095 It("polls the job", func() { 1096 Expect(fakeCloudControllerClient.PollJobToEventStreamCallCount()).To(Equal(1)) 1097 actualJobURL := fakeCloudControllerClient.PollJobToEventStreamArgsForCall(0) 1098 Expect(actualJobURL).To(BeEquivalentTo("a fake job url")) 1099 }) 1100 1101 It("returns an event stream and warnings", func() { 1102 Expect(err).NotTo(HaveOccurred()) 1103 Expect(warnings).To(ConsistOf("get warning", "delete warning")) 1104 Eventually(stream).Should(Receive(Equal(PollJobEvent{ 1105 State: JobPolling, 1106 Err: errors.New("fake error"), 1107 Warnings: Warnings{"fake warning"}, 1108 }))) 1109 }) 1110 }) 1111 1112 When("the delete responds with failure", func() { 1113 BeforeEach(func() { 1114 fakeCloudControllerClient.DeleteServiceInstanceReturns( 1115 "a fake job url", 1116 ccv3.Warnings{"delete warning"}, 1117 errors.New("bong"), 1118 ) 1119 }) 1120 1121 It("return the error and warnings", func() { 1122 Expect(err).To(MatchError("bong")) 1123 Expect(warnings).To(ConsistOf("get warning", "delete warning")) 1124 Expect(stream).To(BeNil()) 1125 }) 1126 }) 1127 }) 1128 1129 When("the service instance does not exist", func() { 1130 BeforeEach(func() { 1131 fakeCloudControllerClient.GetServiceInstanceByNameAndSpaceReturns( 1132 resources.ServiceInstance{}, 1133 ccv3.IncludedResources{}, 1134 ccv3.Warnings{"get warning"}, 1135 ccerror.ServiceInstanceNotFoundError{Name: fakeServiceInstanceName}, 1136 ) 1137 }) 1138 1139 It("returns an error", func() { 1140 Expect(err).To(MatchError(actionerror.ServiceInstanceNotFoundError{Name: fakeServiceInstanceName})) 1141 Expect(warnings).To(ConsistOf("get warning")) 1142 Expect(stream).To(BeNil()) 1143 }) 1144 1145 It("does not try to delete", func() { 1146 Expect(fakeCloudControllerClient.DeleteServiceInstanceCallCount()).To(BeZero()) 1147 }) 1148 }) 1149 1150 When("getting the service instance fails", func() { 1151 BeforeEach(func() { 1152 fakeCloudControllerClient.GetServiceInstanceByNameAndSpaceReturns( 1153 resources.ServiceInstance{}, 1154 ccv3.IncludedResources{}, 1155 ccv3.Warnings{"get warning"}, 1156 errors.New("boom"), 1157 ) 1158 }) 1159 1160 It("returns the error", func() { 1161 Expect(err).To(MatchError("boom")) 1162 Expect(warnings).To(ConsistOf("get warning")) 1163 Expect(stream).To(BeNil()) 1164 }) 1165 1166 It("does not try to delete", func() { 1167 Expect(fakeCloudControllerClient.DeleteServiceInstanceCallCount()).To(BeZero()) 1168 }) 1169 }) 1170 }) 1171 1172 Describe("PurgeServiceInstance", func() { 1173 const ( 1174 fakeServiceInstanceName = "fake-service-instance-name" 1175 fakeSpaceGUID = "fake-space-GUID" 1176 ) 1177 1178 var ( 1179 warnings Warnings 1180 err error 1181 ) 1182 1183 JustBeforeEach(func() { 1184 warnings, err = actor.PurgeServiceInstance(fakeServiceInstanceName, fakeSpaceGUID) 1185 }) 1186 1187 It("makes a request to get the service instance", func() { 1188 Expect(fakeCloudControllerClient.GetServiceInstanceByNameAndSpaceCallCount()).To(Equal(1)) 1189 actualName, actualSpace, actualQuery := fakeCloudControllerClient.GetServiceInstanceByNameAndSpaceArgsForCall(0) 1190 Expect(actualName).To(Equal(fakeServiceInstanceName)) 1191 Expect(actualSpace).To(Equal(fakeSpaceGUID)) 1192 Expect(actualQuery).To(BeEmpty()) 1193 }) 1194 1195 When("the service instance does not exist", func() { 1196 BeforeEach(func() { 1197 fakeCloudControllerClient.GetServiceInstanceByNameAndSpaceReturns( 1198 resources.ServiceInstance{}, 1199 ccv3.IncludedResources{}, 1200 ccv3.Warnings{"get warning"}, 1201 ccerror.ServiceInstanceNotFoundError{Name: fakeServiceInstanceName}, 1202 ) 1203 }) 1204 1205 It("returns the appropriate error", func() { 1206 Expect(err).To(MatchError(actionerror.ServiceInstanceNotFoundError{Name: fakeServiceInstanceName})) 1207 Expect(warnings).To(ConsistOf("get warning")) 1208 }) 1209 1210 It("does not try to purge", func() { 1211 Expect(fakeCloudControllerClient.DeleteServiceInstanceCallCount()).To(BeZero()) 1212 }) 1213 }) 1214 1215 When("the service instance exists", func() { 1216 const fakeServiceInstanceGUID = "fake-si-guid" 1217 1218 BeforeEach(func() { 1219 fakeCloudControllerClient.GetServiceInstanceByNameAndSpaceReturns( 1220 resources.ServiceInstance{GUID: fakeServiceInstanceGUID}, 1221 ccv3.IncludedResources{}, 1222 ccv3.Warnings{"get warning"}, 1223 nil, 1224 ) 1225 1226 fakeCloudControllerClient.DeleteServiceInstanceReturns( 1227 "", 1228 ccv3.Warnings{"purge warning"}, 1229 nil, 1230 ) 1231 }) 1232 1233 It("makes the right call to purge the service instance", func() { 1234 Expect(fakeCloudControllerClient.DeleteServiceInstanceCallCount()).To(Equal(1)) 1235 actualGUID, actualQuery := fakeCloudControllerClient.DeleteServiceInstanceArgsForCall(0) 1236 Expect(actualGUID).To(Equal(fakeServiceInstanceGUID)) 1237 Expect(actualQuery).To(ConsistOf(ccv3.Query{Key: ccv3.Purge, Values: []string{"true"}})) 1238 }) 1239 1240 It("returns warnings", func() { 1241 Expect(err).NotTo(HaveOccurred()) 1242 Expect(warnings).To(ConsistOf("get warning", "purge warning")) 1243 }) 1244 1245 When("the purge responds with failure", func() { 1246 BeforeEach(func() { 1247 fakeCloudControllerClient.DeleteServiceInstanceReturns( 1248 "a fake job url", 1249 ccv3.Warnings{"delete warning"}, 1250 errors.New("bong"), 1251 ) 1252 }) 1253 1254 It("return the error and warnings", func() { 1255 Expect(err).To(MatchError("bong")) 1256 Expect(warnings).To(ConsistOf("get warning", "delete warning")) 1257 }) 1258 }) 1259 }) 1260 1261 When("getting the service instance fails", func() { 1262 BeforeEach(func() { 1263 fakeCloudControllerClient.GetServiceInstanceByNameAndSpaceReturns( 1264 resources.ServiceInstance{}, 1265 ccv3.IncludedResources{}, 1266 ccv3.Warnings{"get warning"}, 1267 errors.New("boom"), 1268 ) 1269 }) 1270 1271 It("returns the error", func() { 1272 Expect(err).To(MatchError("boom")) 1273 Expect(warnings).To(ConsistOf("get warning")) 1274 }) 1275 }) 1276 }) 1277 1278 Describe("UpgradeManagedServiceInstance", func() { 1279 const ( 1280 fakeServiceInstanceName = "fake-service-instance-name" 1281 fakeSpaceGUID = "fake-space-GUID" 1282 ) 1283 1284 var ( 1285 executeErr error 1286 warnings Warnings 1287 stream chan PollJobEvent 1288 ) 1289 1290 JustBeforeEach(func() { 1291 stream, warnings, executeErr = actor.UpgradeManagedServiceInstance(fakeServiceInstanceName, fakeSpaceGUID) 1292 }) 1293 1294 It("makes a request to get the service instance", func() { 1295 Expect(fakeCloudControllerClient.GetServiceInstanceByNameAndSpaceCallCount()).To(Equal(1)) 1296 actualName, actualSpace, actualQuery := fakeCloudControllerClient.GetServiceInstanceByNameAndSpaceArgsForCall(0) 1297 Expect(actualName).To(Equal(fakeServiceInstanceName)) 1298 Expect(actualSpace).To(Equal(fakeSpaceGUID)) 1299 Expect(actualQuery).To(BeEmpty()) 1300 }) 1301 1302 When("the service instance does not exist", func() { 1303 BeforeEach(func() { 1304 fakeCloudControllerClient.GetServiceInstanceByNameAndSpaceReturns( 1305 resources.ServiceInstance{}, 1306 ccv3.IncludedResources{}, 1307 ccv3.Warnings{"get SI warning"}, 1308 ccerror.ServiceInstanceNotFoundError{Name: fakeServiceInstanceName}, 1309 ) 1310 }) 1311 1312 It("does not try to upgrade", func() { 1313 Expect(fakeCloudControllerClient.UpdateServiceInstanceCallCount()).To(BeZero()) 1314 }) 1315 1316 It("returns the appropriate error", func() { 1317 Expect(stream).To(BeNil()) 1318 Expect(warnings).To(ConsistOf("get SI warning")) 1319 Expect(executeErr).To(MatchError(actionerror.ServiceInstanceNotFoundError{ 1320 Name: fakeServiceInstanceName, 1321 })) 1322 }) 1323 }) 1324 1325 When("there's no upgrade available", func() { 1326 BeforeEach(func() { 1327 fakeCloudControllerClient.GetServiceInstanceByNameAndSpaceReturns( 1328 resources.ServiceInstance{ 1329 GUID: "some-guid", 1330 Name: "some-name", 1331 UpgradeAvailable: types.OptionalBoolean{ 1332 IsSet: true, 1333 Value: false, 1334 }, 1335 }, 1336 ccv3.IncludedResources{}, 1337 ccv3.Warnings{"get SI warning"}, 1338 nil, 1339 ) 1340 }) 1341 1342 It("does not try to upgrade", func() { 1343 Expect(fakeCloudControllerClient.UpdateServiceInstanceCallCount()).To(BeZero()) 1344 }) 1345 1346 It("returns the appropriate error", func() { 1347 Expect(stream).To(BeNil()) 1348 Expect(warnings).To(ConsistOf("get SI warning")) 1349 Expect(executeErr).To(MatchError(actionerror.ServiceInstanceUpgradeNotAvailableError{})) 1350 }) 1351 }) 1352 1353 When("there is an upgrade available", func() { 1354 const guid = "some-guid" 1355 const planGUID = "some-plan-guid" 1356 const jobURL = ccv3.JobURL("fake-job-url") 1357 1358 BeforeEach(func() { 1359 fakeCloudControllerClient.GetServiceInstanceByNameAndSpaceReturns( 1360 resources.ServiceInstance{ 1361 Type: resources.ManagedServiceInstance, 1362 GUID: guid, 1363 Name: "some-name", 1364 UpgradeAvailable: types.OptionalBoolean{ 1365 IsSet: true, 1366 Value: true, 1367 }, 1368 ServicePlanGUID: planGUID, 1369 }, 1370 ccv3.IncludedResources{}, 1371 ccv3.Warnings{"warning from get"}, 1372 nil, 1373 ) 1374 fakeCloudControllerClient.GetServicePlanByGUIDReturns( 1375 resources.ServicePlan{ 1376 MaintenanceInfoVersion: "9.1.2", 1377 }, 1378 ccv3.Warnings{"warning from plan"}, 1379 nil, 1380 ) 1381 fakeCloudControllerClient.UpdateServiceInstanceReturns( 1382 jobURL, 1383 ccv3.Warnings{"warning from update"}, 1384 nil, 1385 ) 1386 1387 fakeStream := make(chan ccv3.PollJobEvent) 1388 go func() { 1389 fakeStream <- ccv3.PollJobEvent{ 1390 State: constant.JobProcessing, 1391 Warnings: ccv3.Warnings{"stream warning"}, 1392 } 1393 }() 1394 fakeCloudControllerClient.PollJobToEventStreamReturns(fakeStream) 1395 }) 1396 1397 It("makes the right calls and returns all warnings", func() { 1398 By("getting the service plan", func() { 1399 Expect(fakeCloudControllerClient.GetServicePlanByGUIDCallCount()).To(Equal(1)) 1400 actualPlanGUID := fakeCloudControllerClient.GetServicePlanByGUIDArgsForCall(0) 1401 Expect(actualPlanGUID).To(Equal(planGUID)) 1402 }) 1403 1404 By("updating the service instance", func() { 1405 Expect(fakeCloudControllerClient.UpdateServiceInstanceCallCount()).To(Equal(1)) 1406 actualGUID, actualServiceInstance := fakeCloudControllerClient.UpdateServiceInstanceArgsForCall(0) 1407 Expect(actualGUID).To(Equal(guid)) 1408 Expect(actualServiceInstance).To(Equal(resources.ServiceInstance{ 1409 MaintenanceInfoVersion: "9.1.2", 1410 })) 1411 }) 1412 1413 By("polling the job", func() { 1414 Expect(fakeCloudControllerClient.PollJobToEventStreamCallCount()).To(Equal(1)) 1415 Expect(fakeCloudControllerClient.PollJobToEventStreamArgsForCall(0)).To(Equal(jobURL)) 1416 }) 1417 1418 By("returning a stream, warnings and no error", func() { 1419 Eventually(stream).Should(Receive(Equal(PollJobEvent{ 1420 State: JobProcessing, 1421 Warnings: Warnings{"stream warning"}, 1422 }))) 1423 1424 Expect(executeErr).NotTo(HaveOccurred()) 1425 Expect(warnings).To(ConsistOf("warning from get", "warning from plan", "warning from update")) 1426 }) 1427 }) 1428 }) 1429 }) 1430 })