github.com/jenspinney/cli@v6.42.1-0.20190207184520-7450c600020e+incompatible/api/cloudcontroller/ccv2/service_instance_test.go (about) 1 package ccv2_test 2 3 import ( 4 "net/http" 5 6 "code.cloudfoundry.org/cli/api/cloudcontroller/ccerror" 7 . "code.cloudfoundry.org/cli/api/cloudcontroller/ccv2" 8 "code.cloudfoundry.org/cli/api/cloudcontroller/ccv2/constant" 9 . "github.com/onsi/ginkgo" 10 . "github.com/onsi/gomega" 11 . "github.com/onsi/gomega/ghttp" 12 ) 13 14 var _ = Describe("Service Instance", func() { 15 var client *Client 16 17 BeforeEach(func() { 18 client = NewTestClient() 19 }) 20 21 Describe("Bind", func() { 22 When("the update is successful", func() { 23 When("setting the minimum", func() { // are we **only** encoding the things we want 24 BeforeEach(func() { 25 response := ` 26 { 27 "metadata": { 28 "guid": "some-app-guid" 29 }, 30 "entity": { 31 "name": "some-app-name", 32 "space_guid": "some-space-guid" 33 } 34 }` 35 requestBody := map[string]string{ 36 "name": "some-app-name", 37 "space_guid": "some-space-guid", 38 } 39 server.AppendHandlers( 40 CombineHandlers( 41 VerifyRequest(http.MethodPost, "/v2/apps"), 42 VerifyJSONRepresenting(requestBody), 43 RespondWith(http.StatusCreated, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}), 44 ), 45 ) 46 }) 47 48 It("returns the created object and warnings", func() { 49 app, warnings, err := client.CreateApplication(Application{ 50 Name: "some-app-name", 51 SpaceGUID: "some-space-guid", 52 }) 53 Expect(err).NotTo(HaveOccurred()) 54 55 Expect(app).To(Equal(Application{ 56 GUID: "some-app-guid", 57 Name: "some-app-name", 58 SpaceGUID: "some-space-guid", 59 })) 60 Expect(warnings).To(ConsistOf(Warnings{"this is a warning"})) 61 }) 62 }) 63 }) 64 65 When("the create returns an error", func() { 66 BeforeEach(func() { 67 response := ` 68 { 69 "description": "Request invalid due to parse error: Field: name, Error: Missing field name, Field: space_guid, Error: Missing field space_guid", 70 "error_code": "CF-MessageParseError", 71 "code": 1001 72 }` 73 74 server.AppendHandlers( 75 CombineHandlers( 76 VerifyRequest(http.MethodPost, "/v2/apps"), 77 RespondWith(http.StatusBadRequest, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}), 78 ), 79 ) 80 }) 81 82 It("returns the error and warnings", func() { 83 _, warnings, err := client.CreateApplication(Application{}) 84 Expect(err).To(MatchError(ccerror.BadRequestError{Message: "Request invalid due to parse error: Field: name, Error: Missing field name, Field: space_guid, Error: Missing field space_guid"})) 85 Expect(warnings).To(ConsistOf(Warnings{"this is a warning"})) 86 }) 87 }) 88 }) 89 90 Describe("CreateServiceInstance", func() { 91 When("creating service instance succeeds", func() { 92 var ( 93 spaceGUID string 94 servicePlanGUID string 95 serviceInstance string 96 parameters map[string]interface{} 97 tags []string 98 ) 99 100 BeforeEach(func() { 101 response := `{ 102 "metadata": { 103 "guid": "service-instance-guid" 104 }, 105 "entity": { 106 "name": "my-service-instance", 107 "service_plan_guid": "service-plan-guid", 108 "space_guid": "space-guid", 109 "dashboard_url": "http://dashboard.url", 110 "type": "managed_service_instance", 111 "last_operation": { 112 "type": "create", 113 "state": "in progress", 114 "description": "", 115 "updated_at": "2016-06-08T16:41:26Z", 116 "created_at": "2016-06-08T16:41:29Z" 117 }, 118 "tags": ["a-tag", "another-tag"] 119 } 120 }` 121 spaceGUID = "some-space-guid" 122 servicePlanGUID = "some-plan-guid" 123 serviceInstance = "service-instance-name" 124 parameters = map[string]interface{}{ 125 "param1": "some-value", 126 "param2": "another-value", 127 } 128 tags = []string{"a-tag, another-tag"} 129 requestBody := map[string]interface{}{ 130 "name": serviceInstance, 131 "service_plan_guid": servicePlanGUID, 132 "space_guid": spaceGUID, 133 "parameters": parameters, 134 "tags": tags, 135 } 136 server.AppendHandlers( 137 CombineHandlers( 138 VerifyRequest(http.MethodPost, "/v2/service_instances", "accepts_incomplete=true"), 139 VerifyJSONRepresenting(requestBody), 140 RespondWith(http.StatusOK, response, http.Header{"X-Cf-Warnings": {"warning-1,warning-2"}}), 141 ), 142 ) 143 }) 144 145 It("returns the service instance and all warnings", func() { 146 serviceInstance, warnings, err := client.CreateServiceInstance(spaceGUID, servicePlanGUID, serviceInstance, parameters, tags) 147 Expect(err).NotTo(HaveOccurred()) 148 Expect(warnings).To(ConsistOf(Warnings{"warning-1", "warning-2"})) 149 Expect(serviceInstance).To(Equal(ServiceInstance{ 150 GUID: "service-instance-guid", 151 Name: "my-service-instance", 152 SpaceGUID: "space-guid", 153 ServicePlanGUID: "service-plan-guid", 154 ServiceGUID: "", 155 Type: "managed_service_instance", 156 Tags: []string{"a-tag", "another-tag"}, 157 DashboardURL: "http://dashboard.url", 158 LastOperation: LastOperation{ 159 Type: "create", 160 State: "in progress", 161 Description: "", 162 UpdatedAt: "2016-06-08T16:41:26Z", 163 CreatedAt: "2016-06-08T16:41:29Z", 164 }, 165 })) 166 }) 167 }) 168 169 When("the endpoint returns an error", func() { 170 BeforeEach(func() { 171 response := `{ 172 "code": 10003, 173 "description": "You are not authorized to perform the requested action" 174 }` 175 176 server.AppendHandlers( 177 CombineHandlers( 178 VerifyRequest(http.MethodPost, "/v2/service_instances"), 179 RespondWith(http.StatusForbidden, response, http.Header{"X-Cf-Warnings": {"warning-1, warning-2"}}), 180 )) 181 }) 182 183 It("returns all warnings and propagates the error", func() { 184 _, warnings, err := client.CreateServiceInstance("space-GUID", "service-plan-GUID", "service-instance", map[string]interface{}{}, []string{}) 185 Expect(err).To(MatchError(ccerror.ForbiddenError{ 186 Message: "You are not authorized to perform the requested action", 187 })) 188 Expect(warnings).To(ConsistOf("warning-1", "warning-2")) 189 }) 190 }) 191 }) 192 193 Describe("ServiceInstance", func() { 194 Describe("Managed", func() { 195 When("type is MANAGED_SERVICE", func() { 196 It("returns false", func() { 197 service := ServiceInstance{Type: constant.ServiceInstanceTypeManagedService} 198 Expect(service.Managed()).To(BeTrue()) 199 }) 200 }) 201 202 When("type is USER_PROVIDED_SERVICE", func() { 203 It("returns true", func() { 204 service := ServiceInstance{Type: constant.ServiceInstanceTypeUserProvidedService} 205 Expect(service.Managed()).To(BeFalse()) 206 }) 207 }) 208 }) 209 210 Describe("UserProvided", func() { 211 When("type is USER_PROVIDED_SERVICE", func() { 212 It("returns true", func() { 213 service := ServiceInstance{Type: constant.ServiceInstanceTypeUserProvidedService} 214 Expect(service.UserProvided()).To(BeTrue()) 215 }) 216 }) 217 218 When("type is MANAGED_SERVICE", func() { 219 It("returns false", func() { 220 service := ServiceInstance{Type: constant.ServiceInstanceTypeManagedService} 221 Expect(service.UserProvided()).To(BeFalse()) 222 }) 223 }) 224 }) 225 }) 226 227 Describe("GetServiceInstance", func() { 228 BeforeEach(func() { 229 response := `{ 230 "metadata": { 231 "guid": "some-service-guid" 232 }, 233 "entity": { 234 "name": "some-service-name", 235 "space_guid": "some-space-guid", 236 "service_guid": "some-service-guid", 237 "service_plan_guid": "some-service-plan-guid", 238 "type": "managed_service_instance", 239 "tags": [ 240 "tag-1", 241 "tag-2" 242 ], 243 "dashboard_url": "some-dashboard-url", 244 "route_service_url": "some-route-service-url", 245 "last_operation": { 246 "type": "create", 247 "state": "succeeded", 248 "description": "service broker-provided description", 249 "updated_at": "updated-at-time", 250 "created_at": "created-at-time" 251 } 252 } 253 }` 254 255 server.AppendHandlers( 256 CombineHandlers( 257 VerifyRequest(http.MethodGet, "/v2/service_instances/some-service-guid"), 258 RespondWith(http.StatusOK, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}), 259 ), 260 ) 261 }) 262 263 When("service instances exist", func() { 264 It("returns the service instance and warnings", func() { 265 serviceInstance, warnings, err := client.GetServiceInstance("some-service-guid") 266 Expect(err).NotTo(HaveOccurred()) 267 268 Expect(serviceInstance).To(Equal(ServiceInstance{ 269 GUID: "some-service-guid", 270 Name: "some-service-name", 271 SpaceGUID: "some-space-guid", 272 ServiceGUID: "some-service-guid", 273 ServicePlanGUID: "some-service-plan-guid", 274 Type: constant.ServiceInstanceTypeManagedService, 275 Tags: []string{"tag-1", "tag-2"}, 276 DashboardURL: "some-dashboard-url", 277 RouteServiceURL: "some-route-service-url", 278 LastOperation: LastOperation{ 279 Type: "create", 280 State: "succeeded", 281 Description: "service broker-provided description", 282 UpdatedAt: "updated-at-time", 283 CreatedAt: "created-at-time", 284 }, 285 })) 286 Expect(warnings).To(ConsistOf(Warnings{"this is a warning"})) 287 }) 288 }) 289 }) 290 291 Describe("GetServiceInstances", func() { 292 BeforeEach(func() { 293 response1 := `{ 294 "next_url": "/v2/service_instances?q=space_guid:some-space-guid&page=2", 295 "resources": [ 296 { 297 "metadata": { 298 "guid": "some-service-guid-1" 299 }, 300 "entity": { 301 "name": "some-service-name-1", 302 "space_guid": "some-space-guid", 303 "service_guid": "some-service-guid", 304 "type": "managed_service_instance" 305 } 306 }, 307 { 308 "metadata": { 309 "guid": "some-service-guid-2" 310 }, 311 "entity": { 312 "name": "some-service-name-2", 313 "space_guid": "some-space-guid", 314 "type": "managed_service_instance" 315 } 316 } 317 ] 318 }` 319 320 response2 := `{ 321 "next_url": null, 322 "resources": [ 323 { 324 "metadata": { 325 "guid": "some-service-guid-3" 326 }, 327 "entity": { 328 "name": "some-service-name-3", 329 "space_guid": "some-space-guid", 330 "type": "managed_service_instance" 331 } 332 }, 333 { 334 "metadata": { 335 "guid": "some-service-guid-4" 336 }, 337 "entity": { 338 "name": "some-service-name-4", 339 "space_guid": "some-space-guid", 340 "type": "managed_service_instance" 341 } 342 } 343 ] 344 }` 345 346 server.AppendHandlers( 347 CombineHandlers( 348 VerifyRequest(http.MethodGet, "/v2/service_instances", "q=space_guid:some-space-guid"), 349 RespondWith(http.StatusOK, response1, http.Header{"X-Cf-Warnings": {"this is a warning"}}), 350 ), 351 ) 352 353 server.AppendHandlers( 354 CombineHandlers( 355 VerifyRequest(http.MethodGet, "/v2/service_instances", "q=space_guid:some-space-guid&page=2"), 356 RespondWith(http.StatusOK, response2, http.Header{"X-Cf-Warnings": {"this is another warning"}}), 357 ), 358 ) 359 }) 360 361 When("service instances exist", func() { 362 It("returns all the queried service instances", func() { 363 serviceInstances, warnings, err := client.GetServiceInstances(Filter{ 364 Type: constant.SpaceGUIDFilter, 365 Operator: constant.EqualOperator, 366 Values: []string{"some-space-guid"}, 367 }) 368 Expect(err).NotTo(HaveOccurred()) 369 370 Expect(serviceInstances).To(ConsistOf([]ServiceInstance{ 371 { 372 Name: "some-service-name-1", 373 GUID: "some-service-guid-1", 374 SpaceGUID: "some-space-guid", 375 ServiceGUID: "some-service-guid", 376 Type: constant.ServiceInstanceTypeManagedService, 377 }, 378 { 379 Name: "some-service-name-2", 380 GUID: "some-service-guid-2", 381 SpaceGUID: "some-space-guid", 382 Type: constant.ServiceInstanceTypeManagedService, 383 }, 384 { 385 Name: "some-service-name-3", 386 GUID: "some-service-guid-3", 387 SpaceGUID: "some-space-guid", 388 Type: constant.ServiceInstanceTypeManagedService, 389 }, 390 { 391 Name: "some-service-name-4", 392 GUID: "some-service-guid-4", 393 SpaceGUID: "some-space-guid", 394 Type: constant.ServiceInstanceTypeManagedService, 395 }, 396 })) 397 Expect(warnings).To(ConsistOf(Warnings{"this is a warning", "this is another warning"})) 398 }) 399 }) 400 }) 401 402 Describe("GetSpaceServiceInstances", func() { 403 Context("including user provided services", func() { 404 BeforeEach(func() { 405 response1 := `{ 406 "next_url": "/v2/spaces/some-space-guid/service_instances?return_user_provided_service_instances=true&q=name:foobar&page=2", 407 "resources": [ 408 { 409 "metadata": { 410 "guid": "some-service-guid-1" 411 }, 412 "entity": { 413 "name": "some-service-name-1", 414 "space_guid": "some-space-guid", 415 "service_guid": "some-service-guid", 416 "type": "managed_service_instance" 417 } 418 }, 419 { 420 "metadata": { 421 "guid": "some-service-guid-2" 422 }, 423 "entity": { 424 "name": "some-service-name-2", 425 "space_guid": "some-space-guid", 426 "type": "user_provided_service_instance" 427 } 428 } 429 ] 430 }` 431 432 response2 := `{ 433 "next_url": null, 434 "resources": [ 435 { 436 "metadata": { 437 "guid": "some-service-guid-3" 438 }, 439 "entity": { 440 "name": "some-service-name-3", 441 "space_guid": "some-space-guid", 442 "type": "managed_service_instance" 443 } 444 }, 445 { 446 "metadata": { 447 "guid": "some-service-guid-4" 448 }, 449 "entity": { 450 "name": "some-service-name-4", 451 "space_guid": "some-space-guid", 452 "type": "user_provided_service_instance" 453 } 454 } 455 ] 456 }` 457 458 server.AppendHandlers( 459 CombineHandlers( 460 VerifyRequest(http.MethodGet, "/v2/spaces/some-space-guid/service_instances", "return_user_provided_service_instances=true&q=name:foobar"), 461 RespondWith(http.StatusOK, response1, http.Header{"X-Cf-Warnings": {"this is a warning"}}), 462 ), 463 ) 464 465 server.AppendHandlers( 466 CombineHandlers( 467 VerifyRequest(http.MethodGet, "/v2/spaces/some-space-guid/service_instances", "return_user_provided_service_instances=true&q=name:foobar&page=2"), 468 RespondWith(http.StatusOK, response2, http.Header{"X-Cf-Warnings": {"this is another warning"}}), 469 ), 470 ) 471 }) 472 473 When("service instances exist", func() { 474 It("returns all the queried service instances", func() { 475 serviceInstances, warnings, err := client.GetSpaceServiceInstances("some-space-guid", true, Filter{ 476 Type: constant.NameFilter, 477 Operator: constant.EqualOperator, 478 Values: []string{"foobar"}, 479 }) 480 Expect(err).NotTo(HaveOccurred()) 481 482 Expect(serviceInstances).To(ConsistOf([]ServiceInstance{ 483 {Name: "some-service-name-1", GUID: "some-service-guid-1", SpaceGUID: "some-space-guid", ServiceGUID: "some-service-guid", Type: constant.ServiceInstanceTypeManagedService}, 484 {Name: "some-service-name-2", GUID: "some-service-guid-2", SpaceGUID: "some-space-guid", Type: constant.ServiceInstanceTypeUserProvidedService}, 485 {Name: "some-service-name-3", GUID: "some-service-guid-3", SpaceGUID: "some-space-guid", Type: constant.ServiceInstanceTypeManagedService}, 486 {Name: "some-service-name-4", GUID: "some-service-guid-4", SpaceGUID: "some-space-guid", Type: constant.ServiceInstanceTypeUserProvidedService}, 487 })) 488 Expect(warnings).To(ConsistOf(Warnings{"this is a warning", "this is another warning"})) 489 }) 490 }) 491 }) 492 493 Context("excluding user provided services", func() { 494 BeforeEach(func() { 495 response := `{ 496 "next_url": null, 497 "resources": [ 498 { 499 "metadata": { 500 "guid": "some-service-guid-1" 501 }, 502 "entity": { 503 "name": "some-service-name-1", 504 "space_guid": "some-space-guid", 505 "type": "managed_service_instance" 506 } 507 }, 508 { 509 "metadata": { 510 "guid": "some-service-guid-2" 511 }, 512 "entity": { 513 "name": "some-service-name-2", 514 "space_guid": "some-space-guid", 515 "type": "managed_service_instance" 516 } 517 } 518 ] 519 }` 520 521 server.AppendHandlers( 522 CombineHandlers( 523 VerifyRequest(http.MethodGet, "/v2/spaces/some-space-guid/service_instances", "q=name:foobar"), 524 RespondWith(http.StatusOK, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}), 525 ), 526 ) 527 }) 528 529 When("service instances exist", func() { 530 It("returns all the queried service instances", func() { 531 serviceInstances, warnings, err := client.GetSpaceServiceInstances("some-space-guid", false, Filter{ 532 Type: constant.NameFilter, 533 Operator: constant.EqualOperator, 534 Values: []string{"foobar"}, 535 }) 536 Expect(err).NotTo(HaveOccurred()) 537 538 Expect(serviceInstances).To(ConsistOf([]ServiceInstance{ 539 {Name: "some-service-name-1", GUID: "some-service-guid-1", SpaceGUID: "some-space-guid", Type: constant.ServiceInstanceTypeManagedService}, 540 {Name: "some-service-name-2", GUID: "some-service-guid-2", SpaceGUID: "some-space-guid", Type: constant.ServiceInstanceTypeManagedService}, 541 })) 542 Expect(warnings).To(ConsistOf(Warnings{"this is a warning"})) 543 }) 544 }) 545 }) 546 }) 547 548 Describe("GetUserProvidedServiceInstances", func() { 549 var ( 550 serviceInstances []ServiceInstance 551 warnings Warnings 552 executeErr error 553 ) 554 555 JustBeforeEach(func() { 556 serviceInstances, warnings, executeErr = client.GetUserProvidedServiceInstances(Filter{ 557 Type: constant.SpaceGUIDFilter, 558 Operator: constant.EqualOperator, 559 Values: []string{"some-space-guid"}, 560 }) 561 }) 562 563 When("getting user provided service instances errors", func() { 564 BeforeEach(func() { 565 response := `{ 566 "code": 1, 567 "description": "some error description", 568 "error_code": "CF-SomeError" 569 }` 570 server.AppendHandlers( 571 CombineHandlers( 572 VerifyRequest(http.MethodGet, "/v2/user_provided_service_instances", "q=space_guid:some-space-guid"), 573 RespondWith(http.StatusTeapot, response, http.Header{"X-Cf-Warnings": {"warning-1, warning-2"}}), 574 ), 575 ) 576 }) 577 578 It("returns the error and all warnings", func() { 579 Expect(executeErr).To(MatchError(ccerror.V2UnexpectedResponseError{ 580 V2ErrorResponse: ccerror.V2ErrorResponse{ 581 Code: 1, 582 Description: "some error description", 583 ErrorCode: "CF-SomeError", 584 }, 585 ResponseCode: http.StatusTeapot, 586 })) 587 588 Expect(warnings).To(ConsistOf("warning-1", "warning-2")) 589 }) 590 }) 591 592 When("getting user provided service instances succeeds", func() { 593 BeforeEach(func() { 594 response1 := `{ 595 "next_url": "/v2/user_provided_service_instances?q=space_guid:some-space-guid&page=2", 596 "resources": [ 597 { 598 "metadata": { 599 "guid": "some-service-guid-1" 600 }, 601 "entity": { 602 "name": "some-service-name-1", 603 "route_service_url": "some-route-service-url", 604 "space_guid": "some-space-guid", 605 "type": "user_provided_service_instance" 606 } 607 }, 608 { 609 "metadata": { 610 "guid": "some-service-guid-2" 611 }, 612 "entity": { 613 "name": "some-service-name-2", 614 "route_service_url": "some-route-service-url", 615 "space_guid": "some-space-guid", 616 "type": "user_provided_service_instance" 617 } 618 } 619 ] 620 }` 621 622 response2 := `{ 623 "next_url": null, 624 "resources": [ 625 { 626 "metadata": { 627 "guid": "some-service-guid-3" 628 }, 629 "entity": { 630 "name": "some-service-name-3", 631 "route_service_url": "some-route-service-url", 632 "space_guid": "some-space-guid", 633 "type": "user_provided_service_instance" 634 } 635 }, 636 { 637 "metadata": { 638 "guid": "some-service-guid-4" 639 }, 640 "entity": { 641 "name": "some-service-name-4", 642 "route_service_url": "some-route-service-url", 643 "space_guid": "some-space-guid", 644 "type": "user_provided_service_instance" 645 } 646 } 647 ] 648 }` 649 650 server.AppendHandlers( 651 CombineHandlers( 652 VerifyRequest(http.MethodGet, "/v2/user_provided_service_instances", "q=space_guid:some-space-guid"), 653 RespondWith(http.StatusOK, response1, http.Header{"X-Cf-Warnings": {"this is a warning"}}), 654 ), 655 ) 656 657 server.AppendHandlers( 658 CombineHandlers( 659 VerifyRequest(http.MethodGet, "/v2/user_provided_service_instances", "q=space_guid:some-space-guid&page=2"), 660 RespondWith(http.StatusOK, response2, http.Header{"X-Cf-Warnings": {"this is another warning"}}), 661 ), 662 ) 663 }) 664 665 It("returns all the queried service instances", func() { 666 Expect(executeErr).NotTo(HaveOccurred()) 667 668 Expect(serviceInstances).To(ConsistOf([]ServiceInstance{ 669 { 670 Name: "some-service-name-1", 671 GUID: "some-service-guid-1", 672 SpaceGUID: "some-space-guid", 673 RouteServiceURL: "some-route-service-url", 674 Type: constant.ServiceInstanceTypeUserProvidedService, 675 }, 676 { 677 Name: "some-service-name-2", 678 GUID: "some-service-guid-2", 679 SpaceGUID: "some-space-guid", 680 RouteServiceURL: "some-route-service-url", 681 Type: constant.ServiceInstanceTypeUserProvidedService, 682 }, 683 { 684 Name: "some-service-name-3", 685 GUID: "some-service-guid-3", 686 SpaceGUID: "some-space-guid", 687 RouteServiceURL: "some-route-service-url", 688 Type: constant.ServiceInstanceTypeUserProvidedService, 689 }, 690 { 691 Name: "some-service-name-4", 692 GUID: "some-service-guid-4", 693 SpaceGUID: "some-space-guid", 694 RouteServiceURL: "some-route-service-url", 695 Type: constant.ServiceInstanceTypeUserProvidedService, 696 }, 697 })) 698 699 Expect(warnings).To(ConsistOf(Warnings{"this is a warning", "this is another warning"})) 700 }) 701 }) 702 }) 703 })