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