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(¶metersReceiver, `/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 })