github.com/rakutentech/cli@v6.12.5-0.20151006231303-24468b65536e+incompatible/cf/commands/service/update_service_test.go (about) 1 package service_test 2 3 import ( 4 "errors" 5 "io/ioutil" 6 "os" 7 8 testplanbuilder "github.com/cloudfoundry/cli/cf/actors/plan_builder/fakes" 9 testapi "github.com/cloudfoundry/cli/cf/api/fakes" 10 "github.com/cloudfoundry/cli/cf/command_registry" 11 "github.com/cloudfoundry/cli/cf/configuration/core_config" 12 "github.com/cloudfoundry/cli/cf/models" 13 testcmd "github.com/cloudfoundry/cli/testhelpers/commands" 14 testconfig "github.com/cloudfoundry/cli/testhelpers/configuration" 15 testreq "github.com/cloudfoundry/cli/testhelpers/requirements" 16 testterm "github.com/cloudfoundry/cli/testhelpers/terminal" 17 . "github.com/onsi/ginkgo" 18 . "github.com/onsi/gomega" 19 20 . "github.com/cloudfoundry/cli/testhelpers/matchers" 21 ) 22 23 var _ = Describe("update-service command", func() { 24 var ( 25 ui *testterm.FakeUI 26 config core_config.Repository 27 requirementsFactory *testreq.FakeReqFactory 28 serviceRepo *testapi.FakeServiceRepo 29 planBuilder *testplanbuilder.FakePlanBuilder 30 offering1 models.ServiceOffering 31 deps command_registry.Dependency 32 ) 33 34 updateCommandDependency := func(pluginCall bool) { 35 deps.Ui = ui 36 deps.RepoLocator = deps.RepoLocator.SetServiceRepository(serviceRepo) 37 deps.Config = config 38 deps.PlanBuilder = planBuilder 39 command_registry.Commands.SetCommand(command_registry.Commands.FindCommand("update-service").SetDependency(deps, pluginCall)) 40 } 41 42 BeforeEach(func() { 43 ui = &testterm.FakeUI{} 44 config = testconfig.NewRepositoryWithDefaults() 45 config.SetApiVersion("2.26.0") 46 requirementsFactory = &testreq.FakeReqFactory{LoginSuccess: true, TargetedSpaceSuccess: true} 47 serviceRepo = &testapi.FakeServiceRepo{} 48 planBuilder = &testplanbuilder.FakePlanBuilder{} 49 50 offering1 = models.ServiceOffering{} 51 offering1.Label = "cleardb" 52 offering1.Plans = []models.ServicePlanFields{{ 53 Name: "spark", 54 Guid: "cleardb-spark-guid", 55 }, { 56 Name: "flare", 57 Guid: "cleardb-flare-guid", 58 }, 59 } 60 61 }) 62 63 var callUpdateService = func(args []string) bool { 64 return testcmd.RunCliCommand("update-service", args, requirementsFactory, updateCommandDependency, false) 65 } 66 67 Describe("requirements", func() { 68 It("passes when logged in and a space is targeted", func() { 69 Expect(callUpdateService([]string{"cleardb"})).To(BeTrue()) 70 }) 71 72 It("fails with usage when not provided exactly one arg", func() { 73 Expect(callUpdateService([]string{})).To(BeFalse()) 74 }) 75 76 It("fails when not logged in", func() { 77 requirementsFactory.LoginSuccess = false 78 Expect(callUpdateService([]string{"cleardb", "spark", "my-cleardb-service"})).To(BeFalse()) 79 }) 80 81 It("fails when a space is not targeted", func() { 82 requirementsFactory.TargetedSpaceSuccess = false 83 Expect(callUpdateService([]string{"cleardb", "spark", "my-cleardb-service"})).To(BeFalse()) 84 }) 85 }) 86 87 Context("when no flags are passed", func() { 88 89 Context("when the instance exists", func() { 90 It("prints a user indicating it is a no-op", func() { 91 callUpdateService([]string{"my-service"}) 92 93 Expect(ui.Outputs).To(ContainSubstrings( 94 []string{"OK"}, 95 []string{"No changes were made"}, 96 )) 97 }) 98 }) 99 }) 100 101 Context("when passing arbitrary params", func() { 102 BeforeEach(func() { 103 serviceInstance := models.ServiceInstance{ 104 ServiceInstanceFields: models.ServiceInstanceFields{ 105 Name: "my-service-instance", 106 Guid: "my-service-instance-guid", 107 LastOperation: models.LastOperationFields{ 108 Type: "update", 109 State: "in progress", 110 Description: "fake service instance description", 111 }, 112 }, 113 ServiceOffering: models.ServiceOfferingFields{ 114 Label: "murkydb", 115 Guid: "murkydb-guid", 116 }, 117 } 118 119 servicePlans := []models.ServicePlanFields{{ 120 Name: "spark", 121 Guid: "murkydb-spark-guid", 122 }, { 123 Name: "flare", 124 Guid: "murkydb-flare-guid", 125 }, 126 } 127 serviceRepo.FindInstanceByNameServiceInstance = serviceInstance 128 planBuilder.GetPlansForServiceForOrgReturns(servicePlans, nil) 129 }) 130 131 Context("as a json string", func() { 132 It("successfully updates a service", func() { 133 callUpdateService([]string{"-p", "flare", "-c", `{"foo": "bar"}`, "my-service-instance"}) 134 135 Expect(ui.Outputs).To(ContainSubstrings( 136 []string{"Updating service", "my-service", "as", "my-user", "..."}, 137 []string{"OK"}, 138 []string{"Update in progress. Use 'cf services' or 'cf service my-service-instance' to check operation status."}, 139 )) 140 Expect(serviceRepo.FindInstanceByNameName).To(Equal("my-service-instance")) 141 Expect(serviceRepo.UpdateServiceInstanceArgs.InstanceGuid).To(Equal("my-service-instance-guid")) 142 Expect(serviceRepo.UpdateServiceInstanceArgs.PlanGuid).To(Equal("murkydb-flare-guid")) 143 Expect(serviceRepo.UpdateServiceInstanceArgs.Params).To(Equal(map[string]interface{}{"foo": "bar"})) 144 }) 145 146 Context("that are not valid json", func() { 147 It("returns an error to the UI", func() { 148 callUpdateService([]string{"-p", "flare", "-c", `bad-json`, "my-service-instance"}) 149 150 Expect(ui.Outputs).To(ContainSubstrings( 151 []string{"FAILED"}, 152 []string{"Invalid configuration provided for -c flag. Please provide a valid JSON object or path to a file containing a valid JSON object."}, 153 )) 154 }) 155 }) 156 }) 157 158 Context("as a file that contains json", func() { 159 var jsonFile *os.File 160 var params string 161 162 BeforeEach(func() { 163 params = "{\"foo\": \"bar\"}" 164 }) 165 166 AfterEach(func() { 167 if jsonFile != nil { 168 jsonFile.Close() 169 os.Remove(jsonFile.Name()) 170 } 171 }) 172 173 JustBeforeEach(func() { 174 var err error 175 jsonFile, err = ioutil.TempFile("", "") 176 Expect(err).ToNot(HaveOccurred()) 177 178 err = ioutil.WriteFile(jsonFile.Name(), []byte(params), os.ModePerm) 179 Expect(err).NotTo(HaveOccurred()) 180 }) 181 182 It("successfully updates a service and passes the params as a json", func() { 183 callUpdateService([]string{"-p", "flare", "-c", jsonFile.Name(), "my-service-instance"}) 184 185 Expect(ui.Outputs).To(ContainSubstrings( 186 []string{"Updating service", "my-service", "as", "my-user", "..."}, 187 []string{"OK"}, 188 []string{"Update in progress. Use 'cf services' or 'cf service my-service-instance' to check operation status."}, 189 )) 190 Expect(serviceRepo.FindInstanceByNameName).To(Equal("my-service-instance")) 191 Expect(serviceRepo.UpdateServiceInstanceArgs.InstanceGuid).To(Equal("my-service-instance-guid")) 192 Expect(serviceRepo.UpdateServiceInstanceArgs.PlanGuid).To(Equal("murkydb-flare-guid")) 193 Expect(serviceRepo.UpdateServiceInstanceArgs.Params).To(Equal(map[string]interface{}{"foo": "bar"})) 194 }) 195 196 Context("that are not valid json", func() { 197 BeforeEach(func() { 198 params = "bad-json" 199 }) 200 201 It("returns an error to the UI", func() { 202 callUpdateService([]string{"-p", "flare", "-c", jsonFile.Name(), "my-service-instance"}) 203 204 Expect(ui.Outputs).To(ContainSubstrings( 205 []string{"FAILED"}, 206 []string{"Invalid configuration provided for -c flag. Please provide a valid JSON object or path to a file containing a valid JSON object."}, 207 )) 208 }) 209 }) 210 }) 211 }) 212 213 Context("when passing in tags", func() { 214 It("successfully updates a service and passes the tags as json", func() { 215 callUpdateService([]string{"-t", "tag1, tag2,tag3, tag4", "my-service-instance"}) 216 217 Expect(ui.Outputs).To(ContainSubstrings( 218 []string{"Updating service instance", "my-service-instance"}, 219 []string{"OK"}, 220 )) 221 Expect(serviceRepo.UpdateServiceInstanceArgs.Tags).To(ConsistOf("tag1", "tag2", "tag3", "tag4")) 222 }) 223 224 It("successfully updates a service and passes the tags as json", func() { 225 callUpdateService([]string{"-t", "tag1", "my-service-instance"}) 226 227 Expect(ui.Outputs).To(ContainSubstrings( 228 []string{"Updating service instance", "my-service-instance"}, 229 []string{"OK"}, 230 )) 231 Expect(serviceRepo.UpdateServiceInstanceArgs.Tags).To(ConsistOf("tag1")) 232 }) 233 234 Context("and the tags string is passed with an empty string", func() { 235 It("successfully updates the service", func() { 236 callUpdateService([]string{"-t", "", "my-service-instance"}) 237 238 Expect(ui.Outputs).To(ContainSubstrings( 239 []string{"Updating service instance", "my-service-instance"}, 240 []string{"OK"}, 241 )) 242 Expect(serviceRepo.UpdateServiceInstanceArgs.Tags).To(Equal([]string{})) 243 }) 244 }) 245 }) 246 247 Context("when service update is asynchronous", func() { 248 Context("when the plan flag is passed", func() { 249 BeforeEach(func() { 250 serviceInstance := models.ServiceInstance{ 251 ServiceInstanceFields: models.ServiceInstanceFields{ 252 Name: "my-service-instance", 253 Guid: "my-service-instance-guid", 254 LastOperation: models.LastOperationFields{ 255 Type: "update", 256 State: "in progress", 257 Description: "fake service instance description", 258 }, 259 }, 260 ServiceOffering: models.ServiceOfferingFields{ 261 Label: "murkydb", 262 Guid: "murkydb-guid", 263 }, 264 } 265 266 servicePlans := []models.ServicePlanFields{{ 267 Name: "spark", 268 Guid: "murkydb-spark-guid", 269 }, { 270 Name: "flare", 271 Guid: "murkydb-flare-guid", 272 }, 273 } 274 serviceRepo.FindInstanceByNameServiceInstance = serviceInstance 275 planBuilder.GetPlansForServiceForOrgReturns(servicePlans, nil) 276 }) 277 278 It("successfully updates a service", func() { 279 callUpdateService([]string{"-p", "flare", "my-service-instance"}) 280 281 Expect(ui.Outputs).To(ContainSubstrings( 282 []string{"Updating service", "my-service", "as", "my-user", "..."}, 283 []string{"OK"}, 284 []string{"Update in progress. Use 'cf services' or 'cf service my-service-instance' to check operation status."}, 285 )) 286 Expect(serviceRepo.FindInstanceByNameName).To(Equal("my-service-instance")) 287 Expect(serviceRepo.UpdateServiceInstanceArgs.InstanceGuid).To(Equal("my-service-instance-guid")) 288 Expect(serviceRepo.UpdateServiceInstanceArgs.PlanGuid).To(Equal("murkydb-flare-guid")) 289 }) 290 291 Context("and the CC API Version >= 2.16.0", func() { 292 BeforeEach(func() { 293 config.SetApiVersion("2.16.0") 294 }) 295 296 It("successfully updates a service", func() { 297 callUpdateService([]string{"-p", "flare", "my-service-instance"}) 298 299 Expect(ui.Outputs).To(ContainSubstrings( 300 []string{"Updating service", "my-service", "as", "my-user", "..."}, 301 []string{"OK"}, 302 []string{"Update in progress. Use 'cf services' or 'cf service my-service-instance' to check operation status."}, 303 )) 304 Expect(serviceRepo.FindInstanceByNameName).To(Equal("my-service-instance")) 305 Expect(serviceRepo.UpdateServiceInstanceArgs.InstanceGuid).To(Equal("my-service-instance-guid")) 306 Expect(serviceRepo.UpdateServiceInstanceArgs.PlanGuid).To(Equal("murkydb-flare-guid")) 307 }) 308 309 Context("when there is an err finding the instance", func() { 310 It("returns an error", func() { 311 serviceRepo.FindInstanceByNameErr = true 312 313 callUpdateService([]string{"-p", "flare", "some-stupid-not-real-instance"}) 314 315 Expect(ui.Outputs).To(ContainSubstrings( 316 []string{"Error finding instance"}, 317 []string{"FAILED"}, 318 )) 319 }) 320 }) 321 Context("when there is an err finding service plans", func() { 322 It("returns an error", func() { 323 planBuilder.GetPlansForServiceForOrgReturns(nil, errors.New("Error fetching plans")) 324 325 callUpdateService([]string{"-p", "flare", "some-stupid-not-real-instance"}) 326 327 Expect(ui.Outputs).To(ContainSubstrings( 328 []string{"Error fetching plans"}, 329 []string{"FAILED"}, 330 )) 331 }) 332 }) 333 Context("when the plan specified does not exist in the service offering", func() { 334 It("returns an error", func() { 335 callUpdateService([]string{"-p", "not-a-real-plan", "instance-without-service-offering"}) 336 337 Expect(ui.Outputs).To(ContainSubstrings( 338 []string{"Plan does not exist for the murkydb service"}, 339 []string{"FAILED"}, 340 )) 341 }) 342 }) 343 Context("when there is an error updating the service instance", func() { 344 It("returns an error", func() { 345 serviceRepo.UpdateServiceInstanceReturnsErr = true 346 callUpdateService([]string{"-p", "flare", "my-service-instance"}) 347 348 Expect(ui.Outputs).To(ContainSubstrings( 349 []string{"Error updating service instance"}, 350 []string{"FAILED"}, 351 )) 352 }) 353 }) 354 }) 355 356 Context("and the CC API Version < 2.16.0", func() { 357 BeforeEach(func() { 358 config.SetApiVersion("2.15.0") 359 }) 360 361 It("returns an error", func() { 362 callUpdateService([]string{"-p", "flare", "instance-without-service-offering"}) 363 364 Expect(ui.Outputs).To(ContainSubstrings( 365 []string{"FAILED"}, 366 []string{"Updating a plan requires API v2.16.0 or newer. Your current target is v2.15.0."}, 367 )) 368 }) 369 }) 370 }) 371 }) 372 373 Context("when service update is synchronous", func() { 374 Context("when the plan flag is passed", func() { 375 BeforeEach(func() { 376 serviceInstance := models.ServiceInstance{ 377 ServiceInstanceFields: models.ServiceInstanceFields{ 378 Name: "my-service-instance", 379 Guid: "my-service-instance-guid", 380 }, 381 ServiceOffering: models.ServiceOfferingFields{ 382 Label: "murkydb", 383 Guid: "murkydb-guid", 384 }, 385 } 386 387 servicePlans := []models.ServicePlanFields{{ 388 Name: "spark", 389 Guid: "murkydb-spark-guid", 390 }, { 391 Name: "flare", 392 Guid: "murkydb-flare-guid", 393 }, 394 } 395 serviceRepo.FindInstanceByNameServiceInstance = serviceInstance 396 planBuilder.GetPlansForServiceForOrgReturns(servicePlans, nil) 397 398 }) 399 It("successfully updates a service", func() { 400 callUpdateService([]string{"-p", "flare", "my-service-instance"}) 401 402 Expect(ui.Outputs).To(ContainSubstrings( 403 []string{"Updating service", "my-service", "as", "my-user", "..."}, 404 []string{"OK"}, 405 )) 406 Expect(serviceRepo.FindInstanceByNameName).To(Equal("my-service-instance")) 407 serviceGuid, orgName := planBuilder.GetPlansForServiceForOrgArgsForCall(0) 408 Expect(serviceGuid).To(Equal("murkydb-guid")) 409 Expect(orgName).To(Equal("my-org")) 410 Expect(serviceRepo.UpdateServiceInstanceArgs.InstanceGuid).To(Equal("my-service-instance-guid")) 411 Expect(serviceRepo.UpdateServiceInstanceArgs.PlanGuid).To(Equal("murkydb-flare-guid")) 412 }) 413 414 Context("when there is an err finding the instance", func() { 415 It("returns an error", func() { 416 serviceRepo.FindInstanceByNameErr = true 417 418 callUpdateService([]string{"-p", "flare", "some-stupid-not-real-instance"}) 419 420 Expect(ui.Outputs).To(ContainSubstrings( 421 []string{"Error finding instance"}, 422 []string{"FAILED"}, 423 )) 424 }) 425 }) 426 Context("when there is an err finding service plans", func() { 427 It("returns an error", func() { 428 planBuilder.GetPlansForServiceForOrgReturns(nil, errors.New("Error fetching plans")) 429 430 callUpdateService([]string{"-p", "flare", "some-stupid-not-real-instance"}) 431 432 Expect(ui.Outputs).To(ContainSubstrings( 433 []string{"Error fetching plans"}, 434 []string{"FAILED"}, 435 )) 436 }) 437 }) 438 Context("when the plan specified does not exist in the service offering", func() { 439 It("returns an error", func() { 440 callUpdateService([]string{"-p", "not-a-real-plan", "instance-without-service-offering"}) 441 442 Expect(ui.Outputs).To(ContainSubstrings( 443 []string{"Plan does not exist for the murkydb service"}, 444 []string{"FAILED"}, 445 )) 446 }) 447 }) 448 Context("when there is an error updating the service instance", func() { 449 It("returns an error", func() { 450 serviceRepo.UpdateServiceInstanceReturnsErr = true 451 callUpdateService([]string{"-p", "flare", "my-service-instance"}) 452 453 Expect(ui.Outputs).To(ContainSubstrings( 454 []string{"Error updating service instance"}, 455 []string{"FAILED"}, 456 )) 457 }) 458 }) 459 }) 460 461 }) 462 })