github.com/mook-as/cf-cli@v7.0.0-beta.28.0.20200120190804-b91c115fae48+incompatible/api/cloudcontroller/ccv2/service_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", func() { 15 var client *Client 16 17 BeforeEach(func() { 18 client = NewTestClient() 19 }) 20 21 Describe("GetService", func() { 22 When("the service exists", func() { 23 When("the value of the 'extra' json key is non-empty", func() { 24 BeforeEach(func() { 25 response := `{ 26 "metadata": { 27 "guid": "some-service-guid" 28 }, 29 "entity": { 30 "label": "some-service", 31 "description": "some-description", 32 "service_broker_name": "service-broker", 33 "extra": "{\"provider\":{\"name\":\"The name\"},\"listing\":{\"imageUrl\":\"http://catgifpage.com/cat.gif\",\"blurb\":\"fake broker that is fake\",\"longDescription\":\"A long time ago, in a galaxy far far away...\"},\"displayName\":\"The Fake Broker\",\"shareable\":true}" 34 } 35 }` 36 server.AppendHandlers( 37 CombineHandlers( 38 VerifyRequest(http.MethodGet, "/v2/services/some-service-guid"), 39 RespondWith(http.StatusOK, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}), 40 ), 41 ) 42 }) 43 44 It("returns the service and warnings", func() { 45 service, warnings, err := client.GetService("some-service-guid") 46 Expect(err).NotTo(HaveOccurred()) 47 48 Expect(service).To(Equal(Service{ 49 GUID: "some-service-guid", 50 Label: "some-service", 51 Description: "some-description", 52 ServiceBrokerName: "service-broker", 53 Extra: ServiceExtra{ 54 Shareable: true, 55 }, 56 })) 57 Expect(warnings).To(ConsistOf(Warnings{"this is a warning"})) 58 }) 59 }) 60 61 When("the value of the 'extra' json key is null", func() { 62 BeforeEach(func() { 63 response := `{ 64 "metadata": { 65 "guid": "some-service-guid" 66 }, 67 "entity": { 68 "extra": null 69 } 70 }` 71 server.AppendHandlers( 72 CombineHandlers( 73 VerifyRequest(http.MethodGet, "/v2/services/some-service-guid"), 74 RespondWith(http.StatusOK, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}), 75 ), 76 ) 77 }) 78 79 It("returns extra.shareable == 'false'", func() { 80 service, _, err := client.GetService("some-service-guid") 81 Expect(err).NotTo(HaveOccurred()) 82 83 Expect(service).To(Equal(Service{ 84 GUID: "some-service-guid", 85 Extra: ServiceExtra{Shareable: false}, 86 })) 87 }) 88 }) 89 90 When("the value of the 'extra' json key is the empty string", func() { 91 BeforeEach(func() { 92 response := `{ 93 "metadata": { 94 "guid": "some-service-guid" 95 }, 96 "entity": { 97 "extra": "" 98 } 99 }` 100 server.AppendHandlers( 101 CombineHandlers( 102 VerifyRequest(http.MethodGet, "/v2/services/some-service-guid"), 103 RespondWith(http.StatusOK, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}), 104 ), 105 ) 106 }) 107 108 It("returns extra.shareable == 'false'", func() { 109 service, _, err := client.GetService("some-service-guid") 110 Expect(err).NotTo(HaveOccurred()) 111 112 Expect(service).To(Equal(Service{ 113 GUID: "some-service-guid", 114 Extra: ServiceExtra{Shareable: false}, 115 })) 116 }) 117 }) 118 119 When("the key 'extra' is not in the json response", func() { 120 BeforeEach(func() { 121 response := `{ 122 "metadata": { 123 "guid": "some-service-guid" 124 } 125 }` 126 server.AppendHandlers( 127 CombineHandlers( 128 VerifyRequest(http.MethodGet, "/v2/services/some-service-guid"), 129 RespondWith(http.StatusOK, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}), 130 ), 131 ) 132 }) 133 134 It("returns extra.shareable == 'false'", func() { 135 service, _, err := client.GetService("some-service-guid") 136 Expect(err).NotTo(HaveOccurred()) 137 138 Expect(service).To(Equal(Service{ 139 GUID: "some-service-guid", 140 Extra: ServiceExtra{Shareable: false}, 141 })) 142 }) 143 }) 144 145 When("the documentation url is set", func() { 146 Context("in the entity structure", func() { 147 BeforeEach(func() { 148 response := `{ 149 "metadata": { 150 "guid": "some-service-guid" 151 }, 152 "entity": { 153 "documentation_url": "some-url" 154 } 155 }` 156 server.AppendHandlers( 157 CombineHandlers( 158 VerifyRequest(http.MethodGet, "/v2/services/some-service-guid"), 159 RespondWith(http.StatusOK, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}), 160 ), 161 ) 162 }) 163 164 It("returns the documentation url correctly", func() { 165 service, _, err := client.GetService("some-service-guid") 166 Expect(err).NotTo(HaveOccurred()) 167 168 Expect(service).To(Equal(Service{ 169 GUID: "some-service-guid", 170 DocumentationURL: "some-url", 171 })) 172 }) 173 }) 174 175 Context("in the extra structure", func() { 176 BeforeEach(func() { 177 response := `{ 178 "metadata": { 179 "guid": "some-service-guid" 180 }, 181 "entity": { 182 "extra": "{\"documentationUrl\":\"some-url\"}" 183 } 184 }` 185 server.AppendHandlers( 186 CombineHandlers( 187 VerifyRequest(http.MethodGet, "/v2/services/some-service-guid"), 188 RespondWith(http.StatusOK, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}), 189 ), 190 ) 191 }) 192 193 It("returns the documentation url correctly", func() { 194 service, _, err := client.GetService("some-service-guid") 195 Expect(err).NotTo(HaveOccurred()) 196 197 Expect(service).To(Equal(Service{ 198 GUID: "some-service-guid", 199 DocumentationURL: "some-url", 200 })) 201 }) 202 }) 203 204 Context("in both the entity and extra structures", func() { 205 BeforeEach(func() { 206 response := `{ 207 "metadata": { 208 "guid": "some-service-guid" 209 }, 210 "entity": { 211 "documentation_url": "entity-url", 212 "extra": "{\"documentationUrl\":\"some-url\"}" 213 } 214 }` 215 server.AppendHandlers( 216 CombineHandlers( 217 VerifyRequest(http.MethodGet, "/v2/services/some-service-guid"), 218 RespondWith(http.StatusOK, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}), 219 ), 220 ) 221 }) 222 223 It("prioritises the entity structure", func() { 224 service, _, err := client.GetService("some-service-guid") 225 Expect(err).NotTo(HaveOccurred()) 226 227 Expect(service).To(Equal(Service{ 228 GUID: "some-service-guid", 229 DocumentationURL: "entity-url", 230 })) 231 }) 232 }) 233 }) 234 }) 235 236 When("the service does not exist (testing general error case)", func() { 237 BeforeEach(func() { 238 response := `{ 239 "description": "The service could not be found: non-existant-service-guid", 240 "error_code": "CF-ServiceNotFound", 241 "code": 120003 242 }` 243 244 server.AppendHandlers( 245 CombineHandlers( 246 VerifyRequest(http.MethodGet, "/v2/services/non-existant-service-guid"), 247 RespondWith(http.StatusNotFound, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}), 248 )) 249 }) 250 251 It("returns an error and warnings", func() { 252 _, warnings, err := client.GetService("non-existant-service-guid") 253 Expect(err).To(MatchError(ccerror.ResourceNotFoundError{Message: "The service could not be found: non-existant-service-guid"})) 254 Expect(warnings).To(ConsistOf(Warnings{"this is a warning"})) 255 }) 256 }) 257 }) 258 Describe("GetServices", func() { 259 var ( 260 services []Service 261 warnings Warnings 262 executeErr error 263 ) 264 265 JustBeforeEach(func() { 266 services, warnings, executeErr = client.GetServices(Filter{ 267 Type: constant.LabelFilter, 268 Operator: constant.EqualOperator, 269 Values: []string{"some-label"}, 270 }) 271 }) 272 273 When("the cc returns back services", func() { 274 BeforeEach(func() { 275 response1 := `{ 276 "next_url": "/v2/services?q=label:some-label&page=2", 277 "resources": [ 278 { 279 "metadata": { 280 "guid": "some-service-guid-1" 281 }, 282 "entity": { 283 "label": "some-service", 284 "service_broker_name": "broker-1" 285 } 286 }, 287 { 288 "metadata": { 289 "guid": "some-service-guid-2" 290 }, 291 "entity": { 292 "label": "other-service", 293 "service_broker_name": "broker-2" 294 } 295 } 296 ] 297 }` 298 299 response2 := `{ 300 "next_url": null, 301 "resources": [ 302 { 303 "metadata": { 304 "guid": "some-service-guid-3" 305 }, 306 "entity": { 307 "label": "some-service", 308 "service_broker_name": "broker-3" 309 } 310 }, 311 { 312 "metadata": { 313 "guid": "some-service-guid-4" 314 }, 315 "entity": { 316 "label": "other-service", 317 "service_broker_name": "broker-4" 318 } 319 } 320 ] 321 }` 322 323 server.AppendHandlers( 324 CombineHandlers( 325 VerifyRequest(http.MethodGet, "/v2/services", "q=label:some-label"), 326 RespondWith(http.StatusOK, response1, http.Header{"X-Cf-Warnings": {"this is a warning"}}), 327 ), 328 ) 329 server.AppendHandlers( 330 CombineHandlers( 331 VerifyRequest(http.MethodGet, "/v2/services", "q=label:some-label&page=2"), 332 RespondWith(http.StatusOK, response2, http.Header{"X-Cf-Warnings": {"this is another warning"}}), 333 ), 334 ) 335 }) 336 337 It("returns all the queried services", func() { 338 Expect(executeErr).NotTo(HaveOccurred()) 339 Expect(services).To(ConsistOf([]Service{ 340 {GUID: "some-service-guid-1", Label: "some-service", ServiceBrokerName: "broker-1"}, 341 {GUID: "some-service-guid-2", Label: "other-service", ServiceBrokerName: "broker-2"}, 342 {GUID: "some-service-guid-3", Label: "some-service", ServiceBrokerName: "broker-3"}, 343 {GUID: "some-service-guid-4", Label: "other-service", ServiceBrokerName: "broker-4"}, 344 })) 345 Expect(warnings).To(ConsistOf(Warnings{"this is a warning", "this is another warning"})) 346 }) 347 }) 348 349 When("the cc returns an error", func() { 350 BeforeEach(func() { 351 response := `{ 352 "description": "Some description.", 353 "error_code": "CF-Error", 354 "code": 90003 355 }` 356 server.AppendHandlers( 357 CombineHandlers( 358 VerifyRequest(http.MethodGet, "/v2/services"), 359 RespondWith(http.StatusTeapot, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}), 360 ), 361 ) 362 }) 363 364 It("returns an error and warnings", func() { 365 Expect(executeErr).To(MatchError(ccerror.V2UnexpectedResponseError{ 366 V2ErrorResponse: ccerror.V2ErrorResponse{ 367 Code: 90003, 368 Description: "Some description.", 369 ErrorCode: "CF-Error", 370 }, 371 ResponseCode: http.StatusTeapot, 372 })) 373 Expect(warnings).To(ConsistOf("this is a warning")) 374 }) 375 }) 376 }) 377 Describe("GetSpaceServices", func() { 378 var ( 379 services []Service 380 warnings Warnings 381 executeErr error 382 ) 383 384 JustBeforeEach(func() { 385 services, warnings, executeErr = client.GetSpaceServices("some-space-guid", Filter{ 386 Type: constant.LabelFilter, 387 Operator: constant.EqualOperator, 388 Values: []string{"some-label"}, 389 }) 390 }) 391 392 When("the cc returns back services", func() { 393 BeforeEach(func() { 394 response1 := `{ 395 "next_url": "/v2/spaces/some-space-guid/services?q=label:some-label&page=2", 396 "resources": [ 397 { 398 "metadata": { 399 "guid": "some-service-guid-1" 400 }, 401 "entity": { 402 "label": "some-service" 403 } 404 }, 405 { 406 "metadata": { 407 "guid": "some-service-guid-2" 408 }, 409 "entity": { 410 "label": "other-service" 411 } 412 } 413 ] 414 }` 415 416 response2 := `{ 417 "next_url": null, 418 "resources": [ 419 { 420 "metadata": { 421 "guid": "some-service-guid-3" 422 }, 423 "entity": { 424 "label": "some-service" 425 } 426 }, 427 { 428 "metadata": { 429 "guid": "some-service-guid-4" 430 }, 431 "entity": { 432 "label": "other-service" 433 } 434 } 435 ] 436 }` 437 438 server.AppendHandlers( 439 CombineHandlers( 440 VerifyRequest(http.MethodGet, "/v2/spaces/some-space-guid/services", "q=label:some-label"), 441 RespondWith(http.StatusOK, response1, http.Header{"X-Cf-Warnings": {"this is a warning"}}), 442 ), 443 ) 444 server.AppendHandlers( 445 CombineHandlers( 446 VerifyRequest(http.MethodGet, "/v2/spaces/some-space-guid/services", "q=label:some-label&page=2"), 447 RespondWith(http.StatusOK, response2, http.Header{"X-Cf-Warnings": {"this is another warning"}}), 448 ), 449 ) 450 }) 451 452 It("returns all the queried services", func() { 453 Expect(executeErr).NotTo(HaveOccurred()) 454 Expect(services).To(ConsistOf([]Service{ 455 {GUID: "some-service-guid-1", Label: "some-service"}, 456 {GUID: "some-service-guid-2", Label: "other-service"}, 457 {GUID: "some-service-guid-3", Label: "some-service"}, 458 {GUID: "some-service-guid-4", Label: "other-service"}, 459 })) 460 Expect(warnings).To(ConsistOf(Warnings{"this is a warning", "this is another warning"})) 461 }) 462 }) 463 464 When("the cc returns an error", func() { 465 BeforeEach(func() { 466 response := `{ 467 "description": "Some description.", 468 "error_code": "CF-Error", 469 "code": 90003 470 }` 471 server.AppendHandlers( 472 CombineHandlers( 473 VerifyRequest(http.MethodGet, "/v2/spaces/some-space-guid/services"), 474 RespondWith(http.StatusTeapot, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}), 475 ), 476 ) 477 }) 478 479 It("returns an error and warnings", func() { 480 Expect(executeErr).To(MatchError(ccerror.V2UnexpectedResponseError{ 481 V2ErrorResponse: ccerror.V2ErrorResponse{ 482 Code: 90003, 483 Description: "Some description.", 484 ErrorCode: "CF-Error", 485 }, 486 ResponseCode: http.StatusTeapot, 487 })) 488 Expect(warnings).To(ConsistOf("this is a warning")) 489 }) 490 }) 491 }) 492 493 Describe("DeleteService", func() { 494 var ( 495 purge bool 496 497 warnings Warnings 498 executeErr error 499 ) 500 501 JustBeforeEach(func() { 502 warnings, executeErr = client.DeleteService("some-service-guid", purge) 503 }) 504 505 When("the purge parameter is true", func() { 506 BeforeEach(func() { 507 purge = true 508 509 server.AppendHandlers( 510 CombineHandlers( 511 VerifyRequest(http.MethodDelete, "/v2/services/some-service-guid", "async=true&purge=true"), 512 RespondWith(http.StatusNoContent, nil, http.Header{"X-Cf-Warnings": {"this is a warning"}}), 513 ), 514 ) 515 }) 516 517 It("deletes the service asynchronously, returns no content and any warnings", func() { 518 Expect(executeErr).NotTo(HaveOccurred()) 519 Expect(warnings).To(ConsistOf(Warnings{"this is a warning"})) 520 }) 521 }) 522 523 When("the purge parameter is false", func() { 524 BeforeEach(func() { 525 purge = false 526 527 server.AppendHandlers( 528 CombineHandlers( 529 VerifyRequest(http.MethodDelete, "/v2/services/some-service-guid", "async=true&purge=false"), 530 RespondWith(http.StatusNoContent, nil, http.Header{"X-Cf-Warnings": {"this is a warning"}}), 531 ), 532 ) 533 }) 534 535 It("deletes the service asynchronously, returns no content and any warnings", func() { 536 Expect(executeErr).NotTo(HaveOccurred()) 537 Expect(warnings).To(ConsistOf(Warnings{"this is a warning"})) 538 }) 539 }) 540 541 When("deleting the service fails", func() { 542 BeforeEach(func() { 543 purge = false 544 545 response := `{ 546 "code": 1, 547 "description": "some error description", 548 "error_code": "CF-SomeError" 549 }` 550 server.AppendHandlers( 551 CombineHandlers( 552 VerifyRequest(http.MethodDelete, "/v2/services/some-service-guid", "async=true&purge=false"), 553 RespondWith(http.StatusTeapot, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}), 554 ), 555 ) 556 }) 557 558 It("returns the error and any warnings", func() { 559 Expect(executeErr).To(MatchError(ccerror.V2UnexpectedResponseError{ 560 V2ErrorResponse: ccerror.V2ErrorResponse{ 561 Code: 1, 562 Description: "some error description", 563 ErrorCode: "CF-SomeError", 564 }, 565 ResponseCode: http.StatusTeapot, 566 })) 567 Expect(warnings).To(ConsistOf(Warnings{"this is a warning"})) 568 }) 569 }) 570 }) 571 })