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  })