github.com/loggregator/cli@v6.33.1-0.20180224010324-82334f081791+incompatible/cf/commands/quota/create_quota_test.go (about) 1 package quota_test 2 3 import ( 4 "code.cloudfoundry.org/cli/cf/commandregistry" 5 "code.cloudfoundry.org/cli/cf/configuration/coreconfig" 6 "code.cloudfoundry.org/cli/cf/flags" 7 . "code.cloudfoundry.org/cli/util/testhelpers/matchers" 8 . "github.com/onsi/ginkgo" 9 . "github.com/onsi/gomega" 10 11 "encoding/json" 12 13 "code.cloudfoundry.org/cli/cf/api/quotas/quotasfakes" 14 "code.cloudfoundry.org/cli/cf/api/resources" 15 "code.cloudfoundry.org/cli/cf/commands/quota" 16 "code.cloudfoundry.org/cli/cf/errors" 17 "code.cloudfoundry.org/cli/cf/requirements" 18 "code.cloudfoundry.org/cli/cf/requirements/requirementsfakes" 19 testcmd "code.cloudfoundry.org/cli/util/testhelpers/commands" 20 testconfig "code.cloudfoundry.org/cli/util/testhelpers/configuration" 21 testterm "code.cloudfoundry.org/cli/util/testhelpers/terminal" 22 "github.com/blang/semver" 23 ) 24 25 var _ = Describe("create-quota command", func() { 26 var ( 27 ui *testterm.FakeUI 28 quotaRepo *quotasfakes.FakeQuotaRepository 29 requirementsFactory *requirementsfakes.FakeFactory 30 configRepo coreconfig.Repository 31 deps commandregistry.Dependency 32 ) 33 34 updateCommandDependency := func(pluginCall bool) { 35 deps.UI = ui 36 deps.Config = configRepo 37 deps.RepoLocator = deps.RepoLocator.SetQuotaRepository(quotaRepo) 38 commandregistry.Commands.SetCommand(commandregistry.Commands.FindCommand("create-quota").SetDependency(deps, pluginCall)) 39 } 40 41 BeforeEach(func() { 42 ui = &testterm.FakeUI{} 43 configRepo = testconfig.NewRepositoryWithDefaults() 44 quotaRepo = new(quotasfakes.FakeQuotaRepository) 45 requirementsFactory = new(requirementsfakes.FakeFactory) 46 }) 47 48 runCommand := func(args ...string) bool { 49 return testcmd.RunCLICommand("create-quota", args, requirementsFactory, updateCommandDependency, false, ui) 50 } 51 52 Describe("Help text", func() { 53 var usage string 54 55 BeforeEach(func() { 56 cq := "a.CreateQuota{} 57 up := commandregistry.CLICommandUsagePresenter(cq) 58 usage = up.Usage() 59 }) 60 61 It("has a reserved route ports flag", func() { 62 Expect(usage).To(MatchRegexp(`--reserved-route-ports\s+Maximum number of routes that may be created with reserved ports \(Default: 0\)`)) 63 64 Expect(usage).To(MatchRegexp(`cf create-quota.*\[--reserved-route-ports RESERVED_ROUTE_PORTS\]`)) 65 }) 66 67 It("has an instance memory flag", func() { 68 Expect(usage).To(MatchRegexp(`-i\s+Maximum amount of memory an application instance can have \(e.g. 1024M, 1G, 10G\). -1 represents an unlimited amount.`)) 69 70 Expect(usage).To(MatchRegexp(`cf create-quota.*\[-i INSTANCE_MEMORY\]`)) 71 }) 72 73 It("has a total memory flag", func() { 74 Expect(usage).To(MatchRegexp(`-m\s+Total amount of memory \(e.g. 1024M, 1G, 10G\)`)) 75 76 Expect(usage).To(MatchRegexp(`cf create-quota.*\[-m TOTAL_MEMORY\]`)) 77 }) 78 79 It("has a routes flag", func() { 80 Expect(usage).To(MatchRegexp(`-r\s+Total number of routes`)) 81 82 Expect(usage).To(MatchRegexp(`cf create-quota.*\[-r ROUTES\]`)) 83 }) 84 85 It("has a service instances flag", func() { 86 Expect(usage).To(MatchRegexp(`-s\s+Total number of service instances`)) 87 88 Expect(usage).To(MatchRegexp(`cf create-quota.*\[-s SERVICE_INSTANCES\]`)) 89 }) 90 91 It("has an app instances flag", func() { 92 Expect(usage).To(MatchRegexp(`-a\s+Total number of application instances. -1 represents an unlimited amount. \(Default: unlimited\)`)) 93 94 Expect(usage).To(MatchRegexp(`cf create-quota.*\[-a APP_INSTANCES\]`)) 95 }) 96 }) 97 98 Context("when the user is not logged in", func() { 99 BeforeEach(func() { 100 requirementsFactory.NewLoginRequirementReturns(requirements.Failing{Message: "not logged in"}) 101 }) 102 103 It("fails requirements", func() { 104 Expect(runCommand("my-quota", "-m", "50G")).To(BeFalse()) 105 }) 106 }) 107 108 Context("when the user is logged in", func() { 109 BeforeEach(func() { 110 requirementsFactory.NewLoginRequirementReturns(requirements.Passing{}) 111 requirementsFactory.NewMinAPIVersionRequirementReturns(requirements.Passing{}) 112 }) 113 114 It("fails requirements when called without a quota name", func() { 115 runCommand() 116 Expect(ui.Outputs()).To(ContainSubstrings( 117 []string{"Incorrect Usage", "Requires an argument"}, 118 )) 119 }) 120 121 It("creates a quota with a given name", func() { 122 runCommand("my-quota") 123 Expect(quotaRepo.CreateArgsForCall(0).Name).To(Equal("my-quota")) 124 Expect(ui.Outputs()).To(ContainSubstrings( 125 []string{"Creating quota", "my-quota", "my-user", "..."}, 126 []string{"OK"}, 127 )) 128 }) 129 130 Context("when the -i flag is not provided", func() { 131 It("defaults the memory limit to unlimited", func() { 132 runCommand("my-quota") 133 134 Expect(quotaRepo.CreateArgsForCall(0).InstanceMemoryLimit).To(Equal(int64(-1))) 135 }) 136 }) 137 138 Context("when the -m flag is provided", func() { 139 It("sets the memory limit", func() { 140 runCommand("-m", "50G", "erryday makin fitty jeez") 141 Expect(quotaRepo.CreateArgsForCall(0).MemoryLimit).To(Equal(int64(51200))) 142 }) 143 144 It("alerts the user when parsing the memory limit fails", func() { 145 runCommand("whoops", "12") 146 147 Expect(ui.Outputs()).To(ContainSubstrings([]string{"FAILED"})) 148 }) 149 }) 150 151 Context("when the -i flag is provided", func() { 152 It("sets the memory limit", func() { 153 runCommand("-i", "50G", "erryday makin fitty jeez") 154 Expect(quotaRepo.CreateArgsForCall(0).InstanceMemoryLimit).To(Equal(int64(51200))) 155 }) 156 157 It("alerts the user when parsing the memory limit fails", func() { 158 runCommand("-i", "whoops", "wit mah hussle", "12") 159 160 Expect(ui.Outputs()).To(ContainSubstrings([]string{"FAILED"})) 161 }) 162 163 Context("and the provided value is -1", func() { 164 It("sets the memory limit", func() { 165 runCommand("-i", "-1", "yo") 166 Expect(quotaRepo.CreateArgsForCall(0).InstanceMemoryLimit).To(Equal(int64(-1))) 167 }) 168 }) 169 }) 170 171 Context("when the -a flag is provided", func() { 172 It("sets the app limit", func() { 173 runCommand("my-quota", "-a", "10") 174 175 Expect(quotaRepo.CreateArgsForCall(0).AppInstanceLimit).To(Equal(10)) 176 }) 177 178 It("defaults to unlimited", func() { 179 runCommand("my-quota") 180 181 Expect(quotaRepo.CreateArgsForCall(0).AppInstanceLimit).To(Equal(resources.UnlimitedAppInstances)) 182 }) 183 }) 184 185 Context("when the --reserved-route-ports flag is provided", func() { 186 It("sets route port limit", func() { 187 runCommand("my-quota", "--reserved-route-ports", "5") 188 189 Expect(quotaRepo.CreateArgsForCall(0).ReservedRoutePorts).To(Equal(json.Number("5"))) 190 }) 191 192 It("defaults be empty", func() { 193 runCommand("my-quota") 194 195 Expect(quotaRepo.CreateArgsForCall(0).ReservedRoutePorts).To(BeEmpty()) 196 }) 197 }) 198 199 It("sets the route limit", func() { 200 runCommand("-r", "12", "ecstatic") 201 202 Expect(quotaRepo.CreateArgsForCall(0).RoutesLimit).To(Equal(12)) 203 }) 204 205 It("sets the service instance limit", func() { 206 runCommand("-s", "42", "black star") 207 Expect(quotaRepo.CreateArgsForCall(0).ServicesLimit).To(Equal(42)) 208 }) 209 210 Context("when requesting to allow paid service plans", func() { 211 It("creates the quota with paid service plans allowed", func() { 212 runCommand("--allow-paid-service-plans", "my-for-profit-quota") 213 Expect(quotaRepo.CreateArgsForCall(0).NonBasicServicesAllowed).To(BeTrue()) 214 }) 215 216 It("defaults to not allowing paid service plans", func() { 217 runCommand("my-pro-bono-quota") 218 Expect(quotaRepo.CreateArgsForCall(0).NonBasicServicesAllowed).To(BeFalse()) 219 }) 220 }) 221 222 Context("when creating a quota returns an error", func() { 223 It("alerts the user when creating the quota fails", func() { 224 quotaRepo.CreateReturns(errors.New("WHOOP THERE IT IS")) 225 runCommand("my-quota") 226 227 Expect(ui.Outputs()).To(ContainSubstrings( 228 []string{"Creating quota", "my-quota"}, 229 []string{"FAILED"}, 230 )) 231 }) 232 233 It("warns the user when quota already exists", func() { 234 quotaRepo.CreateReturns(errors.NewHTTPError(400, errors.QuotaDefinitionNameTaken, "Quota Definition is taken: quota-sct")) 235 runCommand("Banana") 236 237 Expect(ui.Outputs()).ToNot(ContainSubstrings( 238 []string{"FAILED"}, 239 )) 240 Expect(ui.WarnOutputs).To(ContainSubstrings([]string{"already exists"})) 241 }) 242 243 }) 244 }) 245 246 Describe("Requirements", func() { 247 var ( 248 requirementsFactory *requirementsfakes.FakeFactory 249 250 ui *testterm.FakeUI 251 cmd commandregistry.Command 252 deps commandregistry.Dependency 253 254 quotaRepo *quotasfakes.FakeQuotaRepository 255 flagContext flags.FlagContext 256 257 loginRequirement requirements.Requirement 258 minAPIVersionRequirement requirements.Requirement 259 ) 260 261 BeforeEach(func() { 262 ui = &testterm.FakeUI{} 263 264 configRepo = testconfig.NewRepositoryWithDefaults() 265 quotaRepo = new(quotasfakes.FakeQuotaRepository) 266 repoLocator := deps.RepoLocator.SetQuotaRepository(quotaRepo) 267 268 deps = commandregistry.Dependency{ 269 UI: ui, 270 Config: configRepo, 271 RepoLocator: repoLocator, 272 } 273 274 requirementsFactory = new(requirementsfakes.FakeFactory) 275 276 cmd = "a.CreateQuota{} 277 cmd.SetDependency(deps, false) 278 279 flagContext = flags.NewFlagContext(cmd.MetaData().Flags) 280 281 loginRequirement = &passingRequirement{Name: "login-requirement"} 282 requirementsFactory.NewLoginRequirementReturns(loginRequirement) 283 284 minAPIVersionRequirement = &passingRequirement{Name: "min-api-version-requirement"} 285 requirementsFactory.NewMinAPIVersionRequirementReturns(minAPIVersionRequirement) 286 }) 287 288 Context("when not provided exactly one arg", func() { 289 BeforeEach(func() { 290 flagContext.Parse("quota", "extra-arg") 291 }) 292 293 It("fails with usage", func() { 294 _, err := cmd.Requirements(requirementsFactory, flagContext) 295 Expect(err).To(HaveOccurred()) 296 Expect(ui.Outputs()).To(ContainSubstrings( 297 []string{"FAILED"}, 298 []string{"Incorrect Usage. Requires an argument"}, 299 )) 300 }) 301 }) 302 303 Context("when provided exactly one arg", func() { 304 BeforeEach(func() { 305 flagContext.Parse("quota") 306 }) 307 308 It("returns a LoginRequirement", func() { 309 actualRequirements, err := cmd.Requirements(requirementsFactory, flagContext) 310 Expect(err).NotTo(HaveOccurred()) 311 Expect(requirementsFactory.NewLoginRequirementCallCount()).To(Equal(1)) 312 Expect(actualRequirements).To(ContainElement(loginRequirement)) 313 }) 314 315 It("does not return a MinAPIVersionRequirement", func() { 316 actualRequirements, err := cmd.Requirements(requirementsFactory, flagContext) 317 Expect(err).NotTo(HaveOccurred()) 318 Expect(requirementsFactory.NewMinAPIVersionRequirementCallCount()).To(Equal(0)) 319 Expect(actualRequirements).NotTo(ContainElement(minAPIVersionRequirement)) 320 }) 321 322 Context("when an app instance limit is passed", func() { 323 BeforeEach(func() { 324 flagContext = flags.NewFlagContext(cmd.MetaData().Flags) 325 flagContext.Parse("domain-name", "-a", "2") 326 }) 327 328 It("returns a MinAPIVersionRequirement as the second requirement", func() { 329 actualRequirements, err := cmd.Requirements(requirementsFactory, flagContext) 330 Expect(err).NotTo(HaveOccurred()) 331 332 expectedVersion, err := semver.Make("2.33.0") 333 Expect(err).NotTo(HaveOccurred()) 334 335 Expect(requirementsFactory.NewMinAPIVersionRequirementCallCount()).To(Equal(1)) 336 feature, requiredVersion := requirementsFactory.NewMinAPIVersionRequirementArgsForCall(0) 337 Expect(feature).To(Equal("Option '-a'")) 338 Expect(requiredVersion).To(Equal(expectedVersion)) 339 Expect(actualRequirements[1]).To(Equal(minAPIVersionRequirement)) 340 }) 341 }) 342 343 Context("when reserved route ports limit is passed", func() { 344 BeforeEach(func() { 345 flagContext = flags.NewFlagContext(cmd.MetaData().Flags) 346 flagContext.Parse("domain-name", "--reserved-route-ports", "3") 347 }) 348 349 It("returns a MinAPIVersionRequirement as the second requirement", func() { 350 actualRequirements, err := cmd.Requirements(requirementsFactory, flagContext) 351 Expect(err).NotTo(HaveOccurred()) 352 353 expectedVersion, err := semver.Make("2.55.0") 354 Expect(err).NotTo(HaveOccurred()) 355 356 Expect(requirementsFactory.NewMinAPIVersionRequirementCallCount()).To(Equal(1)) 357 feature, requiredVersion := requirementsFactory.NewMinAPIVersionRequirementArgsForCall(0) 358 Expect(feature).To(Equal("Option '--reserved-route-ports'")) 359 Expect(requiredVersion).To(Equal(expectedVersion)) 360 Expect(actualRequirements[1]).To(Equal(minAPIVersionRequirement)) 361 }) 362 }) 363 }) 364 }) 365 }) 366 367 type passingRequirement struct { 368 Name string 369 } 370 371 func (r passingRequirement) Execute() error { 372 return nil 373 }