github.com/willmadison/cli@v6.40.1-0.20181018160101-29d5937903ff+incompatible/cf/api/curl_test.go (about)

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