github.com/sleungcy/cli@v7.1.0+incompatible/integration/v7/isolated/bind_service_command_test.go (about)

     1  package isolated
     2  
     3  import (
     4  	"io/ioutil"
     5  	"os"
     6  	"path/filepath"
     7  	"time"
     8  
     9  	"code.cloudfoundry.org/cli/integration/helpers/servicebrokerstub"
    10  
    11  	"code.cloudfoundry.org/cli/integration/helpers"
    12  	. "github.com/onsi/ginkgo"
    13  	. "github.com/onsi/gomega"
    14  	. "github.com/onsi/gomega/gbytes"
    15  	. "github.com/onsi/gomega/gexec"
    16  )
    17  
    18  var _ = Describe("bind-service command", func() {
    19  	Describe("help", func() {
    20  		When("--help flag is set", func() {
    21  			It("Displays command usage to output", func() {
    22  				session := helpers.CF("bind-service", "--help")
    23  				Eventually(session).Should(Say("NAME:"))
    24  				Eventually(session).Should(Say("bind-service - Bind a service instance to an app"))
    25  
    26  				Eventually(session).Should(Say("USAGE:"))
    27  				Eventually(session).Should(Say("cf bind-service APP_NAME SERVICE_INSTANCE \\[-c PARAMETERS_AS_JSON\\] \\[--binding-name BINDING_NAME\\]"))
    28  				Eventually(session).Should(Say("Optionally provide service-specific configuration parameters in a valid JSON object in-line:"))
    29  				Eventually(session).Should(Say("cf bind-service APP_NAME SERVICE_INSTANCE -c '{\"name\":\"value\",\"name\":\"value\"}'"))
    30  				Eventually(session).Should(Say("Optionally provide a file containing service-specific configuration parameters in a valid JSON object."))
    31  				Eventually(session).Should(Say("The path to the parameters file can be an absolute or relative path to a file."))
    32  				Eventually(session).Should(Say("cf bind-service APP_NAME SERVICE_INSTANCE -c PATH_TO_FILE"))
    33  				Eventually(session).Should(Say("Example of valid JSON object:"))
    34  				Eventually(session).Should(Say("{"))
    35  				Eventually(session).Should(Say("\"permissions\": \"read-only\""))
    36  				Eventually(session).Should(Say("}"))
    37  				Eventually(session).Should(Say("Optionally provide a binding name for the association between an app and a service instance:"))
    38  				Eventually(session).Should(Say("cf bind-service APP_NAME SERVICE_INSTANCE --binding-name BINDING_NAME"))
    39  				Eventually(session).Should(Say("EXAMPLES:"))
    40  				Eventually(session).Should(Say("Linux/Mac:"))
    41  				Eventually(session).Should(Say("cf bind-service myapp mydb -c '{\"permissions\":\"read-only\"}'"))
    42  				Eventually(session).Should(Say("Windows Command Line:"))
    43  				Eventually(session).Should(Say("cf bind-service myapp mydb -c \"{\\\\\"permissions\\\\\":\\\\\"read-only\\\\\"}\""))
    44  				Eventually(session).Should(Say("Windows PowerShell:"))
    45  				Eventually(session).Should(Say("cf bind-service myapp mydb -c '{\\\\\"permissions\\\\\":\\\\\"read-only\\\\\"}'"))
    46  				Eventually(session).Should(Say("cf bind-service myapp mydb -c ~/workspace/tmp/instance_config.json --binding-name BINDING_NAME"))
    47  				Eventually(session).Should(Say("ALIAS:"))
    48  				Eventually(session).Should(Say("bs"))
    49  				Eventually(session).Should(Say("OPTIONS:"))
    50  				Eventually(session).Should(Say("--binding-name\\s+Name to expose service instance to app process with \\(Default: service instance name\\)"))
    51  				Eventually(session).Should(Say("-c\\s+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."))
    52  				Eventually(session).Should(Say("SEE ALSO:"))
    53  				Eventually(session).Should(Say("services"))
    54  				Eventually(session).Should(Exit(0))
    55  			})
    56  		})
    57  	})
    58  
    59  	var (
    60  		serviceInstance string
    61  		appName         string
    62  	)
    63  
    64  	BeforeEach(func() {
    65  		serviceInstance = helpers.PrefixedRandomName("si")
    66  		appName = helpers.PrefixedRandomName("app")
    67  	})
    68  
    69  	When("the environment is not setup correctly", func() {
    70  		It("fails with the appropriate errors", func() {
    71  			helpers.CheckEnvironmentTargetedCorrectly(true, true, ReadOnlyOrg, "bind-service", "app-name", "service-name")
    72  		})
    73  	})
    74  
    75  	When("provided invalid flag values", func() {
    76  		When("the --binding-name flag is provided and its value is the empty string", func() {
    77  			It("returns an invalid usage error and the help text", func() {
    78  				session := helpers.CF("bind-service", appName, serviceInstance, "--binding-name", "")
    79  				Eventually(session.Err).Should(Say("--binding-name must be at least 1 character in length"))
    80  
    81  				Eventually(session).Should(Say("NAME:"))
    82  				Eventually(session).Should(Exit(1))
    83  			})
    84  		})
    85  	})
    86  
    87  	When("the environment is setup correctly", func() {
    88  		var (
    89  			org      string
    90  			space    string
    91  			username string
    92  		)
    93  
    94  		BeforeEach(func() {
    95  			org = helpers.NewOrgName()
    96  			space = helpers.NewSpaceName()
    97  			username, _ = helpers.GetCredentials()
    98  
    99  			helpers.SetupCF(org, space)
   100  		})
   101  
   102  		AfterEach(func() {
   103  			helpers.QuickDeleteOrg(org)
   104  		})
   105  
   106  		When("the app does not exist", func() {
   107  			It("displays FAILED and app not found", func() {
   108  				session := helpers.CF("bind-service", "does-not-exist", serviceInstance)
   109  				Eventually(session).Should(Say("FAILED"))
   110  				Eventually(session.Err).Should(Say("App '%s' not found", "does-not-exist"))
   111  				Eventually(session).Should(Exit(1))
   112  			})
   113  		})
   114  
   115  		When("the app exists", func() {
   116  			BeforeEach(func() {
   117  				helpers.WithHelloWorldApp(func(appDir string) {
   118  					Eventually(helpers.CF("push", appName, "--no-start", "-p", appDir, "-b", "staticfile_buildpack", "--no-route")).Should(Exit(0))
   119  				})
   120  			})
   121  
   122  			When("the service does not exist", func() {
   123  				It("displays FAILED and service not found", func() {
   124  					session := helpers.CF("bind-service", appName, "does-not-exist")
   125  					Eventually(session).Should(Say("FAILED"))
   126  					Eventually(session.Err).Should(Say("Service instance %s not found", "does-not-exist"))
   127  					Eventually(session).Should(Exit(1))
   128  				})
   129  			})
   130  
   131  			When("the service exists", func() {
   132  				BeforeEach(func() {
   133  					Eventually(helpers.CF("create-user-provided-service", serviceInstance, "-p", "{}")).Should(Exit(0))
   134  					helpers.WithHelloWorldApp(func(appDir string) {
   135  						Eventually(helpers.CF("push", appName, "--no-start", "-p", appDir, "-b", "staticfile_buildpack", "--no-route")).Should(Exit(0))
   136  					})
   137  				})
   138  
   139  				AfterEach(func() {
   140  					Eventually(helpers.CF("unbind-service", appName, serviceInstance)).Should(Exit(0))
   141  					Eventually(helpers.CF("delete-service", serviceInstance, "-f")).Should(Exit(0))
   142  				})
   143  
   144  				It("binds the service to the app, displays OK and TIP", func() {
   145  					session := helpers.CF("bind-service", appName, serviceInstance)
   146  					Eventually(session).Should(Say("Binding service %s to app %s in org %s / space %s as %s...", serviceInstance, appName, org, space, username))
   147  
   148  					Eventually(session).Should(Say("OK"))
   149  					Eventually(session).Should(Say("TIP: Use 'cf restage %s' to ensure your env variable changes take effect", appName))
   150  					Eventually(session).Should(Exit(0))
   151  				})
   152  
   153  				When("the service is already bound to an app", func() {
   154  					BeforeEach(func() {
   155  						Eventually(helpers.CF("bind-service", appName, serviceInstance)).Should(Exit(0))
   156  					})
   157  
   158  					It("displays OK and that the app is already bound to the service", func() {
   159  						session := helpers.CF("bind-service", appName, serviceInstance)
   160  
   161  						Eventually(session).Should(Say("Binding service %s to app %s in org %s / space %s as %s...", serviceInstance, appName, org, space, username))
   162  						Eventually(session).Should(Say("App %s is already bound to %s.", appName, serviceInstance))
   163  						Eventually(session).Should(Say("OK"))
   164  
   165  						Eventually(session).Should(Exit(0))
   166  					})
   167  				})
   168  
   169  				When("the --binding-name flag is provided and the value is a non-empty string", func() {
   170  					It("binds the service to the app, displays OK and TIP", func() {
   171  						session := helpers.CF("bind-service", appName, serviceInstance, "--binding-name", "i-am-a-binding")
   172  						Eventually(session.Out).Should(Say("Binding service %s to app %s with binding name %s in org %s / space %s as %s...", serviceInstance, appName, "i-am-a-binding", org, space, username))
   173  
   174  						Eventually(session.Out).Should(Say("OK"))
   175  						Eventually(session.Out).Should(Say("TIP: Use 'cf restage %s' to ensure your env variable changes take effect", appName))
   176  						Eventually(session).Should(Exit(0))
   177  					})
   178  				})
   179  
   180  				When("configuration parameters are provided in a file", func() {
   181  					var configurationFile *os.File
   182  
   183  					When("the file-path does not exist", func() {
   184  						It("displays FAILED and the invalid configuration error", func() {
   185  							session := helpers.CF("bind-service", appName, serviceInstance, "-c", "i-do-not-exist")
   186  							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."))
   187  
   188  							Eventually(session).Should(Exit(1))
   189  						})
   190  					})
   191  
   192  					When("the file contians invalid json", func() {
   193  						BeforeEach(func() {
   194  							var err error
   195  							content := []byte("{i-am-very-bad-json")
   196  							configurationFile, err = ioutil.TempFile("", "CF_CLI")
   197  							Expect(err).ToNot(HaveOccurred())
   198  
   199  							_, err = configurationFile.Write(content)
   200  							Expect(err).ToNot(HaveOccurred())
   201  
   202  							err = configurationFile.Close()
   203  							Expect(err).ToNot(HaveOccurred())
   204  						})
   205  
   206  						AfterEach(func() {
   207  							Expect(os.RemoveAll(configurationFile.Name())).ToNot(HaveOccurred())
   208  						})
   209  
   210  						It("displays FAILED and the invalid configuration error", func() {
   211  							session := helpers.CF("bind-service", appName, serviceInstance, "-c", configurationFile.Name())
   212  							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."))
   213  
   214  							Eventually(session).Should(Exit(1))
   215  						})
   216  					})
   217  
   218  					When("the file-path is relative", func() {
   219  						BeforeEach(func() {
   220  							var err error
   221  							content := []byte("{\"i-am-good-json\":\"good-boy\"}")
   222  							configurationFile, err = ioutil.TempFile("", "CF_CLI")
   223  							Expect(err).ToNot(HaveOccurred())
   224  
   225  							_, err = configurationFile.Write(content)
   226  							Expect(err).ToNot(HaveOccurred())
   227  
   228  							err = configurationFile.Close()
   229  							Expect(err).ToNot(HaveOccurred())
   230  						})
   231  
   232  						AfterEach(func() {
   233  							Expect(os.RemoveAll(configurationFile.Name())).ToNot(HaveOccurred())
   234  						})
   235  
   236  						It("binds the service to the app, displays OK and TIP", func() {
   237  							session := helpers.CF("bind-service", appName, serviceInstance, "-c", configurationFile.Name())
   238  							Eventually(session).Should(Say("Binding service %s to app %s in org %s / space %s as %s...", serviceInstance, appName, org, space, username))
   239  
   240  							Eventually(session).Should(Say("OK"))
   241  							Eventually(session).Should(Say("TIP: Use 'cf restage %s' to ensure your env variable changes take effect", appName))
   242  							Eventually(session).Should(Exit(0))
   243  						})
   244  					})
   245  
   246  					When("the file-path is absolute", func() {
   247  						BeforeEach(func() {
   248  							var err error
   249  							content := []byte("{\"i-am-good-json\":\"good-boy\"}")
   250  							configurationFile, err = ioutil.TempFile("", "CF_CLI")
   251  							Expect(err).ToNot(HaveOccurred())
   252  
   253  							_, err = configurationFile.Write(content)
   254  							Expect(err).ToNot(HaveOccurred())
   255  
   256  							err = configurationFile.Close()
   257  							Expect(err).ToNot(HaveOccurred())
   258  						})
   259  
   260  						AfterEach(func() {
   261  							Expect(os.RemoveAll(configurationFile.Name())).ToNot(HaveOccurred())
   262  						})
   263  
   264  						It("binds the service to the app, displays OK and TIP", func() {
   265  							absolutePath, err := filepath.Abs(configurationFile.Name())
   266  							Expect(err).ToNot(HaveOccurred())
   267  							session := helpers.CF("bind-service", appName, serviceInstance, "-c", absolutePath)
   268  							Eventually(session).Should(Say("Binding service %s to app %s in org %s / space %s as %s...", serviceInstance, appName, org, space, username))
   269  
   270  							Eventually(session).Should(Say("OK"))
   271  							Eventually(session).Should(Say("TIP: Use 'cf restage %s' to ensure your env variable changes take effect", appName))
   272  							Eventually(session).Should(Exit(0))
   273  						})
   274  					})
   275  				})
   276  
   277  				When("configuration paramters are provided as in-line JSON", func() {
   278  					When("the JSON is invalid", func() {
   279  						It("displays FAILED and the invalid configuration error", func() {
   280  							session := helpers.CF("bind-service", appName, serviceInstance, "-c", "i-am-invalid-json")
   281  							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."))
   282  
   283  							Eventually(session).Should(Exit(1))
   284  						})
   285  					})
   286  
   287  					When("the JSON is valid", func() {
   288  						It("binds the service to the app, displays OK and TIP", func() {
   289  							session := helpers.CF("bind-service", appName, serviceInstance, "-c", "{\"i-am-valid-json\":\"dope dude\"}")
   290  							Eventually(session).Should(Say("Binding service %s to app %s in org %s / space %s as %s...", serviceInstance, appName, org, space, username))
   291  
   292  							Eventually(session).Should(Say("OK"))
   293  							Eventually(session).Should(Say("TIP: Use 'cf restage %s' to ensure your env variable changes take effect", appName))
   294  							Eventually(session).Should(Exit(0))
   295  						})
   296  					})
   297  				})
   298  			})
   299  
   300  			When("the service is provided by a broker", func() {
   301  				var broker *servicebrokerstub.ServiceBrokerStub
   302  
   303  				AfterEach(func() {
   304  					broker.Forget()
   305  				})
   306  
   307  				When("the service binding is blocking", func() {
   308  					BeforeEach(func() {
   309  						broker = servicebrokerstub.EnableServiceAccess()
   310  
   311  						Eventually(helpers.CF("create-service", broker.FirstServiceOfferingName(), broker.FirstServicePlanName(), serviceInstance)).Should(Exit(0))
   312  					})
   313  
   314  					It("binds the service to the app, displays OK and TIP", func() {
   315  						session := helpers.CF("bind-service", appName, serviceInstance, "-c", `{"wheres":"waldo"}`)
   316  						Eventually(session).Should(Say("Binding service %s to app %s in org %s / space %s as %s...", serviceInstance, appName, org, space, username))
   317  
   318  						Eventually(session).Should(Say("OK"))
   319  						Eventually(session).Should(Say("TIP: Use 'cf restage %s' to ensure your env variable changes take effect", appName))
   320  						Eventually(session).Should(Exit(0))
   321  
   322  						session = helpers.CF("service", serviceInstance)
   323  						Eventually(session).Should(Say(appName))
   324  						Eventually(session).Should(Exit(0))
   325  					})
   326  				})
   327  
   328  				When("the service binding is asynchronous", func() {
   329  					BeforeEach(func() {
   330  						broker = servicebrokerstub.New().WithAsyncDelay(time.Millisecond).EnableServiceAccess()
   331  
   332  						Eventually(helpers.CF("create-service", broker.FirstServiceOfferingName(), broker.FirstServicePlanName(), serviceInstance)).Should(Exit(0))
   333  
   334  						Eventually(func() *Session {
   335  							session := helpers.CF("service", serviceInstance)
   336  							return session.Wait()
   337  						}, time.Minute*5, time.Second*5).Should(Say("create succeeded"))
   338  					})
   339  
   340  					It("binds the service to the app, displays OK and TIP", func() {
   341  						session := helpers.CF("bind-service", appName, serviceInstance, "-c", `{"wheres":"waldo"}`)
   342  						Eventually(session).Should(Say("Binding service %s to app %s in org %s / space %s as %s...", serviceInstance, appName, org, space, username))
   343  
   344  						Eventually(session).Should(Say("OK"))
   345  						Eventually(session).Should(Say("Binding in progress. Use 'cf service %s' to check operation status.", serviceInstance))
   346  						Eventually(session).Should(Say("TIP: Once this operation succeeds, use 'cf restage %s' to ensure your env variable changes take effect", appName))
   347  						Eventually(session).Should(Exit(0))
   348  
   349  						session = helpers.CF("service", serviceInstance)
   350  						Eventually(session).Should(Say(appName))
   351  						Eventually(session).Should(Exit(0))
   352  					})
   353  				})
   354  			})
   355  		})
   356  	})
   357  })