github.com/loggregator/cli@v6.33.1-0.20180224010324-82334f081791+incompatible/cf/commands/service/migrate_service_instances_test.go (about) 1 package service_test 2 3 import ( 4 "code.cloudfoundry.org/cli/cf/api/apifakes" 5 "code.cloudfoundry.org/cli/cf/api/resources" 6 "code.cloudfoundry.org/cli/cf/commandregistry" 7 "code.cloudfoundry.org/cli/cf/configuration/coreconfig" 8 "code.cloudfoundry.org/cli/cf/errors" 9 "code.cloudfoundry.org/cli/cf/requirements" 10 "code.cloudfoundry.org/cli/cf/requirements/requirementsfakes" 11 testcmd "code.cloudfoundry.org/cli/util/testhelpers/commands" 12 testconfig "code.cloudfoundry.org/cli/util/testhelpers/configuration" 13 testterm "code.cloudfoundry.org/cli/util/testhelpers/terminal" 14 . "github.com/onsi/ginkgo" 15 . "github.com/onsi/gomega" 16 17 . "code.cloudfoundry.org/cli/util/testhelpers/matchers" 18 ) 19 20 var _ = Describe("migrating service instances from v1 to v2", func() { 21 var ( 22 ui *testterm.FakeUI 23 serviceRepo *apifakes.FakeServiceRepository 24 config coreconfig.Repository 25 requirementsFactory *requirementsfakes.FakeFactory 26 args []string 27 deps commandregistry.Dependency 28 ) 29 30 updateCommandDependency := func(pluginCall bool) { 31 deps.UI = ui 32 deps.RepoLocator = deps.RepoLocator.SetServiceRepository(serviceRepo) 33 deps.Config = config 34 commandregistry.Commands.SetCommand(commandregistry.Commands.FindCommand("migrate-service-instances").SetDependency(deps, pluginCall)) 35 } 36 37 BeforeEach(func() { 38 ui = &testterm.FakeUI{} 39 config = testconfig.NewRepository() 40 serviceRepo = new(apifakes.FakeServiceRepository) 41 requirementsFactory = new(requirementsfakes.FakeFactory) 42 requirementsFactory.NewLoginRequirementReturns(requirements.Failing{Message: "not logged in"}) 43 args = []string{} 44 }) 45 46 Describe("requirements", func() { 47 It("requires you to be logged in", func() { 48 Expect(testcmd.RunCLICommand("migrate-service-instances", args, requirementsFactory, updateCommandDependency, false, ui)).To(BeFalse()) 49 }) 50 51 It("requires five arguments to run", func() { 52 args = []string{"one", "two", "three"} 53 54 Expect(testcmd.RunCLICommand("migrate-service-instances", args, requirementsFactory, updateCommandDependency, false, ui)).To(BeFalse()) 55 }) 56 57 It("requires CC API version 2.47 or lower", func() { 58 requirementsFactory.NewMaxAPIVersionRequirementReturns(requirements.Failing{Message: "max api version not met"}) 59 requirementsFactory.NewLoginRequirementReturns(requirements.Passing{}) 60 args = []string{"one", "two", "three", "four", "five"} 61 ui.Inputs = append(ui.Inputs, "no") 62 63 Expect(testcmd.RunCLICommand("migrate-service-instances", args, requirementsFactory, updateCommandDependency, false, ui)).To(BeFalse()) 64 }) 65 66 It("passes requirements if user is logged in and provided five args to run", func() { 67 requirementsFactory.NewMaxAPIVersionRequirementReturns(requirements.Passing{}) 68 requirementsFactory.NewLoginRequirementReturns(requirements.Passing{}) 69 args = []string{"one", "two", "three", "four", "five"} 70 ui.Inputs = append(ui.Inputs, "no") 71 serviceRepo.GetServiceInstanceCountForServicePlanReturns(1, nil) 72 73 Expect(testcmd.RunCLICommand("migrate-service-instances", args, requirementsFactory, updateCommandDependency, false, ui)).To(BeTrue()) 74 }) 75 }) 76 77 Describe("migrating service instances", func() { 78 BeforeEach(func() { 79 requirementsFactory.NewMaxAPIVersionRequirementReturns(requirements.Passing{}) 80 requirementsFactory.NewLoginRequirementReturns(requirements.Passing{}) 81 args = []string{"v1-service-label", "v1-provider-name", "v1-plan-name", "v2-service-label", "v2-plan-name"} 82 serviceRepo.GetServiceInstanceCountForServicePlanReturns(1, nil) 83 }) 84 85 It("displays the warning and the prompt including info about the instances and plan to migrate", func() { 86 ui.Inputs = []string{""} 87 testcmd.RunCLICommand("migrate-service-instances", args, requirementsFactory, updateCommandDependency, false, ui) 88 89 Expect(ui.Outputs()).To(ContainSubstrings([]string{"WARNING:", "this operation is to replace a service broker"})) 90 Expect(ui.Prompts).To(ContainSubstrings( 91 []string{"Really migrate", "1 service instance", 92 "from plan", "v1-service-label", "v1-provider-name", "v1-plan-name", 93 "to", "v2-service-label", "v2-plan-name"}, 94 )) 95 }) 96 97 Context("when the user confirms", func() { 98 BeforeEach(func() { 99 ui.Inputs = []string{"yes"} 100 }) 101 102 Context("when the v1 and v2 service instances exists", func() { 103 BeforeEach(func() { 104 var findServicePlanByDescriptionCallCount int 105 serviceRepo.FindServicePlanByDescriptionStub = func(planDescription resources.ServicePlanDescription) (string, error) { 106 findServicePlanByDescriptionCallCount++ 107 if findServicePlanByDescriptionCallCount == 1 { 108 return "v1-guid", nil 109 } 110 return "v2-guid", nil 111 } 112 113 serviceRepo.MigrateServicePlanFromV1ToV2Returns(1, nil) 114 }) 115 116 It("makes a request to migrate the v1 service instance", func() { 117 testcmd.RunCLICommand("migrate-service-instances", args, requirementsFactory, updateCommandDependency, false, ui) 118 119 v1PlanGUID, v2PlanGUID := serviceRepo.MigrateServicePlanFromV1ToV2ArgsForCall(0) 120 Expect(v1PlanGUID).To(Equal("v1-guid")) 121 Expect(v2PlanGUID).To(Equal("v2-guid")) 122 }) 123 124 It("finds the v1 service plan by its name, provider and service label", func() { 125 testcmd.RunCLICommand("migrate-service-instances", args, requirementsFactory, updateCommandDependency, false, ui) 126 127 expectedV1 := resources.ServicePlanDescription{ 128 ServicePlanName: "v1-plan-name", 129 ServiceProvider: "v1-provider-name", 130 ServiceLabel: "v1-service-label", 131 } 132 Expect(serviceRepo.FindServicePlanByDescriptionArgsForCall(0)).To(Equal(expectedV1)) 133 }) 134 135 It("finds the v2 service plan by its name and service label", func() { 136 testcmd.RunCLICommand("migrate-service-instances", args, requirementsFactory, updateCommandDependency, false, ui) 137 138 expectedV2 := resources.ServicePlanDescription{ 139 ServicePlanName: "v2-plan-name", 140 ServiceLabel: "v2-service-label", 141 } 142 Expect(serviceRepo.FindServicePlanByDescriptionArgsForCall(1)).To(Equal(expectedV2)) 143 }) 144 145 It("notifies the user that the migration was successful", func() { 146 serviceRepo.GetServiceInstanceCountForServicePlanReturns(2, nil) 147 testcmd.RunCLICommand("migrate-service-instances", args, requirementsFactory, updateCommandDependency, false, ui) 148 149 Expect(ui.Outputs()).To(ContainSubstrings( 150 []string{"Attempting to migrate", "2", "service instances"}, 151 []string{"1", "service instance", "migrated"}, 152 []string{"OK"}, 153 )) 154 }) 155 }) 156 157 Context("when finding the v1 plan fails", func() { 158 Context("because the plan does not exist", func() { 159 BeforeEach(func() { 160 serviceRepo.FindServicePlanByDescriptionReturns("", errors.NewModelNotFoundError("Service Plan", "")) 161 }) 162 163 It("notifies the user of the failure", func() { 164 testcmd.RunCLICommand("migrate-service-instances", args, requirementsFactory, updateCommandDependency, false, ui) 165 166 Expect(ui.Outputs()).To(ContainSubstrings( 167 []string{"FAILED"}, 168 []string{"Plan", "v1-service-label", "v1-provider-name", "v1-plan-name", "cannot be found"}, 169 )) 170 }) 171 172 It("does not display the warning", func() { 173 testcmd.RunCLICommand("migrate-service-instances", args, requirementsFactory, updateCommandDependency, false, ui) 174 175 Expect(ui.Outputs()).ToNot(ContainSubstrings([]string{"WARNING:", "this operation is to replace a service broker"})) 176 }) 177 }) 178 179 Context("because there was an http error", func() { 180 BeforeEach(func() { 181 serviceRepo.FindServicePlanByDescriptionReturns("", errors.New("uh oh")) 182 }) 183 184 It("notifies the user of the failure", func() { 185 testcmd.RunCLICommand("migrate-service-instances", args, requirementsFactory, updateCommandDependency, false, ui) 186 187 Expect(ui.Outputs()).To(ContainSubstrings( 188 []string{"FAILED"}, 189 []string{"uh oh"}, 190 )) 191 }) 192 193 It("does not display the warning", func() { 194 testcmd.RunCLICommand("migrate-service-instances", args, requirementsFactory, updateCommandDependency, false, ui) 195 196 Expect(ui.Outputs()).ToNot(ContainSubstrings([]string{"WARNING:", "this operation is to replace a service broker"})) 197 }) 198 }) 199 }) 200 201 Context("when finding the v2 plan fails", func() { 202 Context("because the plan does not exist", func() { 203 BeforeEach(func() { 204 var findServicePlanByDescriptionCallCount int 205 serviceRepo.FindServicePlanByDescriptionStub = func(planDescription resources.ServicePlanDescription) (string, error) { 206 findServicePlanByDescriptionCallCount++ 207 if findServicePlanByDescriptionCallCount == 1 { 208 return "", nil 209 } 210 return "", errors.NewModelNotFoundError("Service Plan", "") 211 } 212 }) 213 214 It("notifies the user of the failure", func() { 215 testcmd.RunCLICommand("migrate-service-instances", args, requirementsFactory, updateCommandDependency, false, ui) 216 217 Expect(ui.Outputs()).To(ContainSubstrings( 218 []string{"FAILED"}, 219 []string{"Plan", "v2-service-label", "v2-plan-name", "cannot be found"}, 220 )) 221 }) 222 223 It("does not display the warning", func() { 224 testcmd.RunCLICommand("migrate-service-instances", args, requirementsFactory, updateCommandDependency, false, ui) 225 226 Expect(ui.Outputs()).ToNot(ContainSubstrings([]string{"WARNING:", "this operation is to replace a service broker"})) 227 }) 228 }) 229 230 Context("because there was an http error", func() { 231 BeforeEach(func() { 232 serviceRepo.FindServicePlanByDescriptionReturns("", errors.New("uh oh")) 233 }) 234 235 It("notifies the user of the failure", func() { 236 testcmd.RunCLICommand("migrate-service-instances", args, requirementsFactory, updateCommandDependency, false, ui) 237 238 Expect(ui.Outputs()).To(ContainSubstrings( 239 []string{"FAILED"}, 240 []string{"uh oh"}, 241 )) 242 }) 243 244 It("does not display the warning", func() { 245 testcmd.RunCLICommand("migrate-service-instances", args, requirementsFactory, updateCommandDependency, false, ui) 246 247 Expect(ui.Outputs()).ToNot(ContainSubstrings([]string{"WARNING:", "this operation is to replace a service broker"})) 248 }) 249 }) 250 }) 251 252 Context("when migrating the plans fails", func() { 253 BeforeEach(func() { 254 serviceRepo.MigrateServicePlanFromV1ToV2Returns(0, errors.New("ruh roh")) 255 }) 256 257 It("notifies the user of the failure", func() { 258 testcmd.RunCLICommand("migrate-service-instances", args, requirementsFactory, updateCommandDependency, false, ui) 259 260 Expect(ui.Outputs()).To(ContainSubstrings( 261 []string{"FAILED"}, 262 []string{"ruh roh"}, 263 )) 264 }) 265 }) 266 267 Context("when there are no instances to migrate", func() { 268 BeforeEach(func() { 269 var findServicePlanByDescriptionCallCount int 270 serviceRepo.FindServicePlanByDescriptionStub = func(planDescription resources.ServicePlanDescription) (string, error) { 271 findServicePlanByDescriptionCallCount++ 272 if findServicePlanByDescriptionCallCount == 1 { 273 return "v1-guid", nil 274 } 275 return "v2-guid", nil 276 } 277 serviceRepo.GetServiceInstanceCountForServicePlanReturns(0, nil) 278 }) 279 280 It("returns a meaningful error", func() { 281 testcmd.RunCLICommand("migrate-service-instances", args, requirementsFactory, updateCommandDependency, false, ui) 282 283 Expect(ui.Outputs()).To(ContainSubstrings( 284 []string{"FAILED"}, 285 []string{"no service instances to migrate"}, 286 )) 287 }) 288 289 It("does not show the user the warning", func() { 290 testcmd.RunCLICommand("migrate-service-instances", args, requirementsFactory, updateCommandDependency, false, ui) 291 292 Expect(ui.Outputs()).ToNot(ContainSubstrings([]string{"WARNING:", "this operation is to replace a service broker"})) 293 }) 294 }) 295 296 Context("when it cannot fetch the number of instances", func() { 297 BeforeEach(func() { 298 serviceRepo.GetServiceInstanceCountForServicePlanReturns(0, errors.New("service instance fetch is very bad")) 299 }) 300 301 It("notifies the user of the failure", func() { 302 testcmd.RunCLICommand("migrate-service-instances", args, requirementsFactory, updateCommandDependency, false, ui) 303 304 Expect(ui.Outputs()).To(ContainSubstrings( 305 []string{"FAILED"}, 306 []string{"service instance fetch is very bad"}, 307 )) 308 }) 309 }) 310 }) 311 312 Context("when the user does not confirm", func() { 313 BeforeEach(func() { 314 ui.Inputs = append(ui.Inputs, "no") 315 }) 316 317 It("does not continue the migration", func() { 318 testcmd.RunCLICommand("migrate-service-instances", args, requirementsFactory, updateCommandDependency, false, ui) 319 320 Expect(ui.Outputs()).ToNot(ContainSubstrings([]string{"Migrating"})) 321 Expect(serviceRepo.MigrateServicePlanFromV1ToV2CallCount()).To(BeZero()) 322 }) 323 }) 324 325 Context("when the user ignores confirmation using the force flag", func() { 326 It("does not prompt the user for confirmation", func() { 327 args = []string{"-f", "v1-service-label", "v1-provider-name", "v1-plan-name", "v2-service-label", "v2-plan-name"} 328 329 testcmd.RunCLICommand("migrate-service-instances", args, requirementsFactory, updateCommandDependency, false, ui) 330 331 Expect(ui.Outputs()).ToNot(ContainSubstrings([]string{"Really migrate"})) 332 Expect(serviceRepo.MigrateServicePlanFromV1ToV2CallCount()).To(Equal(1)) 333 }) 334 }) 335 }) 336 })