github.com/LukasHeimann/cloudfoundrycli/v8@v8.4.4/integration/v7/isolated/bind_route_service_command_test.go (about)

     1  package isolated
     2  
     3  import (
     4  	"os"
     5  	"time"
     6  
     7  	"github.com/LukasHeimann/cloudfoundrycli/v8/integration/helpers"
     8  	"github.com/LukasHeimann/cloudfoundrycli/v8/integration/helpers/servicebrokerstub"
     9  	"github.com/LukasHeimann/cloudfoundrycli/v8/resources"
    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("bind-route-service command", func() {
    17  	const command = "bind-route-service"
    18  
    19  	Describe("help", func() {
    20  		matchHelpMessage := SatisfyAll(
    21  			Say(`NAME:\n`),
    22  			Say(`\s+%s - Bind a service instance to an HTTP route\n`, command),
    23  			Say(`\n`),
    24  			Say(`USAGE:\n`),
    25  			Say(`\s+cf bind-route-service DOMAIN \[--hostname HOSTNAME\] \[--path PATH\] SERVICE_INSTANCE \[-c PARAMETERS_AS_JSON\]\n`),
    26  			Say(`\n`),
    27  			Say(`EXAMPLES:\n`),
    28  			Say(`\s+cf bind-route-service example.com --hostname myapp --path foo myratelimiter\n`),
    29  			Say(`\s+cf bind-route-service example.com myratelimiter -c file.json\n`),
    30  			Say(`\s+cf bind-route-service example.com myratelimiter -c '{"valid":"json"}'\n`),
    31  			Say(`\n`),
    32  			Say(`\s+In Windows PowerShell use double-quoted, escaped JSON: "\{\\"valid\\":\\"json\\"\}"\n`),
    33  			Say(`\s+In Windows Command Line use single-quoted, escaped JSON: '\{\\"valid\\":\\"json\\"\}'\n`),
    34  			Say(`\n`),
    35  			Say(`ALIAS:\n`),
    36  			Say(`\s+brs\n`),
    37  			Say(`\n`),
    38  			Say(`OPTIONS:\n`),
    39  			Say(`\s+-c\s+Valid JSON object containing service-specific configuration parameters, provided inline or in a file. For a list of supported configuration parameters, see documentation for the particular service offering.\n`),
    40  			Say(`\s+--hostname, -n\s+Hostname used in combination with DOMAIN to specify the route to bind\n`),
    41  			Say(`\s+--path\s+Path used in combination with HOSTNAME and DOMAIN to specify the route to bind\n`),
    42  			Say(`\s+--wait, -w\s+Wait for the operation to complete\n`),
    43  			Say(`\n`),
    44  			Say(`SEE ALSO:\n`),
    45  			Say(`\s+routes, services\n`),
    46  		)
    47  
    48  		When("the -h flag is specified", func() {
    49  			It("succeeds and prints help", func() {
    50  				session := helpers.CF(command, "-h")
    51  				Eventually(session).Should(Exit(0))
    52  				Expect(session.Out).To(matchHelpMessage)
    53  			})
    54  		})
    55  
    56  		When("the --help flag is specified", func() {
    57  			It("succeeds and prints help", func() {
    58  				session := helpers.CF(command, "--help")
    59  				Eventually(session).Should(Exit(0))
    60  				Expect(session.Out).To(matchHelpMessage)
    61  			})
    62  		})
    63  
    64  		When("no arguments are provided", func() {
    65  			It("displays a warning, the help text, and exits 1", func() {
    66  				session := helpers.CF(command)
    67  				Eventually(session).Should(Exit(1))
    68  				Expect(session.Err).To(Say("Incorrect Usage: the required arguments `DOMAIN` and `SERVICE_INSTANCE` were not provided"))
    69  				Expect(session.Out).To(matchHelpMessage)
    70  			})
    71  		})
    72  
    73  		When("unknown flag is passed", func() {
    74  			It("displays a warning, the help text, and exits 1", func() {
    75  				session := helpers.CF(command, "-u")
    76  				Eventually(session).Should(Exit(1))
    77  				Expect(session.Err).To(Say("Incorrect Usage: unknown flag `u"))
    78  				Expect(session.Out).To(matchHelpMessage)
    79  			})
    80  		})
    81  
    82  		When("-c is provided with invalid JSON", func() {
    83  			It("displays a warning, the help text, and exits 1", func() {
    84  				session := helpers.CF(command, "-c", `{"not":json"}`)
    85  				Eventually(session).Should(Exit(1))
    86  				Expect(session.Err).To(Say("Incorrect Usage: Invalid configuration provided for -c flag. Please provide a valid JSON object or path to a file containing a valid JSON object."))
    87  				Expect(session.Out).To(matchHelpMessage)
    88  			})
    89  		})
    90  
    91  		When("-c is provided with invalid JSON file", func() {
    92  			It("displays a warning, the help text, and exits 1", func() {
    93  				filename := helpers.TempFileWithContent(`{"not":json"}`)
    94  				defer os.Remove(filename)
    95  
    96  				session := helpers.CF(command, "-c", filename)
    97  				Eventually(session).Should(Exit(1))
    98  				Expect(session.Err).To(Say("Incorrect Usage: Invalid configuration provided for -c flag. Please provide a valid JSON object or path to a file containing a valid JSON object."))
    99  				Expect(session.Out).To(matchHelpMessage)
   100  			})
   101  
   102  		})
   103  	})
   104  
   105  	When("the environment is not setup correctly", func() {
   106  		It("fails with the appropriate errors", func() {
   107  			helpers.CheckEnvironmentTargetedCorrectly(true, true, ReadOnlyOrg, command, "foo", "bar")
   108  		})
   109  	})
   110  
   111  	When("targeting a space", func() {
   112  		var (
   113  			orgName   string
   114  			spaceName string
   115  			username  string
   116  		)
   117  
   118  		routeBindingStateForSI := func(serviceInstanceName string) string {
   119  			var receiver struct {
   120  				Resources []resources.RouteBinding `json:"resources"`
   121  			}
   122  			helpers.Curl(&receiver, "/v3/service_route_bindings?service_instance_names=%s", serviceInstanceName)
   123  			Expect(receiver.Resources).To(HaveLen(1))
   124  
   125  			return string(receiver.Resources[0].LastOperation.State)
   126  		}
   127  
   128  		BeforeEach(func() {
   129  			orgName = helpers.NewOrgName()
   130  			spaceName = helpers.NewSpaceName()
   131  			helpers.SetupCF(orgName, spaceName)
   132  
   133  			username, _ = helpers.GetCredentials()
   134  		})
   135  
   136  		AfterEach(func() {
   137  			helpers.QuickDeleteOrg(orgName)
   138  		})
   139  
   140  		Context("user-provided route service", func() {
   141  			var (
   142  				routeServiceURL     string
   143  				serviceInstanceName string
   144  				domain              string
   145  				hostname            string
   146  				path                string
   147  			)
   148  
   149  			BeforeEach(func() {
   150  				routeServiceURL = helpers.RandomURL()
   151  				serviceInstanceName = helpers.NewServiceInstanceName()
   152  				Eventually(helpers.CF("cups", serviceInstanceName, "-r", routeServiceURL)).Should(Exit(0))
   153  
   154  				domain = helpers.DefaultSharedDomain()
   155  				hostname = helpers.NewHostName()
   156  				path = helpers.PrefixedRandomName("path")
   157  				Eventually(helpers.CF("create-route", domain, "--hostname", hostname, "--path", path)).Should(Exit(0))
   158  			})
   159  
   160  			It("creates a route binding", func() {
   161  				session := helpers.CF(command, domain, "--hostname", hostname, "--path", path, serviceInstanceName)
   162  				Eventually(session).Should(Exit(0))
   163  
   164  				Expect(session.Out).To(SatisfyAll(
   165  					Say(`Binding route %s.%s/%s to service instance %s in org %s / space %s as %s\.\.\.\n`, hostname, domain, path, serviceInstanceName, orgName, spaceName, username),
   166  					Say(`OK\n`),
   167  				))
   168  
   169  				Expect(string(session.Err.Contents())).To(BeEmpty())
   170  
   171  				Expect(routeBindingStateForSI(serviceInstanceName)).To(Equal("succeeded"))
   172  			})
   173  
   174  			When("parameters are specified", func() {
   175  				It("fails with an error returned by the CC", func() {
   176  					session := helpers.CF(command, domain, "--hostname", hostname, "--path", path, serviceInstanceName, "-c", `{"foo":"bar"}`)
   177  					Eventually(session).Should(Exit(1))
   178  
   179  					Expect(session.Out).To(SatisfyAll(
   180  						Say(`Binding route %s.%s/%s to service instance %s in org %s / space %s as %s\.\.\.\n`, hostname, domain, path, serviceInstanceName, orgName, spaceName, username),
   181  						Say(`FAILED\n`),
   182  					))
   183  
   184  					Expect(session.Err).To(Say(`Binding parameters are not supported for user-provided service instances\n`))
   185  				})
   186  			})
   187  		})
   188  
   189  		Context("managed route service with synchronous broker response", func() {
   190  			var (
   191  				broker              *servicebrokerstub.ServiceBrokerStub
   192  				serviceInstanceName string
   193  				domain              string
   194  				hostname            string
   195  				path                string
   196  			)
   197  
   198  			BeforeEach(func() {
   199  				broker = servicebrokerstub.New().WithRouteService().EnableServiceAccess()
   200  				serviceInstanceName = helpers.NewServiceInstanceName()
   201  				helpers.CreateManagedServiceInstance(broker.FirstServiceOfferingName(), broker.FirstServicePlanName(), serviceInstanceName)
   202  
   203  				domain = helpers.DefaultSharedDomain()
   204  				hostname = helpers.NewHostName()
   205  				path = helpers.PrefixedRandomName("path")
   206  				Eventually(helpers.CF("create-route", domain, "--hostname", hostname, "--path", path)).Should(Exit(0))
   207  			})
   208  
   209  			AfterEach(func() {
   210  				broker.Forget()
   211  			})
   212  
   213  			It("creates a route binding", func() {
   214  				session := helpers.CF(command, domain, "--hostname", hostname, "--path", path, serviceInstanceName)
   215  				Eventually(session).Should(Exit(0))
   216  
   217  				Expect(session.Out).To(SatisfyAll(
   218  					Say(`Binding route %s.%s/%s to service instance %s in org %s / space %s as %s\.\.\.\n`, hostname, domain, path, serviceInstanceName, orgName, spaceName, username),
   219  					Say(`OK\n`),
   220  				))
   221  
   222  				Expect(string(session.Err.Contents())).To(BeEmpty())
   223  
   224  				Expect(routeBindingStateForSI(serviceInstanceName)).To(Equal("succeeded"))
   225  			})
   226  
   227  			When("parameters are specified", func() {
   228  				It("sends the parameters to the broker", func() {
   229  					session := helpers.CF(command, domain, "--hostname", hostname, "--path", path, serviceInstanceName, "-c", `{"foo":"bar"}`)
   230  					Eventually(session).Should(Exit(0))
   231  
   232  					var receiver struct {
   233  						Resources []resources.RouteBinding `json:"resources"`
   234  					}
   235  					helpers.Curl(&receiver, "/v3/service_route_bindings?service_instance_names=%s", serviceInstanceName)
   236  					Expect(receiver.Resources).To(HaveLen(1))
   237  
   238  					var parametersReceiver map[string]interface{}
   239  					helpers.Curl(&parametersReceiver, `/v3/service_route_bindings/%s/parameters`, receiver.Resources[0].GUID)
   240  					Expect(parametersReceiver).To(Equal(map[string]interface{}{"foo": "bar"}))
   241  				})
   242  			})
   243  		})
   244  
   245  		Context("managed route service with asynchronous broker response", func() {
   246  			var (
   247  				broker              *servicebrokerstub.ServiceBrokerStub
   248  				serviceInstanceName string
   249  				domain              string
   250  				hostname            string
   251  				path                string
   252  			)
   253  
   254  			BeforeEach(func() {
   255  				broker = servicebrokerstub.New().WithRouteService().EnableServiceAccess()
   256  				serviceInstanceName = helpers.NewServiceInstanceName()
   257  				helpers.CreateManagedServiceInstance(broker.FirstServiceOfferingName(), broker.FirstServicePlanName(), serviceInstanceName)
   258  
   259  				domain = helpers.DefaultSharedDomain()
   260  				hostname = helpers.NewHostName()
   261  				path = helpers.PrefixedRandomName("path")
   262  				Eventually(helpers.CF("create-route", domain, "--hostname", hostname, "--path", path)).Should(Exit(0))
   263  
   264  				broker.WithAsyncDelay(time.Second).Configure()
   265  			})
   266  
   267  			AfterEach(func() {
   268  				broker.Forget()
   269  			})
   270  
   271  			It("starts to create a route binding", func() {
   272  				session := helpers.CF(command, domain, "--hostname", hostname, "--path", path, serviceInstanceName)
   273  				Eventually(session).Should(Exit(0))
   274  
   275  				Expect(session.Out).To(SatisfyAll(
   276  					Say(`Binding route %s.%s/%s to service instance %s in org %s / space %s as %s\.\.\.\n`, hostname, domain, path, serviceInstanceName, orgName, spaceName, username),
   277  					Say(`OK\n`),
   278  					Say(`\n`),
   279  					Say(`Binding in progress\.\n`),
   280  				))
   281  
   282  				Expect(string(session.Err.Contents())).To(BeEmpty())
   283  
   284  				Expect(routeBindingStateForSI(serviceInstanceName)).To(Equal("in progress"))
   285  			})
   286  
   287  			When("--wait flag specified", func() {
   288  				It("waits for completion", func() {
   289  					session := helpers.CF(command, domain, "--hostname", hostname, "--path", path, serviceInstanceName, "--wait")
   290  					Eventually(session).Should(Exit(0))
   291  
   292  					Expect(session.Out).To(SatisfyAll(
   293  						Say(`Binding route %s.%s/%s to service instance %s in org %s / space %s as %s\.\.\.\n`, hostname, domain, path, serviceInstanceName, orgName, spaceName, username),
   294  						Say(`Waiting for the operation to complete\.+\n`),
   295  						Say(`\n`),
   296  						Say(`OK\n`),
   297  					))
   298  
   299  					Expect(string(session.Err.Contents())).To(BeEmpty())
   300  
   301  					Expect(routeBindingStateForSI(serviceInstanceName)).To(Equal("succeeded"))
   302  				})
   303  			})
   304  		})
   305  
   306  		Context("route binding already exists", func() {
   307  			var (
   308  				routeServiceURL     string
   309  				serviceInstanceName string
   310  				domain              string
   311  				hostname            string
   312  				path                string
   313  			)
   314  
   315  			BeforeEach(func() {
   316  				routeServiceURL = helpers.RandomURL()
   317  				serviceInstanceName = helpers.NewServiceInstanceName()
   318  				Eventually(helpers.CF("cups", serviceInstanceName, "-r", routeServiceURL)).Should(Exit(0))
   319  
   320  				domain = helpers.DefaultSharedDomain()
   321  				hostname = helpers.NewHostName()
   322  				path = helpers.PrefixedRandomName("path")
   323  				Eventually(helpers.CF("create-route", domain, "--hostname", hostname, "--path", path)).Should(Exit(0))
   324  
   325  				session := helpers.CF(command, domain, "--hostname", hostname, "--path", path, serviceInstanceName)
   326  				Eventually(session).Should(Exit(0))
   327  			})
   328  
   329  			It("says OK", func() {
   330  				session := helpers.CF(command, domain, "--hostname", hostname, "--path", path, serviceInstanceName)
   331  				Eventually(session).Should(Exit(0))
   332  
   333  				Expect(session.Out).To(SatisfyAll(
   334  					Say(`Binding route %s.%s/%s to service instance %s in org %s / space %s as %s\.\.\.\n`, hostname, domain, path, serviceInstanceName, orgName, spaceName, username),
   335  					Say(`Route %s.%s/%s is already bound to service instance %s\.\n`, hostname, domain, path, serviceInstanceName),
   336  					Say(`OK\n`),
   337  				))
   338  
   339  				Expect(string(session.Err.Contents())).To(BeEmpty())
   340  			})
   341  		})
   342  	})
   343  })