github.com/cloudfoundry-community/cloudfoundry-cli@v6.44.1-0.20240130060226-cda5ed8e89a5+incompatible/integration/shared/isolated/create_service_command_test.go (about)

     1  package isolated
     2  
     3  import (
     4  	"io/ioutil"
     5  	"os"
     6  	"path/filepath"
     7  
     8  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccversion"
     9  	"code.cloudfoundry.org/cli/integration/helpers"
    10  	. "github.com/onsi/ginkgo"
    11  	. "github.com/onsi/gomega"
    12  	. "github.com/onsi/gomega/gbytes"
    13  	. "github.com/onsi/gomega/gexec"
    14  )
    15  
    16  var _ = Describe("create-service command", func() {
    17  	Describe("help", func() {
    18  		When("--help flag is set", func() {
    19  			It("displays command usage to output", func() {
    20  				session := helpers.CF("create-service", "--help")
    21  				Eventually(session).Should(Say("NAME:"))
    22  				Eventually(session).Should(Say(`\s+create-service - Create a service instance`))
    23  				Eventually(session).Should(Say(`USAGE:`))
    24  				Eventually(session).Should(Say(`\s+cf create-service SERVICE PLAN SERVICE_INSTANCE \[-b BROKER\] \[-c PARAMETERS_AS_JSON\] \[-t TAGS\]`))
    25  				Eventually(session).Should(Say(`\s+Optionally provide service-specific configuration parameters in a valid JSON object in-line:`))
    26  				Eventually(session).Should(Say(`\s+cf create-service SERVICE PLAN SERVICE_INSTANCE -c '{\"name\":\"value\",\"name\":\"value\"}'`))
    27  				Eventually(session).Should(Say(`\s+Optionally provide a file containing service-specific configuration parameters in a valid JSON object\.`))
    28  				Eventually(session).Should(Say(`\s+The path to the parameters file can be an absolute or relative path to a file:`))
    29  				Eventually(session).Should(Say(`\s+cf create-service SERVICE PLAN SERVICE_INSTANCE -c PATH_TO_FILE`))
    30  				Eventually(session).Should(Say(`\s+Example of valid JSON object:`))
    31  				Eventually(session).Should(Say(`\s+{`))
    32  				Eventually(session).Should(Say(`\s+\"cluster_nodes\": {`))
    33  				Eventually(session).Should(Say(`\s+\"count\": 5,`))
    34  				Eventually(session).Should(Say(`\s+\"memory_mb\": 1024`))
    35  				Eventually(session).Should(Say(`\s+}`))
    36  				Eventually(session).Should(Say(`\s+}`))
    37  				Eventually(session).Should(Say(`TIP:`))
    38  				Eventually(session).Should(Say(`\s+Use 'cf create-user-provided-service' to make user-provided services available to CF apps`))
    39  				Eventually(session).Should(Say(`EXAMPLES:`))
    40  				Eventually(session).Should(Say(`\s+Linux/Mac:`))
    41  				Eventually(session).Should(Say(`\s+cf create-service db-service silver mydb -c '{\"ram_gb\":4}'`))
    42  				Eventually(session).Should(Say(`\s+Windows Command Line:`))
    43  				Eventually(session).Should(Say(`\s+cf create-service db-service silver mydb -c \"{\\\"ram_gb\\\":4}\"`))
    44  				Eventually(session).Should(Say(`\s+Windows PowerShell:`))
    45  				Eventually(session).Should(Say(`\s+cf create-service db-service silver mydb -c '{\\\"ram_gb\\\":4}'`))
    46  				Eventually(session).Should(Say(`\s+cf create-service db-service silver mydb -c ~/workspace/tmp/instance_config.json`))
    47  				Eventually(session).Should(Say(`\s+cf create-service db-service silver mydb -t \"list, of, tags\"`))
    48  				Eventually(session).Should(Say(`ALIAS:`))
    49  				Eventually(session).Should(Say(`\s+cs`))
    50  				Eventually(session).Should(Say(`OPTIONS:`))
    51  				Eventually(session).Should(Say(`\s+-b      Create a service instance from a particular broker\. Required when service name is ambiguous`))
    52  				Eventually(session).Should(Say(`\s+-c      Valid JSON object containing service-specific configuration parameters, provided either in-line or in a file\. For a list of supported configuration parameters, see documentation for the particular service offering\.`))
    53  				Eventually(session).Should(Say(`\s+-t      User provided tags`))
    54  				Eventually(session).Should(Say(`SEE ALSO:`))
    55  				Eventually(session).Should(Say(`\s+bind-service, create-user-provided-service, marketplace, services`))
    56  				Eventually(session).Should(Exit(0))
    57  			})
    58  		})
    59  	})
    60  
    61  	When("not logged in", func() {
    62  		BeforeEach(func() {
    63  			helpers.LogoutCF()
    64  		})
    65  
    66  		It("displays FAILED, an informative error message, and exits 1", func() {
    67  			session := helpers.CF("create-service", "service", "plan", "my-service")
    68  			Eventually(session).Should(Say("FAILED"))
    69  			Eventually(session.Err).Should(Say("Not logged in. Use 'cf login' to log in\\."))
    70  			Eventually(session).Should(Exit(1))
    71  		})
    72  	})
    73  
    74  	When("logged in", func() {
    75  		BeforeEach(func() {
    76  			helpers.LoginCF()
    77  		})
    78  
    79  		When("the environment is not setup correctly", func() {
    80  			It("fails with the appropriate errors", func() {
    81  				helpers.CheckEnvironmentTargetedCorrectly(true, true, ReadOnlyOrg, "create-service", "service-name", "simple", "new-service")
    82  			})
    83  		})
    84  
    85  		When("the environment is setup correctly", func() {
    86  			var (
    87  				org      string
    88  				space    string
    89  				domain   string
    90  				username string
    91  			)
    92  
    93  			BeforeEach(func() {
    94  				org = helpers.NewOrgName()
    95  				space = helpers.NewSpaceName()
    96  
    97  				helpers.SetupCF(org, space)
    98  
    99  				username, _ = helpers.GetCredentials()
   100  				domain = helpers.DefaultSharedDomain()
   101  			})
   102  
   103  			AfterEach(func() {
   104  				helpers.QuickDeleteOrg(org)
   105  			})
   106  
   107  			When("not providing any arguments", func() {
   108  				It("displays an invalid usage error and the help text, and exits 1", func() {
   109  					session := helpers.CF("create-service")
   110  					Eventually(session.Err).Should(Say("Incorrect Usage: the required arguments `SERVICE`, `SERVICE_PLAN` and `SERVICE_INSTANCE` were not provided"))
   111  
   112  					// checking partial help text, too long and it's tested earlier
   113  					Eventually(session).Should(Say("NAME:"))
   114  					Eventually(session).Should(Say(`\s+create-service - Create a service instance`))
   115  					Eventually(session).Should(Exit(1))
   116  				})
   117  			})
   118  
   119  			When("invalid arguments are passed", func() {
   120  				When("with an invalid json for -c", func() {
   121  					It("displays an informative error message, exits 1", func() {
   122  						session := helpers.CF("create-service", "foo", "bar", "my-service", "-c", "{")
   123  						Eventually(session.Err).Should(Say("Invalid configuration provided for -c flag. Please provide a valid JSON object or path to a file containing a valid JSON object\\."))
   124  						Eventually(session).Should(Exit(1))
   125  					})
   126  				})
   127  
   128  				When("the provided file contains invalid json", func() {
   129  					var tempFilePath string
   130  
   131  					BeforeEach(func() {
   132  						tempFilePath = helpers.TempFileWithContent(`{"invalid"}`)
   133  					})
   134  
   135  					AfterEach(func() {
   136  						Expect(os.Remove(tempFilePath)).To(Succeed())
   137  					})
   138  
   139  					It("displays an informative message and exits 1", func() {
   140  						session := helpers.CF("create-service", "foo", "bar", "my-service", "-c", tempFilePath)
   141  						Eventually(session.Err).Should(Say("Invalid configuration provided for -c flag. Please provide a valid JSON object or path to a file containing a valid JSON object\\."))
   142  						Eventually(session).Should(Exit(1))
   143  					})
   144  				})
   145  
   146  				When("the provided file cannot be read", func() {
   147  					var emptyDir string
   148  
   149  					BeforeEach(func() {
   150  						var err error
   151  						emptyDir, err = ioutil.TempDir("", "")
   152  						Expect(err).NotTo(HaveOccurred())
   153  					})
   154  
   155  					AfterEach(func() {
   156  						Expect(os.RemoveAll(emptyDir)).To(Succeed())
   157  					})
   158  
   159  					It("displays an informative message and exits 1", func() {
   160  						session := helpers.CF("create-service", "foo", "bar", "my-service", "-c", filepath.Join(emptyDir, "non-existent-file"))
   161  						Eventually(session.Err).Should(Say("Invalid configuration provided for -c flag. Please provide a valid JSON object or path to a file containing a valid JSON object\\."))
   162  						Eventually(session).Should(Exit(1))
   163  					})
   164  				})
   165  			})
   166  
   167  			When("the service provided is not accessible", func() {
   168  				It("displays an informative message, exits 1", func() {
   169  					session := helpers.CF("create-service", "some-service", "some-plan", "my-service")
   170  					Eventually(session).Should(Say("Creating service instance %s in org %s / space %s as %s\\.\\.\\.",
   171  						"my-service", org, space, username))
   172  					Eventually(session).Should(Say("FAILED"))
   173  					Eventually(session.Err).Should(Say("Service offering 'some-service' not found"))
   174  					Eventually(session).Should(Exit(1))
   175  				})
   176  			})
   177  
   178  			When("the service provided is accessible", func() {
   179  				var (
   180  					service     string
   181  					servicePlan string
   182  					broker      helpers.ServiceBroker
   183  				)
   184  
   185  				BeforeEach(func() {
   186  					service = helpers.PrefixedRandomName("SERVICE")
   187  					servicePlan = helpers.PrefixedRandomName("SERVICE-PLAN")
   188  
   189  					broker = helpers.NewServiceBroker(helpers.NewServiceBrokerName(), helpers.NewAssets().ServiceBroker, domain, service, servicePlan)
   190  					broker.Push()
   191  					broker.Configure(true)
   192  					broker.Create()
   193  					Eventually(helpers.CF("enable-service-access", service)).Should(Exit(0))
   194  				})
   195  
   196  				AfterEach(func() {
   197  					broker.Destroy()
   198  				})
   199  
   200  				It("displays an informative success message, exits 0", func() {
   201  					By("creating the service")
   202  					session := helpers.CF("create-service", service, servicePlan, "my-service")
   203  					Eventually(session).Should(Say("Creating service instance %s in org %s / space %s as %s\\.\\.\\.",
   204  						"my-service", org, space, username))
   205  					Eventually(session).Should(Say("OK"))
   206  					Eventually(session).Should(Exit(0))
   207  
   208  					session = helpers.CF("services")
   209  					Eventually(session).Should(Exit(0))
   210  					Eventually(session).Should(Say("%s\\s+%s\\s+%s\\s+create succeeded",
   211  						"my-service",
   212  						service,
   213  						servicePlan,
   214  					))
   215  
   216  					By("displaying the service already exists when using a duplicate name")
   217  					session = helpers.CF("create-service", service, servicePlan, "my-service")
   218  					Eventually(session).Should(Say("OK"))
   219  					Eventually(session).Should(Say("Service my-service already exists"))
   220  					Eventually(session).Should(Exit(0))
   221  				})
   222  
   223  				When("the provided plan does not exist", func() {
   224  					It("displays an informative error message, exits 1", func() {
   225  						session := helpers.CF("create-service", service, "some-plan", "service-instance")
   226  						Eventually(session).Should(Say("Creating service instance %s in org %s / space %s as %s\\.\\.\\.",
   227  							"service-instance", org, space, username))
   228  						Eventually(session).Should(Say("FAILED"))
   229  						Eventually(session.Err).Should(Say("The plan %s could not be found for service %s", "some-plan", service))
   230  						Eventually(session).Should(Exit(1))
   231  					})
   232  				})
   233  
   234  				When("creating with valid params json", func() {
   235  					It("displays an informative success message, exits 0", func() {
   236  						session := helpers.CF("create-service", service, servicePlan, "my-service", "-c", "{}")
   237  						Eventually(session).Should(Say("Creating service instance %s in org %s / space %s as %s\\.\\.\\.",
   238  							"my-service", org, space, username))
   239  						Eventually(session).Should(Say("OK"))
   240  						Eventually(session).Should(Exit(0))
   241  
   242  						session = helpers.CF("services")
   243  						Eventually(session).Should(Exit(0))
   244  						Eventually(session).Should(Say("%s\\s+%s\\s+%s\\s+create succeeded",
   245  							"my-service",
   246  							service,
   247  							servicePlan,
   248  						))
   249  					})
   250  				})
   251  
   252  				When("creating with valid params json in a file", func() {
   253  					var tempFilePath string
   254  
   255  					BeforeEach(func() {
   256  						tempFilePath = helpers.TempFileWithContent(`{"valid":"json"}`)
   257  					})
   258  
   259  					AfterEach(func() {
   260  						Expect(os.Remove(tempFilePath)).To(Succeed())
   261  					})
   262  
   263  					It("displays an informative success message, exits 0", func() {
   264  						session := helpers.CF("create-service", service, servicePlan, "my-service", "-c", tempFilePath)
   265  						Eventually(session).Should(Say("Creating service instance %s in org %s / space %s as %s\\.\\.\\.",
   266  							"my-service", org, space, username))
   267  						Eventually(session).Should(Say("OK"))
   268  						Eventually(session).Should(Exit(0))
   269  
   270  						session = helpers.CF("services")
   271  						Eventually(session).Should(Exit(0))
   272  						Eventually(session).Should(Say("%s\\s+%s\\s+%s\\s+create succeeded",
   273  							"my-service",
   274  							service,
   275  							servicePlan,
   276  						))
   277  					})
   278  				})
   279  
   280  				When("creating with tags", func() {
   281  					It("displays an informative message, exits 0, and creates the service with tags", func() {
   282  						session := helpers.CF("create-service", service, servicePlan, "my-service", "-t", "sapi, rocks")
   283  						Eventually(session).Should(Say("Creating service instance %s in org %s / space %s as %s\\.\\.\\.",
   284  							"my-service", org, space, username))
   285  						Eventually(session).Should(Say("OK"))
   286  						Eventually(session).Should(Exit(0))
   287  
   288  						session = helpers.CF("service", "my-service")
   289  						Eventually(session).Should(Exit(0))
   290  						Eventually(session).Should(Say("tags:\\s+sapi, rocks"))
   291  					})
   292  				})
   293  			})
   294  
   295  			When("the service provided is async and accessible", func() {
   296  				var (
   297  					service     string
   298  					servicePlan string
   299  					broker      helpers.ServiceBroker
   300  				)
   301  
   302  				BeforeEach(func() {
   303  					service = helpers.PrefixedRandomName("SERVICE")
   304  					servicePlan = helpers.PrefixedRandomName("SERVICE-PLAN")
   305  
   306  					broker = helpers.NewAsynchServiceBroker(helpers.NewServiceBrokerName(), helpers.NewAssets().ServiceBroker, domain, service, servicePlan)
   307  					broker.Push()
   308  					broker.Configure(true)
   309  					broker.Create()
   310  					Eventually(helpers.CF("enable-service-access", service)).Should(Exit(0))
   311  				})
   312  
   313  				AfterEach(func() {
   314  					broker.Destroy()
   315  				})
   316  
   317  				It("creates the service and displays a message that creation is in progress", func() {
   318  					session := helpers.CF("create-service", service, servicePlan, "my-service", "-v")
   319  					Eventually(session).Should(Say("Creating service instance %s in org %s / space %s as %s\\.\\.\\.",
   320  						"my-service", org, space, username))
   321  					Eventually(session).Should(Say("OK"))
   322  					Eventually(session).Should(Say("Create in progress. Use 'cf services' or 'cf service my-service' to check operation status."))
   323  					Eventually(session).Should(Exit(0))
   324  				})
   325  			})
   326  
   327  			When("there are two services with the same name from different brokers", func() {
   328  				var (
   329  					service     string
   330  					servicePlan string
   331  					broker1     helpers.ServiceBroker
   332  					broker2     helpers.ServiceBroker
   333  				)
   334  
   335  				BeforeEach(func() {
   336  					helpers.SkipIfVersionLessThan(ccversion.MinVersionMultiServiceRegistrationV2)
   337  					service = helpers.PrefixedRandomName("SERVICE")
   338  					servicePlan = helpers.PrefixedRandomName("SERVICE-PLAN")
   339  
   340  					broker1 = helpers.CreateBroker(domain, service, servicePlan)
   341  					broker2 = helpers.CreateBroker(domain, service, servicePlan)
   342  
   343  					Eventually(helpers.CF("enable-service-access", service, "-b", broker1.Name)).Should(Exit(0))
   344  					Eventually(helpers.CF("enable-service-access", service, "-b", broker2.Name)).Should(Exit(0))
   345  				})
   346  
   347  				AfterEach(func() {
   348  					broker1.Destroy()
   349  					broker2.Destroy()
   350  				})
   351  
   352  				When("the user does not specify which broker to use", func() {
   353  					It("displays an informative error message, exits 1", func() {
   354  						session := helpers.CF("create-service", service, servicePlan, "my-service")
   355  						Eventually(session).Should(Say("Creating service instance %s in org %s / space %s as %s\\.\\.\\.",
   356  							"my-service", org, space, username))
   357  						Eventually(session.Err).Should(Say("Service '%s' is provided by multiple service brokers\\. Specify a broker by using the '-b' flag\\.", service))
   358  						Eventually(session).Should(Say("FAILED"))
   359  						Eventually(session).Should(Exit(1))
   360  					})
   361  				})
   362  
   363  				When("the user specifies which broker to use", func() {
   364  					When("the user is a space developer", func() {
   365  						BeforeEach(func() {
   366  							username = helpers.SwitchToSpaceRole(org, space, "SpaceDeveloper")
   367  							helpers.TargetOrgAndSpace(org, space)
   368  						})
   369  
   370  						AfterEach(func() {
   371  							helpers.SetupCF(org, space)
   372  						})
   373  
   374  						It("displays an informative success message, exits 0", func() {
   375  							By("creating the service with -b flag")
   376  							session := helpers.CF("create-service", service, servicePlan, "my-service", "-b", broker1.Name)
   377  							Eventually(session).Should(Say("Creating service instance %s in org %s / space %s as %s\\.\\.\\.",
   378  								"my-service", org, space, username))
   379  							Eventually(session).Should(Say("OK"))
   380  							Eventually(session).Should(Exit(0))
   381  
   382  							session = helpers.CF("services")
   383  							Eventually(session).Should(Exit(0))
   384  							Eventually(session).Should(Say("%s\\s+%s\\s+%s\\s+create succeeded",
   385  								"my-service",
   386  								service,
   387  								servicePlan,
   388  							))
   389  						})
   390  
   391  						Context("the broker is not accessible by that user", func() {
   392  							It("displays an informative error message, exits 1", func() {
   393  								session := helpers.CF("create-service", service, servicePlan, "my-service", "-b", "non-existent-broker")
   394  								Eventually(session).Should(Say("Creating service instance %s in org %s / space %s as %s\\.\\.\\.",
   395  									"my-service", org, space, username))
   396  								Eventually(session.Err).Should(Say("Service '%s' provided by service broker '%s' not found\\.", service, "non-existent-broker"))
   397  								Eventually(session).Should(Say("FAILED"))
   398  								Eventually(session).Should(Exit(1))
   399  							})
   400  						})
   401  					})
   402  				})
   403  			})
   404  		})
   405  	})
   406  })