github.com/mook-as/cf-cli@v7.0.0-beta.28.0.20200120190804-b91c115fae48+incompatible/cf/commands/service/create_service_test.go (about)

     1  package service_test
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"os"
     7  
     8  	"code.cloudfoundry.org/cli/cf/actors/servicebuilder/servicebuilderfakes"
     9  	"code.cloudfoundry.org/cli/cf/configuration/coreconfig"
    10  	"code.cloudfoundry.org/cli/cf/errors"
    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  	testcmd "code.cloudfoundry.org/cli/cf/util/testhelpers/commands"
    17  	testconfig "code.cloudfoundry.org/cli/cf/util/testhelpers/configuration"
    18  	testterm "code.cloudfoundry.org/cli/cf/util/testhelpers/terminal"
    19  
    20  	"code.cloudfoundry.org/cli/cf/commandregistry"
    21  
    22  	. "github.com/onsi/ginkgo"
    23  	. "github.com/onsi/gomega"
    24  
    25  	. "code.cloudfoundry.org/cli/cf/util/testhelpers/matchers"
    26  )
    27  
    28  var _ = Describe("create-service command", func() {
    29  	var (
    30  		ui                  *testterm.FakeUI
    31  		config              coreconfig.Repository
    32  		requirementsFactory *requirementsfakes.FakeFactory
    33  		serviceRepo         *apifakes.FakeServiceRepository
    34  		serviceBuilder      *servicebuilderfakes.FakeServiceBuilder
    35  
    36  		offering1 models.ServiceOffering
    37  		offering2 models.ServiceOffering
    38  		deps      commandregistry.Dependency
    39  	)
    40  
    41  	updateCommandDependency := func(pluginCall bool) {
    42  		deps.UI = ui
    43  		deps.Config = config
    44  		deps.RepoLocator = deps.RepoLocator.SetServiceRepository(serviceRepo)
    45  		deps.ServiceBuilder = serviceBuilder
    46  		commandregistry.Commands.SetCommand(commandregistry.Commands.FindCommand("create-service").SetDependency(deps, pluginCall))
    47  	}
    48  
    49  	BeforeEach(func() {
    50  		ui = &testterm.FakeUI{}
    51  		config = testconfig.NewRepositoryWithDefaults()
    52  		requirementsFactory = new(requirementsfakes.FakeFactory)
    53  		requirementsFactory.NewLoginRequirementReturns(requirements.Passing{})
    54  		requirementsFactory.NewTargetedSpaceRequirementReturns(requirements.Passing{})
    55  		serviceRepo = new(apifakes.FakeServiceRepository)
    56  		serviceBuilder = new(servicebuilderfakes.FakeServiceBuilder)
    57  
    58  		offering1 = models.ServiceOffering{}
    59  		offering1.Label = "cleardb"
    60  		offering1.Plans = []models.ServicePlanFields{{
    61  			Name: "spark",
    62  			GUID: "cleardb-spark-guid",
    63  			Free: true,
    64  		}, {
    65  			Name: "expensive",
    66  			GUID: "luxury-guid",
    67  			Free: false,
    68  		}}
    69  
    70  		offering2 = models.ServiceOffering{}
    71  		offering2.Label = "postgres"
    72  
    73  		serviceBuilder.GetServicesByNameForSpaceWithPlansReturns(models.ServiceOfferings([]models.ServiceOffering{offering1, offering2}), nil)
    74  	})
    75  
    76  	var callCreateService = func(args []string) bool {
    77  		return testcmd.RunCLICommand("create-service", args, requirementsFactory, updateCommandDependency, false, ui)
    78  	}
    79  
    80  	Describe("requirements", func() {
    81  		It("passes when logged in and a space is targeted", func() {
    82  			Expect(callCreateService([]string{"cleardb", "spark", "my-cleardb-service"})).To(BeTrue())
    83  		})
    84  
    85  		It("fails when not logged in", func() {
    86  			requirementsFactory.NewLoginRequirementReturns(requirements.Failing{Message: "not logged in"})
    87  			Expect(callCreateService([]string{"cleardb", "spark", "my-cleardb-service"})).To(BeFalse())
    88  		})
    89  
    90  		It("fails when a space is not targeted", func() {
    91  			requirementsFactory.NewTargetedSpaceRequirementReturns(requirements.Failing{Message: "not targeted"})
    92  			Expect(callCreateService([]string{"cleardb", "spark", "my-cleardb-service"})).To(BeFalse())
    93  		})
    94  	})
    95  
    96  	It("successfully creates a service", func() {
    97  		callCreateService([]string{"cleardb", "spark", "my-cleardb-service"})
    98  
    99  		spaceGUID, serviceName := serviceBuilder.GetServicesByNameForSpaceWithPlansArgsForCall(0)
   100  		Expect(spaceGUID).To(Equal(config.SpaceFields().GUID))
   101  		Expect(serviceName).To(Equal("cleardb"))
   102  		Expect(ui.Outputs()).To(ContainSubstrings(
   103  			[]string{"Creating service instance", "my-cleardb-service", "my-org", "my-space", "my-user"},
   104  			[]string{"OK"},
   105  		))
   106  		name, planGUID, _, _ := serviceRepo.CreateServiceInstanceArgsForCall(0)
   107  		Expect(name).To(Equal("my-cleardb-service"))
   108  		Expect(planGUID).To(Equal("cleardb-spark-guid"))
   109  	})
   110  
   111  	Context("when passing in tags", func() {
   112  		It("sucessfully creates a service and passes the tags as json", func() {
   113  			callCreateService([]string{"cleardb", "spark", "my-cleardb-service", "-t", "tag1, tag2,tag3,  tag4"})
   114  
   115  			Expect(ui.Outputs()).To(ContainSubstrings(
   116  				[]string{"Creating service instance", "my-cleardb-service", "my-org", "my-space", "my-user"},
   117  				[]string{"OK"},
   118  			))
   119  			_, _, _, tags := serviceRepo.CreateServiceInstanceArgsForCall(0)
   120  			Expect(tags).To(ConsistOf("tag1", "tag2", "tag3", "tag4"))
   121  		})
   122  	})
   123  
   124  	Context("when passing arbitrary params", func() {
   125  		Context("as a json string", func() {
   126  			It("successfully creates a service and passes the params as a json string", func() {
   127  				callCreateService([]string{"cleardb", "spark", "my-cleardb-service", "-c", `{"foo": "bar"}`})
   128  
   129  				Expect(ui.Outputs()).To(ContainSubstrings(
   130  					[]string{"Creating service instance", "my-cleardb-service", "my-org", "my-space", "my-user"},
   131  					[]string{"OK"},
   132  				))
   133  				_, _, params, _ := serviceRepo.CreateServiceInstanceArgsForCall(0)
   134  				Expect(params).To(Equal(map[string]interface{}{"foo": "bar"}))
   135  			})
   136  
   137  			Context("that are not valid json", func() {
   138  				It("returns an error to the UI", func() {
   139  					callCreateService([]string{"cleardb", "spark", "my-cleardb-service", "-c", `bad-json`})
   140  
   141  					Expect(ui.Outputs()).To(ContainSubstrings(
   142  						[]string{"FAILED"},
   143  						[]string{"Invalid configuration provided for -c flag. Please provide a valid JSON object or path to a file containing a valid JSON object."},
   144  					))
   145  				})
   146  			})
   147  		})
   148  
   149  		Context("as a file that contains json", func() {
   150  			var jsonFile *os.File
   151  			var params string
   152  
   153  			BeforeEach(func() {
   154  				params = "{\"foo\": \"bar\"}"
   155  			})
   156  
   157  			AfterEach(func() {
   158  				if jsonFile != nil {
   159  					jsonFile.Close()
   160  					os.Remove(jsonFile.Name())
   161  				}
   162  			})
   163  
   164  			JustBeforeEach(func() {
   165  				var err error
   166  				jsonFile, err = ioutil.TempFile("", "")
   167  				Expect(err).ToNot(HaveOccurred())
   168  
   169  				err = ioutil.WriteFile(jsonFile.Name(), []byte(params), os.ModePerm)
   170  				Expect(err).NotTo(HaveOccurred())
   171  			})
   172  
   173  			It("successfully creates a service and passes the params as a json", func() {
   174  				callCreateService([]string{"cleardb", "spark", "my-cleardb-service", "-c", jsonFile.Name()})
   175  
   176  				Expect(ui.Outputs()).To(ContainSubstrings(
   177  					[]string{"Creating service instance", "my-cleardb-service", "my-org", "my-space", "my-user"},
   178  					[]string{"OK"},
   179  				))
   180  				_, _, params, _ := serviceRepo.CreateServiceInstanceArgsForCall(0)
   181  				Expect(params).To(Equal(map[string]interface{}{"foo": "bar"}))
   182  			})
   183  
   184  			Context("that are not valid json", func() {
   185  				BeforeEach(func() {
   186  					params = "bad-json"
   187  				})
   188  
   189  				It("returns an error to the UI", func() {
   190  					callCreateService([]string{"cleardb", "spark", "my-cleardb-service", "-c", jsonFile.Name()})
   191  
   192  					Expect(ui.Outputs()).To(ContainSubstrings(
   193  						[]string{"FAILED"},
   194  						[]string{"Invalid configuration provided for -c flag. Please provide a valid JSON object or path to a file containing a valid JSON object."},
   195  					))
   196  				})
   197  			})
   198  		})
   199  	})
   200  
   201  	Context("when service creation is asynchronous", func() {
   202  		var serviceInstance models.ServiceInstance
   203  
   204  		BeforeEach(func() {
   205  			serviceInstance = models.ServiceInstance{
   206  				ServiceInstanceFields: models.ServiceInstanceFields{
   207  					Name: "my-cleardb-service",
   208  					LastOperation: models.LastOperationFields{
   209  						Type:        "create",
   210  						State:       "in progress",
   211  						Description: "fake service instance description",
   212  					},
   213  				},
   214  			}
   215  			serviceRepo.FindInstanceByNameReturns(serviceInstance, nil)
   216  		})
   217  
   218  		It("successfully starts async service creation", func() {
   219  			callCreateService([]string{"cleardb", "spark", "my-cleardb-service"})
   220  
   221  			spaceGUID, serviceName := serviceBuilder.GetServicesByNameForSpaceWithPlansArgsForCall(0)
   222  			Expect(spaceGUID).To(Equal(config.SpaceFields().GUID))
   223  			Expect(serviceName).To(Equal("cleardb"))
   224  
   225  			creatingServiceMessage := fmt.Sprintf("Create in progress. Use 'cf services' or 'cf service %s' to check operation status.", serviceInstance.ServiceInstanceFields.Name)
   226  
   227  			Expect(ui.Outputs()).To(ContainSubstrings(
   228  				[]string{"Creating service instance", "my-cleardb-service", "my-org", "my-space", "my-user"},
   229  				[]string{"OK"},
   230  				[]string{creatingServiceMessage},
   231  			))
   232  			name, planGUID, _, _ := serviceRepo.CreateServiceInstanceArgsForCall(0)
   233  			Expect(name).To(Equal("my-cleardb-service"))
   234  			Expect(planGUID).To(Equal("cleardb-spark-guid"))
   235  		})
   236  
   237  		It("fails when service instance could is created but cannot be found", func() {
   238  			serviceRepo.FindInstanceByNameReturns(models.ServiceInstance{}, errors.New("Error finding instance"))
   239  			callCreateService([]string{"cleardb", "spark", "fake-service-instance-name"})
   240  
   241  			Expect(ui.Outputs()).To(ContainSubstrings(
   242  				[]string{"Creating service instance fake-service-instance-name in org my-org / space my-space as my-user..."},
   243  				[]string{"FAILED"},
   244  				[]string{"Error finding instance"}))
   245  		})
   246  	})
   247  
   248  	Describe("warning the user about paid services", func() {
   249  		It("does not warn the user when the service is free", func() {
   250  			callCreateService([]string{"cleardb", "spark", "my-free-cleardb-service"})
   251  			Expect(ui.Outputs()).To(ContainSubstrings(
   252  				[]string{"Creating service instance", "my-free-cleardb-service", "my-org", "my-space", "my-user"},
   253  				[]string{"OK"},
   254  			))
   255  			Expect(ui.Outputs()).NotTo(ContainSubstrings([]string{"will incurr a cost"}))
   256  		})
   257  
   258  		It("warns the user when the service is not free", func() {
   259  			callCreateService([]string{"cleardb", "expensive", "my-expensive-cleardb-service"})
   260  			Expect(ui.Outputs()).To(ContainSubstrings(
   261  				[]string{"Creating service instance", "my-expensive-cleardb-service", "my-org", "my-space", "my-user"},
   262  				[]string{"OK"},
   263  				[]string{"Attention: The plan `expensive` of service `cleardb` is not free.  The instance `my-expensive-cleardb-service` will incur a cost.  Contact your administrator if you think this is in error."},
   264  			))
   265  		})
   266  	})
   267  
   268  	It("warns the user when the service already exists with the same service plan", func() {
   269  		serviceRepo.CreateServiceInstanceReturns(errors.NewModelAlreadyExistsError("Service", "my-cleardb-service"))
   270  
   271  		callCreateService([]string{"cleardb", "spark", "my-cleardb-service"})
   272  
   273  		Expect(ui.Outputs()).To(ContainSubstrings(
   274  			[]string{"Creating service instance", "my-cleardb-service"},
   275  			[]string{"OK"},
   276  			[]string{"my-cleardb-service", "already exists"},
   277  		))
   278  
   279  		name, planGUID, _, _ := serviceRepo.CreateServiceInstanceArgsForCall(0)
   280  		Expect(name).To(Equal("my-cleardb-service"))
   281  		Expect(planGUID).To(Equal("cleardb-spark-guid"))
   282  	})
   283  
   284  	Context("When there are multiple services with the same label", func() {
   285  		It("finds the plan even if it has to search multiple services", func() {
   286  			offering2.Label = "cleardb"
   287  
   288  			serviceRepo.CreateServiceInstanceReturns(errors.NewModelAlreadyExistsError("Service", "my-cleardb-service"))
   289  			callCreateService([]string{"cleardb", "spark", "my-cleardb-service"})
   290  
   291  			Expect(ui.Outputs()).To(ContainSubstrings(
   292  				[]string{"Creating service instance", "my-cleardb-service", "my-org", "my-space", "my-user"},
   293  				[]string{"OK"},
   294  			))
   295  
   296  			name, planGUID, _, _ := serviceRepo.CreateServiceInstanceArgsForCall(0)
   297  			Expect(name).To(Equal("my-cleardb-service"))
   298  			Expect(planGUID).To(Equal("cleardb-spark-guid"))
   299  		})
   300  	})
   301  })