github.com/swisscom/cloudfoundry-cli@v7.1.0+incompatible/api/cloudcontroller/ccv3/route_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/resources" 10 "code.cloudfoundry.org/cli/types" 11 . "github.com/onsi/ginkgo" 12 . "github.com/onsi/gomega" 13 . "github.com/onsi/gomega/ghttp" 14 ) 15 16 var _ = Describe("Route", func() { 17 var client *Client 18 19 BeforeEach(func() { 20 client, _ = NewTestClient() 21 }) 22 23 Describe("CreateRoute", func() { 24 var ( 25 route resources.Route 26 warnings Warnings 27 executeErr error 28 spaceGUID string 29 domainGUID string 30 host string 31 path string 32 port int 33 ccv3Route resources.Route 34 ) 35 36 BeforeEach(func() { 37 host = "" 38 path = "" 39 port = 0 40 }) 41 42 JustBeforeEach(func() { 43 spaceGUID = "space-guid" 44 domainGUID = "domain-guid" 45 ccv3Route = resources.Route{SpaceGUID: spaceGUID, DomainGUID: domainGUID, Host: host, Path: path, Port: port} 46 route, warnings, executeErr = client.CreateRoute(ccv3Route) 47 }) 48 49 When("the request succeeds", func() { 50 When("no additional flags", func() { 51 BeforeEach(func() { 52 host = "" 53 response := `{ 54 "guid": "some-route-guid", 55 "relationships": { 56 "space": { 57 "data": { "guid": "space-guid" } 58 }, 59 "domain": { 60 "data": { "guid": "domain-guid" } 61 } 62 }, 63 "host": "" 64 }` 65 66 expectedBody := `{ 67 "relationships": { 68 "space": { 69 "data": { "guid": "space-guid" } 70 }, 71 "domain": { 72 "data": { "guid": "domain-guid" } 73 } 74 } 75 }` 76 77 server.AppendHandlers( 78 CombineHandlers( 79 VerifyRequest(http.MethodPost, "/v3/routes"), 80 VerifyJSON(expectedBody), 81 RespondWith(http.StatusCreated, response, http.Header{"X-Cf-Warnings": {"warning-1"}}), 82 ), 83 ) 84 }) 85 86 It("returns the given route and all warnings", func() { 87 Expect(executeErr).ToNot(HaveOccurred()) 88 Expect(warnings).To(ConsistOf("warning-1")) 89 90 Expect(route).To(Equal(resources.Route{ 91 GUID: "some-route-guid", 92 SpaceGUID: "space-guid", 93 DomainGUID: "domain-guid", 94 })) 95 }) 96 }) 97 98 When("hostname is passed in", func() { 99 100 BeforeEach(func() { 101 host = "cheesecake" 102 response := `{ 103 "guid": "some-route-guid", 104 "relationships": { 105 "space": { 106 "data": { "guid": "space-guid" } 107 }, 108 "domain": { 109 "data": { "guid": "domain-guid" } 110 } 111 }, 112 "host": "cheesecake" 113 }` 114 115 expectedBody := `{ 116 "relationships": { 117 "space": { 118 "data": { "guid": "space-guid" } 119 }, 120 "domain": { 121 "data": { "guid": "domain-guid" } 122 } 123 }, 124 "host": "cheesecake" 125 }` 126 127 server.AppendHandlers( 128 CombineHandlers( 129 VerifyRequest(http.MethodPost, "/v3/routes"), 130 VerifyJSON(expectedBody), 131 RespondWith(http.StatusCreated, response, http.Header{"X-Cf-Warnings": {"warning-1"}}), 132 ), 133 ) 134 }) 135 136 It("returns the given route and all warnings", func() { 137 Expect(executeErr).ToNot(HaveOccurred()) 138 Expect(warnings).To(ConsistOf("warning-1")) 139 140 Expect(route).To(Equal(resources.Route{ 141 GUID: "some-route-guid", 142 SpaceGUID: "space-guid", 143 DomainGUID: "domain-guid", 144 Host: "cheesecake", 145 })) 146 }) 147 }) 148 149 When("path is passed in", func() { 150 BeforeEach(func() { 151 path = "lion" 152 153 response := `{ 154 "guid": "this-route-guid", 155 "relationships": { 156 "space": { 157 "data": { 158 "guid": "space-guid" 159 } 160 }, 161 "domain": { 162 "data": { 163 "guid": "domain-guid" 164 } 165 } 166 }, 167 "path": "lion" 168 }` 169 expectedRequestBody := `{ 170 "relationships": { 171 "space": { 172 "data": { 173 "guid": "space-guid" 174 } 175 }, 176 "domain": { 177 "data": { 178 "guid": "domain-guid" 179 } 180 } 181 }, 182 "path": "lion" 183 }` 184 185 server.AppendHandlers( 186 CombineHandlers( 187 VerifyRequest(http.MethodPost, "/v3/routes"), 188 VerifyJSON(expectedRequestBody), 189 RespondWith(http.StatusCreated, response, http.Header{"X-Cf-Warnings": {"warning-1"}}), 190 ), 191 ) 192 }) 193 When("the request succeeds", func() { 194 It("returns the given route and all warnings", func() { 195 Expect(executeErr).ToNot(HaveOccurred()) 196 Expect(warnings).To(ConsistOf("warning-1")) 197 198 Expect(route).To(Equal(resources.Route{ 199 GUID: "this-route-guid", 200 SpaceGUID: "space-guid", 201 DomainGUID: "domain-guid", 202 Path: "lion", 203 })) 204 }) 205 }) 206 }) 207 208 When("port is passed in", func() { 209 BeforeEach(func() { 210 port = 1234 211 212 response := `{ 213 "guid": "this-route-guid", 214 "relationships": { 215 "space": { 216 "data": { 217 "guid": "space-guid" 218 } 219 }, 220 "domain": { 221 "data": { 222 "guid": "domain-guid" 223 } 224 } 225 }, 226 "port": 1234 227 }` 228 expectedRequestBody := `{ 229 "relationships": { 230 "space": { 231 "data": { 232 "guid": "space-guid" 233 } 234 }, 235 "domain": { 236 "data": { 237 "guid": "domain-guid" 238 } 239 } 240 }, 241 "port": 1234 242 }` 243 244 server.AppendHandlers( 245 CombineHandlers( 246 VerifyRequest(http.MethodPost, "/v3/routes"), 247 VerifyJSON(expectedRequestBody), 248 RespondWith(http.StatusCreated, response, http.Header{"X-Cf-Warnings": {"warning-1"}}), 249 ), 250 ) 251 }) 252 When("the request succeeds", func() { 253 It("returns the given route and all warnings", func() { 254 Expect(executeErr).ToNot(HaveOccurred()) 255 Expect(warnings).To(ConsistOf("warning-1")) 256 257 Expect(route).To(Equal(resources.Route{ 258 GUID: "this-route-guid", 259 SpaceGUID: "space-guid", 260 DomainGUID: "domain-guid", 261 Port: 1234, 262 })) 263 }) 264 }) 265 }) 266 }) 267 268 When("the cloud controller returns errors and warnings", func() { 269 BeforeEach(func() { 270 response := `{ 271 "errors": [ 272 { 273 "code": 10008, 274 "detail": "The request is semantically invalid: command presence", 275 "title": "CF-UnprocessableEntity" 276 }, 277 { 278 "code": 10010, 279 "detail": "Isolation segment not found", 280 "title": "CF-ResourceNotFound" 281 } 282 ] 283 }` 284 server.AppendHandlers( 285 CombineHandlers( 286 VerifyRequest(http.MethodPost, "/v3/routes"), 287 RespondWith(http.StatusTeapot, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}), 288 ), 289 ) 290 }) 291 292 It("returns the error and all warnings", func() { 293 Expect(executeErr).To(MatchError(ccerror.MultiError{ 294 ResponseCode: http.StatusTeapot, 295 Errors: []ccerror.V3Error{ 296 { 297 Code: 10008, 298 Detail: "The request is semantically invalid: command presence", 299 Title: "CF-UnprocessableEntity", 300 }, 301 { 302 Code: 10010, 303 Detail: "Isolation segment not found", 304 Title: "CF-ResourceNotFound", 305 }, 306 }, 307 })) 308 Expect(warnings).To(ConsistOf("this is a warning")) 309 }) 310 }) 311 }) 312 313 Describe("GetRoutes", func() { 314 var ( 315 query Query 316 routes []resources.Route 317 warnings Warnings 318 executeErr error 319 ) 320 321 JustBeforeEach(func() { 322 routes, warnings, executeErr = client.GetRoutes(query) 323 }) 324 325 When("the request succeeds", func() { 326 var ( 327 response1 string 328 response2 string 329 ) 330 331 BeforeEach(func() { 332 response1 = fmt.Sprintf(` 333 { 334 "pagination": { 335 "next": { 336 "href": "%s/v3/routes?page=2" 337 } 338 }, 339 "resources": [ 340 { 341 "guid": "route-1-guid", 342 "url": "hello", 343 "metadata": { 344 "labels": { 345 "key1": "value1" 346 } 347 } 348 }, 349 { 350 "guid": "route-2-guid", 351 "url": "bye" 352 } 353 ] 354 }`, server.URL()) 355 356 response2 = ` 357 { 358 "pagination": { 359 "next": null 360 }, 361 "resources": [ 362 { 363 "guid": "route-3-guid" 364 } 365 ] 366 }` 367 }) 368 369 When("not passing any filters", func() { 370 BeforeEach(func() { 371 query = Query{} 372 373 server.AppendHandlers( 374 CombineHandlers( 375 VerifyRequest(http.MethodGet, "/v3/routes"), 376 RespondWith(http.StatusOK, response1, http.Header{"X-Cf-Warnings": {"warning-1"}}), 377 ), 378 ) 379 server.AppendHandlers( 380 CombineHandlers( 381 VerifyRequest(http.MethodGet, "/v3/routes", "page=2"), 382 RespondWith(http.StatusOK, response2, http.Header{"X-Cf-Warnings": {"warning-2"}}), 383 ), 384 ) 385 }) 386 387 It("returns the given route and all warnings", func() { 388 Expect(executeErr).ToNot(HaveOccurred()) 389 Expect(warnings).To(ConsistOf("warning-1", "warning-2")) 390 391 Expect(routes).To(Equal([]resources.Route{ 392 { 393 GUID: "route-1-guid", 394 URL: "hello", 395 Metadata: &resources.Metadata{ 396 Labels: map[string]types.NullString{ 397 "key1": types.NewNullString("value1"), 398 }, 399 }, 400 }, 401 { 402 GUID: "route-2-guid", 403 URL: "bye", 404 }, 405 { 406 GUID: "route-3-guid", 407 }, 408 })) 409 }) 410 }) 411 412 When("passing in a query", func() { 413 BeforeEach(func() { 414 query = Query{Key: "space_guids", Values: []string{"guid1", "guid2"}} 415 416 server.AppendHandlers( 417 CombineHandlers( 418 VerifyRequest(http.MethodGet, "/v3/routes", "space_guids=guid1,guid2"), 419 RespondWith(http.StatusOK, response1, http.Header{"X-Cf-Warnings": {"warning-1"}}), 420 ), 421 ) 422 server.AppendHandlers( 423 CombineHandlers( 424 VerifyRequest(http.MethodGet, "/v3/routes", "page=2", "space_guids=guid1,guid2"), 425 RespondWith(http.StatusOK, response2, http.Header{"X-Cf-Warnings": {"warning-2"}}), 426 ), 427 ) 428 }) 429 430 It("passes query params", func() { 431 Expect(executeErr).ToNot(HaveOccurred()) 432 Expect(warnings).To(ConsistOf("warning-1", "warning-2")) 433 434 Expect(routes).To(Equal([]resources.Route{ 435 { 436 GUID: "route-1-guid", 437 URL: "hello", 438 Metadata: &resources.Metadata{ 439 Labels: map[string]types.NullString{ 440 "key1": types.NewNullString("value1"), 441 }, 442 }, 443 }, 444 { 445 GUID: "route-2-guid", 446 URL: "bye", 447 }, 448 { 449 GUID: "route-3-guid", 450 }, 451 })) 452 }) 453 }) 454 }) 455 }) 456 457 Describe("DeleteRoute", func() { 458 var ( 459 routeGUID string 460 jobURLString string 461 jobURL JobURL 462 warnings Warnings 463 executeErr error 464 ) 465 466 JustBeforeEach(func() { 467 jobURL, warnings, executeErr = client.DeleteRoute(routeGUID) 468 }) 469 470 When("route exists", func() { 471 routeGUID = "route-guid" 472 jobURLString = "https://api.test.com/v3/jobs/job-guid" 473 474 BeforeEach(func() { 475 server.AppendHandlers( 476 CombineHandlers( 477 VerifyRequest(http.MethodDelete, "/v3/routes/route-guid"), 478 RespondWith(http.StatusAccepted, nil, http.Header{ 479 "X-Cf-Warnings": {"this is a warning"}, 480 "Location": {jobURLString}, 481 }), 482 ), 483 ) 484 }) 485 486 It("returns all warnings", func() { 487 Expect(executeErr).NotTo(HaveOccurred()) 488 Expect(jobURL).To(Equal(JobURL(jobURLString))) 489 Expect(warnings).To(ConsistOf("this is a warning")) 490 }) 491 }) 492 493 When("the cloud controller returns errors and warnings", func() { 494 BeforeEach(func() { 495 response := `{ 496 "errors": [ 497 { 498 "code": 10008, 499 "detail": "The request is semantically invalid: command presence", 500 "title": "CF-UnprocessableEntity" 501 }, 502 { 503 "code": 10010, 504 "detail": "Isolation segment not found", 505 "title": "CF-ResourceNotFound" 506 } 507 ] 508 }` 509 server.AppendHandlers( 510 CombineHandlers( 511 VerifyRequest(http.MethodDelete, "/v3/routes/route-guid"), 512 RespondWith(http.StatusTeapot, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}), 513 ), 514 ) 515 }) 516 517 It("returns the error and all warnings", func() { 518 Expect(executeErr).To(MatchError(ccerror.MultiError{ 519 ResponseCode: http.StatusTeapot, 520 Errors: []ccerror.V3Error{ 521 { 522 Code: 10008, 523 Detail: "The request is semantically invalid: command presence", 524 Title: "CF-UnprocessableEntity", 525 }, 526 { 527 Code: 10010, 528 Detail: "Isolation segment not found", 529 Title: "CF-ResourceNotFound", 530 }, 531 }, 532 })) 533 Expect(warnings).To(ConsistOf("this is a warning")) 534 }) 535 }) 536 }) 537 538 Describe("MapRoute", func() { 539 var ( 540 routeGUID = "route-guid" 541 appGUID = "app-guid" 542 warnings Warnings 543 executeErr error 544 ) 545 546 JustBeforeEach(func() { 547 warnings, executeErr = client.MapRoute(routeGUID, appGUID) 548 }) 549 550 When("the request is successful", func() { 551 BeforeEach(func() { 552 expectedBody := fmt.Sprintf(` 553 { 554 "destinations": [ 555 { 556 "app": { 557 "guid": "%s" 558 } 559 } 560 ] 561 } 562 `, appGUID) 563 564 response := `{}` 565 566 server.AppendHandlers( 567 CombineHandlers( 568 VerifyRequest(http.MethodPost, "/v3/routes/route-guid/destinations"), 569 VerifyJSON(expectedBody), 570 RespondWith(http.StatusOK, response, http.Header{"X-Cf-Warnings": {"warning-1"}}), 571 ), 572 ) 573 }) 574 575 It("returns the warnings and no error", func() { 576 Expect(executeErr).ToNot(HaveOccurred()) 577 Expect(warnings).To(ConsistOf("warning-1")) 578 }) 579 }) 580 581 When("the cloud controller returns errors and warnings", func() { 582 BeforeEach(func() { 583 response := `{ 584 "errors": [ 585 { 586 "code": 10008, 587 "detail": "The request is semantically invalid: command presence", 588 "title": "CF-UnprocessableEntity" 589 }, 590 { 591 "code": 10010, 592 "detail": "Isolation segment not found", 593 "title": "CF-ResourceNotFound" 594 } 595 ] 596 }` 597 server.AppendHandlers( 598 CombineHandlers( 599 VerifyRequest(http.MethodPost, "/v3/routes/route-guid/destinations"), 600 RespondWith(http.StatusTeapot, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}), 601 ), 602 ) 603 }) 604 605 It("returns the error and all warnings", func() { 606 Expect(executeErr).To(MatchError(ccerror.MultiError{ 607 ResponseCode: http.StatusTeapot, 608 Errors: []ccerror.V3Error{ 609 { 610 Code: 10008, 611 Detail: "The request is semantically invalid: command presence", 612 Title: "CF-UnprocessableEntity", 613 }, 614 { 615 Code: 10010, 616 Detail: "Isolation segment not found", 617 Title: "CF-ResourceNotFound", 618 }, 619 }, 620 })) 621 Expect(warnings).To(ConsistOf("this is a warning")) 622 }) 623 }) 624 }) 625 626 Describe("GetRouteDestinations", func() { 627 var ( 628 routeGUID = "some-route-guid" 629 destinations []resources.RouteDestination 630 warnings Warnings 631 executeErr error 632 ) 633 634 JustBeforeEach(func() { 635 destinations, warnings, executeErr = client.GetRouteDestinations(routeGUID) 636 }) 637 638 When("the request succeeds", func() { 639 var ( 640 response string 641 ) 642 643 BeforeEach(func() { 644 response = ` 645 { 646 "destinations": [ 647 { 648 "guid": "destination-1-guid", 649 "app": { 650 "guid": "app-1-guid", 651 "process": { 652 "type": "web" 653 } 654 } 655 }, 656 { 657 "guid": "destination-2-guid", 658 "app": { 659 "guid": "app-2-guid", 660 "process": { 661 "type": "worker" 662 } 663 } 664 } 665 ] 666 }` 667 }) 668 669 When("the request succeeds", func() { 670 BeforeEach(func() { 671 server.AppendHandlers( 672 CombineHandlers( 673 VerifyRequest(http.MethodGet, "/v3/routes/some-route-guid/destinations"), 674 RespondWith(http.StatusOK, response, http.Header{"X-Cf-Warnings": {"warning-1"}}), 675 ), 676 ) 677 }) 678 679 It("returns destinations and all warnings", func() { 680 Expect(executeErr).ToNot(HaveOccurred()) 681 Expect(warnings).To(ConsistOf("warning-1")) 682 683 Expect(destinations).To(Equal([]resources.RouteDestination{ 684 { 685 GUID: "destination-1-guid", 686 App: resources.RouteDestinationApp{GUID: "app-1-guid", Process: struct{ Type string }{Type: "web"}}, 687 }, 688 { 689 GUID: "destination-2-guid", 690 App: resources.RouteDestinationApp{GUID: "app-2-guid", Process: struct{ Type string }{Type: "worker"}}, 691 }, 692 })) 693 }) 694 }) 695 }) 696 }) 697 698 Describe("UnmapRoute", func() { 699 var ( 700 routeGUID string 701 destinationGUID string 702 warnings Warnings 703 executeErr error 704 ) 705 706 JustBeforeEach(func() { 707 warnings, executeErr = client.UnmapRoute(routeGUID, destinationGUID) 708 }) 709 710 When("route exists", func() { 711 routeGUID = "route-guid" 712 destinationGUID = "destination-guid" 713 714 BeforeEach(func() { 715 server.AppendHandlers( 716 CombineHandlers( 717 VerifyRequest(http.MethodDelete, "/v3/routes/route-guid/destinations/destination-guid"), 718 RespondWith(http.StatusNoContent, nil, http.Header{ 719 "X-Cf-Warnings": {"this is a warning"}, 720 }), 721 ), 722 ) 723 }) 724 725 It("returns all warnings", func() { 726 Expect(executeErr).NotTo(HaveOccurred()) 727 Expect(warnings).To(ConsistOf("this is a warning")) 728 }) 729 }) 730 731 When("the cloud controller returns errors and warnings", func() { 732 BeforeEach(func() { 733 response := `{ 734 "errors": [ 735 { 736 "code": 10008, 737 "detail": "The request is semantically invalid: command presence", 738 "title": "CF-UnprocessableEntity" 739 }, 740 { 741 "code": 10010, 742 "detail": "Isolation segment not found", 743 "title": "CF-ResourceNotFound" 744 } 745 ] 746 }` 747 server.AppendHandlers( 748 CombineHandlers( 749 VerifyRequest(http.MethodDelete, "/v3/routes/route-guid/destinations/destination-guid"), 750 RespondWith(http.StatusTeapot, response, http.Header{ 751 "X-Cf-Warnings": {"this is a warning"}, 752 }), 753 ), 754 ) 755 }) 756 757 It("returns the error and all warnings", func() { 758 Expect(executeErr).To(MatchError(ccerror.MultiError{ 759 ResponseCode: http.StatusTeapot, 760 Errors: []ccerror.V3Error{ 761 { 762 Code: 10008, 763 Detail: "The request is semantically invalid: command presence", 764 Title: "CF-UnprocessableEntity", 765 }, 766 { 767 Code: 10010, 768 Detail: "Isolation segment not found", 769 Title: "CF-ResourceNotFound", 770 }, 771 }, 772 })) 773 Expect(warnings).To(ConsistOf("this is a warning")) 774 }) 775 }) 776 }) 777 778 Describe("DeleteOrphanedRoutes", func() { 779 var ( 780 spaceGUID string 781 warnings Warnings 782 executeErr error 783 jobURL JobURL 784 ) 785 JustBeforeEach(func() { 786 jobURL, warnings, executeErr = client.DeleteOrphanedRoutes(spaceGUID) 787 }) 788 789 When("the API succeeds", func() { 790 BeforeEach(func() { 791 spaceGUID = "space-guid" 792 server.AppendHandlers( 793 CombineHandlers( 794 VerifyRequest(http.MethodDelete, "/v3/spaces/space-guid/routes", "unmapped=true"), 795 RespondWith( 796 http.StatusAccepted, 797 nil, 798 http.Header{"X-Cf-Warnings": {"orphaned-warning"}, "Location": {"job-url"}}, 799 ), 800 ), 801 ) 802 }) 803 804 It("returns the warnings and a job", func() { 805 Expect(executeErr).ToNot(HaveOccurred()) 806 Expect(warnings).To(ConsistOf("orphaned-warning")) 807 Expect(jobURL).To(Equal(JobURL("job-url"))) 808 }) 809 }) 810 811 When("the API fails", func() { 812 BeforeEach(func() { 813 spaceGUID = "space-guid" 814 response := `{ 815 "errors": [ 816 { 817 "code": 10008, 818 "detail": "The request is semantically invalid: command presence", 819 "title": "CF-UnprocessableEntity" 820 }, 821 { 822 "code": 10010, 823 "detail": "Isolation segment not found", 824 "title": "CF-ResourceNotFound" 825 } 826 ] 827 }` 828 server.AppendHandlers( 829 CombineHandlers( 830 VerifyRequest(http.MethodDelete, "/v3/spaces/space-guid/routes", "unmapped=true"), 831 RespondWith( 832 http.StatusTeapot, 833 response, 834 http.Header{"X-Cf-Warnings": {"orphaned-warning"}}, 835 ), 836 ), 837 ) 838 }) 839 840 It("returns the warnings and a job", func() { 841 842 Expect(executeErr).To(MatchError(ccerror.MultiError{ 843 ResponseCode: http.StatusTeapot, 844 Errors: []ccerror.V3Error{ 845 { 846 Code: 10008, 847 Detail: "The request is semantically invalid: command presence", 848 Title: "CF-UnprocessableEntity", 849 }, 850 { 851 Code: 10010, 852 Detail: "Isolation segment not found", 853 Title: "CF-ResourceNotFound", 854 }, 855 }, 856 })) 857 Expect(warnings).To(ConsistOf("orphaned-warning")) 858 }) 859 }) 860 }) 861 862 Describe("GetApplicationRoutes", func() { 863 var ( 864 appGUID string 865 866 routes []resources.Route 867 warnings Warnings 868 executeErr error 869 ) 870 871 BeforeEach(func() { 872 appGUID = "some-app-guid" 873 }) 874 875 JustBeforeEach(func() { 876 routes, warnings, executeErr = client.GetApplicationRoutes(appGUID) 877 }) 878 879 When("the request succeeds", func() { 880 BeforeEach(func() { 881 body := `{ 882 "resources": [ 883 { 884 "guid": "route-guid", 885 "host": "host", 886 "path": "/path", 887 "url": "host.domain.com/path", 888 "relationships": { 889 "space": { 890 "data": { 891 "guid": "space-guid" 892 } 893 }, 894 "domain": { 895 "data": { 896 "guid": "domain-guid" 897 } 898 } 899 } 900 }, { 901 "guid": "route2-guid", 902 "host": "", 903 "path": "", 904 "url": "domain.com", 905 "relationships": { 906 "space": { 907 "data": { 908 "guid": "space-guid" 909 } 910 }, 911 "domain": { 912 "data": { 913 "guid": "domain2-guid" 914 } 915 } 916 } 917 } 918 ] 919 }` 920 server.AppendHandlers( 921 CombineHandlers( 922 VerifyRequest(http.MethodGet, "/v3/apps/some-app-guid/routes"), 923 RespondWith( 924 http.StatusOK, 925 body, 926 http.Header{"X-Cf-Warnings": {"get-app-routes-warning"}, "Location": {"job-url"}}, 927 ), 928 ), 929 ) 930 }) 931 932 It("returns an array of routes", func() { 933 Expect(executeErr).NotTo(HaveOccurred()) 934 Expect(warnings).To(ConsistOf("get-app-routes-warning")) 935 936 Expect(routes).To(ConsistOf( 937 resources.Route{ 938 GUID: "route-guid", 939 DomainGUID: "domain-guid", 940 SpaceGUID: "space-guid", 941 Host: "host", 942 Path: "/path", 943 URL: "host.domain.com/path", 944 }, 945 resources.Route{ 946 GUID: "route2-guid", 947 DomainGUID: "domain2-guid", 948 SpaceGUID: "space-guid", 949 Host: "", 950 Path: "", 951 URL: "domain.com", 952 }, 953 )) 954 }) 955 }) 956 957 When("there is a cc error", func() { 958 BeforeEach(func() { 959 response := `{ 960 "errors": [ 961 { 962 "code": 10008, 963 "detail": "The request is semantically invalid: command presence", 964 "title": "CF-UnprocessableEntity" 965 }, 966 { 967 "code": 10010, 968 "detail": "Isolation segment not found", 969 "title": "CF-ResourceNotFound" 970 } 971 ] 972 }` 973 server.AppendHandlers( 974 CombineHandlers( 975 VerifyRequest(http.MethodGet, "/v3/apps/some-app-guid/routes"), 976 RespondWith(http.StatusTeapot, response, http.Header{"X-Cf-Warnings": {"get-app-routes-warning"}, "Location": {"job-url"}}), 977 ), 978 ) 979 }) 980 981 It("returns the error", func() { 982 Expect(executeErr).To(MatchError(ccerror.MultiError{ 983 ResponseCode: http.StatusTeapot, 984 Errors: []ccerror.V3Error{ 985 { 986 Code: 10008, 987 Detail: "The request is semantically invalid: command presence", 988 Title: "CF-UnprocessableEntity", 989 }, 990 { 991 Code: 10010, 992 Detail: "Isolation segment not found", 993 Title: "CF-ResourceNotFound", 994 }, 995 }, 996 })) 997 Expect(warnings).To(ConsistOf("get-app-routes-warning")) 998 }) 999 }) 1000 }) 1001 })