github.com/mook-as/cf-cli@v7.0.0-beta.28.0.20200120190804-b91c115fae48+incompatible/api/cloudcontroller/ccv3/role_test.go (about) 1 package ccv3_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/ccv3" 9 "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant" 10 . "github.com/onsi/ginkgo" 11 . "github.com/onsi/gomega" 12 . "github.com/onsi/gomega/ghttp" 13 ) 14 15 var _ = Describe("Role", func() { 16 var client *Client 17 18 BeforeEach(func() { 19 client, _ = NewTestClient() 20 }) 21 22 Describe("CreateRole", func() { 23 var ( 24 roleType constant.RoleType 25 userGUID string 26 userName string 27 origin string 28 orgGUID string 29 spaceGUID string 30 31 createdRole Role 32 warnings Warnings 33 executeErr error 34 ) 35 36 BeforeEach(func() { 37 userGUID = "" 38 userName = "" 39 origin = "uaa" 40 orgGUID = "" 41 spaceGUID = "" 42 }) 43 44 JustBeforeEach(func() { 45 createdRole, warnings, executeErr = client.CreateRole(Role{ 46 Type: roleType, 47 UserGUID: userGUID, 48 Username: userName, 49 Origin: origin, 50 OrgGUID: orgGUID, 51 SpaceGUID: spaceGUID, 52 }) 53 }) 54 55 Describe("create org role by username/origin", func() { 56 BeforeEach(func() { 57 roleType = constant.OrgAuditorRole 58 userName = "user-name" 59 origin = "uaa" 60 orgGUID = "org-guid" 61 }) 62 63 When("the request succeeds", func() { 64 When("no additional flags", func() { 65 BeforeEach(func() { 66 response := `{ 67 "guid": "some-role-guid", 68 "type": "organization_auditor", 69 "relationships": { 70 "organization": { 71 "data": { "guid": "org-guid" } 72 }, 73 "user": { 74 "data": { "guid": "user-guid" } 75 } 76 } 77 }` 78 79 expectedBody := `{ 80 "type": "organization_auditor", 81 "relationships": { 82 "organization": { 83 "data": { "guid": "org-guid" } 84 }, 85 "user": { 86 "data": { "username": "user-name", "origin": "uaa" } 87 } 88 } 89 }` 90 91 server.AppendHandlers( 92 CombineHandlers( 93 VerifyRequest(http.MethodPost, "/v3/roles"), 94 VerifyJSON(expectedBody), 95 RespondWith(http.StatusCreated, response, http.Header{"X-Cf-Warnings": {"warning-1"}}), 96 ), 97 ) 98 }) 99 100 It("returns the given role and all warnings", func() { 101 Expect(executeErr).ToNot(HaveOccurred()) 102 Expect(warnings).To(ConsistOf("warning-1")) 103 104 Expect(createdRole).To(Equal(Role{ 105 GUID: "some-role-guid", 106 Type: constant.OrgAuditorRole, 107 UserGUID: "user-guid", 108 OrgGUID: "org-guid", 109 })) 110 }) 111 }) 112 }) 113 114 When("the cloud controller returns errors and warnings", func() { 115 BeforeEach(func() { 116 response := `{ 117 "errors": [ 118 { 119 "code": 10008, 120 "detail": "The request is semantically invalid: command presence", 121 "title": "CF-UnprocessableEntity" 122 }, 123 { 124 "code": 10010, 125 "detail": "Isolation segment not found", 126 "title": "CF-ResourceNotFound" 127 } 128 ] 129 }` 130 server.AppendHandlers( 131 CombineHandlers( 132 VerifyRequest(http.MethodPost, "/v3/roles"), 133 RespondWith(http.StatusTeapot, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}), 134 ), 135 ) 136 }) 137 138 It("returns the error and all warnings", func() { 139 Expect(executeErr).To(MatchError(ccerror.MultiError{ 140 ResponseCode: http.StatusTeapot, 141 Errors: []ccerror.V3Error{ 142 { 143 Code: 10008, 144 Detail: "The request is semantically invalid: command presence", 145 Title: "CF-UnprocessableEntity", 146 }, 147 { 148 Code: 10010, 149 Detail: "Isolation segment not found", 150 Title: "CF-ResourceNotFound", 151 }, 152 }, 153 })) 154 Expect(warnings).To(ConsistOf("this is a warning")) 155 }) 156 }) 157 }) 158 159 Describe("create space role by username/origin", func() { 160 BeforeEach(func() { 161 roleType = constant.SpaceAuditorRole 162 userName = "user-name" 163 spaceGUID = "space-guid" 164 }) 165 166 When("the request succeeds", func() { 167 When("no additional flags", func() { 168 BeforeEach(func() { 169 response := `{ 170 "guid": "some-role-guid", 171 "type": "space_auditor", 172 "relationships": { 173 "space": { 174 "data": { "guid": "space-guid" } 175 }, 176 "user": { 177 "data": { "guid": "user-guid" } 178 } 179 } 180 }` 181 182 expectedBody := `{ 183 "type": "space_auditor", 184 "relationships": { 185 "space": { 186 "data": { "guid": "space-guid" } 187 }, 188 "user": { 189 "data": { "username": "user-name", "origin": "uaa" } 190 } 191 } 192 }` 193 194 server.AppendHandlers( 195 CombineHandlers( 196 VerifyRequest(http.MethodPost, "/v3/roles"), 197 VerifyJSON(expectedBody), 198 RespondWith(http.StatusCreated, response, http.Header{"X-Cf-Warnings": {"warning-1"}}), 199 ), 200 ) 201 }) 202 203 It("returns the given route and all warnings", func() { 204 Expect(executeErr).ToNot(HaveOccurred()) 205 Expect(warnings).To(ConsistOf("warning-1")) 206 207 Expect(createdRole).To(Equal(Role{ 208 GUID: "some-role-guid", 209 Type: constant.SpaceAuditorRole, 210 UserGUID: "user-guid", 211 SpaceGUID: "space-guid", 212 })) 213 }) 214 }) 215 }) 216 }) 217 218 Describe("create org role by guid", func() { 219 BeforeEach(func() { 220 roleType = constant.OrgAuditorRole 221 userGUID = "user-guid" 222 orgGUID = "org-guid" 223 }) 224 225 When("the request succeeds", func() { 226 When("no additional flags", func() { 227 BeforeEach(func() { 228 response := `{ 229 "guid": "some-role-guid", 230 "type": "organization_auditor", 231 "relationships": { 232 "organization": { 233 "data": { "guid": "org-guid" } 234 }, 235 "user": { 236 "data": { "guid": "user-guid" } 237 } 238 } 239 }` 240 241 expectedBody := `{ 242 "type": "organization_auditor", 243 "relationships": { 244 "organization": { 245 "data": { "guid": "org-guid" } 246 }, 247 "user": { 248 "data": { "guid": "user-guid" } 249 } 250 } 251 }` 252 253 server.AppendHandlers( 254 CombineHandlers( 255 VerifyRequest(http.MethodPost, "/v3/roles"), 256 VerifyJSON(expectedBody), 257 RespondWith(http.StatusCreated, response, http.Header{"X-Cf-Warnings": {"warning-1"}}), 258 ), 259 ) 260 }) 261 262 It("returns the given route and all warnings", func() { 263 Expect(executeErr).ToNot(HaveOccurred()) 264 Expect(warnings).To(ConsistOf("warning-1")) 265 266 Expect(createdRole).To(Equal(Role{ 267 GUID: "some-role-guid", 268 Type: constant.OrgAuditorRole, 269 UserGUID: "user-guid", 270 OrgGUID: "org-guid", 271 })) 272 }) 273 }) 274 }) 275 276 When("the cloud controller returns errors and warnings", func() { 277 BeforeEach(func() { 278 response := `{ 279 "errors": [ 280 { 281 "code": 10008, 282 "detail": "Something was not processable", 283 "title": "CF-UnprocessableEntity" 284 }, 285 { 286 "code": 10010, 287 "detail": "Something was not found", 288 "title": "CF-ResourceNotFound" 289 } 290 ] 291 }` 292 server.AppendHandlers( 293 CombineHandlers( 294 VerifyRequest(http.MethodPost, "/v3/roles"), 295 RespondWith(http.StatusTeapot, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}), 296 ), 297 ) 298 }) 299 300 It("returns the error and all warnings", func() { 301 Expect(executeErr).To(MatchError(ccerror.MultiError{ 302 ResponseCode: http.StatusTeapot, 303 Errors: []ccerror.V3Error{ 304 { 305 Code: 10008, 306 Detail: "Something was not processable", 307 Title: "CF-UnprocessableEntity", 308 }, 309 { 310 Code: 10010, 311 Detail: "Something was not found", 312 Title: "CF-ResourceNotFound", 313 }, 314 }, 315 })) 316 Expect(warnings).To(ConsistOf("this is a warning")) 317 }) 318 }) 319 }) 320 321 Describe("create space role by guid", func() { 322 BeforeEach(func() { 323 roleType = constant.SpaceAuditorRole 324 userGUID = "user-guid" 325 spaceGUID = "space-guid" 326 }) 327 328 When("the request succeeds", func() { 329 When("no additional flags", func() { 330 BeforeEach(func() { 331 response := `{ 332 "guid": "some-role-guid", 333 "type": "space_auditor", 334 "relationships": { 335 "space": { 336 "data": { "guid": "space-guid" } 337 }, 338 "user": { 339 "data": { "guid": "user-guid" } 340 } 341 } 342 }` 343 344 expectedBody := `{ 345 "type": "space_auditor", 346 "relationships": { 347 "space": { 348 "data": { "guid": "space-guid" } 349 }, 350 "user": { 351 "data": { "guid": "user-guid" } 352 } 353 } 354 }` 355 356 server.AppendHandlers( 357 CombineHandlers( 358 VerifyRequest(http.MethodPost, "/v3/roles"), 359 VerifyJSON(expectedBody), 360 RespondWith(http.StatusCreated, response, http.Header{"X-Cf-Warnings": {"warning-1"}}), 361 ), 362 ) 363 }) 364 365 It("returns the given route and all warnings", func() { 366 Expect(executeErr).ToNot(HaveOccurred()) 367 Expect(warnings).To(ConsistOf("warning-1")) 368 369 Expect(createdRole).To(Equal(Role{ 370 GUID: "some-role-guid", 371 Type: constant.SpaceAuditorRole, 372 UserGUID: "user-guid", 373 SpaceGUID: "space-guid", 374 })) 375 }) 376 }) 377 }) 378 }) 379 }) 380 381 Describe("GetRoles", func() { 382 var ( 383 roles []Role 384 includes IncludedResources 385 warnings Warnings 386 executeErr error 387 query []Query 388 ) 389 390 BeforeEach(func() { 391 query = []Query{ 392 { 393 Key: OrganizationGUIDFilter, 394 Values: []string{"some-org-name"}, 395 }, 396 { 397 Key: Include, 398 Values: []string{"users"}, 399 }, 400 } 401 }) 402 JustBeforeEach(func() { 403 roles, includes, warnings, executeErr = client.GetRoles(query...) 404 }) 405 406 Describe("listing roles", func() { 407 When("the request succeeds", func() { 408 BeforeEach(func() { 409 response1 := fmt.Sprintf(`{ 410 "pagination": { 411 "next": { 412 "href": "%s/v3/roles?organization_guids=some-org-name&page=2&per_page=1&include=users" 413 } 414 }, 415 "resources": [ 416 { 417 "guid": "role-guid-1", 418 "type": "organization_user" 419 } 420 ] 421 }`, server.URL()) 422 response2 := `{ 423 "pagination": { 424 "next": null 425 }, 426 "resources": [ 427 { 428 "guid": "role-guid-2", 429 "type": "organization_manager" 430 } 431 ] 432 }` 433 434 server.AppendHandlers( 435 CombineHandlers( 436 VerifyRequest(http.MethodGet, "/v3/roles", "organization_guids=some-org-name&include=users"), 437 RespondWith(http.StatusOK, response1, http.Header{"X-Cf-Warnings": {"warning-1"}}), 438 ), 439 ) 440 server.AppendHandlers( 441 CombineHandlers( 442 VerifyRequest(http.MethodGet, "/v3/roles", "organization_guids=some-org-name&page=2&per_page=1&include=users"), 443 RespondWith(http.StatusOK, response2, http.Header{"X-Cf-Warnings": {"warning-2"}}), 444 ), 445 ) 446 }) 447 448 It("returns the given route and all warnings", func() { 449 Expect(executeErr).ToNot(HaveOccurred()) 450 Expect(warnings).To(ConsistOf("warning-1", "warning-2")) 451 452 Expect(roles).To(Equal([]Role{{ 453 GUID: "role-guid-1", 454 Type: constant.OrgUserRole, 455 }, { 456 GUID: "role-guid-2", 457 Type: constant.OrgManagerRole, 458 }})) 459 }) 460 }) 461 462 When("the request uses the `include` query key", func() { 463 BeforeEach(func() { 464 response1 := fmt.Sprintf(`{ 465 "pagination": { 466 "next": { 467 "href": "%s/v3/roles?organization_guids=some-org-name&page=2&per_page=1&include=users" 468 } 469 }, 470 "resources": [ 471 { 472 "guid": "role-guid-1", 473 "type": "organization_user", 474 "relationships": { 475 "user": { 476 "data": {"guid": "user-guid-1"} 477 } 478 } 479 } 480 ], 481 "included": { 482 "users": [ 483 { 484 "guid": "user-guid-1", 485 "username": "user-name-1", 486 "origin": "uaa" 487 } 488 ] 489 } 490 }`, server.URL()) 491 response2 := `{ 492 "pagination": { 493 "next": null 494 }, 495 "resources": [ 496 { 497 "guid": "role-guid-2", 498 "type": "organization_manager", 499 "relationships": { 500 "user": { 501 "data": {"guid": "user-guid-2"} 502 } 503 } 504 } 505 ], 506 "included": { 507 "users": [ 508 { 509 "guid": "user-guid-2", 510 "username": "user-name-2", 511 "origin": "uaa" 512 } 513 ] 514 } 515 }` 516 517 server.AppendHandlers( 518 CombineHandlers( 519 VerifyRequest(http.MethodGet, "/v3/roles", "organization_guids=some-org-name&include=users"), 520 RespondWith(http.StatusOK, response1, http.Header{"X-Cf-Warnings": {"warning-1"}}), 521 ), 522 ) 523 server.AppendHandlers( 524 CombineHandlers( 525 VerifyRequest(http.MethodGet, "/v3/roles", "organization_guids=some-org-name&page=2&per_page=1&include=users"), 526 RespondWith(http.StatusOK, response2, http.Header{"X-Cf-Warnings": {"warning-2"}}), 527 ), 528 ) 529 }) 530 531 It("returns the given route and all warnings", func() { 532 Expect(executeErr).ToNot(HaveOccurred()) 533 Expect(warnings).To(ConsistOf("warning-1", "warning-2")) 534 535 Expect(roles).To(Equal([]Role{{ 536 GUID: "role-guid-1", 537 Type: constant.OrgUserRole, 538 UserGUID: "user-guid-1", 539 }, { 540 GUID: "role-guid-2", 541 Type: constant.OrgManagerRole, 542 UserGUID: "user-guid-2", 543 }})) 544 545 Expect(includes).To(Equal(IncludedResources{ 546 Users: []User{ 547 {GUID: "user-guid-1", Username: "user-name-1", Origin: "uaa"}, 548 {GUID: "user-guid-2", Username: "user-name-2", Origin: "uaa"}, 549 }, 550 })) 551 }) 552 }) 553 554 When("the cloud controller returns errors and warnings", func() { 555 BeforeEach(func() { 556 response := `{ 557 "errors": [ 558 { 559 "code": 10008, 560 "detail": "The request is semantically invalid: command presence", 561 "title": "CF-UnprocessableEntity" 562 }, 563 { 564 "code": 10010, 565 "detail": "Org not found", 566 "title": "CF-ResourceNotFound" 567 } 568 ] 569 }` 570 server.AppendHandlers( 571 CombineHandlers( 572 VerifyRequest(http.MethodGet, "/v3/roles"), 573 RespondWith(http.StatusTeapot, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}), 574 ), 575 ) 576 }) 577 578 It("returns the error and all warnings", func() { 579 Expect(executeErr).To(MatchError(ccerror.MultiError{ 580 ResponseCode: http.StatusTeapot, 581 Errors: []ccerror.V3Error{ 582 { 583 Code: 10008, 584 Detail: "The request is semantically invalid: command presence", 585 Title: "CF-UnprocessableEntity", 586 }, 587 { 588 Code: 10010, 589 Detail: "Org not found", 590 Title: "CF-ResourceNotFound", 591 }, 592 }, 593 })) 594 Expect(warnings).To(ConsistOf("this is a warning")) 595 }) 596 }) 597 }) 598 }) 599 600 Describe("DeleteRoles", func() { 601 var ( 602 roleGUID string 603 jobURL JobURL 604 jobURLString string 605 warnings Warnings 606 executeErr error 607 ) 608 609 BeforeEach(func() { 610 roleGUID = "role-guid" 611 }) 612 613 JustBeforeEach(func() { 614 jobURL, warnings, executeErr = client.DeleteRole(roleGUID) 615 }) 616 617 When("role exists", func() { 618 roleGUID = "role-guid" 619 jobURLString = "https://api.test.com/v3/jobs/job-guid" 620 621 BeforeEach(func() { 622 server.AppendHandlers( 623 CombineHandlers( 624 VerifyRequest(http.MethodDelete, "/v3/roles/role-guid"), 625 RespondWith(http.StatusAccepted, nil, http.Header{ 626 "X-Cf-Warnings": {"this is a warning"}, 627 "Location": {jobURLString}, 628 }), 629 ), 630 ) 631 }) 632 633 It("returns all warnings", func() { 634 Expect(executeErr).NotTo(HaveOccurred()) 635 Expect(jobURL).To(Equal(JobURL(jobURLString))) 636 Expect(warnings).To(ConsistOf("this is a warning")) 637 }) 638 }) 639 640 When("the cloud controller returns errors and warnings", func() { 641 BeforeEach(func() { 642 response := `{ 643 "errors": [ 644 { 645 "code": 10008, 646 "detail": "The request is semantically invalid: command presence", 647 "title": "CF-UnprocessableEntity" 648 }, 649 { 650 "code": 10010, 651 "detail": "Isolation segment not found", 652 "title": "CF-ResourceNotFound" 653 } 654 ] 655 }` 656 server.AppendHandlers( 657 CombineHandlers( 658 VerifyRequest(http.MethodDelete, "/v3/roles/role-guid"), 659 RespondWith(http.StatusTeapot, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}), 660 ), 661 ) 662 }) 663 664 It("returns the error and all warnings", func() { 665 Expect(executeErr).To(MatchError(ccerror.MultiError{ 666 ResponseCode: http.StatusTeapot, 667 Errors: []ccerror.V3Error{ 668 { 669 Code: 10008, 670 Detail: "The request is semantically invalid: command presence", 671 Title: "CF-UnprocessableEntity", 672 }, 673 { 674 Code: 10010, 675 Detail: "Isolation segment not found", 676 Title: "CF-ResourceNotFound", 677 }, 678 }, 679 })) 680 Expect(warnings).To(ConsistOf("this is a warning")) 681 }) 682 }) 683 }) 684 })