github.com/jenspinney/cli@v6.42.1-0.20190207184520-7450c600020e+incompatible/cf/api/curl_test.go (about)

     1  package api_test
     2  
     3  import (
     4  	"net/http"
     5  	"net/http/httptest"
     6  	"strings"
     7  	"time"
     8  
     9  	"code.cloudfoundry.org/cli/cf/api/apifakes"
    10  	"code.cloudfoundry.org/cli/cf/configuration/coreconfig"
    11  	"code.cloudfoundry.org/cli/cf/net"
    12  	"code.cloudfoundry.org/cli/cf/terminal/terminalfakes"
    13  	testconfig "code.cloudfoundry.org/cli/cf/util/testhelpers/configuration"
    14  	testnet "code.cloudfoundry.org/cli/cf/util/testhelpers/net"
    15  
    16  	. "code.cloudfoundry.org/cli/cf/api"
    17  	"code.cloudfoundry.org/cli/cf/trace/tracefakes"
    18  	. "code.cloudfoundry.org/cli/cf/util/testhelpers/matchers"
    19  	. "github.com/onsi/ginkgo"
    20  	. "github.com/onsi/gomega"
    21  	"github.com/onsi/gomega/ghttp"
    22  )
    23  
    24  var _ = Describe("CloudControllerCurlRepository ", func() {
    25  	var (
    26  		headers string
    27  		body    string
    28  		apiErr  error
    29  	)
    30  
    31  	Describe("GET requests", func() {
    32  		BeforeEach(func() {
    33  			req := apifakes.NewCloudControllerTestRequest(testnet.TestRequest{
    34  				Method: "GET",
    35  				Path:   "/v2/endpoint",
    36  				Response: testnet.TestResponse{
    37  					Status: http.StatusOK,
    38  					Body:   expectedJSONResponse},
    39  			})
    40  			ts, handler := testnet.NewServer([]testnet.TestRequest{req})
    41  			defer ts.Close()
    42  
    43  			deps := newCurlDependencies()
    44  			deps.config.SetAPIEndpoint(ts.URL)
    45  
    46  			repo := NewCloudControllerCurlRepository(deps.config, deps.gateway)
    47  			headers, body, apiErr = repo.Request("GET", "/v2/endpoint", "", "", false)
    48  
    49  			Expect(handler).To(HaveAllRequestsCalled())
    50  			Expect(apiErr).NotTo(HaveOccurred())
    51  		})
    52  
    53  		It("returns headers with the status code", func() {
    54  			Expect(headers).To(ContainSubstring("200"))
    55  		})
    56  
    57  		It("returns the header content type", func() {
    58  			Expect(headers).To(ContainSubstring("Content-Type"))
    59  			Expect(headers).To(ContainSubstring("text/plain"))
    60  		})
    61  
    62  		It("returns the body as a JSON-encoded string", func() {
    63  			Expect(removeWhitespace(body)).To(Equal(removeWhitespace(expectedJSONResponse)))
    64  		})
    65  	})
    66  
    67  	Describe("POST requests", func() {
    68  		BeforeEach(func() {
    69  			req := apifakes.NewCloudControllerTestRequest(testnet.TestRequest{
    70  				Method:  "POST",
    71  				Path:    "/v2/endpoint",
    72  				Matcher: testnet.RequestBodyMatcher(`{"key":"val"}`),
    73  				Response: testnet.TestResponse{
    74  					Status: http.StatusOK,
    75  					Body:   expectedJSONResponse},
    76  			})
    77  
    78  			ts, handler := testnet.NewServer([]testnet.TestRequest{req})
    79  			defer ts.Close()
    80  
    81  			deps := newCurlDependencies()
    82  			deps.config.SetAPIEndpoint(ts.URL)
    83  
    84  			repo := NewCloudControllerCurlRepository(deps.config, deps.gateway)
    85  			headers, body, apiErr = repo.Request("POST", "/v2/endpoint", "", `{"key":"val"}`, false)
    86  			Expect(handler).To(HaveAllRequestsCalled())
    87  		})
    88  
    89  		It("does not return an error", func() {
    90  			Expect(apiErr).NotTo(HaveOccurred())
    91  		})
    92  
    93  		Context("when the server returns a 400 Bad Request header", func() {
    94  			var (
    95  				deps            curlDependencies
    96  				handler         *testnet.TestHandler
    97  				ts              *httptest.Server
    98  				failOnHTTPError bool
    99  			)
   100  
   101  			BeforeEach(func() {
   102  				req := apifakes.NewCloudControllerTestRequest(testnet.TestRequest{
   103  					Method:  "POST",
   104  					Path:    "/v2/endpoint",
   105  					Matcher: testnet.RequestBodyMatcher(`{"key":"val"}`),
   106  					Response: testnet.TestResponse{
   107  						Status: http.StatusBadRequest,
   108  						Body:   expectedJSONResponse},
   109  				})
   110  
   111  				ts, handler = testnet.NewServer([]testnet.TestRequest{req})
   112  
   113  				deps = newCurlDependencies()
   114  				deps.config.SetAPIEndpoint(ts.URL)
   115  				failOnHTTPError = false
   116  			})
   117  
   118  			AfterEach(func() {
   119  				ts.Close()
   120  			})
   121  
   122  			JustBeforeEach(func() {
   123  				repo := NewCloudControllerCurlRepository(deps.config, deps.gateway)
   124  				_, body, apiErr = repo.Request("POST", "/v2/endpoint", "", `{"key":"val"}`, failOnHTTPError)
   125  				Expect(handler).To(HaveAllRequestsCalled())
   126  			})
   127  
   128  			It("returns the response body", func() {
   129  				Expect(removeWhitespace(body)).To(Equal(removeWhitespace(expectedJSONResponse)))
   130  			})
   131  
   132  			It("does not return an error", func() {
   133  				Expect(apiErr).NotTo(HaveOccurred())
   134  			})
   135  
   136  			When("the failOnHttpError is true", func() {
   137  				BeforeEach(func() {
   138  					failOnHTTPError = true
   139  				})
   140  
   141  				It("returns the error", func() {
   142  					Expect(apiErr).To(HaveOccurred())
   143  				})
   144  			})
   145  		})
   146  
   147  		Context("when provided with invalid headers", func() {
   148  			It("returns an error", func() {
   149  				deps := newCurlDependencies()
   150  				repo := NewCloudControllerCurlRepository(deps.config, deps.gateway)
   151  				_, _, apiErr := repo.Request("POST", "/v2/endpoint", "not-valid", "", false)
   152  				Expect(apiErr).To(HaveOccurred())
   153  				Expect(apiErr.Error()).To(ContainSubstring("headers"))
   154  			})
   155  		})
   156  
   157  		Context("when provided with valid headers", func() {
   158  			It("sends them along with the POST body", func() {
   159  				req := apifakes.NewCloudControllerTestRequest(testnet.TestRequest{
   160  					Method: "POST",
   161  					Path:   "/v2/endpoint",
   162  					Matcher: func(req *http.Request) {
   163  						Expect(req.Header.Get("content-type")).To(Equal("ascii/cats"))
   164  						Expect(req.Header.Get("x-something-else")).To(Equal("5"))
   165  					},
   166  					Response: testnet.TestResponse{
   167  						Status: http.StatusOK,
   168  						Body:   expectedJSONResponse},
   169  				})
   170  				ts, handler := testnet.NewServer([]testnet.TestRequest{req})
   171  				defer ts.Close()
   172  
   173  				deps := newCurlDependencies()
   174  				deps.config.SetAPIEndpoint(ts.URL)
   175  
   176  				headers := "content-type: ascii/cats\nx-something-else:5"
   177  				repo := NewCloudControllerCurlRepository(deps.config, deps.gateway)
   178  				_, _, apiErr := repo.Request("POST", "/v2/endpoint", headers, "", false)
   179  				Expect(handler).To(HaveAllRequestsCalled())
   180  				Expect(apiErr).NotTo(HaveOccurred())
   181  			})
   182  		})
   183  	})
   184  
   185  	It("uses POST as the default method when a body is provided", func() {
   186  		ccServer := ghttp.NewServer()
   187  		ccServer.AppendHandlers(
   188  			ghttp.VerifyRequest("POST", "/v2/endpoint"),
   189  		)
   190  
   191  		deps := newCurlDependencies()
   192  		deps.config.SetAPIEndpoint(ccServer.URL())
   193  
   194  		repo := NewCloudControllerCurlRepository(deps.config, deps.gateway)
   195  		_, _, err := repo.Request("", "/v2/endpoint", "", "body", false)
   196  		Expect(err).NotTo(HaveOccurred())
   197  
   198  		Expect(ccServer.ReceivedRequests()).To(HaveLen(1))
   199  	})
   200  
   201  	It("uses GET as the default method when a body is not provided", func() {
   202  		ccServer := ghttp.NewServer()
   203  		ccServer.AppendHandlers(
   204  			ghttp.VerifyRequest("GET", "/v2/endpoint"),
   205  		)
   206  
   207  		deps := newCurlDependencies()
   208  		deps.config.SetAPIEndpoint(ccServer.URL())
   209  
   210  		repo := NewCloudControllerCurlRepository(deps.config, deps.gateway)
   211  		_, _, err := repo.Request("", "/v2/endpoint", "", "", false)
   212  		Expect(err).NotTo(HaveOccurred())
   213  
   214  		Expect(ccServer.ReceivedRequests()).To(HaveLen(1))
   215  	})
   216  })
   217  
   218  const expectedJSONResponse = `
   219  	{"resources": [
   220  		{
   221  		  "metadata": { "guid": "my-quota-guid" },
   222  		  "entity": { "name": "my-remote-quota", "memory_limit": 1024 }
   223  		}
   224  	]}
   225  `
   226  
   227  type curlDependencies struct {
   228  	config  coreconfig.ReadWriter
   229  	gateway net.Gateway
   230  }
   231  
   232  func newCurlDependencies() (deps curlDependencies) {
   233  	deps.config = testconfig.NewRepository()
   234  	deps.config.SetAccessToken("BEARER my_access_token")
   235  	deps.gateway = net.NewCloudControllerGateway(deps.config, time.Now, new(terminalfakes.FakeUI), new(tracefakes.FakePrinter), "")
   236  	return
   237  }
   238  
   239  func removeWhitespace(body string) string {
   240  	body = strings.Replace(body, " ", "", -1)
   241  	body = strings.Replace(body, "\n", "", -1)
   242  	body = strings.Replace(body, "\r", "", -1)
   243  	body = strings.Replace(body, "\t", "", -1)
   244  	return body
   245  }