github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/api/http_test.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package api_test
     5  
     6  import (
     7  	"net/http"
     8  	"net/http/httptest"
     9  	"reflect"
    10  
    11  	"github.com/juju/errors"
    12  	"github.com/juju/httprequest"
    13  	jc "github.com/juju/testing/checkers"
    14  	gc "gopkg.in/check.v1"
    15  
    16  	"github.com/juju/juju/apiserver/params"
    17  	jujutesting "github.com/juju/juju/juju/testing"
    18  )
    19  
    20  type httpSuite struct {
    21  	jujutesting.JujuConnSuite
    22  
    23  	client *httprequest.Client
    24  }
    25  
    26  var _ = gc.Suite(&httpSuite{})
    27  
    28  func (s *httpSuite) SetUpTest(c *gc.C) {
    29  	s.JujuConnSuite.SetUpTest(c)
    30  
    31  	client, err := s.APIState.HTTPClient()
    32  	c.Assert(err, gc.IsNil)
    33  	s.client = client
    34  }
    35  
    36  var httpClientTests = []struct {
    37  	about           string
    38  	handler         http.HandlerFunc
    39  	expectResponse  interface{}
    40  	expectError     string
    41  	expectErrorCode string
    42  	expectErrorInfo *params.ErrorInfo
    43  }{{
    44  	about: "success",
    45  	handler: func(w http.ResponseWriter, req *http.Request) {
    46  		httprequest.WriteJSON(w, http.StatusOK, "hello, world")
    47  	},
    48  	expectResponse: newString("hello, world"),
    49  }, {
    50  	about: "unauthorized status without discharge-required error",
    51  	handler: func(w http.ResponseWriter, req *http.Request) {
    52  		httprequest.WriteJSON(w, http.StatusUnauthorized, params.Error{
    53  			Message: "something",
    54  		})
    55  	},
    56  	expectError: `GET http://.*/: something`,
    57  }, {
    58  	about:       "non-JSON error response",
    59  	handler:     http.NotFound,
    60  	expectError: `GET http://.*/: unexpected content type text/plain; want application/json; content: 404 page not found`,
    61  }, {
    62  	about: "bad error response",
    63  	handler: func(w http.ResponseWriter, req *http.Request) {
    64  		type badResponse struct {
    65  			Message map[string]int
    66  		}
    67  		httprequest.WriteJSON(w, http.StatusUnauthorized, badResponse{
    68  			Message: make(map[string]int),
    69  		})
    70  	},
    71  	expectError: `GET http://.*/: incompatible error response: json: cannot unmarshal object into Go value of type string`,
    72  }, {
    73  	about: "bad charms error response",
    74  	handler: func(w http.ResponseWriter, req *http.Request) {
    75  		type badResponse struct {
    76  			Error    string
    77  			CharmURL map[string]int
    78  		}
    79  		httprequest.WriteJSON(w, http.StatusUnauthorized, badResponse{
    80  			Error:    "something",
    81  			CharmURL: make(map[string]int),
    82  		})
    83  	},
    84  	expectError: `GET http://.*/: incompatible error response: json: cannot unmarshal object into Go value of type string`,
    85  }, {
    86  	about: "no message in ErrorResponse",
    87  	handler: func(w http.ResponseWriter, req *http.Request) {
    88  		httprequest.WriteJSON(w, http.StatusUnauthorized, params.ErrorResult{
    89  			Error: &params.Error{},
    90  		})
    91  	},
    92  	expectError: `GET http://.*/: error response with no message`,
    93  }, {
    94  	about: "no message in Error",
    95  	handler: func(w http.ResponseWriter, req *http.Request) {
    96  		httprequest.WriteJSON(w, http.StatusUnauthorized, params.Error{})
    97  	},
    98  	expectError: `GET http://.*/: error response with no message`,
    99  }, {
   100  	about: "charms error response",
   101  	handler: func(w http.ResponseWriter, req *http.Request) {
   102  		httprequest.WriteJSON(w, http.StatusBadRequest, params.CharmsResponse{
   103  			Error:     "some error",
   104  			ErrorCode: params.CodeBadRequest,
   105  			ErrorInfo: &params.ErrorInfo{
   106  				MacaroonPath: "foo",
   107  			},
   108  		})
   109  	},
   110  	expectError:     `GET http://.*/: some error`,
   111  	expectErrorCode: params.CodeBadRequest,
   112  	expectErrorInfo: &params.ErrorInfo{
   113  		MacaroonPath: "foo",
   114  	},
   115  }, {
   116  	about: "discharge-required response with no error info",
   117  	handler: func(w http.ResponseWriter, req *http.Request) {
   118  		httprequest.WriteJSON(w, http.StatusUnauthorized, params.Error{
   119  			Message: "some error",
   120  			Code:    params.CodeDischargeRequired,
   121  		})
   122  	},
   123  	expectError:     `GET http://.*/: no error info found in discharge-required response error: some error`,
   124  	expectErrorCode: params.CodeDischargeRequired,
   125  }, {
   126  	about: "discharge-required response with no macaroon",
   127  	handler: func(w http.ResponseWriter, req *http.Request) {
   128  		httprequest.WriteJSON(w, http.StatusUnauthorized, params.Error{
   129  			Message: "some error",
   130  			Code:    params.CodeDischargeRequired,
   131  			Info:    &params.ErrorInfo{},
   132  		})
   133  	},
   134  	expectError: `GET http://.*/: no macaroon found in discharge-required response`,
   135  }}
   136  
   137  func (s *httpSuite) TestHTTPClient(c *gc.C) {
   138  	var handler http.HandlerFunc
   139  	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
   140  		handler(w, req)
   141  	}))
   142  	defer srv.Close()
   143  	s.client.BaseURL = srv.URL
   144  	for i, test := range httpClientTests {
   145  		c.Logf("test %d: %s", i, test.about)
   146  		handler = test.handler
   147  		var resp interface{}
   148  		if test.expectResponse != nil {
   149  			resp = reflect.New(reflect.TypeOf(test.expectResponse).Elem()).Interface()
   150  		}
   151  		err := s.client.Get("/", resp)
   152  		if test.expectError != "" {
   153  			c.Assert(err, gc.ErrorMatches, test.expectError)
   154  			c.Assert(params.ErrCode(err), gc.Equals, test.expectErrorCode)
   155  			if err, ok := errors.Cause(err).(*params.Error); ok {
   156  				c.Assert(err.Info, jc.DeepEquals, test.expectErrorInfo)
   157  			} else if test.expectErrorInfo != nil {
   158  				c.Fatalf("no error info found in error")
   159  			}
   160  			continue
   161  		}
   162  		c.Assert(err, gc.IsNil)
   163  		c.Assert(resp, jc.DeepEquals, test.expectResponse)
   164  	}
   165  }
   166  
   167  // Note: the fact that the code works against the actual API server is
   168  // well tested by some of the other API tests.
   169  // This suite focuses on less reachable paths by changing
   170  // the BaseURL of the httprequest.Client so that
   171  // we can use our own custom servers.
   172  
   173  func newString(s string) *string {
   174  	return &s
   175  }