github.com/mook-as/cf-cli@v7.0.0-beta.28.0.20200120190804-b91c115fae48+incompatible/cf/commands/service/bind_route_service_test.go (about) 1 package service_test 2 3 import ( 4 "io/ioutil" 5 "net/http" 6 "os" 7 8 "code.cloudfoundry.org/cli/cf/commandregistry" 9 "code.cloudfoundry.org/cli/cf/commands/service" 10 "code.cloudfoundry.org/cli/cf/configuration/coreconfig" 11 "code.cloudfoundry.org/cli/cf/errors" 12 "code.cloudfoundry.org/cli/cf/flags" 13 "code.cloudfoundry.org/cli/cf/models" 14 "code.cloudfoundry.org/cli/cf/requirements" 15 "code.cloudfoundry.org/cli/cf/requirements/requirementsfakes" 16 17 "code.cloudfoundry.org/cli/cf/api/apifakes" 18 testconfig "code.cloudfoundry.org/cli/cf/util/testhelpers/configuration" 19 testterm "code.cloudfoundry.org/cli/cf/util/testhelpers/terminal" 20 21 . "code.cloudfoundry.org/cli/cf/util/testhelpers/matchers" 22 . "github.com/onsi/ginkgo" 23 . "github.com/onsi/gomega" 24 ) 25 26 var _ = Describe("BindRouteService", func() { 27 var ( 28 ui *testterm.FakeUI 29 configRepo coreconfig.Repository 30 routeRepo *apifakes.FakeRouteRepository 31 routeServiceBindingRepo *apifakes.FakeRouteServiceBindingRepository 32 33 cmd commandregistry.Command 34 deps commandregistry.Dependency 35 factory *requirementsfakes.FakeFactory 36 flagContext flags.FlagContext 37 38 fakeDomain models.DomainFields 39 40 loginRequirement requirements.Requirement 41 targetRequirement requirements.Requirement 42 domainRequirement *requirementsfakes.FakeDomainRequirement 43 serviceInstanceRequirement *requirementsfakes.FakeServiceInstanceRequirement 44 minAPIVersionRequirement requirements.Requirement 45 ) 46 47 BeforeEach(func() { 48 ui = new(testterm.FakeUI) 49 50 configRepo = testconfig.NewRepositoryWithDefaults() 51 52 routeRepo = new(apifakes.FakeRouteRepository) 53 repoLocator := deps.RepoLocator.SetRouteRepository(routeRepo) 54 55 routeServiceBindingRepo = new(apifakes.FakeRouteServiceBindingRepository) 56 repoLocator = repoLocator.SetRouteServiceBindingRepository(routeServiceBindingRepo) 57 58 deps = commandregistry.Dependency{ 59 UI: ui, 60 Config: configRepo, 61 RepoLocator: repoLocator, 62 } 63 64 cmd = new(service.BindRouteService) 65 cmd.SetDependency(deps, false) 66 67 flagContext = flags.NewFlagContext(cmd.MetaData().Flags) 68 69 factory = new(requirementsfakes.FakeFactory) 70 71 loginRequirement = &passingRequirement{Name: "login-requirement"} 72 factory.NewLoginRequirementReturns(loginRequirement) 73 74 targetRequirement = &passingRequirement{Name: "target-requirement"} 75 factory.NewTargetedSpaceRequirementReturns(targetRequirement) 76 77 domainRequirement = new(requirementsfakes.FakeDomainRequirement) 78 factory.NewDomainRequirementReturns(domainRequirement) 79 80 fakeDomain = models.DomainFields{ 81 GUID: "fake-domain-guid", 82 Name: "fake-domain-name", 83 } 84 domainRequirement.GetDomainReturns(fakeDomain) 85 86 serviceInstanceRequirement = new(requirementsfakes.FakeServiceInstanceRequirement) 87 factory.NewServiceInstanceRequirementReturns(serviceInstanceRequirement) 88 89 minAPIVersionRequirement = &passingRequirement{Name: "min-api-version-requirement"} 90 factory.NewMinAPIVersionRequirementReturns(minAPIVersionRequirement) 91 }) 92 93 Describe("Requirements", func() { 94 Context("when not provided exactly two args", func() { 95 BeforeEach(func() { 96 flagContext.Parse("domain-name") 97 }) 98 99 It("fails with usage", func() { 100 _, err := cmd.Requirements(factory, flagContext) 101 Expect(err).To(HaveOccurred()) 102 Expect(ui.Outputs()).To(ContainSubstrings( 103 []string{"FAILED"}, 104 []string{"Incorrect Usage. Requires DOMAIN and SERVICE_INSTANCE as arguments"}, 105 )) 106 }) 107 }) 108 109 Context("when provided exactly two args", func() { 110 BeforeEach(func() { 111 flagContext.Parse("domain-name", "service-instance") 112 }) 113 114 It("returns a LoginRequirement", func() { 115 actualRequirements, err := cmd.Requirements(factory, flagContext) 116 Expect(err).NotTo(HaveOccurred()) 117 Expect(factory.NewLoginRequirementCallCount()).To(Equal(1)) 118 Expect(actualRequirements).To(ContainElement(loginRequirement)) 119 }) 120 121 It("returns a TargetedSpaceRequirement", func() { 122 actualRequirements, err := cmd.Requirements(factory, flagContext) 123 Expect(err).NotTo(HaveOccurred()) 124 Expect(factory.NewTargetedSpaceRequirementCallCount()).To(Equal(1)) 125 Expect(actualRequirements).To(ContainElement(targetRequirement)) 126 }) 127 128 It("returns a DomainRequirement", func() { 129 actualRequirements, err := cmd.Requirements(factory, flagContext) 130 Expect(err).NotTo(HaveOccurred()) 131 Expect(factory.NewDomainRequirementCallCount()).To(Equal(1)) 132 Expect(actualRequirements).To(ContainElement(domainRequirement)) 133 }) 134 135 It("returns a ServiceInstanceRequirement", func() { 136 actualRequirements, err := cmd.Requirements(factory, flagContext) 137 Expect(err).NotTo(HaveOccurred()) 138 Expect(factory.NewServiceInstanceRequirementCallCount()).To(Equal(1)) 139 Expect(actualRequirements).To(ContainElement(serviceInstanceRequirement)) 140 }) 141 }) 142 }) 143 144 Describe("Execute", func() { 145 var runCLIErr error 146 147 BeforeEach(func() { 148 err := flagContext.Parse("domain-name", "service-instance") 149 Expect(err).NotTo(HaveOccurred()) 150 cmd.Requirements(factory, flagContext) 151 }) 152 153 JustBeforeEach(func() { 154 runCLIErr = cmd.Execute(flagContext) 155 }) 156 157 It("tries to find the route", func() { 158 Expect(runCLIErr).NotTo(HaveOccurred()) 159 Expect(routeRepo.FindCallCount()).To(Equal(1)) 160 host, domain, path, port := routeRepo.FindArgsForCall(0) 161 Expect(host).To(Equal("")) 162 Expect(domain).To(Equal(fakeDomain)) 163 Expect(path).To(Equal("")) 164 Expect(port).To(Equal(0)) 165 }) 166 167 Context("when given a hostname", func() { 168 BeforeEach(func() { 169 flagContext = flags.NewFlagContext(cmd.MetaData().Flags) 170 err := flagContext.Parse("domain-name", "service-instance", "-n", "the-hostname") 171 Expect(err).NotTo(HaveOccurred()) 172 }) 173 174 It("tries to find the route with the given hostname", func() { 175 Expect(runCLIErr).NotTo(HaveOccurred()) 176 Expect(routeRepo.FindCallCount()).To(Equal(1)) 177 host, _, _, _ := routeRepo.FindArgsForCall(0) 178 Expect(host).To(Equal("the-hostname")) 179 }) 180 }) 181 182 Context("when given a path", func() { 183 BeforeEach(func() { 184 flagContext = flags.NewFlagContext(cmd.MetaData().Flags) 185 err := flagContext.Parse("domain-name", "service-instance", "--path", "/path") 186 Expect(err).NotTo(HaveOccurred()) 187 }) 188 189 It("tries to find the route with the given path", func() { 190 Expect(runCLIErr).NotTo(HaveOccurred()) 191 Expect(routeRepo.FindCallCount()).To(Equal(1)) 192 _, _, path, _ := routeRepo.FindArgsForCall(0) 193 Expect(path).To(Equal("/path")) 194 }) 195 196 Context("when the path does not have a leading slash", func() { 197 BeforeEach(func() { 198 flagContext = flags.NewFlagContext(cmd.MetaData().Flags) 199 err := flagContext.Parse("domain-name", "service-instance", "--path", "path") 200 Expect(err).NotTo(HaveOccurred()) 201 }) 202 203 It("prepends a leading slash and tries to find the route with the given path", func() { 204 Expect(runCLIErr).NotTo(HaveOccurred()) 205 Expect(routeRepo.FindCallCount()).To(Equal(1)) 206 _, _, path, _ := routeRepo.FindArgsForCall(0) 207 Expect(path).To(Equal("/path")) 208 }) 209 }) 210 }) 211 212 Context("when given a path and a hostname", func() { 213 BeforeEach(func() { 214 flagContext = flags.NewFlagContext(cmd.MetaData().Flags) 215 err := flagContext.Parse("domain-name", "service-instance", "-n", "the-hostname", "--path", "/path") 216 Expect(err).NotTo(HaveOccurred()) 217 }) 218 219 It("tries to find the route with both the given hostname and path", func() { 220 Expect(runCLIErr).NotTo(HaveOccurred()) 221 Expect(routeRepo.FindCallCount()).To(Equal(1)) 222 host, _, path, _ := routeRepo.FindArgsForCall(0) 223 Expect(host).To(Equal("the-hostname")) 224 Expect(path).To(Equal("/path")) 225 }) 226 }) 227 228 Context("when the route can be found", func() { 229 BeforeEach(func() { 230 routeRepo.FindReturns(models.Route{GUID: "route-guid"}, nil) 231 }) 232 233 Context("when the service instance is not user-provided and requires route forwarding", func() { 234 BeforeEach(func() { 235 serviceInstance := models.ServiceInstance{ 236 ServiceOffering: models.ServiceOfferingFields{ 237 Requires: []string{"route_forwarding"}, 238 }, 239 } 240 serviceInstance.ServicePlan = models.ServicePlanFields{ 241 GUID: "service-plan-guid", 242 } 243 serviceInstanceRequirement.GetServiceInstanceReturns(serviceInstance) 244 }) 245 246 It("does not warn", func() { 247 Expect(runCLIErr).NotTo(HaveOccurred()) 248 Expect(ui.Outputs()).NotTo(ContainSubstrings( 249 []string{"Bind cancelled"}, 250 )) 251 }) 252 253 It("tries to bind the route service", func() { 254 Expect(runCLIErr).NotTo(HaveOccurred()) 255 Expect(routeServiceBindingRepo.BindCallCount()).To(Equal(1)) 256 }) 257 258 Context("when binding the route service succeeds", func() { 259 BeforeEach(func() { 260 routeServiceBindingRepo.BindReturns(nil) 261 }) 262 263 It("says OK", func() { 264 Expect(runCLIErr).NotTo(HaveOccurred()) 265 Expect(ui.Outputs()).To(ContainSubstrings( 266 []string{"OK"}, 267 )) 268 }) 269 }) 270 271 Context("when binding the route service fails because it is already bound", func() { 272 BeforeEach(func() { 273 routeServiceBindingRepo.BindReturns(errors.NewHTTPError(http.StatusOK, errors.ServiceInstanceAlreadyBoundToSameRoute, "http-err")) 274 }) 275 276 It("says OK", func() { 277 Expect(runCLIErr).NotTo(HaveOccurred()) 278 Expect(ui.Outputs()).To(ContainSubstrings( 279 []string{"OK"}, 280 )) 281 }) 282 }) 283 284 Context("when binding the route service fails for any other reason", func() { 285 BeforeEach(func() { 286 routeServiceBindingRepo.BindReturns(errors.New("bind-err")) 287 }) 288 289 It("fails with the error", func() { 290 Expect(runCLIErr).To(HaveOccurred()) 291 Expect(runCLIErr.Error()).To(Equal("bind-err")) 292 }) 293 }) 294 295 Context("when the -f flag has been passed", func() { 296 BeforeEach(func() { 297 flagContext = flags.NewFlagContext(cmd.MetaData().Flags) 298 }) 299 300 It("does not alter the behavior", func() { 301 err := flagContext.Parse("domain-name", "-f") 302 Expect(err).NotTo(HaveOccurred()) 303 304 Expect(runCLIErr).NotTo(HaveOccurred()) 305 Expect(ui.Outputs()).To(ContainSubstrings( 306 []string{"OK"}, 307 )) 308 }) 309 }) 310 }) 311 312 Context("when the service instance does not require route forwarding", func() { 313 BeforeEach(func() { 314 serviceInstance := models.ServiceInstance{ 315 ServiceOffering: models.ServiceOfferingFields{ 316 Requires: []string{""}, 317 }, 318 } 319 serviceInstanceRequirement.GetServiceInstanceReturns(serviceInstance) 320 }) 321 322 It("does not ask the user to confirm", func() { 323 Expect(runCLIErr).NotTo(HaveOccurred()) 324 Expect(ui.Prompts).NotTo(ContainSubstrings( 325 []string{"Binding may cause requests for route", "Do you want to proceed?"}, 326 )) 327 }) 328 329 It("tells the user it is binding the route service", func() { 330 Expect(runCLIErr).NotTo(HaveOccurred()) 331 Expect(ui.Outputs()).To(ContainSubstrings( 332 []string{"Binding route", "to service instance"}, 333 )) 334 }) 335 336 It("tries to bind the route service", func() { 337 Expect(runCLIErr).NotTo(HaveOccurred()) 338 Expect(routeServiceBindingRepo.BindCallCount()).To(Equal(1)) 339 }) 340 341 Context("when binding the route service succeeds", func() { 342 BeforeEach(func() { 343 routeServiceBindingRepo.BindReturns(nil) 344 }) 345 346 It("says OK", func() { 347 Expect(runCLIErr).NotTo(HaveOccurred()) 348 Expect(ui.Outputs()).To(ContainSubstrings( 349 []string{"OK"}, 350 )) 351 }) 352 }) 353 354 Context("when binding the route service fails because it is already bound", func() { 355 BeforeEach(func() { 356 routeServiceBindingRepo.BindReturns(errors.NewHTTPError(http.StatusOK, errors.ServiceInstanceAlreadyBoundToSameRoute, "http-err")) 357 }) 358 359 It("says OK", func() { 360 Expect(runCLIErr).NotTo(HaveOccurred()) 361 Expect(ui.Outputs()).To(ContainSubstrings( 362 []string{"OK"}, 363 )) 364 }) 365 }) 366 367 Context("when binding the route service fails for any other reason", func() { 368 BeforeEach(func() { 369 routeServiceBindingRepo.BindReturns(errors.New("bind-err")) 370 }) 371 372 It("fails with the error", func() { 373 Expect(runCLIErr).To(HaveOccurred()) 374 Expect(runCLIErr.Error()).To(Equal("bind-err")) 375 }) 376 }) 377 }) 378 379 Context("when the service instance is user-provided", func() { 380 BeforeEach(func() { 381 serviceInstance := models.ServiceInstance{} 382 serviceInstance.GUID = "service-instance-guid" 383 serviceInstance.Type = "user_provided_service_instance" 384 serviceInstance.ServicePlan = models.ServicePlanFields{ 385 GUID: "", 386 } 387 serviceInstanceRequirement.GetServiceInstanceReturns(serviceInstance) 388 }) 389 390 It("does not ask the user to confirm", func() { 391 Expect(runCLIErr).NotTo(HaveOccurred()) 392 Expect(ui.Prompts).NotTo(ContainSubstrings( 393 []string{"Binding may cause requests for route", "Do you want to proceed?"}, 394 )) 395 }) 396 397 It("tries to bind the route service", func() { 398 Expect(runCLIErr).NotTo(HaveOccurred()) 399 Expect(routeServiceBindingRepo.BindCallCount()).To(Equal(1)) 400 serviceInstanceGUID, routeGUID, isUserProvided, parameters := routeServiceBindingRepo.BindArgsForCall(0) 401 Expect(serviceInstanceGUID).To(Equal("service-instance-guid")) 402 Expect(routeGUID).To(Equal("route-guid")) 403 Expect(isUserProvided).To(BeTrue()) 404 Expect(parameters).To(Equal("")) 405 }) 406 407 Context("when given parameters as JSON", func() { 408 BeforeEach(func() { 409 flagContext = flags.NewFlagContext(cmd.MetaData().Flags) 410 err := flagContext.Parse("domain-name", "service-instance", "-c", `"{"some":"json"}"`) 411 Expect(err).NotTo(HaveOccurred()) 412 }) 413 414 It("tries to find the route with the given parameters", func() { 415 Expect(runCLIErr).NotTo(HaveOccurred()) 416 Expect(routeRepo.FindCallCount()).To(Equal(1)) 417 _, _, _, parameters := routeServiceBindingRepo.BindArgsForCall(0) 418 Expect(parameters).To(Equal(`{"some":"json"}`)) 419 }) 420 }) 421 422 Context("when given parameters as a file containing JSON", func() { 423 var filename string 424 BeforeEach(func() { 425 flagContext = flags.NewFlagContext(cmd.MetaData().Flags) 426 tempfile, err := ioutil.TempFile("", "get-data-test") 427 Expect(err).NotTo(HaveOccurred()) 428 Expect(tempfile.Close()).NotTo(HaveOccurred()) 429 filename = tempfile.Name() 430 431 jsonData := `{"some":"json"}` 432 ioutil.WriteFile(filename, []byte(jsonData), os.ModePerm) 433 err = flagContext.Parse("domain-name", "service-instance", "-c", filename) 434 Expect(err).NotTo(HaveOccurred()) 435 }) 436 437 AfterEach(func() { 438 os.RemoveAll(filename) 439 }) 440 441 It("tries to find the route with the given parameters", func() { 442 Expect(runCLIErr).NotTo(HaveOccurred()) 443 Expect(routeRepo.FindCallCount()).To(Equal(1)) 444 _, _, _, parameters := routeServiceBindingRepo.BindArgsForCall(0) 445 Expect(parameters).To(Equal(`{"some":"json"}`)) 446 }) 447 }) 448 449 Context("when binding the route service succeeds", func() { 450 BeforeEach(func() { 451 routeServiceBindingRepo.BindReturns(nil) 452 }) 453 454 It("says OK", func() { 455 Expect(runCLIErr).NotTo(HaveOccurred()) 456 Expect(ui.Outputs()).To(ContainSubstrings( 457 []string{"OK"}, 458 )) 459 }) 460 }) 461 462 Context("when binding the route service fails because it is already bound", func() { 463 BeforeEach(func() { 464 routeServiceBindingRepo.BindReturns(errors.NewHTTPError(http.StatusOK, errors.ServiceInstanceAlreadyBoundToSameRoute, "http-err")) 465 }) 466 467 It("says OK", func() { 468 Expect(runCLIErr).NotTo(HaveOccurred()) 469 Expect(ui.Outputs()).To(ContainSubstrings( 470 []string{"OK"}, 471 )) 472 }) 473 }) 474 475 Context("when binding the route service fails for any other reason", func() { 476 BeforeEach(func() { 477 routeServiceBindingRepo.BindReturns(errors.New("bind-err")) 478 }) 479 480 It("fails with the error", func() { 481 Expect(runCLIErr).To(HaveOccurred()) 482 Expect(runCLIErr.Error()).To(Equal("bind-err")) 483 }) 484 }) 485 }) 486 }) 487 488 Context("when finding the route results in an error", func() { 489 BeforeEach(func() { 490 routeRepo.FindReturns(models.Route{GUID: "route-guid"}, errors.New("find-err")) 491 }) 492 493 It("fails with error", func() { 494 Expect(runCLIErr).To(HaveOccurred()) 495 Expect(runCLIErr.Error()).To(Equal("find-err")) 496 }) 497 }) 498 }) 499 })