github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/resource/api/server/handler_test.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package server_test
     5  
     6  import (
     7  	"encoding/json"
     8  	"fmt"
     9  	"net/http"
    10  	"strconv"
    11  	"strings"
    12  
    13  	"github.com/juju/errors"
    14  	"github.com/juju/testing"
    15  	jc "github.com/juju/testing/checkers"
    16  	gc "gopkg.in/check.v1"
    17  	"gopkg.in/juju/names.v2"
    18  
    19  	"github.com/juju/juju/apiserver/params"
    20  	"github.com/juju/juju/resource/api"
    21  	"github.com/juju/juju/resource/api/server"
    22  )
    23  
    24  type LegacyHTTPHandlerSuite struct {
    25  	BaseSuite
    26  
    27  	username string
    28  	req      *http.Request
    29  	header   http.Header
    30  	resp     *stubHTTPResponseWriter
    31  	result   *api.UploadResult
    32  }
    33  
    34  var _ = gc.Suite(&LegacyHTTPHandlerSuite{})
    35  
    36  func (s *LegacyHTTPHandlerSuite) SetUpTest(c *gc.C) {
    37  	s.BaseSuite.SetUpTest(c)
    38  
    39  	method := "..."
    40  	urlStr := "..."
    41  	body := strings.NewReader("...")
    42  	req, err := http.NewRequest(method, urlStr, body)
    43  	c.Assert(err, jc.ErrorIsNil)
    44  
    45  	s.req = req
    46  	s.header = make(http.Header)
    47  	s.resp = &stubHTTPResponseWriter{
    48  		stub:         s.stub,
    49  		returnHeader: s.header,
    50  	}
    51  	s.result = &api.UploadResult{}
    52  }
    53  
    54  func (s *LegacyHTTPHandlerSuite) connect(req *http.Request) (server.DataStore, names.Tag, error) {
    55  	s.stub.AddCall("Connect", req)
    56  	if err := s.stub.NextErr(); err != nil {
    57  		return nil, nil, errors.Trace(err)
    58  	}
    59  
    60  	tag := names.NewUserTag(s.username)
    61  	return s.data, tag, nil
    62  }
    63  
    64  func (s *LegacyHTTPHandlerSuite) handleUpload(username string, st server.DataStore, req *http.Request) (*api.UploadResult, error) {
    65  	s.stub.AddCall("HandleUpload", username, st, req)
    66  	if err := s.stub.NextErr(); err != nil {
    67  		return nil, errors.Trace(err)
    68  	}
    69  
    70  	return s.result, nil
    71  }
    72  
    73  func (s *LegacyHTTPHandlerSuite) TestServeHTTPConnectFailure(c *gc.C) {
    74  	s.username = "youknowwho"
    75  	handler := server.LegacyHTTPHandler{
    76  		Connect:      s.connect,
    77  		HandleUpload: s.handleUpload,
    78  	}
    79  	copied := *s.req
    80  	req := &copied
    81  	failure, expected := apiFailure(c, "<failure>", "")
    82  	s.stub.SetErrors(failure)
    83  
    84  	handler.ServeHTTP(s.resp, req)
    85  
    86  	s.stub.CheckCallNames(c,
    87  		"Connect",
    88  		"Header",
    89  		"Header",
    90  		"WriteHeader",
    91  		"Write",
    92  	)
    93  	s.stub.CheckCall(c, 0, "Connect", req)
    94  	s.stub.CheckCall(c, 3, "WriteHeader", http.StatusInternalServerError)
    95  	s.stub.CheckCall(c, 4, "Write", expected)
    96  	c.Check(req, jc.DeepEquals, s.req) // did not change
    97  	c.Check(s.header, jc.DeepEquals, http.Header{
    98  		"Content-Type":   []string{"application/json"},
    99  		"Content-Length": []string{strconv.Itoa(len(expected))},
   100  	})
   101  }
   102  
   103  func (s *LegacyHTTPHandlerSuite) TestServeHTTPUnsupportedMethod(c *gc.C) {
   104  	s.username = "youknowwho"
   105  	handler := server.LegacyHTTPHandler{
   106  		Connect:      s.connect,
   107  		HandleUpload: s.handleUpload,
   108  	}
   109  	s.req.Method = "POST"
   110  	copied := *s.req
   111  	req := &copied
   112  	_, expected := apiFailure(c, `unsupported method: "POST"`, params.CodeMethodNotAllowed)
   113  
   114  	handler.ServeHTTP(s.resp, req)
   115  
   116  	s.stub.CheckCallNames(c,
   117  		"Connect",
   118  		"Header",
   119  		"Header",
   120  		"WriteHeader",
   121  		"Write",
   122  	)
   123  	s.stub.CheckCall(c, 0, "Connect", req)
   124  	s.stub.CheckCall(c, 3, "WriteHeader", http.StatusMethodNotAllowed)
   125  	s.stub.CheckCall(c, 4, "Write", expected)
   126  	c.Check(req, jc.DeepEquals, s.req) // did not change
   127  	c.Check(s.header, jc.DeepEquals, http.Header{
   128  		"Content-Type":   []string{"application/json"},
   129  		"Content-Length": []string{strconv.Itoa(len(expected))},
   130  	})
   131  }
   132  
   133  func (s *LegacyHTTPHandlerSuite) TestServeHTTPPutSuccess(c *gc.C) {
   134  	s.result.Resource.Name = "spam"
   135  	expected, err := json.Marshal(s.result)
   136  	c.Assert(err, jc.ErrorIsNil)
   137  	s.username = "youknowwho"
   138  	handler := server.LegacyHTTPHandler{
   139  		Connect:      s.connect,
   140  		HandleUpload: s.handleUpload,
   141  	}
   142  	s.req.Method = "PUT"
   143  	copied := *s.req
   144  	req := &copied
   145  
   146  	handler.ServeHTTP(s.resp, req)
   147  
   148  	s.stub.CheckCallNames(c,
   149  		"Connect",
   150  		"HandleUpload",
   151  		"Header",
   152  		"Header",
   153  		"WriteHeader",
   154  		"Write",
   155  	)
   156  	s.stub.CheckCall(c, 0, "Connect", req)
   157  	s.stub.CheckCall(c, 1, "HandleUpload", "youknowwho", s.data, req)
   158  	s.stub.CheckCall(c, 4, "WriteHeader", http.StatusOK)
   159  	s.stub.CheckCall(c, 5, "Write", string(expected))
   160  	c.Check(req, jc.DeepEquals, s.req) // did not change
   161  	c.Check(s.header, jc.DeepEquals, http.Header{
   162  		"Content-Type":   []string{"application/json"},
   163  		"Content-Length": []string{fmt.Sprint(len(expected))},
   164  	})
   165  }
   166  
   167  func (s *LegacyHTTPHandlerSuite) TestServeHTTPPutHandleUploadFailure(c *gc.C) {
   168  	s.username = "youknowwho"
   169  	handler := server.LegacyHTTPHandler{
   170  		Connect:      s.connect,
   171  		HandleUpload: s.handleUpload,
   172  	}
   173  	s.req.Method = "PUT"
   174  	copied := *s.req
   175  	req := &copied
   176  	failure, expected := apiFailure(c, "<failure>", "")
   177  	s.stub.SetErrors(nil, failure)
   178  
   179  	handler.ServeHTTP(s.resp, req)
   180  
   181  	s.stub.CheckCallNames(c,
   182  		"Connect",
   183  		"HandleUpload",
   184  		"Header",
   185  		"Header",
   186  		"WriteHeader",
   187  		"Write",
   188  	)
   189  	s.stub.CheckCall(c, 0, "Connect", req)
   190  	s.stub.CheckCall(c, 1, "HandleUpload", "youknowwho", s.data, req)
   191  	s.stub.CheckCall(c, 4, "WriteHeader", http.StatusInternalServerError)
   192  	s.stub.CheckCall(c, 5, "Write", expected)
   193  	c.Check(req, jc.DeepEquals, s.req) // did not change
   194  	c.Check(s.header, jc.DeepEquals, http.Header{
   195  		"Content-Type":   []string{"application/json"},
   196  		"Content-Length": []string{strconv.Itoa(len(expected))},
   197  	})
   198  }
   199  
   200  func apiFailure(c *gc.C, msg, code string) (error, string) {
   201  	failure := errors.New(msg)
   202  
   203  	data, err := json.Marshal(params.ErrorResult{
   204  		Error: &params.Error{
   205  			Message: msg,
   206  			Code:    code,
   207  		},
   208  	})
   209  	c.Assert(err, jc.ErrorIsNil)
   210  
   211  	return failure, string(data)
   212  }
   213  
   214  type stubHTTPResponseWriter struct {
   215  	stub *testing.Stub
   216  
   217  	returnHeader http.Header
   218  }
   219  
   220  func (s *stubHTTPResponseWriter) Header() http.Header {
   221  	s.stub.AddCall("Header")
   222  	s.stub.NextErr() // Pop one off.
   223  
   224  	return s.returnHeader
   225  }
   226  
   227  func (s *stubHTTPResponseWriter) Write(data []byte) (int, error) {
   228  	s.stub.AddCall("Write", string(data))
   229  	if err := s.stub.NextErr(); err != nil {
   230  		return 0, errors.Trace(err)
   231  	}
   232  
   233  	return len(data), nil
   234  }
   235  
   236  func (s *stubHTTPResponseWriter) WriteHeader(code int) {
   237  	s.stub.AddCall("WriteHeader", code)
   238  	s.stub.NextErr() // Pop one off.
   239  }