github.com/jenspinney/cli@v6.42.1-0.20190207184520-7450c600020e+incompatible/cf/api/routes_test.go (about)

     1  package api_test
     2  
     3  import (
     4  	"net/http"
     5  	"net/http/httptest"
     6  	"net/url"
     7  	"time"
     8  
     9  	"code.cloudfoundry.org/cli/cf/api/apifakes"
    10  	"code.cloudfoundry.org/cli/cf/configuration/coreconfig"
    11  	"code.cloudfoundry.org/cli/cf/errors"
    12  	"code.cloudfoundry.org/cli/cf/models"
    13  	"code.cloudfoundry.org/cli/cf/net"
    14  	"code.cloudfoundry.org/cli/cf/terminal/terminalfakes"
    15  	"code.cloudfoundry.org/cli/cf/trace/tracefakes"
    16  	testconfig "code.cloudfoundry.org/cli/cf/util/testhelpers/configuration"
    17  	testnet "code.cloudfoundry.org/cli/cf/util/testhelpers/net"
    18  
    19  	. "code.cloudfoundry.org/cli/cf/api"
    20  	. "code.cloudfoundry.org/cli/cf/util/testhelpers/matchers"
    21  	. "github.com/onsi/ginkgo"
    22  	. "github.com/onsi/gomega"
    23  	"github.com/onsi/gomega/ghttp"
    24  )
    25  
    26  var _ = Describe("route repository", func() {
    27  	var (
    28  		ts         *httptest.Server
    29  		handler    *testnet.TestHandler
    30  		configRepo coreconfig.Repository
    31  		repo       CloudControllerRouteRepository
    32  	)
    33  
    34  	BeforeEach(func() {
    35  		configRepo = testconfig.NewRepositoryWithDefaults()
    36  		configRepo.SetSpaceFields(models.SpaceFields{
    37  			GUID: "the-space-guid",
    38  			Name: "the-space-name",
    39  		})
    40  		gateway := net.NewCloudControllerGateway(configRepo, time.Now, new(terminalfakes.FakeUI), new(tracefakes.FakePrinter), "")
    41  		repo = NewCloudControllerRouteRepository(configRepo, gateway)
    42  	})
    43  
    44  	AfterEach(func() {
    45  		if ts != nil {
    46  			ts.Close()
    47  		}
    48  	})
    49  
    50  	Describe("List routes", func() {
    51  		It("lists routes in the current space", func() {
    52  			ts, handler = testnet.NewServer([]testnet.TestRequest{
    53  				apifakes.NewCloudControllerTestRequest(testnet.TestRequest{
    54  					Method:   "GET",
    55  					Path:     "/v2/spaces/the-space-guid/routes?inline-relations-depth=1",
    56  					Response: firstPageRoutesResponse,
    57  				}),
    58  				apifakes.NewCloudControllerTestRequest(testnet.TestRequest{
    59  					Method:   "GET",
    60  					Path:     "/v2/spaces/the-space-guid/routes?inline-relations-depth=1&page=2",
    61  					Response: secondPageRoutesResponse,
    62  				}),
    63  			})
    64  			configRepo.SetAPIEndpoint(ts.URL)
    65  
    66  			routes := []models.Route{}
    67  			apiErr := repo.ListRoutes(func(route models.Route) bool {
    68  				routes = append(routes, route)
    69  				return true
    70  			})
    71  
    72  			Expect(len(routes)).To(Equal(2))
    73  			Expect(routes[0].GUID).To(Equal("route-1-guid"))
    74  			Expect(routes[0].Path).To(Equal(""))
    75  			Expect(routes[0].ServiceInstance.GUID).To(Equal("service-guid"))
    76  			Expect(routes[0].ServiceInstance.Name).To(Equal("test-service"))
    77  			Expect(routes[1].GUID).To(Equal("route-2-guid"))
    78  			Expect(routes[1].Path).To(Equal("/path-2"))
    79  			Expect(handler).To(HaveAllRequestsCalled())
    80  			Expect(apiErr).NotTo(HaveOccurred())
    81  		})
    82  
    83  		It("lists routes from all the spaces of current org", func() {
    84  			ts, handler = testnet.NewServer([]testnet.TestRequest{
    85  				apifakes.NewCloudControllerTestRequest(testnet.TestRequest{
    86  					Method:   "GET",
    87  					Path:     "/v2/routes?q=organization_guid:my-org-guid&inline-relations-depth=1",
    88  					Response: firstPageRoutesOrgLvlResponse,
    89  				}),
    90  				apifakes.NewCloudControllerTestRequest(testnet.TestRequest{
    91  					Method:   "GET",
    92  					Path:     "/v2/routes?q=organization_guid:my-org-guid&inline-relations-depth=1&page=2",
    93  					Response: secondPageRoutesResponse,
    94  				}),
    95  			})
    96  			configRepo.SetAPIEndpoint(ts.URL)
    97  
    98  			routes := []models.Route{}
    99  			apiErr := repo.ListAllRoutes(func(route models.Route) bool {
   100  				routes = append(routes, route)
   101  				return true
   102  			})
   103  
   104  			Expect(len(routes)).To(Equal(2))
   105  			Expect(routes[0].GUID).To(Equal("route-1-guid"))
   106  			Expect(routes[0].Space.GUID).To(Equal("space-1-guid"))
   107  			Expect(routes[0].ServiceInstance.GUID).To(Equal("service-guid"))
   108  			Expect(routes[0].ServiceInstance.Name).To(Equal("test-service"))
   109  			Expect(routes[1].GUID).To(Equal("route-2-guid"))
   110  			Expect(routes[1].Space.GUID).To(Equal("space-2-guid"))
   111  
   112  			Expect(handler).To(HaveAllRequestsCalled())
   113  			Expect(apiErr).NotTo(HaveOccurred())
   114  		})
   115  	})
   116  
   117  	Describe("Find", func() {
   118  		var ccServer *ghttp.Server
   119  		BeforeEach(func() {
   120  			ccServer = ghttp.NewServer()
   121  			configRepo.SetAPIEndpoint(ccServer.URL())
   122  		})
   123  
   124  		AfterEach(func() {
   125  			ccServer.Close()
   126  		})
   127  
   128  		Context("when the port is not specified", func() {
   129  			BeforeEach(func() {
   130  				v := url.Values{}
   131  				v.Set("inline-relations-depth", "1")
   132  				v.Set("q", "host:my-cool-app;domain_guid:my-domain-guid;path:/somepath")
   133  
   134  				ccServer.AppendHandlers(
   135  					ghttp.CombineHandlers(
   136  						ghttp.VerifyRequest("GET", "/v2/routes", v.Encode()),
   137  						ghttp.VerifyHeader(http.Header{
   138  							"accept": []string{"application/json"},
   139  						}),
   140  						ghttp.RespondWith(http.StatusCreated, findResponseBodyForHostAndDomainAndPath),
   141  					),
   142  				)
   143  			})
   144  
   145  			It("returns the route", func() {
   146  				domain := models.DomainFields{}
   147  				domain.GUID = "my-domain-guid"
   148  
   149  				route, apiErr := repo.Find("my-cool-app", domain, "somepath", 0)
   150  
   151  				Expect(apiErr).NotTo(HaveOccurred())
   152  				Expect(route.Host).To(Equal("my-cool-app"))
   153  				Expect(route.GUID).To(Equal("my-route-guid"))
   154  				Expect(route.Path).To(Equal("/somepath"))
   155  				Expect(route.Port).To(Equal(0))
   156  				Expect(route.Domain.GUID).To(Equal(domain.GUID))
   157  			})
   158  		})
   159  
   160  		Context("when the path is empty", func() {
   161  			BeforeEach(func() {
   162  				v := url.Values{}
   163  				v.Set("inline-relations-depth", "1")
   164  				v.Set("q", "host:my-cool-app;domain_guid:my-domain-guid")
   165  
   166  				ccServer.AppendHandlers(
   167  					ghttp.CombineHandlers(
   168  						ghttp.VerifyRequest("GET", "/v2/routes", v.Encode()),
   169  						ghttp.VerifyHeader(http.Header{
   170  							"accept": []string{"application/json"},
   171  						}),
   172  						ghttp.RespondWith(http.StatusCreated, findResponseBodyForHostAndDomain),
   173  					),
   174  				)
   175  			})
   176  
   177  			It("returns the route", func() {
   178  				domain := models.DomainFields{}
   179  				domain.GUID = "my-domain-guid"
   180  
   181  				route, apiErr := repo.Find("my-cool-app", domain, "", 0)
   182  
   183  				Expect(apiErr).NotTo(HaveOccurred())
   184  				Expect(route.Host).To(Equal("my-cool-app"))
   185  				Expect(route.GUID).To(Equal("my-route-guid"))
   186  				Expect(route.Path).To(Equal(""))
   187  				Expect(route.Domain.GUID).To(Equal(domain.GUID))
   188  			})
   189  		})
   190  
   191  		Context("when the route is found", func() {
   192  			BeforeEach(func() {
   193  				v := url.Values{}
   194  				v.Set("inline-relations-depth", "1")
   195  				v.Set("q", "host:my-cool-app;domain_guid:my-domain-guid;path:/somepath;port:8148")
   196  
   197  				ccServer.AppendHandlers(
   198  					ghttp.CombineHandlers(
   199  						ghttp.VerifyRequest("GET", "/v2/routes", v.Encode()),
   200  						ghttp.VerifyHeader(http.Header{
   201  							"accept": []string{"application/json"},
   202  						}),
   203  						ghttp.RespondWith(http.StatusCreated, findResponseBody),
   204  					),
   205  				)
   206  			})
   207  
   208  			It("returns the route", func() {
   209  				domain := models.DomainFields{}
   210  				domain.GUID = "my-domain-guid"
   211  
   212  				route, apiErr := repo.Find("my-cool-app", domain, "somepath", 8148)
   213  
   214  				Expect(apiErr).NotTo(HaveOccurred())
   215  				Expect(route.Host).To(Equal("my-cool-app"))
   216  				Expect(route.GUID).To(Equal("my-route-guid"))
   217  				Expect(route.Path).To(Equal("/somepath"))
   218  				Expect(route.Port).To(Equal(8148))
   219  				Expect(route.Domain.GUID).To(Equal(domain.GUID))
   220  			})
   221  		})
   222  
   223  		Context("when the route is not found", func() {
   224  			BeforeEach(func() {
   225  				v := url.Values{}
   226  				v.Set("inline-relations-depth", "1")
   227  				v.Set("q", "host:my-cool-app;domain_guid:my-domain-guid;path:/somepath;port:1478")
   228  
   229  				ccServer.AppendHandlers(
   230  					ghttp.CombineHandlers(
   231  						ghttp.VerifyRequest("GET", "/v2/routes", v.Encode()),
   232  						ghttp.VerifyHeader(http.Header{
   233  							"accept": []string{"application/json"},
   234  						}),
   235  						ghttp.RespondWith(http.StatusOK, `{ "resources": [] }`),
   236  					),
   237  				)
   238  			})
   239  
   240  			It("returns 'not found'", func() {
   241  				ts, handler = testnet.NewServer([]testnet.TestRequest{
   242  					apifakes.NewCloudControllerTestRequest(testnet.TestRequest{
   243  						Method:   "GET",
   244  						Path:     "/v2/routes?q=host%3Amy-cool-app%3Bdomain_guid%3Amy-domain-guid",
   245  						Response: testnet.TestResponse{Status: http.StatusOK, Body: `{ "resources": [ ] }`},
   246  					}),
   247  				})
   248  				configRepo.SetAPIEndpoint(ts.URL)
   249  
   250  				domain := models.DomainFields{}
   251  				domain.GUID = "my-domain-guid"
   252  
   253  				_, apiErr := repo.Find("my-cool-app", domain, "somepath", 1478)
   254  
   255  				Expect(handler).To(HaveAllRequestsCalled())
   256  
   257  				Expect(apiErr.(*errors.ModelNotFoundError)).NotTo(BeNil())
   258  			})
   259  		})
   260  	})
   261  
   262  	Describe("CreateInSpace", func() {
   263  		var ccServer *ghttp.Server
   264  		BeforeEach(func() {
   265  			ccServer = ghttp.NewServer()
   266  			configRepo.SetAPIEndpoint(ccServer.URL())
   267  		})
   268  
   269  		AfterEach(func() {
   270  			if ccServer != nil {
   271  				ccServer.Close()
   272  			}
   273  		})
   274  
   275  		Context("when no host, path, or port are given", func() {
   276  			BeforeEach(func() {
   277  				ccServer.AppendHandlers(
   278  					ghttp.CombineHandlers(
   279  						ghttp.VerifyRequest("POST", "/v2/routes", "inline-relations-depth=1&async=true"),
   280  						ghttp.VerifyJSON(`
   281  							{
   282  								"domain_guid":"my-domain-guid",
   283  								"space_guid":"my-space-guid"
   284  							}
   285  						`),
   286  						ghttp.VerifyHeader(http.Header{
   287  							"accept": []string{"application/json"},
   288  						}),
   289  					),
   290  				)
   291  			})
   292  
   293  			It("tries to create a route", func() {
   294  				repo.CreateInSpace("", "", "my-domain-guid", "my-space-guid", 0, false)
   295  				Expect(ccServer.ReceivedRequests()).To(HaveLen(1))
   296  			})
   297  
   298  			Context("when creating the route succeeds", func() {
   299  				BeforeEach(func() {
   300  					h := ccServer.GetHandler(0)
   301  					ccServer.SetHandler(0, ghttp.CombineHandlers(
   302  						h,
   303  						ghttp.RespondWith(http.StatusCreated, `
   304  								{
   305  									"metadata": { "guid": "my-route-guid" },
   306  									"entity": { "host": "my-cool-app" }
   307  								}
   308  							`),
   309  					))
   310  				})
   311  
   312  				It("returns the created route", func() {
   313  					createdRoute, err := repo.CreateInSpace("", "", "my-domain-guid", "my-space-guid", 0, false)
   314  					Expect(err).NotTo(HaveOccurred())
   315  					Expect(createdRoute.GUID).To(Equal("my-route-guid"))
   316  				})
   317  			})
   318  		})
   319  
   320  		Context("when a host is given", func() {
   321  			BeforeEach(func() {
   322  				ccServer.AppendHandlers(
   323  					ghttp.CombineHandlers(
   324  						ghttp.VerifyRequest("POST", "/v2/routes", "inline-relations-depth=1&async=true"),
   325  						ghttp.VerifyJSON(`
   326  							{
   327  								"host":"the-host",
   328  								"domain_guid":"my-domain-guid",
   329  								"space_guid":"my-space-guid"
   330  							}
   331  						`),
   332  						ghttp.VerifyHeader(http.Header{
   333  							"accept": []string{"application/json"},
   334  						}),
   335  					),
   336  				)
   337  			})
   338  
   339  			It("tries to create a route", func() {
   340  				repo.CreateInSpace("the-host", "", "my-domain-guid", "my-space-guid", 0, false)
   341  				Expect(ccServer.ReceivedRequests()).To(HaveLen(1))
   342  			})
   343  
   344  			Context("when creating the route succeeds", func() {
   345  				BeforeEach(func() {
   346  					h := ccServer.GetHandler(0)
   347  					ccServer.SetHandler(0, ghttp.CombineHandlers(
   348  						h,
   349  						ghttp.RespondWith(http.StatusCreated, `
   350  								{
   351  									"metadata": { "guid": "my-route-guid" },
   352  									"entity": { "host": "the-host" }
   353  								}
   354  							`),
   355  					))
   356  				})
   357  
   358  				It("returns the created route", func() {
   359  					createdRoute, err := repo.CreateInSpace("the-host", "", "my-domain-guid", "my-space-guid", 0, false)
   360  					Expect(err).NotTo(HaveOccurred())
   361  					Expect(createdRoute.Host).To(Equal("the-host"))
   362  				})
   363  			})
   364  		})
   365  
   366  		Context("when a path is given", func() {
   367  			BeforeEach(func() {
   368  				ccServer.AppendHandlers(
   369  					ghttp.CombineHandlers(
   370  						ghttp.VerifyRequest("POST", "/v2/routes", "inline-relations-depth=1&async=true"),
   371  						ghttp.VerifyJSON(`
   372  							{
   373  								"domain_guid":"my-domain-guid",
   374  								"space_guid":"my-space-guid",
   375  								"path":"/the-path"
   376  							}
   377  						`),
   378  						ghttp.VerifyHeader(http.Header{
   379  							"accept": []string{"application/json"},
   380  						}),
   381  					),
   382  				)
   383  			})
   384  
   385  			It("tries to create a route", func() {
   386  				repo.CreateInSpace("", "the-path", "my-domain-guid", "my-space-guid", 0, false)
   387  				Expect(ccServer.ReceivedRequests()).To(HaveLen(1))
   388  			})
   389  
   390  			Context("when creating the route succeeds", func() {
   391  				BeforeEach(func() {
   392  					h := ccServer.GetHandler(0)
   393  					ccServer.SetHandler(0, ghttp.CombineHandlers(
   394  						h,
   395  						ghttp.RespondWith(http.StatusCreated, `
   396  								{
   397  									"metadata": { "guid": "my-route-guid" },
   398  									"entity": { "path": "the-path" }
   399  								}
   400  							`),
   401  					))
   402  				})
   403  
   404  				It("returns the created route", func() {
   405  					createdRoute, err := repo.CreateInSpace("", "the-path", "my-domain-guid", "my-space-guid", 0, false)
   406  					Expect(err).NotTo(HaveOccurred())
   407  					Expect(createdRoute.Path).To(Equal("the-path"))
   408  				})
   409  			})
   410  
   411  			Context("when creating the route fails", func() {
   412  				BeforeEach(func() {
   413  					ccServer.Close()
   414  					ccServer = nil
   415  				})
   416  
   417  				It("returns an error", func() {
   418  					_, err := repo.CreateInSpace("", "the-path", "my-domain-guid", "my-space-guid", 0, false)
   419  					Expect(err).To(HaveOccurred())
   420  				})
   421  			})
   422  		})
   423  
   424  		Context("when a port is given", func() {
   425  			BeforeEach(func() {
   426  				ccServer.AppendHandlers(
   427  					ghttp.CombineHandlers(
   428  						ghttp.VerifyRequest("POST", "/v2/routes", "inline-relations-depth=1&async=true"),
   429  						ghttp.VerifyJSON(`
   430  							{
   431  								"port":9090,
   432  								"domain_guid":"my-domain-guid",
   433  								"space_guid":"my-space-guid"
   434  							}
   435  						`),
   436  						ghttp.VerifyHeader(http.Header{
   437  							"accept": []string{"application/json"},
   438  						}),
   439  					),
   440  				)
   441  			})
   442  
   443  			It("tries to create a route", func() {
   444  				repo.CreateInSpace("", "", "my-domain-guid", "my-space-guid", 9090, false)
   445  				Expect(ccServer.ReceivedRequests()).To(HaveLen(1))
   446  			})
   447  
   448  			Context("when creating the route succeeds", func() {
   449  				BeforeEach(func() {
   450  					h := ccServer.GetHandler(0)
   451  					ccServer.SetHandler(0, ghttp.CombineHandlers(
   452  						h,
   453  						ghttp.RespondWith(http.StatusCreated, `
   454  							{
   455  								"metadata": { "guid": "my-route-guid" },
   456  								"entity": { "port": 9090 }
   457  							}
   458  						`),
   459  					))
   460  				})
   461  
   462  				It("returns the created route", func() {
   463  					createdRoute, err := repo.CreateInSpace("", "", "my-domain-guid", "my-space-guid", 9090, false)
   464  					Expect(err).NotTo(HaveOccurred())
   465  					Expect(createdRoute.Port).To(Equal(9090))
   466  				})
   467  			})
   468  		})
   469  
   470  		Context("when random-port is true", func() {
   471  			BeforeEach(func() {
   472  				ccServer.AppendHandlers(
   473  					ghttp.CombineHandlers(
   474  						ghttp.VerifyRequest("POST", "/v2/routes", "inline-relations-depth=1&async=true&generate_port=true"),
   475  						ghttp.VerifyJSON(`
   476  							{
   477  								"domain_guid":"my-domain-guid",
   478  								"space_guid":"my-space-guid"
   479  							}
   480  						`),
   481  						ghttp.VerifyHeader(http.Header{
   482  							"accept": []string{"application/json"},
   483  						}),
   484  					),
   485  				)
   486  			})
   487  
   488  			It("tries to create a route", func() {
   489  				repo.CreateInSpace("", "", "my-domain-guid", "my-space-guid", 0, true)
   490  				Expect(ccServer.ReceivedRequests()).To(HaveLen(1))
   491  			})
   492  
   493  			Context("when creating the route succeeds", func() {
   494  				BeforeEach(func() {
   495  					h := ccServer.GetHandler(0)
   496  					ccServer.SetHandler(0, ghttp.CombineHandlers(
   497  						h,
   498  						ghttp.RespondWith(http.StatusCreated, `
   499  							{
   500  								"metadata": { "guid": "my-route-guid" },
   501  								"entity": { "port": 50321 }
   502  							}
   503  						`),
   504  					))
   505  				})
   506  
   507  				It("returns the created route", func() {
   508  					createdRoute, err := repo.CreateInSpace("", "", "my-domain-guid", "my-space-guid", 0, true)
   509  					Expect(err).NotTo(HaveOccurred())
   510  					Expect(createdRoute.Port).To(Equal(50321))
   511  				})
   512  			})
   513  		})
   514  	})
   515  
   516  	Describe("Check routes", func() {
   517  		var (
   518  			ccServer *ghttp.Server
   519  			domain   models.DomainFields
   520  		)
   521  
   522  		BeforeEach(func() {
   523  			domain = models.DomainFields{
   524  				GUID: "domain-guid",
   525  			}
   526  			ccServer = ghttp.NewServer()
   527  			configRepo.SetAPIEndpoint(ccServer.URL())
   528  		})
   529  
   530  		AfterEach(func() {
   531  			ccServer.Close()
   532  		})
   533  
   534  		Context("when the route is found", func() {
   535  			BeforeEach(func() {
   536  				ccServer.AppendHandlers(
   537  					ghttp.CombineHandlers(
   538  						ghttp.VerifyRequest("GET", "/v2/routes/reserved/domain/domain-guid/host/my-host", "path=/some-path"),
   539  						ghttp.VerifyHeader(http.Header{
   540  							"accept": []string{"application/json"},
   541  						}),
   542  						ghttp.RespondWith(http.StatusNoContent, nil),
   543  					),
   544  				)
   545  			})
   546  
   547  			It("returns true", func() {
   548  				found, err := repo.CheckIfExists("my-host", domain, "some-path")
   549  				Expect(err).NotTo(HaveOccurred())
   550  				Expect(found).To(BeTrue())
   551  			})
   552  		})
   553  
   554  		Context("when the route is not found", func() {
   555  			BeforeEach(func() {
   556  				ccServer.AppendHandlers(
   557  					ghttp.CombineHandlers(
   558  						ghttp.VerifyRequest("GET", "/v2/routes/reserved/domain/domain-guid/host/my-host", "path=/some-path"),
   559  						ghttp.VerifyHeader(http.Header{
   560  							"accept": []string{"application/json"},
   561  						}),
   562  						ghttp.RespondWith(http.StatusNotFound, nil),
   563  					),
   564  				)
   565  			})
   566  
   567  			It("returns false", func() {
   568  				found, err := repo.CheckIfExists("my-host", domain, "some-path")
   569  				Expect(err).NotTo(HaveOccurred())
   570  				Expect(found).To(BeFalse())
   571  			})
   572  		})
   573  
   574  		Context("when finding the route fails", func() {
   575  			BeforeEach(func() {
   576  				ccServer.AppendHandlers(
   577  					ghttp.CombineHandlers(
   578  						ghttp.VerifyRequest("GET", "/v2/routes/reserved/domain/domain-guid/host/my-host", "path=/some-path"),
   579  						ghttp.VerifyHeader(http.Header{
   580  							"accept": []string{"application/json"},
   581  						}),
   582  						ghttp.RespondWith(http.StatusForbidden, nil),
   583  					),
   584  				)
   585  			})
   586  
   587  			It("returns an error", func() {
   588  				_, err := repo.CheckIfExists("my-host", domain, "some-path")
   589  				Expect(err).To(HaveOccurred())
   590  			})
   591  		})
   592  
   593  		Context("when the path is empty", func() {
   594  			BeforeEach(func() {
   595  				ccServer.AppendHandlers(
   596  					ghttp.CombineHandlers(
   597  						ghttp.RespondWith(http.StatusNoContent, nil),
   598  					),
   599  				)
   600  			})
   601  
   602  			It("should not add a path query param", func() {
   603  				_, err := repo.CheckIfExists("my-host", domain, "")
   604  				Expect(err).NotTo(HaveOccurred())
   605  				Expect(len(ccServer.ReceivedRequests())).To(Equal(1))
   606  				req := ccServer.ReceivedRequests()[0]
   607  				vals := req.URL.Query()
   608  				_, ok := vals["path"]
   609  				Expect(ok).To(BeFalse())
   610  			})
   611  		})
   612  	})
   613  
   614  	Describe("Bind routes", func() {
   615  		It("binds routes", func() {
   616  			ts, handler = testnet.NewServer([]testnet.TestRequest{
   617  				apifakes.NewCloudControllerTestRequest(testnet.TestRequest{
   618  					Method:   "PUT",
   619  					Path:     "/v2/apps/my-cool-app-guid/routes/my-cool-route-guid",
   620  					Response: testnet.TestResponse{Status: http.StatusCreated, Body: ""},
   621  				}),
   622  			})
   623  			configRepo.SetAPIEndpoint(ts.URL)
   624  
   625  			apiErr := repo.Bind("my-cool-route-guid", "my-cool-app-guid")
   626  			Expect(handler).To(HaveAllRequestsCalled())
   627  			Expect(apiErr).NotTo(HaveOccurred())
   628  		})
   629  
   630  		It("unbinds routes", func() {
   631  			ts, handler = testnet.NewServer([]testnet.TestRequest{
   632  				apifakes.NewCloudControllerTestRequest(testnet.TestRequest{
   633  					Method:   "DELETE",
   634  					Path:     "/v2/apps/my-cool-app-guid/routes/my-cool-route-guid",
   635  					Response: testnet.TestResponse{Status: http.StatusCreated, Body: ""},
   636  				}),
   637  			})
   638  			configRepo.SetAPIEndpoint(ts.URL)
   639  
   640  			apiErr := repo.Unbind("my-cool-route-guid", "my-cool-app-guid")
   641  			Expect(handler).To(HaveAllRequestsCalled())
   642  			Expect(apiErr).NotTo(HaveOccurred())
   643  		})
   644  
   645  	})
   646  
   647  	Describe("Delete routes", func() {
   648  		It("deletes routes", func() {
   649  			ts, handler = testnet.NewServer([]testnet.TestRequest{
   650  				apifakes.NewCloudControllerTestRequest(testnet.TestRequest{
   651  					Method:   "DELETE",
   652  					Path:     "/v2/routes/my-cool-route-guid",
   653  					Response: testnet.TestResponse{Status: http.StatusCreated, Body: ""},
   654  				}),
   655  			})
   656  			configRepo.SetAPIEndpoint(ts.URL)
   657  
   658  			apiErr := repo.Delete("my-cool-route-guid")
   659  			Expect(handler).To(HaveAllRequestsCalled())
   660  			Expect(apiErr).NotTo(HaveOccurred())
   661  		})
   662  	})
   663  
   664  })
   665  
   666  var firstPageRoutesResponse = testnet.TestResponse{Status: http.StatusOK, Body: `
   667  {
   668    "next_url": "/v2/spaces/the-space-guid/routes?inline-relations-depth=1&page=2",
   669    "resources": [
   670      {
   671        "metadata": {
   672          "guid": "route-1-guid"
   673        },
   674        "entity": {
   675          "host": "route-1-host",
   676          "path": "",
   677          "domain": {
   678            "metadata": {
   679              "guid": "domain-1-guid"
   680            },
   681            "entity": {
   682              "name": "cfapps.io"
   683            }
   684          },
   685          "space": {
   686            "metadata": {
   687              "guid": "space-1-guid"
   688            },
   689            "entity": {
   690              "name": "space-1"
   691            }
   692          },
   693          "apps": [
   694         	  {
   695         	    "metadata": {
   696                "guid": "app-1-guid"
   697              },
   698              "entity": {
   699                "name": "app-1"
   700         	    }
   701         	  }
   702          ],
   703           "service_instance_url": "/v2/service_instances/service-guid",
   704          "service_instance": {
   705             "metadata": {
   706                "guid": "service-guid",
   707                "url": "/v2/service_instances/service-guid"
   708             },
   709             "entity": {
   710                "name": "test-service",
   711                "credentials": {
   712                   "username": "user",
   713                   "password": "password"
   714                },
   715                "type": "managed_service_instance",
   716                "route_service_url": "https://something.awesome.com",
   717                "space_url": "/v2/spaces/space-1-guid"
   718             }
   719          }
   720        }
   721      }
   722    ]
   723  }`}
   724  
   725  var secondPageRoutesResponse = testnet.TestResponse{Status: http.StatusOK, Body: `
   726  {
   727    "resources": [
   728      {
   729        "metadata": {
   730          "guid": "route-2-guid"
   731        },
   732        "entity": {
   733          "host": "route-2-host",
   734          "path": "/path-2",
   735          "domain": {
   736            "metadata": {
   737              "guid": "domain-2-guid"
   738            },
   739            "entity": {
   740              "name": "example.com"
   741            }
   742          },
   743          "space": {
   744            "metadata": {
   745              "guid": "space-2-guid"
   746            },
   747            "entity": {
   748              "name": "space-2"
   749            }
   750          },
   751          "apps": [
   752         	  {
   753         	    "metadata": {
   754                "guid": "app-2-guid"
   755              },
   756              "entity": {
   757                "name": "app-2"
   758         	    }
   759         	  },
   760         	  {
   761         	    "metadata": {
   762                "guid": "app-3-guid"
   763              },
   764              "entity": {
   765                "name": "app-3"
   766         	    }
   767         	  }
   768          ]
   769        }
   770      }
   771    ]
   772  }`}
   773  
   774  var findResponseBody = `
   775  { "resources": [
   776  	{
   777  		"metadata": {
   778  			"guid": "my-route-guid"
   779  		},
   780  		"entity": {
   781  			"host": "my-cool-app",
   782  			"domain": {
   783  				"metadata": {
   784  					"guid": "my-domain-guid"
   785  				}
   786  			},
   787  			"port": 8148,
   788  			"path": "/somepath"
   789  		}
   790  	}
   791  ]}`
   792  
   793  var findResponseBodyForHostAndDomain = `
   794  { "resources": [
   795  	{
   796  		"metadata": {
   797  			"guid": "my-second-route-guid"
   798  		},
   799  		"entity": {
   800  			"host": "my-cool-app",
   801  			"domain": {
   802  				"metadata": {
   803  					"guid": "my-domain-guid"
   804  				}
   805  			},
   806  			"path": "/somepath"
   807  		}
   808  	},
   809  	{
   810  		"metadata": {
   811  			"guid": "my-route-guid"
   812  		},
   813  		"entity": {
   814  			"host": "my-cool-app",
   815  			"domain": {
   816  				"metadata": {
   817  					"guid": "my-domain-guid"
   818  				}
   819  			}
   820  		}
   821  	}
   822  ]}`
   823  
   824  var findResponseBodyForHostAndDomainAndPath = `
   825  { "resources": [
   826  	{
   827  		"metadata": {
   828  			"guid": "my-second-route-guid"
   829  		},
   830  		"entity": {
   831  			"host": "my-cool-app",
   832  			"domain": {
   833  				"metadata": {
   834  					"guid": "my-domain-guid"
   835  				}
   836  			},
   837  			"port": 8148,
   838  			"path": "/somepath"
   839  		}
   840  	},
   841  	{
   842  		"metadata": {
   843  			"guid": "my-route-guid"
   844  		},
   845  		"entity": {
   846  			"host": "my-cool-app",
   847  			"domain": {
   848  				"metadata": {
   849  					"guid": "my-domain-guid"
   850  				}
   851  			},
   852  			"path": "/somepath"
   853  		}
   854  	}
   855  ]}`
   856  
   857  var firstPageRoutesOrgLvlResponse = testnet.TestResponse{Status: http.StatusOK, Body: `
   858  {
   859    "next_url": "/v2/routes?q=organization_guid:my-org-guid&inline-relations-depth=1&page=2",
   860    "resources": [
   861      {
   862        "metadata": {
   863          "guid": "route-1-guid"
   864        },
   865        "entity": {
   866          "host": "route-1-host",
   867          "domain": {
   868            "metadata": {
   869              "guid": "domain-1-guid"
   870            },
   871            "entity": {
   872              "name": "cfapps.io"
   873            }
   874          },
   875          "space": {
   876            "metadata": {
   877              "guid": "space-1-guid"
   878            },
   879            "entity": {
   880              "name": "space-1"
   881            }
   882          },
   883          "apps": [
   884            {
   885              "metadata": {
   886                "guid": "app-1-guid"
   887              },
   888              "entity": {
   889                "name": "app-1"
   890              }
   891            }
   892          ],
   893          "service_instance_url": "/v2/service_instances/service-guid",
   894          "service_instance": {
   895             "metadata": {
   896                "guid": "service-guid",
   897                "url": "/v2/service_instances/service-guid"
   898             },
   899             "entity": {
   900                "name": "test-service",
   901                "credentials": {
   902                   "username": "user",
   903                   "password": "password"
   904                },
   905                "type": "managed_service_instance",
   906                "route_service_url": "https://something.awesome.com",
   907                "space_url": "/v2/spaces/space-1-guid"
   908             }
   909          }
   910        }
   911      }
   912    ]
   913  }`}