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  })