github.com/loggregator/cli@v6.33.1-0.20180224010324-82334f081791+incompatible/cf/commands/service/create_service_test.go (about) 1 package service_test 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "os" 7 8 "code.cloudfoundry.org/cli/cf/actors/servicebuilder/servicebuilderfakes" 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/requirements" 13 "code.cloudfoundry.org/cli/cf/requirements/requirementsfakes" 14 15 "code.cloudfoundry.org/cli/cf/api/apifakes" 16 testcmd "code.cloudfoundry.org/cli/util/testhelpers/commands" 17 testconfig "code.cloudfoundry.org/cli/util/testhelpers/configuration" 18 testterm "code.cloudfoundry.org/cli/util/testhelpers/terminal" 19 20 "code.cloudfoundry.org/cli/cf/commandregistry" 21 22 . "github.com/onsi/ginkgo" 23 . "github.com/onsi/gomega" 24 25 . "code.cloudfoundry.org/cli/util/testhelpers/matchers" 26 ) 27 28 var _ = Describe("create-service command", func() { 29 var ( 30 ui *testterm.FakeUI 31 config coreconfig.Repository 32 requirementsFactory *requirementsfakes.FakeFactory 33 serviceRepo *apifakes.FakeServiceRepository 34 serviceBuilder *servicebuilderfakes.FakeServiceBuilder 35 36 offering1 models.ServiceOffering 37 offering2 models.ServiceOffering 38 deps commandregistry.Dependency 39 ) 40 41 updateCommandDependency := func(pluginCall bool) { 42 deps.UI = ui 43 deps.Config = config 44 deps.RepoLocator = deps.RepoLocator.SetServiceRepository(serviceRepo) 45 deps.ServiceBuilder = serviceBuilder 46 commandregistry.Commands.SetCommand(commandregistry.Commands.FindCommand("create-service").SetDependency(deps, pluginCall)) 47 } 48 49 BeforeEach(func() { 50 ui = &testterm.FakeUI{} 51 config = testconfig.NewRepositoryWithDefaults() 52 requirementsFactory = new(requirementsfakes.FakeFactory) 53 requirementsFactory.NewLoginRequirementReturns(requirements.Passing{}) 54 requirementsFactory.NewTargetedSpaceRequirementReturns(requirements.Passing{}) 55 serviceRepo = new(apifakes.FakeServiceRepository) 56 serviceBuilder = new(servicebuilderfakes.FakeServiceBuilder) 57 58 offering1 = models.ServiceOffering{} 59 offering1.Label = "cleardb" 60 offering1.Plans = []models.ServicePlanFields{{ 61 Name: "spark", 62 GUID: "cleardb-spark-guid", 63 Free: true, 64 }, { 65 Name: "expensive", 66 GUID: "luxury-guid", 67 Free: false, 68 }} 69 70 offering2 = models.ServiceOffering{} 71 offering2.Label = "postgres" 72 73 serviceBuilder.GetServicesByNameForSpaceWithPlansReturns(models.ServiceOfferings([]models.ServiceOffering{offering1, offering2}), nil) 74 }) 75 76 var callCreateService = func(args []string) bool { 77 return testcmd.RunCLICommand("create-service", args, requirementsFactory, updateCommandDependency, false, ui) 78 } 79 80 Describe("requirements", func() { 81 It("passes when logged in and a space is targeted", func() { 82 Expect(callCreateService([]string{"cleardb", "spark", "my-cleardb-service"})).To(BeTrue()) 83 }) 84 85 It("fails when not logged in", func() { 86 requirementsFactory.NewLoginRequirementReturns(requirements.Failing{Message: "not logged in"}) 87 Expect(callCreateService([]string{"cleardb", "spark", "my-cleardb-service"})).To(BeFalse()) 88 }) 89 90 It("fails when a space is not targeted", func() { 91 requirementsFactory.NewTargetedSpaceRequirementReturns(requirements.Failing{Message: "not targeted"}) 92 Expect(callCreateService([]string{"cleardb", "spark", "my-cleardb-service"})).To(BeFalse()) 93 }) 94 }) 95 96 It("successfully creates a service", func() { 97 callCreateService([]string{"cleardb", "spark", "my-cleardb-service"}) 98 99 spaceGUID, serviceName := serviceBuilder.GetServicesByNameForSpaceWithPlansArgsForCall(0) 100 Expect(spaceGUID).To(Equal(config.SpaceFields().GUID)) 101 Expect(serviceName).To(Equal("cleardb")) 102 Expect(ui.Outputs()).To(ContainSubstrings( 103 []string{"Creating service instance", "my-cleardb-service", "my-org", "my-space", "my-user"}, 104 []string{"OK"}, 105 )) 106 name, planGUID, _, _ := serviceRepo.CreateServiceInstanceArgsForCall(0) 107 Expect(name).To(Equal("my-cleardb-service")) 108 Expect(planGUID).To(Equal("cleardb-spark-guid")) 109 }) 110 111 Context("when passing in tags", func() { 112 It("sucessfully creates a service and passes the tags as json", func() { 113 callCreateService([]string{"cleardb", "spark", "my-cleardb-service", "-t", "tag1, tag2,tag3, tag4"}) 114 115 Expect(ui.Outputs()).To(ContainSubstrings( 116 []string{"Creating service instance", "my-cleardb-service", "my-org", "my-space", "my-user"}, 117 []string{"OK"}, 118 )) 119 _, _, _, tags := serviceRepo.CreateServiceInstanceArgsForCall(0) 120 Expect(tags).To(ConsistOf("tag1", "tag2", "tag3", "tag4")) 121 }) 122 }) 123 124 Context("when passing arbitrary params", func() { 125 Context("as a json string", func() { 126 It("successfully creates a service and passes the params as a json string", func() { 127 callCreateService([]string{"cleardb", "spark", "my-cleardb-service", "-c", `{"foo": "bar"}`}) 128 129 Expect(ui.Outputs()).To(ContainSubstrings( 130 []string{"Creating service instance", "my-cleardb-service", "my-org", "my-space", "my-user"}, 131 []string{"OK"}, 132 )) 133 _, _, params, _ := serviceRepo.CreateServiceInstanceArgsForCall(0) 134 Expect(params).To(Equal(map[string]interface{}{"foo": "bar"})) 135 }) 136 137 Context("that are not valid json", func() { 138 It("returns an error to the UI", func() { 139 callCreateService([]string{"cleardb", "spark", "my-cleardb-service", "-c", `bad-json`}) 140 141 Expect(ui.Outputs()).To(ContainSubstrings( 142 []string{"FAILED"}, 143 []string{"Invalid configuration provided for -c flag. Please provide a valid JSON object or path to a file containing a valid JSON object."}, 144 )) 145 }) 146 }) 147 }) 148 149 Context("as a file that contains json", func() { 150 var jsonFile *os.File 151 var params string 152 153 BeforeEach(func() { 154 params = "{\"foo\": \"bar\"}" 155 }) 156 157 AfterEach(func() { 158 if jsonFile != nil { 159 jsonFile.Close() 160 os.Remove(jsonFile.Name()) 161 } 162 }) 163 164 JustBeforeEach(func() { 165 var err error 166 jsonFile, err = ioutil.TempFile("", "") 167 Expect(err).ToNot(HaveOccurred()) 168 169 err = ioutil.WriteFile(jsonFile.Name(), []byte(params), os.ModePerm) 170 Expect(err).NotTo(HaveOccurred()) 171 }) 172 173 It("successfully creates a service and passes the params as a json", func() { 174 callCreateService([]string{"cleardb", "spark", "my-cleardb-service", "-c", jsonFile.Name()}) 175 176 Expect(ui.Outputs()).To(ContainSubstrings( 177 []string{"Creating service instance", "my-cleardb-service", "my-org", "my-space", "my-user"}, 178 []string{"OK"}, 179 )) 180 _, _, params, _ := serviceRepo.CreateServiceInstanceArgsForCall(0) 181 Expect(params).To(Equal(map[string]interface{}{"foo": "bar"})) 182 }) 183 184 Context("that are not valid json", func() { 185 BeforeEach(func() { 186 params = "bad-json" 187 }) 188 189 It("returns an error to the UI", func() { 190 callCreateService([]string{"cleardb", "spark", "my-cleardb-service", "-c", jsonFile.Name()}) 191 192 Expect(ui.Outputs()).To(ContainSubstrings( 193 []string{"FAILED"}, 194 []string{"Invalid configuration provided for -c flag. Please provide a valid JSON object or path to a file containing a valid JSON object."}, 195 )) 196 }) 197 }) 198 }) 199 }) 200 201 Context("when service creation is asynchronous", func() { 202 var serviceInstance models.ServiceInstance 203 204 BeforeEach(func() { 205 serviceInstance = models.ServiceInstance{ 206 ServiceInstanceFields: models.ServiceInstanceFields{ 207 Name: "my-cleardb-service", 208 LastOperation: models.LastOperationFields{ 209 Type: "create", 210 State: "in progress", 211 Description: "fake service instance description", 212 }, 213 }, 214 } 215 serviceRepo.FindInstanceByNameReturns(serviceInstance, nil) 216 }) 217 218 It("successfully starts async service creation", func() { 219 callCreateService([]string{"cleardb", "spark", "my-cleardb-service"}) 220 221 spaceGUID, serviceName := serviceBuilder.GetServicesByNameForSpaceWithPlansArgsForCall(0) 222 Expect(spaceGUID).To(Equal(config.SpaceFields().GUID)) 223 Expect(serviceName).To(Equal("cleardb")) 224 225 creatingServiceMessage := fmt.Sprintf("Create in progress. Use 'cf services' or 'cf service %s' to check operation status.", serviceInstance.ServiceInstanceFields.Name) 226 227 Expect(ui.Outputs()).To(ContainSubstrings( 228 []string{"Creating service instance", "my-cleardb-service", "my-org", "my-space", "my-user"}, 229 []string{"OK"}, 230 []string{creatingServiceMessage}, 231 )) 232 name, planGUID, _, _ := serviceRepo.CreateServiceInstanceArgsForCall(0) 233 Expect(name).To(Equal("my-cleardb-service")) 234 Expect(planGUID).To(Equal("cleardb-spark-guid")) 235 }) 236 237 It("fails when service instance could is created but cannot be found", func() { 238 serviceRepo.FindInstanceByNameReturns(models.ServiceInstance{}, errors.New("Error finding instance")) 239 callCreateService([]string{"cleardb", "spark", "fake-service-instance-name"}) 240 241 Expect(ui.Outputs()).To(ContainSubstrings( 242 []string{"Creating service instance fake-service-instance-name in org my-org / space my-space as my-user..."}, 243 []string{"FAILED"}, 244 []string{"Error finding instance"})) 245 }) 246 }) 247 248 Describe("warning the user about paid services", func() { 249 It("does not warn the user when the service is free", func() { 250 callCreateService([]string{"cleardb", "spark", "my-free-cleardb-service"}) 251 Expect(ui.Outputs()).To(ContainSubstrings( 252 []string{"Creating service instance", "my-free-cleardb-service", "my-org", "my-space", "my-user"}, 253 []string{"OK"}, 254 )) 255 Expect(ui.Outputs()).NotTo(ContainSubstrings([]string{"will incurr a cost"})) 256 }) 257 258 It("warns the user when the service is not free", func() { 259 callCreateService([]string{"cleardb", "expensive", "my-expensive-cleardb-service"}) 260 Expect(ui.Outputs()).To(ContainSubstrings( 261 []string{"Creating service instance", "my-expensive-cleardb-service", "my-org", "my-space", "my-user"}, 262 []string{"OK"}, 263 []string{"Attention: The plan `expensive` of service `cleardb` is not free. The instance `my-expensive-cleardb-service` will incur a cost. Contact your administrator if you think this is in error."}, 264 )) 265 }) 266 }) 267 268 It("warns the user when the service already exists with the same service plan", func() { 269 serviceRepo.CreateServiceInstanceReturns(errors.NewModelAlreadyExistsError("Service", "my-cleardb-service")) 270 271 callCreateService([]string{"cleardb", "spark", "my-cleardb-service"}) 272 273 Expect(ui.Outputs()).To(ContainSubstrings( 274 []string{"Creating service instance", "my-cleardb-service"}, 275 []string{"OK"}, 276 []string{"my-cleardb-service", "already exists"}, 277 )) 278 279 name, planGUID, _, _ := serviceRepo.CreateServiceInstanceArgsForCall(0) 280 Expect(name).To(Equal("my-cleardb-service")) 281 Expect(planGUID).To(Equal("cleardb-spark-guid")) 282 }) 283 284 Context("When there are multiple services with the same label", func() { 285 It("finds the plan even if it has to search multiple services", func() { 286 offering2.Label = "cleardb" 287 288 serviceRepo.CreateServiceInstanceReturns(errors.NewModelAlreadyExistsError("Service", "my-cleardb-service")) 289 callCreateService([]string{"cleardb", "spark", "my-cleardb-service"}) 290 291 Expect(ui.Outputs()).To(ContainSubstrings( 292 []string{"Creating service instance", "my-cleardb-service", "my-org", "my-space", "my-user"}, 293 []string{"OK"}, 294 )) 295 296 name, planGUID, _, _ := serviceRepo.CreateServiceInstanceArgsForCall(0) 297 Expect(name).To(Equal("my-cleardb-service")) 298 Expect(planGUID).To(Equal("cleardb-spark-guid")) 299 }) 300 }) 301 })