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