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 := &quota.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 = &quota.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  }