github.com/loggregator/cli@v6.33.1-0.20180224010324-82334f081791+incompatible/cf/api/organizations/organizations_test.go (about) 1 package organizations_test 2 3 import ( 4 "net/http" 5 "net/http/httptest" 6 "time" 7 8 "code.cloudfoundry.org/cli/cf/api/apifakes" 9 "code.cloudfoundry.org/cli/cf/errors" 10 "code.cloudfoundry.org/cli/cf/models" 11 "code.cloudfoundry.org/cli/cf/net" 12 "code.cloudfoundry.org/cli/cf/terminal/terminalfakes" 13 testconfig "code.cloudfoundry.org/cli/util/testhelpers/configuration" 14 testnet "code.cloudfoundry.org/cli/util/testhelpers/net" 15 16 . "code.cloudfoundry.org/cli/cf/api/organizations" 17 "code.cloudfoundry.org/cli/cf/trace/tracefakes" 18 . "code.cloudfoundry.org/cli/util/testhelpers/matchers" 19 . "github.com/onsi/ginkgo" 20 . "github.com/onsi/gomega" 21 "github.com/onsi/gomega/ghttp" 22 ) 23 24 var _ = Describe("Organization Repository", func() { 25 Describe("ListOrgs", func() { 26 var ( 27 ccServer *ghttp.Server 28 repo CloudControllerOrganizationRepository 29 ) 30 31 Context("when there are orgs", func() { 32 BeforeEach(func() { 33 ccServer = ghttp.NewServer() 34 configRepo := testconfig.NewRepositoryWithDefaults() 35 configRepo.SetAPIEndpoint(ccServer.URL()) 36 gateway := net.NewCloudControllerGateway(configRepo, time.Now, new(terminalfakes.FakeUI), new(tracefakes.FakePrinter), "") 37 repo = NewCloudControllerOrganizationRepository(configRepo, gateway) 38 ccServer.AppendHandlers( 39 ghttp.CombineHandlers( 40 ghttp.VerifyRequest("GET", "/v2/organizations", "order-by=name"), 41 ghttp.VerifyHeader(http.Header{ 42 "accept": []string{"application/json"}, 43 }), 44 ghttp.RespondWith(http.StatusOK, `{ 45 "total_results": 3, 46 "total_pages": 2, 47 "prev_url": null, 48 "next_url": "/v2/organizations?order-by=name&page=2", 49 "resources": [ 50 { 51 "metadata": { "guid": "org3-guid" }, 52 "entity": { "name": "Alpha" } 53 }, 54 { 55 "metadata": { "guid": "org2-guid" }, 56 "entity": { "name": "Beta" } 57 } 58 ] 59 }`), 60 ), 61 ) 62 63 ccServer.AppendHandlers( 64 ghttp.CombineHandlers( 65 ghttp.VerifyRequest("GET", "/v2/organizations", "order-by=name&page=2"), 66 ghttp.VerifyHeader(http.Header{ 67 "accept": []string{"application/json"}, 68 }), 69 ghttp.RespondWith(http.StatusOK, `{ 70 "total_results": 3, 71 "total_pages": 2, 72 "prev_url": null, 73 "next_url": null, 74 "resources": [ 75 { 76 "metadata": { "guid": "org1-guid" }, 77 "entity": { "name": "Gamma" } 78 } 79 ] 80 }`), 81 ), 82 ) 83 }) 84 85 AfterEach(func() { 86 ccServer.Close() 87 }) 88 89 Context("when given a non-zero positive limit", func() { 90 It("should return no more than the limit number of organizations", func() { 91 orgs, err := repo.ListOrgs(2) 92 Expect(err).NotTo(HaveOccurred()) 93 Expect(len(orgs)).To(Equal(2)) 94 }) 95 96 It("should not make more requests than necessary to retrieve the requested number of orgs", func() { 97 _, err := repo.ListOrgs(2) 98 Expect(err).NotTo(HaveOccurred()) 99 Expect(ccServer.ReceivedRequests()).Should(HaveLen(1)) 100 }) 101 }) 102 103 Context("when given a zero limit", func() { 104 It("should return all organizations", func() { 105 orgs, err := repo.ListOrgs(0) 106 Expect(err).NotTo(HaveOccurred()) 107 Expect(len(orgs)).To(Equal(3)) 108 }) 109 110 It("lists the orgs from the the /v2/orgs endpoint in alphabetical order", func() { 111 orgs, apiErr := repo.ListOrgs(0) 112 113 Expect(len(orgs)).To(Equal(3)) 114 Expect(orgs[0].GUID).To(Equal("org3-guid")) 115 Expect(orgs[1].GUID).To(Equal("org2-guid")) 116 Expect(orgs[2].GUID).To(Equal("org1-guid")) 117 118 Expect(orgs[0].Name).To(Equal("Alpha")) 119 Expect(orgs[1].Name).To(Equal("Beta")) 120 Expect(orgs[2].Name).To(Equal("Gamma")) 121 Expect(apiErr).NotTo(HaveOccurred()) 122 }) 123 }) 124 }) 125 126 Context("when there are no orgs", func() { 127 BeforeEach(func() { 128 ccServer = ghttp.NewServer() 129 configRepo := testconfig.NewRepositoryWithDefaults() 130 configRepo.SetAPIEndpoint(ccServer.URL()) 131 gateway := net.NewCloudControllerGateway(configRepo, time.Now, new(terminalfakes.FakeUI), new(tracefakes.FakePrinter), "") 132 repo = NewCloudControllerOrganizationRepository(configRepo, gateway) 133 ccServer.AppendHandlers( 134 ghttp.CombineHandlers( 135 ghttp.VerifyRequest("GET", "/v2/organizations"), 136 ghttp.VerifyHeader(http.Header{ 137 "accept": []string{"application/json"}, 138 }), 139 ghttp.RespondWith(http.StatusOK, `{"resources": []}`), 140 ), 141 ) 142 }) 143 144 AfterEach(func() { 145 ccServer.Close() 146 }) 147 148 It("does not call the provided function", func() { 149 _, apiErr := repo.ListOrgs(0) 150 151 Expect(apiErr).NotTo(HaveOccurred()) 152 }) 153 }) 154 }) 155 156 Describe(".GetManyOrgsByGUID", func() { 157 It("requests each org", func() { 158 firstOrgRequest := apifakes.NewCloudControllerTestRequest(testnet.TestRequest{ 159 Method: "GET", 160 Path: "/v2/organizations/org1-guid", 161 Response: testnet.TestResponse{Status: http.StatusOK, Body: `{ 162 "metadata": { "guid": "org1-guid" }, 163 "entity": { "name": "Org1" } 164 }`}, 165 }) 166 secondOrgRequest := apifakes.NewCloudControllerTestRequest(testnet.TestRequest{ 167 Method: "GET", 168 Path: "/v2/organizations/org2-guid", 169 Response: testnet.TestResponse{Status: http.StatusOK, Body: `{ 170 "metadata": { "guid": "org2-guid" }, 171 "entity": { "name": "Org2" } 172 }`}, 173 }) 174 testserver, handler, repo := createOrganizationRepo(firstOrgRequest, secondOrgRequest) 175 defer testserver.Close() 176 177 orgGUIDs := []string{"org1-guid", "org2-guid"} 178 orgs, err := repo.GetManyOrgsByGUID(orgGUIDs) 179 Expect(err).NotTo(HaveOccurred()) 180 181 Expect(handler).To(HaveAllRequestsCalled()) 182 Expect(len(orgs)).To(Equal(2)) 183 Expect(orgs[0].GUID).To(Equal("org1-guid")) 184 Expect(orgs[1].GUID).To(Equal("org2-guid")) 185 }) 186 }) 187 188 Describe("finding organizations by name", func() { 189 It("returns the org with that name", func() { 190 req := apifakes.NewCloudControllerTestRequest(testnet.TestRequest{ 191 Method: "GET", 192 Path: "/v2/organizations?q=name%3Aorg1&inline-relations-depth=1", 193 Response: testnet.TestResponse{Status: http.StatusOK, Body: `{"resources": [{ 194 "metadata": { "guid": "org1-guid" }, 195 "entity": { 196 "name": "Org1", 197 "quota_definition": { 198 "entity": { 199 "name": "not-your-average-quota", 200 "memory_limit": 128 201 } 202 }, 203 "spaces": [{ 204 "metadata": { "guid": "space1-guid" }, 205 "entity": { "name": "Space1" } 206 }], 207 "domains": [{ 208 "metadata": { "guid": "domain1-guid" }, 209 "entity": { "name": "cfapps.io" } 210 }], 211 "space_quota_definitions":[{ 212 "metadata": {"guid": "space-quota1-guid"}, 213 "entity": {"name": "space-quota1"} 214 }] 215 } 216 }]}`}, 217 }) 218 219 testserver, handler, repo := createOrganizationRepo(req) 220 defer testserver.Close() 221 existingOrg := models.Organization{} 222 existingOrg.GUID = "org1-guid" 223 existingOrg.Name = "Org1" 224 225 org, apiErr := repo.FindByName("Org1") 226 Expect(handler).To(HaveAllRequestsCalled()) 227 Expect(apiErr).NotTo(HaveOccurred()) 228 229 Expect(org.Name).To(Equal(existingOrg.Name)) 230 Expect(org.GUID).To(Equal(existingOrg.GUID)) 231 Expect(org.QuotaDefinition.Name).To(Equal("not-your-average-quota")) 232 Expect(org.QuotaDefinition.MemoryLimit).To(Equal(int64(128))) 233 Expect(len(org.Spaces)).To(Equal(1)) 234 Expect(org.Spaces[0].Name).To(Equal("Space1")) 235 Expect(org.Spaces[0].GUID).To(Equal("space1-guid")) 236 Expect(len(org.Domains)).To(Equal(1)) 237 Expect(org.Domains[0].Name).To(Equal("cfapps.io")) 238 Expect(org.Domains[0].GUID).To(Equal("domain1-guid")) 239 Expect(len(org.SpaceQuotas)).To(Equal(1)) 240 Expect(org.SpaceQuotas[0].Name).To(Equal("space-quota1")) 241 Expect(org.SpaceQuotas[0].GUID).To(Equal("space-quota1-guid")) 242 }) 243 244 It("returns a ModelNotFoundError when the org cannot be found", func() { 245 req := apifakes.NewCloudControllerTestRequest(testnet.TestRequest{ 246 Method: "GET", 247 Path: "/v2/organizations?q=name%3Aorg1&inline-relations-depth=1", 248 Response: testnet.TestResponse{Status: http.StatusOK, Body: `{"resources": []}`}, 249 }) 250 251 testserver, handler, repo := createOrganizationRepo(req) 252 defer testserver.Close() 253 254 _, apiErr := repo.FindByName("org1") 255 Expect(handler).To(HaveAllRequestsCalled()) 256 Expect(apiErr.(*errors.ModelNotFoundError)).NotTo(BeNil()) 257 }) 258 259 It("returns an api error when the response is not successful", func() { 260 requestHandler := apifakes.NewCloudControllerTestRequest(testnet.TestRequest{ 261 Method: "GET", 262 Path: "/v2/organizations?q=name%3Aorg1&inline-relations-depth=1", 263 Response: testnet.TestResponse{Status: http.StatusBadGateway, Body: `{"resources": []}`}, 264 }) 265 266 testserver, handler, repo := createOrganizationRepo(requestHandler) 267 defer testserver.Close() 268 269 _, apiErr := repo.FindByName("org1") 270 _, ok := apiErr.(*errors.ModelNotFoundError) 271 Expect(ok).To(BeFalse()) 272 Expect(handler).To(HaveAllRequestsCalled()) 273 }) 274 }) 275 276 Describe(".Create", func() { 277 It("creates the org and sends only the org name if the quota flag is not provided", func() { 278 org := models.Organization{ 279 OrganizationFields: models.OrganizationFields{ 280 Name: "my-org", 281 }} 282 283 req := apifakes.NewCloudControllerTestRequest(testnet.TestRequest{ 284 Method: "POST", 285 Path: "/v2/organizations", 286 Matcher: testnet.RequestBodyMatcher(`{"name":"my-org"}`), 287 Response: testnet.TestResponse{Status: http.StatusCreated}, 288 }) 289 290 testserver, handler, repo := createOrganizationRepo(req) 291 defer testserver.Close() 292 293 apiErr := repo.Create(org) 294 Expect(handler).To(HaveAllRequestsCalled()) 295 Expect(apiErr).NotTo(HaveOccurred()) 296 }) 297 298 It("creates the org with the provided quota", func() { 299 org := models.Organization{ 300 OrganizationFields: models.OrganizationFields{ 301 Name: "my-org", 302 QuotaDefinition: models.QuotaFields{ 303 GUID: "my-quota-guid", 304 }, 305 }} 306 307 req := apifakes.NewCloudControllerTestRequest(testnet.TestRequest{ 308 Method: "POST", 309 Path: "/v2/organizations", 310 Matcher: testnet.RequestBodyMatcher(`{"name":"my-org", "quota_definition_guid":"my-quota-guid"}`), 311 Response: testnet.TestResponse{Status: http.StatusCreated}, 312 }) 313 314 testserver, handler, repo := createOrganizationRepo(req) 315 defer testserver.Close() 316 317 apiErr := repo.Create(org) 318 Expect(handler).To(HaveAllRequestsCalled()) 319 Expect(apiErr).NotTo(HaveOccurred()) 320 }) 321 }) 322 323 Describe("renaming orgs", func() { 324 It("renames the org with the given guid", func() { 325 req := apifakes.NewCloudControllerTestRequest(testnet.TestRequest{ 326 Method: "PUT", 327 Path: "/v2/organizations/my-org-guid", 328 Matcher: testnet.RequestBodyMatcher(`{"name":"my-new-org"}`), 329 Response: testnet.TestResponse{Status: http.StatusCreated}, 330 }) 331 332 testserver, handler, repo := createOrganizationRepo(req) 333 defer testserver.Close() 334 335 apiErr := repo.Rename("my-org-guid", "my-new-org") 336 Expect(handler).To(HaveAllRequestsCalled()) 337 Expect(apiErr).NotTo(HaveOccurred()) 338 }) 339 }) 340 341 Describe("deleting orgs", func() { 342 It("deletes the org with the given guid", func() { 343 req := apifakes.NewCloudControllerTestRequest(testnet.TestRequest{ 344 Method: "DELETE", 345 Path: "/v2/organizations/my-org-guid?recursive=true", 346 Response: testnet.TestResponse{Status: http.StatusOK}, 347 }) 348 349 testserver, handler, repo := createOrganizationRepo(req) 350 defer testserver.Close() 351 352 apiErr := repo.Delete("my-org-guid") 353 Expect(handler).To(HaveAllRequestsCalled()) 354 Expect(apiErr).NotTo(HaveOccurred()) 355 }) 356 }) 357 358 Describe("SharePrivateDomain", func() { 359 It("shares the private domain with the given org", func() { 360 req := apifakes.NewCloudControllerTestRequest(testnet.TestRequest{ 361 Method: "PUT", 362 Path: "/v2/organizations/my-org-guid/private_domains/domain-guid", 363 Response: testnet.TestResponse{Status: http.StatusOK}, 364 }) 365 366 testserver, handler, repo := createOrganizationRepo(req) 367 defer testserver.Close() 368 369 apiErr := repo.SharePrivateDomain("my-org-guid", "domain-guid") 370 Expect(handler).To(HaveAllRequestsCalled()) 371 Expect(apiErr).NotTo(HaveOccurred()) 372 }) 373 }) 374 375 Describe("UnsharePrivateDomain", func() { 376 It("unshares the private domain with the given org", func() { 377 req := apifakes.NewCloudControllerTestRequest(testnet.TestRequest{ 378 Method: "DELETE", 379 Path: "/v2/organizations/my-org-guid/private_domains/domain-guid", 380 Response: testnet.TestResponse{Status: http.StatusOK}, 381 }) 382 383 testserver, handler, repo := createOrganizationRepo(req) 384 defer testserver.Close() 385 386 apiErr := repo.UnsharePrivateDomain("my-org-guid", "domain-guid") 387 Expect(handler).To(HaveAllRequestsCalled()) 388 Expect(apiErr).NotTo(HaveOccurred()) 389 }) 390 }) 391 }) 392 393 func createOrganizationRepo(reqs ...testnet.TestRequest) (testserver *httptest.Server, handler *testnet.TestHandler, repo OrganizationRepository) { 394 testserver, handler = testnet.NewServer(reqs) 395 396 configRepo := testconfig.NewRepositoryWithDefaults() 397 configRepo.SetAPIEndpoint(testserver.URL) 398 gateway := net.NewCloudControllerGateway(configRepo, time.Now, new(terminalfakes.FakeUI), new(tracefakes.FakePrinter), "") 399 repo = NewCloudControllerOrganizationRepository(configRepo, gateway) 400 return 401 }