github.com/swisscom/cloudfoundry-cli@v7.1.0+incompatible/cf/commands/service/unbind_route_service_test.go (about)

     1  package service_test
     2  
     3  import (
     4  	"net/http"
     5  
     6  	"code.cloudfoundry.org/cli/cf/commandregistry"
     7  	"code.cloudfoundry.org/cli/cf/commands/service"
     8  	"code.cloudfoundry.org/cli/cf/configuration/coreconfig"
     9  	"code.cloudfoundry.org/cli/cf/errors"
    10  	"code.cloudfoundry.org/cli/cf/flags"
    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  	testconfig "code.cloudfoundry.org/cli/cf/util/testhelpers/configuration"
    17  	testterm "code.cloudfoundry.org/cli/cf/util/testhelpers/terminal"
    18  
    19  	. "code.cloudfoundry.org/cli/cf/util/testhelpers/matchers"
    20  	. "github.com/onsi/ginkgo"
    21  	. "github.com/onsi/gomega"
    22  )
    23  
    24  var _ = Describe("UnbindRouteService", func() {
    25  	var (
    26  		ui                      *testterm.FakeUI
    27  		configRepo              coreconfig.Repository
    28  		routeRepo               *apifakes.FakeRouteRepository
    29  		routeServiceBindingRepo *apifakes.FakeRouteServiceBindingRepository
    30  
    31  		cmd         commandregistry.Command
    32  		deps        commandregistry.Dependency
    33  		factory     *requirementsfakes.FakeFactory
    34  		flagContext flags.FlagContext
    35  
    36  		fakeDomain models.DomainFields
    37  
    38  		loginRequirement           requirements.Requirement
    39  		minAPIVersionRequirement   requirements.Requirement
    40  		domainRequirement          *requirementsfakes.FakeDomainRequirement
    41  		serviceInstanceRequirement *requirementsfakes.FakeServiceInstanceRequirement
    42  	)
    43  
    44  	BeforeEach(func() {
    45  		ui = &testterm.FakeUI{}
    46  
    47  		configRepo = testconfig.NewRepositoryWithDefaults()
    48  		routeRepo = new(apifakes.FakeRouteRepository)
    49  		repoLocator := deps.RepoLocator.SetRouteRepository(routeRepo)
    50  
    51  		routeServiceBindingRepo = new(apifakes.FakeRouteServiceBindingRepository)
    52  		repoLocator = repoLocator.SetRouteServiceBindingRepository(routeServiceBindingRepo)
    53  
    54  		deps = commandregistry.Dependency{
    55  			UI:          ui,
    56  			Config:      configRepo,
    57  			RepoLocator: repoLocator,
    58  		}
    59  
    60  		cmd = &service.UnbindRouteService{}
    61  		cmd.SetDependency(deps, false)
    62  
    63  		flagContext = flags.NewFlagContext(cmd.MetaData().Flags)
    64  
    65  		factory = new(requirementsfakes.FakeFactory)
    66  
    67  		loginRequirement = &passingRequirement{Name: "login-requirement"}
    68  		factory.NewLoginRequirementReturns(loginRequirement)
    69  
    70  		domainRequirement = new(requirementsfakes.FakeDomainRequirement)
    71  		factory.NewDomainRequirementReturns(domainRequirement)
    72  
    73  		fakeDomain = models.DomainFields{
    74  			GUID: "fake-domain-guid",
    75  			Name: "fake-domain-name",
    76  		}
    77  		domainRequirement.GetDomainReturns(fakeDomain)
    78  
    79  		serviceInstanceRequirement = new(requirementsfakes.FakeServiceInstanceRequirement)
    80  		factory.NewServiceInstanceRequirementReturns(serviceInstanceRequirement)
    81  
    82  		minAPIVersionRequirement = &passingRequirement{Name: "min-api-version-requirement"}
    83  		factory.NewMinAPIVersionRequirementReturns(minAPIVersionRequirement)
    84  	})
    85  
    86  	Describe("Requirements", func() {
    87  		Context("when not provided exactly two args", func() {
    88  			BeforeEach(func() {
    89  				flagContext.Parse("domain-name")
    90  			})
    91  
    92  			It("fails with usage", func() {
    93  				_, err := cmd.Requirements(factory, flagContext)
    94  				Expect(err).To(HaveOccurred())
    95  				Expect(ui.Outputs()).To(ContainSubstrings(
    96  					[]string{"FAILED"},
    97  					[]string{"Incorrect Usage. Requires DOMAIN and SERVICE_INSTANCE as arguments"},
    98  				))
    99  			})
   100  		})
   101  
   102  		Context("when provided exactly two args", func() {
   103  			BeforeEach(func() {
   104  				flagContext.Parse("domain-name", "service-instance")
   105  			})
   106  
   107  			It("returns a LoginRequirement", func() {
   108  				actualRequirements, err := cmd.Requirements(factory, flagContext)
   109  				Expect(err).NotTo(HaveOccurred())
   110  				Expect(factory.NewLoginRequirementCallCount()).To(Equal(1))
   111  				Expect(actualRequirements).To(ContainElement(loginRequirement))
   112  			})
   113  
   114  			It("returns a DomainRequirement", 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 ServiceInstanceRequirement", func() {
   122  				actualRequirements, err := cmd.Requirements(factory, flagContext)
   123  				Expect(err).NotTo(HaveOccurred())
   124  				Expect(factory.NewServiceInstanceRequirementCallCount()).To(Equal(1))
   125  				Expect(actualRequirements).To(ContainElement(serviceInstanceRequirement))
   126  			})
   127  		})
   128  	})
   129  
   130  	Describe("Execute", func() {
   131  		var runCLIErr error
   132  
   133  		BeforeEach(func() {
   134  			err := flagContext.Parse("domain-name", "service-instance")
   135  			Expect(err).NotTo(HaveOccurred())
   136  			cmd.Requirements(factory, flagContext)
   137  			ui.Inputs = []string{"n"}
   138  		})
   139  
   140  		JustBeforeEach(func() {
   141  			runCLIErr = cmd.Execute(flagContext)
   142  		})
   143  
   144  		It("tries to find the route", func() {
   145  			Expect(runCLIErr).NotTo(HaveOccurred())
   146  			Expect(routeRepo.FindCallCount()).To(Equal(1))
   147  			host, domain, path, port := routeRepo.FindArgsForCall(0)
   148  			Expect(host).To(Equal(""))
   149  			Expect(domain).To(Equal(fakeDomain))
   150  			Expect(path).To(Equal(""))
   151  			Expect(port).To(Equal(0))
   152  		})
   153  
   154  		Context("when given a hostname", func() {
   155  			BeforeEach(func() {
   156  				flagContext = flags.NewFlagContext(cmd.MetaData().Flags)
   157  				err := flagContext.Parse("domain-name", "service-instance", "-n", "the-hostname")
   158  				Expect(err).NotTo(HaveOccurred())
   159  				ui.Inputs = []string{"n"}
   160  			})
   161  
   162  			It("tries to find the route with the given hostname", func() {
   163  				Expect(runCLIErr).NotTo(HaveOccurred())
   164  				Expect(routeRepo.FindCallCount()).To(Equal(1))
   165  				host, _, _, _ := routeRepo.FindArgsForCall(0)
   166  				Expect(host).To(Equal("the-hostname"))
   167  			})
   168  		})
   169  
   170  		Context("when given a path", func() {
   171  			BeforeEach(func() {
   172  				flagContext = flags.NewFlagContext(cmd.MetaData().Flags)
   173  				err := flagContext.Parse("domain-name", "service-instance", "--path", "/path")
   174  				Expect(err).NotTo(HaveOccurred())
   175  				ui.Inputs = []string{"n"}
   176  			})
   177  
   178  			It("should attempt to find the route", func() {
   179  				Expect(runCLIErr).NotTo(HaveOccurred())
   180  				Expect(routeRepo.FindCallCount()).To(Equal(1))
   181  				_, _, path, _ := routeRepo.FindArgsForCall(0)
   182  				Expect(path).To(Equal("/path"))
   183  			})
   184  
   185  			Context("when the path does not contain a leading slash", func() {
   186  				BeforeEach(func() {
   187  					flagContext = flags.NewFlagContext(cmd.MetaData().Flags)
   188  					err := flagContext.Parse("domain-name", "service-instance", "--path", "path")
   189  					Expect(err).NotTo(HaveOccurred())
   190  					ui.Inputs = []string{"n"}
   191  				})
   192  
   193  				It("should prefix the path with a leading slash and attempt to find the route", func() {
   194  					Expect(runCLIErr).NotTo(HaveOccurred())
   195  					Expect(routeRepo.FindCallCount()).To(Equal(1))
   196  					_, _, path, _ := routeRepo.FindArgsForCall(0)
   197  					Expect(path).To(Equal("/path"))
   198  				})
   199  			})
   200  		})
   201  
   202  		Context("when given hostname and path", func() {
   203  			BeforeEach(func() {
   204  				flagContext = flags.NewFlagContext(cmd.MetaData().Flags)
   205  				err := flagContext.Parse("domain-name", "service-instance", "--hostname", "the-hostname", "--path", "path")
   206  				Expect(err).NotTo(HaveOccurred())
   207  				ui.Inputs = []string{"n"}
   208  			})
   209  
   210  			It("should attempt to find the route", func() {
   211  				Expect(runCLIErr).NotTo(HaveOccurred())
   212  				Expect(routeRepo.FindCallCount()).To(Equal(1))
   213  				hostname, _, path, _ := routeRepo.FindArgsForCall(0)
   214  				Expect(hostname).To(Equal("the-hostname"))
   215  				Expect(path).To(Equal("/path"))
   216  			})
   217  		})
   218  
   219  		Context("when the route can be found", func() {
   220  			BeforeEach(func() {
   221  				routeRepo.FindReturns(models.Route{GUID: "route-guid"}, nil)
   222  				ui.Inputs = []string{"n"}
   223  			})
   224  
   225  			It("asks the user to confirm", func() {
   226  				Expect(runCLIErr).NotTo(HaveOccurred())
   227  				Expect(ui.Prompts).To(ContainSubstrings(
   228  					[]string{"Unbinding may leave apps mapped to route", "Do you want to proceed?"},
   229  				))
   230  			})
   231  
   232  			Context("when the user confirms", func() {
   233  				BeforeEach(func() {
   234  					ui.Inputs = []string{"y"}
   235  				})
   236  
   237  				It("does not warn", func() {
   238  					Expect(runCLIErr).NotTo(HaveOccurred())
   239  					Expect(func() []string {
   240  						return ui.Outputs()
   241  					}).NotTo(ContainSubstrings(
   242  						[]string{"Unbind cancelled"},
   243  					))
   244  				})
   245  
   246  				It("tells the user it is unbinding the route service", func() {
   247  					Expect(runCLIErr).NotTo(HaveOccurred())
   248  					Expect(ui.Outputs()).To(ContainSubstrings(
   249  						[]string{"Unbinding route", "from service instance"},
   250  					))
   251  				})
   252  
   253  				It("tries to unbind the route service", func() {
   254  					Expect(runCLIErr).NotTo(HaveOccurred())
   255  					Expect(routeServiceBindingRepo.UnbindCallCount()).To(Equal(1))
   256  				})
   257  
   258  				Context("when unbinding the route service succeeds", func() {
   259  					BeforeEach(func() {
   260  						routeServiceBindingRepo.UnbindReturns(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 unbinding the route service fails because it was not bound", func() {
   272  					BeforeEach(func() {
   273  						routeServiceBindingRepo.UnbindReturns(errors.NewHTTPError(http.StatusOK, errors.InvalidRelation, "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  					It("warns", func() {
   284  						Expect(runCLIErr).NotTo(HaveOccurred())
   285  						Expect(ui.Outputs()).To(ContainSubstrings(
   286  							[]string{"Route", "was not bound to service instance"},
   287  						))
   288  					})
   289  				})
   290  
   291  				Context("when unbinding the route service fails for any other reason", func() {
   292  					BeforeEach(func() {
   293  						routeServiceBindingRepo.UnbindReturns(errors.New("unbind-err"))
   294  					})
   295  
   296  					It("fails with the error", func() {
   297  						Expect(runCLIErr).To(HaveOccurred())
   298  						Expect(runCLIErr.Error()).To(Equal("unbind-err"))
   299  					})
   300  				})
   301  			})
   302  
   303  			Context("when the user does not confirm", func() {
   304  				BeforeEach(func() {
   305  					ui.Inputs = []string{"n"}
   306  				})
   307  
   308  				It("warns", func() {
   309  					Expect(runCLIErr).NotTo(HaveOccurred())
   310  					Expect(ui.Outputs()).To(ContainSubstrings(
   311  						[]string{"Unbind cancelled"},
   312  					))
   313  				})
   314  
   315  				It("does not bind the route service", func() {
   316  					Expect(runCLIErr).NotTo(HaveOccurred())
   317  					Expect(routeServiceBindingRepo.UnbindCallCount()).To(Equal(0))
   318  				})
   319  			})
   320  
   321  			Context("when the -f flag has been passed", func() {
   322  				BeforeEach(func() {
   323  					flagContext = flags.NewFlagContext(cmd.MetaData().Flags)
   324  					flagContext.Parse("domain-name", "-f")
   325  				})
   326  
   327  				It("does not ask the user to confirm", func() {
   328  					Expect(runCLIErr).NotTo(HaveOccurred())
   329  					Expect(ui.Prompts).NotTo(ContainSubstrings(
   330  						[]string{"Unbinding may leave apps mapped to route", "Do you want to proceed?"},
   331  					))
   332  				})
   333  			})
   334  		})
   335  
   336  		Context("when finding the route results in an error", func() {
   337  			BeforeEach(func() {
   338  				routeRepo.FindReturns(models.Route{GUID: "route-guid"}, errors.New("find-err"))
   339  			})
   340  
   341  			It("fails with error", func() {
   342  				Expect(runCLIErr).To(HaveOccurred())
   343  				Expect(runCLIErr.Error()).To(Equal("find-err"))
   344  			})
   345  		})
   346  	})
   347  })