github.com/franc20/ayesa_sap@v7.0.0-beta.28.0.20200124003224-302d4d52fa6c+incompatible/integration/v6/isolated/curl_command_test.go (about) 1 package isolated 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "os" 7 "path/filepath" 8 "regexp" 9 "strings" 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("curl command", func() { 19 var ExpectHelpText = func(session *Session) { 20 Eventually(session).Should(Say(`NAME:\n`)) 21 Eventually(session).Should(Say(`curl - Executes a request to the targeted API endpoint\n`)) 22 Eventually(session).Should(Say(`\n`)) 23 24 Eventually(session).Should(Say(`USAGE:\n`)) 25 Eventually(session).Should(Say(`\s+cf curl PATH \[-iv\] \[-X METHOD\] \[-H HEADER\]\.\.\. \[-d DATA\] \[--output FILE\]`)) 26 Eventually(session).Should(Say(`\s+By default 'cf curl' will perform a GET to the specified PATH. If data`)) 27 Eventually(session).Should(Say(`\s+is provided via -d, a POST will be performed instead, and the Content-Type\n`)) 28 Eventually(session).Should(Say(`\s+will be set to application/json. You may override headers with -H and the\n`)) 29 Eventually(session).Should(Say(`\s+request method with -X.\n`)) 30 Eventually(session).Should(Say(`\s+For API documentation, please visit http://apidocs.cloudfoundry.org.\n`)) 31 Eventually(session).Should(Say(`\n`)) 32 33 Eventually(session).Should(Say(`EXAMPLES:\n`)) 34 Eventually(session).Should(Say(`\s+cf curl \"/v2/apps\" -X GET -H \"Content-Type: application/x-www-form-urlencoded\" -d 'q=name:myapp'`)) 35 Eventually(session).Should(Say(`\s+cf curl \"/v2/apps\" -d @/path/to/file`)) 36 Eventually(session).Should(Say(`\n`)) 37 38 Eventually(session).Should(Say(`OPTIONS:\n`)) 39 Eventually(session).Should(Say(`\s+-H\s+Custom headers to include in the request, flag can be specified multiple times`)) 40 Eventually(session).Should(Say(`\s+-X\s+HTTP method \(GET,POST,PUT,DELETE,etc\)`)) 41 Eventually(session).Should(Say(`\s+-d\s+HTTP data to include in the request body, or '@' followed by a file name to read the data from`)) 42 Eventually(session).Should(Say(`\s+--fail,\s+-f\s+Server errors return exit code 22`)) 43 Eventually(session).Should(Say(`\s+-i\s+Include response headers in the output`)) 44 Eventually(session).Should(Say(`\s+--output\s+Write curl body to FILE instead of stdout`)) 45 } 46 47 var ExpectRequestHeaders = func(session *Session) { 48 Eventually(session).Should(Say(`REQUEST: .+`)) 49 Eventually(session).Should(Say(`(GET|POST|PUT|DELETE) /v2/apps HTTP/1.1`)) 50 Eventually(session).Should(Say(`Host: .+`)) 51 Eventually(session).Should(Say(`Accept: .+`)) 52 Eventually(session).Should(Say(`Authorization:\s+\[PRIVATE DATA HIDDEN\]`)) 53 Eventually(session).Should(Say(`Content-Type: .+`)) 54 Eventually(session).Should(Say(`User-Agent: .+`)) 55 } 56 57 var ExpectResponseHeaders = func(session *Session) { 58 Eventually(session).Should(Say("HTTP/1.1 200 OK")) 59 Eventually(session).Should(Say(`Connection: .+`)) 60 Eventually(session).Should(Say(`Content-Length: .+`)) 61 Eventually(session).Should(Say(`Content-Type: .+`)) 62 Eventually(session).Should(Say(`Date: .+`)) 63 Eventually(session).Should(Say(`Server: .+`)) 64 Eventually(session).Should(Say(`X-Content-Type-Options: .+`)) 65 Eventually(session).Should(Say(`X-Vcap-Request-Id: .+`)) 66 } 67 68 Describe("Help Text", func() { 69 When("--help flag is set", func() { 70 It("Displays command usage to the output", func() { 71 session := helpers.CF("curl", "--help") 72 ExpectHelpText(session) 73 Eventually(session).Should(Exit(0)) 74 }) 75 }) 76 }) 77 78 Describe("Incorrect Usage", func() { 79 When("no arguments are provided", func() { 80 It("fails and displays the help text", func() { 81 session := helpers.CF("curl") 82 Eventually(session.Err).Should(Say("Incorrect Usage: the required argument `PATH` was not provided")) 83 ExpectHelpText(session) 84 Eventually(session).Should(Exit(1)) 85 }) 86 }) 87 88 When("unknown flag is specified", func() { 89 It("fails and displays the help text", func() { 90 session := helpers.CF("curl", "--test") 91 Eventually(session.Err).Should(Say("Incorrect Usage: unknown flag `test'")) 92 ExpectHelpText(session) 93 Eventually(session).Should(Exit(1)) 94 }) 95 }) 96 97 When("more than one path is specified", func() { 98 It("fails and displays the help text", func() { 99 session := helpers.CF("curl", "/v2/apps", "/v2/apps") 100 Eventually(session).Should(Say("FAILED\n")) 101 Eventually(session).Should(Say("Incorrect Usage. An argument is missing or not correctly enclosed.")) 102 ExpectHelpText(session) 103 Eventually(session).Should(Exit(1)) 104 }) 105 }) 106 }) 107 108 When("the user is not logged in", func() { 109 It("makes the request and receives an unauthenticated error", func() { 110 session := helpers.CF("curl", "/v2/apps") 111 expectedJSON := `{ 112 "description": "Authentication error", 113 "error_code": "CF-NotAuthenticated", 114 "code": 10002 115 }` 116 Eventually(session).Should(Exit(0)) 117 Expect(session.Out.Contents()).To(MatchJSON(expectedJSON)) 118 }) 119 }) 120 121 Describe("User Agent", func() { 122 It("sets the User-Agent Header to contain the CLI version", func() { 123 getVersionNumber := func() string { 124 versionSession := helpers.CF("version") 125 Eventually(versionSession).Should(Exit(0)) 126 versionPattern := regexp.MustCompile("cf version (.+)") 127 version := versionPattern.FindStringSubmatch(string(versionSession.Out.Contents())) 128 Expect(version).ToNot(BeEmpty()) 129 return regexp.QuoteMeta(version[1]) 130 } 131 session := helpers.CF("curl", "/v2/info", "-v") 132 Eventually(session).Should(Exit(0)) 133 134 Expect(session).To(Say(`User-Agent: go-cli %s`, getVersionNumber())) 135 }) 136 }) 137 138 When("the user is logged in", func() { 139 var orgName string 140 141 BeforeEach(func() { 142 orgName = helpers.NewOrgName() 143 spaceName := helpers.NewSpaceName() 144 145 helpers.SetupCF(orgName, spaceName) 146 helpers.SwitchToOrgRole(orgName, "OrgManager") 147 helpers.TargetOrg(orgName) 148 }) 149 150 When("the path is valid", func() { 151 var expectedJSON string 152 153 BeforeEach(func() { 154 expectedJSON = `{ 155 "total_results": 0, 156 "total_pages": 1, 157 "prev_url": null, 158 "next_url": null, 159 "resources": [] 160 }` 161 }) 162 163 When("the path has multiple initial slashes", func() { 164 It("changes the path to use only one slash", func() { 165 session := helpers.CF("curl", "////v2/apps", "-v") 166 Eventually(session).Should(Exit(0)) 167 168 Eventually(session).Should(Say(`GET /v2/apps HTTP/1.1`)) 169 }) 170 }) 171 172 When("the path has no initial slashes", func() { 173 It("prepends a slash to the path", func() { 174 session := helpers.CF("curl", "v2/apps", "-v") 175 Eventually(session).Should(Exit(0)) 176 177 Eventually(session).Should(Say(`GET /v2/apps HTTP/1.1`)) 178 }) 179 }) 180 181 When("no flag is set", func() { 182 It("makes the request and displays the json response", func() { 183 session := helpers.CF("curl", "/v2/apps") 184 Eventually(session).Should(Exit(0)) 185 Expect(session.Out.Contents()).To(MatchJSON(expectedJSON)) 186 }) 187 }) 188 189 When("-i flag is set", func() { 190 It("displays the response headers", func() { 191 session := helpers.CF("curl", "/v2/apps", "-i") 192 Eventually(session).Should(Exit(0)) 193 194 ExpectResponseHeaders(session) 195 contents := string(session.Out.Contents()) 196 jsonStartsAt := strings.Index(contents, "{") 197 198 actualJSON := contents[jsonStartsAt:] 199 Expect(actualJSON).To(MatchJSON(expectedJSON)) 200 }) 201 }) 202 203 When("-v flag is set", func() { 204 It("displays the request headers and response headers", func() { 205 session := helpers.CF("curl", "/v2/apps", "-v") 206 Eventually(session).Should(Exit(0)) 207 208 ExpectRequestHeaders(session) 209 ExpectResponseHeaders(session) 210 211 contents := string(session.Out.Contents()) 212 jsonStartsAt := strings.Index(contents, "{") 213 214 actualJSON := contents[jsonStartsAt:] 215 Expect(actualJSON).To(MatchJSON(expectedJSON)) 216 }) 217 }) 218 219 When("-H is passed with a custom header", func() { 220 When("the custom header is valid", func() { 221 It("add the custom header to the request", func() { 222 session := helpers.CF("curl", "/v2/apps", "-H", "X-Foo: bar", "-v") 223 Eventually(session).Should(Exit(0)) 224 225 Expect(session).To(Say("REQUEST:")) 226 Expect(session).To(Say("X-Foo: bar")) 227 Expect(session).To(Say("RESPONSE:")) 228 }) 229 230 When("multiple headers are provided", func() { 231 It("adds all the custom headers to the request", func() { 232 session := helpers.CF("curl", "/v2/apps", "-H", "X-Bar: bar", "-H", "X-Foo: foo", "-v") 233 Eventually(session).Should(Exit(0)) 234 235 Expect(session).To(Say("REQUEST:")) 236 Expect(session).To(Say("X-Bar: bar")) 237 Expect(session).To(Say("X-Foo: foo")) 238 Expect(session).To(Say("RESPONSE:")) 239 }) 240 241 When("the same header field is passed", func() { 242 It("adds the same header field twice", func() { 243 session := helpers.CF("curl", "/v2/apps", "-H", "X-Foo: bar", "-H", "X-Foo: foo", "-v") 244 Eventually(session).Should(Exit(0)) 245 246 Expect(session).To(Say("REQUEST:")) 247 Expect(session).To(Say("X-Foo: bar")) 248 Expect(session).To(Say("X-Foo: foo")) 249 Expect(session).To(Say("RESPONSE:")) 250 }) 251 }) 252 }) 253 254 When("-H is provided with a default header", func() { 255 It("overrides the value of User-Agent header", func() { 256 session := helpers.CF("curl", "/v2/apps", "-H", "User-Agent: smith", "-v") 257 Eventually(session).Should(Exit(0)) 258 259 Expect(session).To(Say("REQUEST:")) 260 Expect(session).To(Say("User-Agent: smith")) 261 Expect(session).To(Say("RESPONSE:")) 262 }) 263 264 It("does not override the Host header", func() { 265 getHost := func() string { 266 apiSession := helpers.CF("api") 267 Eventually(apiSession).Should(Exit(0)) 268 output := string(apiSession.Out.Contents()) 269 lines := strings.Split(output, "\n") 270 Expect(len(lines)).To(BeNumerically(">=", 1)) 271 parts := strings.Split(lines[0], "//") 272 Expect(len(parts)).To(BeNumerically(">=", 2)) 273 return parts[1] 274 } 275 session := helpers.CF("curl", "/v2/apps", "-H", "Host: example.com", "-v") 276 Eventually(session).Should(Exit(0)) 277 Expect(session).To(Say("Host: " + getHost())) 278 }) 279 280 It("overrides the value of Accept header", func() { 281 session := helpers.CF("curl", "/v2/apps", "-H", "Accept: application/xml", "-v") 282 Eventually(session).Should(Exit(0)) 283 284 Expect(session).To(Say("REQUEST:")) 285 Expect(session).To(Say("Accept: application/xml")) 286 Expect(session).To(Say("RESPONSE:")) 287 }) 288 289 It("overrides the value of Content-Type header", func() { 290 session := helpers.CF("curl", "/v2/apps", "-H", "Content-Type: application/xml", "-v") 291 Eventually(session).Should(Exit(0)) 292 293 Expect(session).To(Say("REQUEST:")) 294 Expect(session).To(Say("Content-Type: application/xml")) 295 Expect(session).To(Say("RESPONSE:")) 296 }) 297 }) 298 }) 299 300 When("the custom header is not valid", func() { 301 It("tells the user that the header is not valid", func() { 302 session := helpers.CF("curl", "/v2/apps", "-H", "not-a-valid-header", "-v") 303 Eventually(session).Should(Exit(1)) 304 305 Expect(session).Should(Say("FAILED")) 306 Expect(session).Should(Say("Error creating request:")) 307 Expect(session).Should(Say("Error parsing headers: malformed MIME header line: not-a-valid-header")) 308 }) 309 }) 310 }) 311 312 When("-d is passed with a request body", func() { 313 When("the request body is passed as a string", func() { 314 It("sets the method to POST and sends the body", func() { 315 orgGUID := helpers.GetOrgGUID(orgName) 316 spaceName := helpers.NewSpaceName() 317 jsonBody := fmt.Sprintf(`{"name":"%s", "organization_guid":"%s"}`, spaceName, orgGUID) 318 session := helpers.CF("curl", "/v2/spaces", "-d", jsonBody) 319 Eventually(session).Should(Exit(0)) 320 Eventually(helpers.CF("space", spaceName)).Should(Exit(0)) 321 }) 322 }) 323 324 When("the request body is passed as a file", func() { 325 var spaceName, filePath, dir string 326 327 BeforeEach(func() { 328 var err error 329 dir, err = ioutil.TempDir("", "curl-command") 330 Expect(err).ToNot(HaveOccurred()) 331 332 filePath = filepath.Join(dir, "request_body.json") 333 orgGUID := helpers.GetOrgGUID(orgName) 334 spaceName = helpers.NewSpaceName() 335 336 jsonBody := fmt.Sprintf(`{"name":"%s", "organization_guid":"%s"}`, spaceName, orgGUID) 337 err = ioutil.WriteFile(filePath, []byte(jsonBody), 0666) 338 Expect(err).ToNot(HaveOccurred()) 339 }) 340 341 AfterEach(func() { 342 os.RemoveAll(dir) 343 }) 344 345 It("sets the method to POST and sends the body", func() { 346 session := helpers.CF("curl", "/v2/spaces", "-d", "@"+filePath) 347 Eventually(session).Should(Exit(0)) 348 Eventually(helpers.CF("space", spaceName)).Should(Exit(0)) 349 }) 350 351 When("the file does not exist", func() { 352 It("fails and displays an error message", func() { 353 _, err := os.Stat("this-file-does-not-exist") 354 Expect(os.IsExist(err)).To(BeFalse()) 355 356 session := helpers.CF("curl", "/v2/spaces", "-d", "@this-file-does-not-exist") 357 Eventually(session).Should(Exit(1)) 358 Expect(session).To(Say("FAILED")) 359 }) 360 }) 361 362 When("the file is a symlink", func() { 363 It("follows the symlink", func() { 364 linkPath := filepath.Join(dir, "link-name.json") 365 Expect(os.Symlink(filePath, linkPath)).To(Succeed()) 366 session := helpers.CF("curl", "-d", "@"+linkPath, "/v2/spaces") 367 Eventually(session).Should(Exit(0)) 368 Eventually(helpers.CF("space", spaceName)).Should(Exit(0)) 369 }) 370 }) 371 }) 372 }) 373 374 When("-X is passed with the HTTP method", func() { 375 var spaceGUID, spaceName string 376 377 BeforeEach(func() { 378 spaceName = helpers.NewSpaceName() 379 helpers.CreateSpace(spaceName) 380 spaceGUID = helpers.GetSpaceGUID(spaceName) 381 }) 382 383 It("changes the HTTP method of the request", func() { 384 path := fmt.Sprintf("/v2/spaces/%s", spaceGUID) 385 session := helpers.CF("curl", path, "-X", "DELETE", "-v") 386 Eventually(session).Should(Exit(0)) 387 388 Eventually(helpers.CF("space", spaceName)).Should(Exit(1)) 389 }) 390 }) 391 392 When("--output is passed with a file name", func() { 393 It("writes the response body to the file but the other output to stdout", func() { 394 outFile, err := ioutil.TempFile("", "output*.json") 395 Expect(err).ToNot(HaveOccurred()) 396 session := helpers.CF("curl", "/v2/apps", "-i", "--output", outFile.Name()) 397 Eventually(session).Should(Exit(0)) 398 ExpectResponseHeaders(session) 399 body, err := ioutil.ReadFile(outFile.Name()) 400 Expect(err).ToNot(HaveOccurred()) 401 Expect(string(body)).To(MatchJSON(expectedJSON)) 402 }) 403 404 When("--output is passed and CF_TRACE is set to a file", func() { 405 var tempDir, traceFile, outFile string 406 BeforeEach(func() { 407 var err error 408 tempDir, err = ioutil.TempDir("", "") 409 Expect(err).ToNot(HaveOccurred()) 410 traceFile = filepath.Join(tempDir, "trace.log") 411 outFile = filepath.Join(tempDir, "output") 412 }) 413 414 AfterEach(func() { 415 Expect(os.RemoveAll(tempDir)).To(Succeed()) 416 }) 417 418 It("writes the response body to the --output file and everything to the trace file", func() { 419 session := helpers.CFWithEnv(map[string]string{"CF_TRACE": traceFile}, "curl", "/v2/apps", "--output", outFile) 420 Eventually(session).Should(Exit(0)) 421 422 outBytes, err := ioutil.ReadFile(outFile) 423 Expect(err).ToNot(HaveOccurred()) 424 Expect(string(outBytes)).To(MatchJSON(expectedJSON)) 425 426 traceBytes, err := ioutil.ReadFile(traceFile) 427 Expect(traceBytes).To(ContainSubstring("REQUEST: ")) 428 Expect(traceBytes).To(ContainSubstring("HTTP/1.1 200 OK")) 429 }) 430 }) 431 }) 432 433 Describe("Flag combinations", func() { 434 When("-i and -v flags are set", func() { 435 It("prints both the request and response headers", func() { 436 session := helpers.CF("curl", "/v2/apps", "-v", "-i") 437 Eventually(session).Should(Exit(0)) 438 439 ExpectRequestHeaders(session) 440 ExpectResponseHeaders(session) 441 442 contents := string(session.Out.Contents()) 443 jsonStartsAt := strings.Index(contents, "{") 444 445 actualJSON := contents[jsonStartsAt:] 446 Expect(actualJSON).To(MatchJSON(expectedJSON)) 447 }) 448 }) 449 450 XWhen("-v and --output flags are passed", func() { 451 It("prints the headers to the terminal and the response to the file", func() { 452 // TODO This is a bug in the legacy CLI. Please write the test and fix the bug after refactor [#162432878] 453 }) 454 }) 455 456 When("-X, -H and -d flags are passed", func() { 457 var spaceName, filePath, dir, jsonBody string 458 459 BeforeEach(func() { 460 var err error 461 dir, err = ioutil.TempDir("", "curl-command") 462 Expect(err).ToNot(HaveOccurred()) 463 464 filePath = filepath.Join(dir, "request_body.json") 465 orgGUID := helpers.GetOrgGUID(orgName) 466 spaceName = helpers.NewSpaceName() 467 468 jsonBody = fmt.Sprintf(`{"name":"%s", "organization_guid":"%s"}`, spaceName, orgGUID) 469 err = ioutil.WriteFile(filePath, []byte(jsonBody), 0666) 470 Expect(err).ToNot(HaveOccurred()) 471 }) 472 473 AfterEach(func() { 474 os.RemoveAll(dir) 475 }) 476 477 It("sets the custom header and use the request body from -d", func() { 478 session := helpers.CF("curl", "/v2/spaces", "-X", "POST", "-H", "X-Foo: foo", "-H", "X-Bar: bar", "-d", "@"+filePath, "-v") 479 Eventually(session).Should(Exit(0)) 480 481 Expect(session).Should(Say("REQUEST:")) 482 Expect(session).Should(Say("POST")) 483 484 Expect(session).Should(Say("X-Bar: bar")) 485 Expect(session).Should(Say("X-Foo: foo")) 486 487 contents := string(session.Out.Contents()) 488 outputContents := contents[strings.Index(contents, "X-Foo: foo"):] 489 jsonStartsAt := strings.Index(outputContents, "{") 490 jsonEndsAt := strings.Index(outputContents[jsonStartsAt:], "}") 491 492 actualJSON := outputContents[jsonStartsAt : jsonStartsAt+jsonEndsAt+1] 493 Expect(actualJSON).To(MatchJSON(jsonBody)) 494 495 Expect(session).Should(Say("RESPONSE:")) 496 497 Eventually(helpers.CF("space", spaceName)).Should(Exit(0)) 498 }) 499 }) 500 }) 501 502 When("the auth token is invalid", func() { 503 var spaceGUID, spaceName string 504 505 BeforeEach(func() { 506 spaceName = helpers.NewSpaceName() 507 helpers.CreateSpace(spaceName) 508 spaceGUID = helpers.GetSpaceGUID(spaceName) 509 }) 510 511 It("generates a new auth token by using the refresh token", func() { 512 path := fmt.Sprintf("/v2/spaces/%s", spaceGUID) 513 authHeader := fmt.Sprintf("Authorization: %s", helpers.ExpiredAccessToken()) 514 session := helpers.CF("curl", path, "-H", authHeader, "-X", "DELETE", "-v") 515 Eventually(session).Should(Exit(0)) 516 517 Expect(session).To(Say("POST /oauth/token")) 518 519 Eventually(helpers.CF("space", spaceName)).Should(Exit(1)) 520 }) 521 }) 522 }) 523 524 When("the path is invalid", func() { 525 It("makes the request and displays the unknown request json", func() { 526 expectedJSON := `{ 527 "description": "Unknown request", 528 "error_code": "CF-NotFound", 529 "code": 10000 530 }` 531 session := helpers.CF("curl", "/some-random-path") 532 Eventually(session).Should(Exit(0)) 533 Expect(session.Out.Contents()).To(MatchJSON(expectedJSON)) 534 }) 535 536 When("the -f flag is passed", func() { 537 It("should exit 22", func() { 538 session := helpers.CF("curl", "/v2/garbage-endpoint", "-f") 539 Eventually(session).Should(Exit(22)) 540 }) 541 }) 542 }) 543 }) 544 })