code.cloudfoundry.org/cli@v7.1.0+incompatible/cf/commands/curl_test.go (about) 1 package commands_test 2 3 import ( 4 "io/ioutil" 5 "os" 6 "path/filepath" 7 8 "code.cloudfoundry.org/cli/cf/api/apifakes" 9 "code.cloudfoundry.org/cli/cf/configuration/coreconfig" 10 "code.cloudfoundry.org/cli/cf/errors" 11 "code.cloudfoundry.org/cli/cf/requirements" 12 "code.cloudfoundry.org/cli/cf/requirements/requirementsfakes" 13 testcmd "code.cloudfoundry.org/cli/cf/util/testhelpers/commands" 14 testconfig "code.cloudfoundry.org/cli/cf/util/testhelpers/configuration" 15 testterm "code.cloudfoundry.org/cli/cf/util/testhelpers/terminal" 16 "code.cloudfoundry.org/gofileutils/fileutils" 17 18 "code.cloudfoundry.org/cli/cf/commandregistry" 19 "code.cloudfoundry.org/cli/cf/trace" 20 . "code.cloudfoundry.org/cli/cf/util/testhelpers/matchers" 21 . "github.com/onsi/ginkgo" 22 . "github.com/onsi/gomega" 23 ) 24 25 var _ = Describe("curl command", func() { 26 var ( 27 ui *testterm.FakeUI 28 config coreconfig.Repository 29 requirementsFactory *requirementsfakes.FakeFactory 30 curlRepo *apifakes.OldFakeCurlRepository 31 deps commandregistry.Dependency 32 ) 33 34 updateCommandDependency := func(pluginCall bool) { 35 deps.UI = ui 36 deps.RepoLocator = deps.RepoLocator.SetCurlRepository(curlRepo) 37 deps.Config = config 38 commandregistry.Commands.SetCommand(commandregistry.Commands.FindCommand("curl").SetDependency(deps, pluginCall)) 39 } 40 41 BeforeEach(func() { 42 ui = &testterm.FakeUI{} 43 config = testconfig.NewRepository() 44 requirementsFactory = new(requirementsfakes.FakeFactory) 45 requirementsFactory.NewAPIEndpointRequirementReturns(requirements.Passing{}) 46 curlRepo = new(apifakes.OldFakeCurlRepository) 47 48 trace.LoggingToStdout = false 49 }) 50 51 runCurlWithInputs := func(args []string) bool { 52 return testcmd.RunCLICommand("curl", args, requirementsFactory, updateCommandDependency, false, ui) 53 } 54 55 runCurlAsPluginWithInputs := func(args []string) bool { 56 return testcmd.RunCLICommand("curl", args, requirementsFactory, updateCommandDependency, true, ui) 57 } 58 59 It("fails with usage when not given enough input", func() { 60 runCurlWithInputs([]string{}) 61 Expect(ui.Outputs()).To(ContainSubstrings( 62 []string{"Incorrect Usage", "An argument is missing or not correctly enclosed"}, 63 )) 64 }) 65 66 Context("requirements", func() { 67 Context("when no api is set", func() { 68 BeforeEach(func() { 69 requirementsFactory.NewAPIEndpointRequirementReturns(requirements.Failing{Message: "no api set"}) 70 }) 71 72 It("fails", func() { 73 Expect(runCurlWithInputs([]string{"/foo"})).To(BeFalse()) 74 }) 75 }) 76 77 Context("when api is set", func() { 78 BeforeEach(func() { 79 requirementsFactory.NewAPIEndpointRequirementReturns(requirements.Passing{}) 80 }) 81 82 It("passes", func() { 83 Expect(runCurlWithInputs([]string{"/foo"})).To(BeTrue()) 84 }) 85 }) 86 }) 87 88 It("makes a get request given an endpoint", func() { 89 curlRepo.ResponseHeader = "Content-Size:1024" 90 curlRepo.ResponseBody = "response for get" 91 runCurlWithInputs([]string{"/foo"}) 92 93 Expect(curlRepo.Method).To(Equal("")) 94 Expect(curlRepo.Path).To(Equal("/foo")) 95 Expect(ui.Outputs()).To(ContainSubstrings([]string{"response for get"})) 96 Expect(ui.Outputs()).ToNot(ContainSubstrings( 97 []string{"FAILED"}, 98 []string{"Content-Size:1024"}, 99 )) 100 }) 101 102 Context("when the --output flag is provided", func() { 103 It("saves the body of the response to the given filepath if it exists", func() { 104 fileutils.TempFile("poor-mans-pipe", func(tempFile *os.File, err error) { 105 Expect(err).ToNot(HaveOccurred()) 106 curlRepo.ResponseBody = "hai" 107 108 runCurlWithInputs([]string{"--output", tempFile.Name(), "/foo"}) 109 contents, err := ioutil.ReadAll(tempFile) 110 Expect(err).ToNot(HaveOccurred()) 111 Expect(string(contents)).To(Equal("hai")) 112 }) 113 }) 114 115 It("saves the body of the response to the given filepath if it doesn't exists", func() { 116 fileutils.TempDir("poor-mans-dir", func(tmpDir string, err error) { 117 Expect(err).ToNot(HaveOccurred()) 118 curlRepo.ResponseBody = "hai" 119 120 filePath := filepath.Join(tmpDir, "subdir1", "banana.txt") 121 runCurlWithInputs([]string{"--output", filePath, "/foo"}) 122 123 file, err := os.Open(filePath) 124 Expect(err).ToNot(HaveOccurred()) 125 126 contents, err := ioutil.ReadAll(file) 127 Expect(err).ToNot(HaveOccurred()) 128 Expect(string(contents)).To(Equal("hai")) 129 }) 130 }) 131 }) 132 133 It("makes a post request given -X", func() { 134 runCurlWithInputs([]string{"-X", "post", "/foo"}) 135 136 Expect(curlRepo.Method).To(Equal("post")) 137 Expect(ui.Outputs()).ToNot(ContainSubstrings([]string{"FAILED"})) 138 }) 139 When("--fail/-f is passed", func() { 140 BeforeEach(func() { 141 curlRepo.Error = errors.NewHTTPError(500, "", "") 142 }) 143 144 It("fails on HTTP errors given --fail", func() { 145 runCurlWithInputs([]string{"--fail", "/foo"}) 146 147 Expect(curlRepo.FailOnHTTPError).To(Equal(true)) 148 Expect(ui.Outputs()).To(ContainSubstrings([]string{"The requested URL returned error: 500"})) 149 }) 150 151 It("does not fail on HTTP erros if --fail is false", func() { 152 runCurlWithInputs([]string{"--fail", "false", "/foo"}) 153 154 Expect(curlRepo.FailOnHTTPError).To(Equal(false)) 155 }) 156 157 }) 158 It("sends headers given -H", func() { 159 runCurlWithInputs([]string{"-H", "Content-Type:cat", "/foo"}) 160 161 Expect(curlRepo.Header).To(Equal("Content-Type:cat")) 162 Expect(ui.Outputs()).ToNot(ContainSubstrings([]string{"FAILED"})) 163 }) 164 165 It("sends multiple headers given multiple -H flags", func() { 166 runCurlWithInputs([]string{"-H", "Content-Type:cat", "-H", "Content-Length:12", "/foo"}) 167 168 Expect(curlRepo.Header).To(Equal("Content-Type:cat\nContent-Length:12")) 169 Expect(ui.Outputs()).ToNot(ContainSubstrings([]string{"FAILED"})) 170 }) 171 172 It("prints out the response headers given -i", func() { 173 curlRepo.ResponseHeader = "Content-Size:1024" 174 curlRepo.ResponseBody = "response for get" 175 runCurlWithInputs([]string{"-i", "/foo"}) 176 177 Expect(ui.Outputs()).To(ContainSubstrings( 178 []string{"Content-Size:1024"}, 179 []string{"response for get"}, 180 )) 181 Expect(ui.Outputs()).ToNot(ContainSubstrings([]string{"FAILED"})) 182 }) 183 184 Context("when -d is provided", func() { 185 It("sets the request body", func() { 186 runCurlWithInputs([]string{"-d", "body content to upload", "/foo"}) 187 188 Expect(curlRepo.Body).To(Equal("body content to upload")) 189 Expect(ui.Outputs()).ToNot(ContainSubstrings([]string{"FAILED"})) 190 }) 191 192 It("does not fail with empty string", func() { 193 runCurlWithInputs([]string{"/foo", "-d", ""}) 194 195 Expect(curlRepo.Body).To(Equal("")) 196 Expect(curlRepo.Method).To(Equal("POST")) 197 Expect(ui.Outputs()).NotTo(ContainSubstrings([]string{"FAILED"})) 198 }) 199 200 It("uses given http verb if -X is also provided", func() { 201 runCurlWithInputs([]string{"/foo", "-d", "some body", "-X", "PUT"}) 202 203 Expect(curlRepo.Body).To(Equal("some body")) 204 Expect(curlRepo.Method).To(Equal("PUT")) 205 Expect(ui.Outputs()).NotTo(ContainSubstrings([]string{"FAILED"})) 206 }) 207 208 It("sets the request body with an @-prefixed file", func() { 209 tempfile, err := ioutil.TempFile("", "get-data-test") 210 Expect(err).NotTo(HaveOccurred()) 211 defer os.RemoveAll(tempfile.Name()) 212 jsonData := `{"some":"json"}` 213 ioutil.WriteFile(tempfile.Name(), []byte(jsonData), os.ModePerm) 214 215 runCurlWithInputs([]string{"-d", "@" + tempfile.Name(), "/foo"}) 216 217 Expect(curlRepo.Body).To(Equal(`{"some":"json"}`)) 218 Expect(ui.Outputs()).ToNot(ContainSubstrings([]string{"FAILED"})) 219 }) 220 }) 221 222 It("does not print the response when verbose output is enabled", func() { 223 // This is to prevent the response from being printed twice 224 225 trace.LoggingToStdout = true 226 227 curlRepo.ResponseHeader = "Content-Size:1024" 228 curlRepo.ResponseBody = "response for get" 229 230 runCurlWithInputs([]string{"/foo"}) 231 232 Expect(ui.Outputs()).ToNot(ContainSubstrings([]string{"response for get"})) 233 }) 234 235 It("prints the response even when verbose output is enabled if in a plugin call", func() { 236 trace.LoggingToStdout = true 237 238 curlRepo.ResponseHeader = "Content-Size:1024" 239 curlRepo.ResponseBody = "response for get" 240 241 runCurlAsPluginWithInputs([]string{"/foo"}) 242 243 Expect(ui.Outputs()).To(ContainSubstrings([]string{"response for get"})) 244 }) 245 246 It("prints a failure message when the response is not success", func() { 247 curlRepo.Error = errors.New("ooops") 248 runCurlWithInputs([]string{"/foo"}) 249 250 Expect(ui.Outputs()).To(ContainSubstrings( 251 []string{"FAILED"}, 252 []string{"ooops"}, 253 )) 254 }) 255 256 Context("Whent the content type is JSON", func() { 257 BeforeEach(func() { 258 curlRepo.ResponseHeader = "Content-Type: application/json;charset=utf-8" 259 curlRepo.ResponseBody = `{"total_results":0,"total_pages":1,"prev_url":null,"next_url":null,"resources":[]}` 260 }) 261 262 It("pretty-prints the response body", func() { 263 runCurlWithInputs([]string{"/ugly-printed-json-endpoint"}) 264 265 Expect(ui.Outputs()).To(ContainSubstrings( 266 []string{"{"}, 267 []string{" \"total_results", "0"}, 268 []string{" \"total_pages", "1"}, 269 []string{" \"prev_url", "null"}, 270 []string{" \"next_url", "null"}, 271 []string{" \"resources", "[]"}, 272 []string{"}"}, 273 )) 274 }) 275 276 Context("But the body is not JSON", func() { 277 BeforeEach(func() { 278 curlRepo.ResponseBody = "FAIL: crumpets need MOAR butterz" 279 }) 280 281 It("regular-prints the response body", func() { 282 runCurlWithInputs([]string{"/whateverz"}) 283 284 Expect(ui.Outputs()).To(Equal([]string{"FAIL: crumpets need MOAR butterz"})) 285 }) 286 }) 287 }) 288 })