github.com/loggregator/cli@v6.33.1-0.20180224010324-82334f081791+incompatible/cf/api/spacequotas/space_quotas_test.go (about) 1 package spacequotas_test 2 3 import ( 4 "encoding/json" 5 "net/http" 6 "time" 7 8 "code.cloudfoundry.org/cli/cf/api/spacequotas" 9 "code.cloudfoundry.org/cli/cf/configuration/coreconfig" 10 "code.cloudfoundry.org/cli/cf/errors" 11 "code.cloudfoundry.org/cli/cf/models" 12 "code.cloudfoundry.org/cli/cf/net" 13 "github.com/onsi/gomega/ghttp" 14 15 "code.cloudfoundry.org/cli/cf/terminal/terminalfakes" 16 testconfig "code.cloudfoundry.org/cli/util/testhelpers/configuration" 17 18 "code.cloudfoundry.org/cli/cf/trace/tracefakes" 19 . "github.com/onsi/ginkgo" 20 . "github.com/onsi/gomega" 21 ) 22 23 var _ = Describe("CloudControllerQuotaRepository", func() { 24 var ( 25 ccServer *ghttp.Server 26 configRepo coreconfig.ReadWriter 27 repo spacequotas.CloudControllerSpaceQuotaRepository 28 ) 29 30 BeforeEach(func() { 31 ccServer = ghttp.NewServer() 32 configRepo = testconfig.NewRepositoryWithDefaults() 33 configRepo.SetAPIEndpoint(ccServer.URL()) 34 gateway := net.NewCloudControllerGateway(configRepo, time.Now, new(terminalfakes.FakeUI), new(tracefakes.FakePrinter), "") 35 repo = spacequotas.NewCloudControllerSpaceQuotaRepository(configRepo, gateway) 36 }) 37 38 AfterEach(func() { 39 ccServer.Close() 40 }) 41 42 Describe("FindByName", func() { 43 BeforeEach(func() { 44 ccServer.AppendHandlers( 45 ghttp.CombineHandlers( 46 ghttp.VerifyRequest("GET", "/v2/organizations/my-org-guid/space_quota_definitions"), 47 ghttp.RespondWith(http.StatusOK, `{ 48 "next_url": "/v2/organizations/my-org-guid/space_quota_definitions?page=2", 49 "resources": [ 50 { 51 "metadata": { "guid": "my-quota-guid" }, 52 "entity": { 53 "name": "my-remote-quota", 54 "memory_limit": 1024, 55 "total_routes": 123, 56 "total_services": 321, 57 "non_basic_services_allowed": true, 58 "organization_guid": "my-org-guid", 59 "app_instance_limit": 333, 60 "total_reserved_route_ports": 14 61 } 62 } 63 ] 64 }`), 65 ), 66 ghttp.CombineHandlers( 67 ghttp.VerifyRequest("GET", "/v2/organizations/my-org-guid/space_quota_definitions", "page=2"), 68 ghttp.RespondWith(http.StatusOK, `{ 69 "resources": [ 70 { 71 "metadata": { "guid": "my-quota-guid2" }, 72 "entity": { "name": "my-remote-quota2", "memory_limit": 1024, "organization_guid": "my-org-guid" } 73 }, 74 { 75 "metadata": { "guid": "my-quota-guid3" }, 76 "entity": { "name": "my-remote-quota3", "memory_limit": 1024, "organization_guid": "my-org-guid" } 77 } 78 ] 79 }`), 80 ), 81 ) 82 }) 83 84 It("Finds Quota definitions by name", func() { 85 quota, err := repo.FindByName("my-remote-quota") 86 Expect(err).NotTo(HaveOccurred()) 87 Expect(ccServer.ReceivedRequests()).To(HaveLen(2)) 88 Expect(quota).To(Equal(models.SpaceQuota{ 89 GUID: "my-quota-guid", 90 Name: "my-remote-quota", 91 MemoryLimit: 1024, 92 RoutesLimit: 123, 93 ServicesLimit: 321, 94 NonBasicServicesAllowed: true, 95 OrgGUID: "my-org-guid", 96 AppInstanceLimit: 333, 97 ReservedRoutePortsLimit: "14", 98 })) 99 }) 100 101 It("Returns an error if the quota cannot be found", func() { 102 _, err := repo.FindByName("totally-not-a-quota") 103 Expect(err.(*errors.ModelNotFoundError)).NotTo(BeNil()) 104 }) 105 }) 106 107 Describe("FindByNameAndOrgGUID", func() { 108 Context("when the org exists", func() { 109 Context("when the app_instance_limit is provided", func() { 110 BeforeEach(func() { 111 ccServer.AppendHandlers( 112 ghttp.CombineHandlers( 113 ghttp.VerifyRequest("GET", "/v2/organizations/other-org-guid/space_quota_definitions"), 114 ghttp.RespondWith(http.StatusOK, `{ 115 "next_url": "/v2/organizations/other-org-guid/space_quota_definitions?page=2", 116 "resources": [ 117 { 118 "metadata": { "guid": "my-quota-guid" }, 119 "entity": { 120 "name": "my-remote-quota", 121 "memory_limit": 1024, 122 "total_routes": 123, 123 "total_services": 321, 124 "non_basic_services_allowed": true, 125 "organization_guid": "other-org-guid", 126 "app_instance_limit": 333, 127 "total_reserved_route_ports": 14 128 } 129 } 130 ] 131 }`), 132 ), 133 ghttp.CombineHandlers( 134 ghttp.VerifyRequest("GET", "/v2/organizations/other-org-guid/space_quota_definitions", "page=2"), 135 ghttp.RespondWith(http.StatusOK, `{ 136 "resources": [ 137 { 138 "metadata": { "guid": "my-quota-guid2" }, 139 "entity": { "name": "my-remote-quota2", "memory_limit": 1024, "organization_guid": "other-org-guid" } 140 }, 141 { 142 "metadata": { "guid": "my-quota-guid3" }, 143 "entity": { "name": "my-remote-quota3", "memory_limit": 1024, "organization_guid": "other-org-guid" } 144 } 145 ] 146 }`), 147 ), 148 ) 149 }) 150 151 It("Finds Quota definitions by name and org guid", func() { 152 quota, err := repo.FindByNameAndOrgGUID("my-remote-quota", "other-org-guid") 153 Expect(err).NotTo(HaveOccurred()) 154 Expect(ccServer.ReceivedRequests()).To(HaveLen(2)) 155 Expect(quota).To(Equal(models.SpaceQuota{ 156 GUID: "my-quota-guid", 157 Name: "my-remote-quota", 158 MemoryLimit: 1024, 159 RoutesLimit: 123, 160 ServicesLimit: 321, 161 NonBasicServicesAllowed: true, 162 OrgGUID: "other-org-guid", 163 AppInstanceLimit: 333, 164 ReservedRoutePortsLimit: "14", 165 })) 166 }) 167 168 It("Returns an error if the quota cannot be found", func() { 169 _, err := repo.FindByNameAndOrgGUID("totally-not-a-quota", "other-org-guid") 170 Expect(err.(*errors.ModelNotFoundError)).To(HaveOccurred()) 171 }) 172 }) 173 174 Context("when the app_instance_limit and total_reserved_route_ports are not provided", func() { 175 BeforeEach(func() { 176 ccServer.AppendHandlers( 177 ghttp.CombineHandlers( 178 ghttp.VerifyRequest("GET", "/v2/organizations/other-org-guid/space_quota_definitions"), 179 ghttp.RespondWith(http.StatusOK, `{ 180 "next_url": "/v2/organizations/other-org-guid/space_quota_definitions?page=2", 181 "resources": [ 182 { 183 "metadata": { "guid": "my-quota-guid" }, 184 "entity": { 185 "name": "my-remote-quota", 186 "memory_limit": 1024, 187 "total_routes": 123, 188 "total_services": 321, 189 "non_basic_services_allowed": true, 190 "organization_guid": "other-org-guid" 191 } 192 } 193 ] 194 }`), 195 ), 196 ghttp.CombineHandlers( 197 ghttp.VerifyRequest("GET", "/v2/organizations/other-org-guid/space_quota_definitions", "page=2"), 198 ghttp.RespondWith(http.StatusOK, `{ 199 "resources": [ 200 { 201 "metadata": { "guid": "my-quota-guid2" }, 202 "entity": { "name": "my-remote-quota2", "memory_limit": 1024, "organization_guid": "other-org-guid" } 203 }, 204 { 205 "metadata": { "guid": "my-quota-guid3" }, 206 "entity": { "name": "my-remote-quota3", "memory_limit": 1024, "organization_guid": "other-org-guid" } 207 } 208 ] 209 }`), 210 ), 211 ) 212 }) 213 214 It("sets app instance limit to -1 and ReservedRoutePortsLimit is left blank", func() { 215 quota, err := repo.FindByNameAndOrgGUID("my-remote-quota", "other-org-guid") 216 Expect(err).NotTo(HaveOccurred()) 217 Expect(ccServer.ReceivedRequests()).To(HaveLen(2)) 218 Expect(quota).To(Equal(models.SpaceQuota{ 219 GUID: "my-quota-guid", 220 Name: "my-remote-quota", 221 MemoryLimit: 1024, 222 RoutesLimit: 123, 223 ServicesLimit: 321, 224 NonBasicServicesAllowed: true, 225 OrgGUID: "other-org-guid", 226 AppInstanceLimit: -1, 227 ReservedRoutePortsLimit: "", 228 })) 229 }) 230 }) 231 }) 232 233 Context("when the org does not exist", func() { 234 BeforeEach(func() { 235 ccServer.AppendHandlers( 236 ghttp.CombineHandlers( 237 ghttp.VerifyRequest("GET", "/v2/organizations/totally-not-an-org/space_quota_definitions"), 238 ghttp.RespondWith(http.StatusNotFound, ""), 239 ), 240 ) 241 }) 242 243 It("returns an error", func() { 244 _, err := repo.FindByNameAndOrgGUID("my-remote-quota", "totally-not-an-org") 245 Expect(err.(*errors.HTTPNotFoundError)).To(HaveOccurred()) 246 }) 247 }) 248 }) 249 250 Describe("FindByOrg", func() { 251 BeforeEach(func() { 252 ccServer.AppendHandlers( 253 ghttp.CombineHandlers( 254 ghttp.VerifyRequest("GET", "/v2/organizations/my-org-guid/space_quota_definitions"), 255 ghttp.RespondWith(http.StatusOK, `{ 256 "next_url": "/v2/organizations/my-org-guid/space_quota_definitions?page=2", 257 "resources": [ 258 { 259 "metadata": { "guid": "my-quota-guid" }, 260 "entity": { 261 "name": "my-remote-quota", 262 "memory_limit": 1024, 263 "total_routes": 123, 264 "total_services": 321, 265 "non_basic_services_allowed": true, 266 "organization_guid": "my-org-guid", 267 "total_reserved_route_ports": 14 268 } 269 } 270 ] 271 }`), 272 ), 273 ghttp.CombineHandlers( 274 ghttp.VerifyRequest("GET", "/v2/organizations/my-org-guid/space_quota_definitions", "page=2"), 275 ghttp.RespondWith(http.StatusOK, `{ 276 "resources": [ 277 { 278 "metadata": { "guid": "my-quota-guid2" }, 279 "entity": { "name": "my-remote-quota2", "memory_limit": 1024, "organization_guid": "my-org-guid" } 280 }, 281 { 282 "metadata": { "guid": "my-quota-guid3" }, 283 "entity": { "name": "my-remote-quota3", "memory_limit": 1024, "organization_guid": "my-org-guid" } 284 } 285 ] 286 }`), 287 ), 288 ) 289 }) 290 291 It("finds all quota definitions by org guid", func() { 292 quotas, err := repo.FindByOrg("my-org-guid") 293 Expect(err).NotTo(HaveOccurred()) 294 Expect(quotas).To(HaveLen(3)) 295 296 Expect(quotas[0].GUID).To(Equal("my-quota-guid")) 297 Expect(quotas[0].Name).To(Equal("my-remote-quota")) 298 Expect(quotas[0].MemoryLimit).To(Equal(int64(1024))) 299 Expect(quotas[0].RoutesLimit).To(Equal(123)) 300 Expect(quotas[0].ServicesLimit).To(Equal(321)) 301 Expect(quotas[0].OrgGUID).To(Equal("my-org-guid")) 302 Expect(quotas[0].ReservedRoutePortsLimit).To(Equal(json.Number("14"))) 303 304 Expect(quotas[1].GUID).To(Equal("my-quota-guid2")) 305 Expect(quotas[1].OrgGUID).To(Equal("my-org-guid")) 306 Expect(quotas[2].GUID).To(Equal("my-quota-guid3")) 307 Expect(quotas[2].OrgGUID).To(Equal("my-org-guid")) 308 }) 309 }) 310 311 Describe("FindByGUID", func() { 312 BeforeEach(func() { 313 ccServer.AppendHandlers( 314 ghttp.CombineHandlers( 315 ghttp.VerifyRequest("GET", "/v2/organizations/my-org-guid/space_quota_definitions"), 316 ghttp.RespondWith(http.StatusOK, `{ 317 "next_url": "/v2/organizations/my-org-guid/space_quota_definitions?page=2", 318 "resources": [ 319 { 320 "metadata": { "guid": "my-quota-guid" }, 321 "entity": { 322 "name": "my-remote-quota", 323 "memory_limit": 1024, 324 "total_routes": 123, 325 "total_services": 321, 326 "non_basic_services_allowed": true, 327 "organization_guid": "my-org-guid", 328 "total_reserved_route_ports": 14 329 } 330 } 331 ] 332 }`), 333 ), 334 ghttp.CombineHandlers( 335 ghttp.VerifyRequest("GET", "/v2/organizations/my-org-guid/space_quota_definitions", "page=2"), 336 ghttp.RespondWith(http.StatusOK, `{ 337 "resources": [ 338 { 339 "metadata": { "guid": "my-quota-guid2" }, 340 "entity": { "name": "my-remote-quota2", "memory_limit": 1024, "organization_guid": "my-org-guid" } 341 }, 342 { 343 "metadata": { "guid": "my-quota-guid3" }, 344 "entity": { "name": "my-remote-quota3", "memory_limit": 1024, "organization_guid": "my-org-guid" } 345 } 346 ] 347 }`), 348 ), 349 ) 350 }) 351 352 It("Finds Quota definitions by GUID", func() { 353 quota, err := repo.FindByGUID("my-quota-guid") 354 Expect(err).NotTo(HaveOccurred()) 355 Expect(quota).To(Equal(models.SpaceQuota{ 356 GUID: "my-quota-guid", 357 Name: "my-remote-quota", 358 MemoryLimit: 1024, 359 RoutesLimit: 123, 360 ServicesLimit: 321, 361 NonBasicServicesAllowed: true, 362 OrgGUID: "my-org-guid", 363 AppInstanceLimit: -1, 364 ReservedRoutePortsLimit: "14", 365 })) 366 }) 367 368 It("Returns an error if the quota cannot be found", func() { 369 _, err := repo.FindByGUID("totally-not-a-quota-guid") 370 Expect(err.(*errors.ModelNotFoundError)).NotTo(BeNil()) 371 Expect(ccServer.ReceivedRequests()).To(HaveLen(2)) 372 }) 373 }) 374 375 Describe("AssociateSpaceWithQuota", func() { 376 BeforeEach(func() { 377 ccServer.AppendHandlers( 378 ghttp.VerifyRequest("PUT", "/v2/space_quota_definitions/my-quota-guid/spaces/my-space-guid"), 379 ghttp.RespondWith(http.StatusCreated, nil), 380 ) 381 }) 382 383 It("sets the quota for a space", func() { 384 err := repo.AssociateSpaceWithQuota("my-space-guid", "my-quota-guid") 385 Expect(ccServer.ReceivedRequests()).To(HaveLen(1)) 386 Expect(err).NotTo(HaveOccurred()) 387 }) 388 }) 389 390 Describe("UnassignQuotaFromSpace", func() { 391 BeforeEach(func() { 392 ccServer.AppendHandlers( 393 ghttp.CombineHandlers( 394 ghttp.VerifyRequest("DELETE", "/v2/space_quota_definitions/my-quota-guid/spaces/my-space-guid"), 395 ghttp.RespondWith(http.StatusNoContent, nil), 396 ), 397 ) 398 }) 399 400 It("deletes the association between the quota and the space", func() { 401 err := repo.UnassignQuotaFromSpace("my-space-guid", "my-quota-guid") 402 Expect(err).NotTo(HaveOccurred()) 403 Expect(ccServer.ReceivedRequests()).To(HaveLen(1)) 404 }) 405 }) 406 407 Describe("Create", func() { 408 BeforeEach(func() { 409 ccServer.AppendHandlers( 410 ghttp.CombineHandlers( 411 ghttp.VerifyRequest("POST", "/v2/space_quota_definitions"), 412 ghttp.VerifyJSON(`{ 413 "name": "not-so-strict", 414 "non_basic_services_allowed": false, 415 "total_services": 1, 416 "total_routes": 12, 417 "memory_limit": 123, 418 "instance_memory_limit": 0, 419 "organization_guid": "my-org-guid", 420 "app_instance_limit": 10, 421 "total_reserved_route_ports": 5 422 }`), 423 ghttp.RespondWith(http.StatusNoContent, nil), 424 ), 425 ) 426 }) 427 428 It("creates a new quota with the given name", func() { 429 quota := models.SpaceQuota{ 430 Name: "not-so-strict", 431 ServicesLimit: 1, 432 RoutesLimit: 12, 433 MemoryLimit: 123, 434 OrgGUID: "my-org-guid", 435 AppInstanceLimit: 10, 436 ReservedRoutePortsLimit: "5", 437 } 438 err := repo.Create(quota) 439 Expect(err).NotTo(HaveOccurred()) 440 Expect(ccServer.ReceivedRequests()).To(HaveLen(1)) 441 }) 442 }) 443 444 Describe("Update", func() { 445 BeforeEach(func() { 446 ccServer.AppendHandlers( 447 ghttp.CombineHandlers( 448 ghttp.VerifyRequest("PUT", "/v2/space_quota_definitions/my-quota-guid"), 449 ghttp.VerifyJSON(`{ 450 "guid": "my-quota-guid", 451 "non_basic_services_allowed": false, 452 "name": "amazing-quota", 453 "total_services": 1, 454 "total_routes": 12, 455 "memory_limit": 123, 456 "instance_memory_limit": 1234, 457 "organization_guid": "myorgguid", 458 "app_instance_limit": 23, 459 "total_reserved_route_ports": 5 460 }`), 461 ghttp.RespondWith(http.StatusOK, nil), 462 ), 463 ) 464 }) 465 466 It("updates an existing quota", func() { 467 quota := models.SpaceQuota{ 468 GUID: "my-quota-guid", 469 Name: "amazing-quota", 470 NonBasicServicesAllowed: false, 471 ServicesLimit: 1, 472 RoutesLimit: 12, 473 MemoryLimit: 123, 474 InstanceMemoryLimit: 1234, 475 AppInstanceLimit: 23, 476 OrgGUID: "myorgguid", 477 ReservedRoutePortsLimit: "5", 478 } 479 480 err := repo.Update(quota) 481 Expect(err).NotTo(HaveOccurred()) 482 Expect(ccServer.ReceivedRequests()).To(HaveLen(1)) 483 }) 484 }) 485 486 Describe("Delete", func() { 487 BeforeEach(func() { 488 ccServer.AppendHandlers( 489 ghttp.VerifyRequest("DELETE", "/v2/space_quota_definitions/my-quota-guid"), 490 ghttp.RespondWith(http.StatusNoContent, nil), 491 ) 492 }) 493 494 It("deletes the quota with the given name", func() { 495 err := repo.Delete("my-quota-guid") 496 Expect(err).NotTo(HaveOccurred()) 497 Expect(ccServer.ReceivedRequests()).To(HaveLen(1)) 498 }) 499 }) 500 })