github.com/cloudfoundry/cli@v7.1.0+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/cf/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  })