github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/resource/api/private/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  	"bytes"
     8  	"fmt"
     9  	"io"
    10  	"net/http"
    11  	"net/url"
    12  
    13  	"github.com/juju/errors"
    14  	"github.com/juju/testing"
    15  	jc "github.com/juju/testing/checkers"
    16  	"github.com/juju/testing/filetesting"
    17  	gc "gopkg.in/check.v1"
    18  
    19  	"github.com/juju/juju/resource"
    20  	"github.com/juju/juju/resource/api"
    21  	"github.com/juju/juju/resource/api/private/server"
    22  	"github.com/juju/juju/resource/resourcetesting"
    23  )
    24  
    25  var _ = gc.Suite(&LegacyHTTPHandlerSuite{})
    26  
    27  type LegacyHTTPHandlerSuite struct {
    28  	testing.IsolationSuite
    29  
    30  	stub   *testing.Stub
    31  	opener *stubResourceOpener
    32  	deps   *stubLegacyHTTPHandlerDeps
    33  	resp   *stubResponseWriter
    34  }
    35  
    36  func (s *LegacyHTTPHandlerSuite) SetUpTest(c *gc.C) {
    37  	s.IsolationSuite.SetUpTest(c)
    38  
    39  	s.stub = &testing.Stub{}
    40  	s.opener = &stubResourceOpener{Stub: s.stub}
    41  	s.deps = &stubLegacyHTTPHandlerDeps{Stub: s.stub}
    42  	s.resp = newStubResponseWriter(s.stub)
    43  }
    44  
    45  func (s *LegacyHTTPHandlerSuite) TestIntegration(c *gc.C) {
    46  	opened := resourcetesting.NewResource(c, s.stub, "spam", "a-application", "some data")
    47  	s.opener.ReturnOpenResource = opened
    48  	s.deps.ReturnNewResourceOpener = s.opener
    49  	deps := server.NewLegacyHTTPHandlerDeps(s.deps)
    50  	h := server.NewLegacyHTTPHandler(deps)
    51  	req, err := api.NewHTTPDownloadRequest("spam")
    52  	c.Assert(err, jc.ErrorIsNil)
    53  	req.URL, err = url.ParseRequestURI("https://api:17018/units/eggs/1/resources/spam?:resource=spam")
    54  	c.Assert(err, jc.ErrorIsNil)
    55  	resp := &fakeResponseWriter{
    56  		stubResponseWriter: s.resp,
    57  	}
    58  
    59  	c.Logf("%#v", opened.ReadCloser)
    60  	h.ServeHTTP(resp, req)
    61  
    62  	resp.checkWritten(c, "some data", http.Header{
    63  		"Content-Type":   []string{api.ContentTypeRaw},
    64  		"Content-Length": []string{"9"}, // len("some data")
    65  		"Content-Sha384": []string{opened.Fingerprint.String()},
    66  	})
    67  }
    68  
    69  func (s *LegacyHTTPHandlerSuite) TestNewLegacyHTTPHandler(c *gc.C) {
    70  	h := server.NewLegacyHTTPHandler(s.deps)
    71  
    72  	s.stub.CheckNoCalls(c)
    73  	c.Check(h, gc.NotNil)
    74  }
    75  
    76  func (s *LegacyHTTPHandlerSuite) TestServeHTTPDownloadOkay(c *gc.C) {
    77  	s.deps.ReturnNewResourceOpener = s.opener
    78  	opened := resourcetesting.NewResource(c, s.stub, "spam", "a-application", "some data")
    79  	s.deps.ReturnHandleDownload = opened
    80  	h := &server.LegacyHTTPHandler{
    81  		LegacyHTTPHandlerDeps: s.deps,
    82  	}
    83  	req, err := http.NewRequest("GET", "...", nil)
    84  	c.Assert(err, jc.ErrorIsNil)
    85  
    86  	h.ServeHTTP(s.resp, req)
    87  
    88  	s.stub.CheckCallNames(c,
    89  		"NewResourceOpener",
    90  		"HandleDownload",
    91  		"UpdateDownloadResponse",
    92  		"WriteHeader",
    93  		"Copy",
    94  		"Close",
    95  	)
    96  	s.stub.CheckCall(c, 0, "NewResourceOpener", req)
    97  	s.stub.CheckCall(c, 1, "HandleDownload", s.opener, req)
    98  	s.stub.CheckCall(c, 2, "UpdateDownloadResponse", s.resp, opened.Resource)
    99  	s.stub.CheckCall(c, 3, "WriteHeader", http.StatusOK)
   100  	s.stub.CheckCall(c, 4, "Copy", s.resp, opened)
   101  }
   102  
   103  func (s *LegacyHTTPHandlerSuite) TestServeHTTPDownloadHandlerFailed(c *gc.C) {
   104  	h := &server.LegacyHTTPHandler{
   105  		LegacyHTTPHandlerDeps: s.deps,
   106  	}
   107  	failure := errors.New("<failure>")
   108  	s.stub.SetErrors(nil, failure)
   109  	req, err := http.NewRequest("GET", "...", nil)
   110  	c.Assert(err, jc.ErrorIsNil)
   111  
   112  	h.ServeHTTP(s.resp, req)
   113  
   114  	s.stub.CheckCallNames(c,
   115  		"NewResourceOpener",
   116  		"HandleDownload",
   117  		"SendHTTPError",
   118  	)
   119  	s.stub.CheckCall(c, 2, "SendHTTPError", s.resp, failure)
   120  }
   121  
   122  func (s *LegacyHTTPHandlerSuite) TestServeHTTPDownloadCopyFailed(c *gc.C) {
   123  	s.deps.ReturnHandleDownload = resourcetesting.NewResource(c, s.stub, "spam", "a-application", "some data")
   124  	h := &server.LegacyHTTPHandler{
   125  		LegacyHTTPHandlerDeps: s.deps,
   126  	}
   127  	failure := errors.New("<failure>")
   128  	s.stub.SetErrors(nil, nil, failure)
   129  	req, err := http.NewRequest("GET", "...", nil)
   130  	c.Assert(err, jc.ErrorIsNil)
   131  
   132  	h.ServeHTTP(s.resp, req)
   133  
   134  	s.stub.CheckCallNames(c,
   135  		"NewResourceOpener",
   136  		"HandleDownload",
   137  		"UpdateDownloadResponse",
   138  		"WriteHeader",
   139  		"Copy",
   140  		"Close",
   141  	)
   142  }
   143  
   144  func (s *LegacyHTTPHandlerSuite) TestServeHTTPConnectFailed(c *gc.C) {
   145  	h := &server.LegacyHTTPHandler{
   146  		LegacyHTTPHandlerDeps: s.deps,
   147  	}
   148  	failure := errors.New("<failure>")
   149  	s.stub.SetErrors(failure)
   150  	req, err := http.NewRequest("GET", "...", nil)
   151  	c.Assert(err, jc.ErrorIsNil)
   152  
   153  	h.ServeHTTP(s.resp, req)
   154  
   155  	s.stub.CheckCallNames(c,
   156  		"NewResourceOpener",
   157  		"SendHTTPError",
   158  	)
   159  	s.stub.CheckCall(c, 1, "SendHTTPError", s.resp, failure)
   160  }
   161  
   162  func (s *LegacyHTTPHandlerSuite) TestServeHTTPUnsupportedMethod(c *gc.C) {
   163  	h := &server.LegacyHTTPHandler{
   164  		LegacyHTTPHandlerDeps: s.deps,
   165  	}
   166  	req, err := http.NewRequest("HEAD", "...", nil)
   167  	c.Assert(err, jc.ErrorIsNil)
   168  
   169  	h.ServeHTTP(s.resp, req)
   170  
   171  	s.stub.CheckCallNames(c,
   172  		"NewResourceOpener",
   173  		"SendHTTPError",
   174  	)
   175  }
   176  
   177  type stubLegacyHTTPHandlerDeps struct {
   178  	*testing.Stub
   179  
   180  	ReturnNewResourceOpener resource.Opener
   181  	ReturnHandleDownload    resource.Opened
   182  }
   183  
   184  func (s *stubLegacyHTTPHandlerDeps) NewResourceOpener(req *http.Request) (resource.Opener, error) {
   185  	s.AddCall("NewResourceOpener", req)
   186  	if err := s.NextErr(); err != nil {
   187  		return nil, err
   188  	}
   189  
   190  	return s.ReturnNewResourceOpener, nil
   191  }
   192  
   193  func (s *stubLegacyHTTPHandlerDeps) SendHTTPError(resp http.ResponseWriter, err error) {
   194  	s.AddCall("SendHTTPError", resp, err)
   195  	s.NextErr() // Pop one off.
   196  }
   197  
   198  func (s *stubLegacyHTTPHandlerDeps) UpdateDownloadResponse(resp http.ResponseWriter, info resource.Resource) {
   199  	s.AddCall("UpdateDownloadResponse", resp, info)
   200  	s.NextErr() // Pop one off.
   201  }
   202  
   203  func (s *stubLegacyHTTPHandlerDeps) HandleDownload(opener resource.Opener, req *http.Request) (resource.Opened, error) {
   204  	s.AddCall("HandleDownload", opener, req)
   205  	if err := s.NextErr(); err != nil {
   206  		return resource.Opened{}, err
   207  	}
   208  
   209  	return s.ReturnHandleDownload, nil
   210  }
   211  
   212  type stubResourceOpener struct {
   213  	*testing.Stub
   214  
   215  	ReturnOpenResource resource.Opened
   216  }
   217  
   218  func (s *stubResourceOpener) OpenResource(name string) (resource.Opened, error) {
   219  	s.AddCall("OpenResource", name)
   220  	if err := s.NextErr(); err != nil {
   221  		return resource.Opened{}, err
   222  	}
   223  
   224  	return s.ReturnOpenResource, nil
   225  }
   226  
   227  func (s *stubLegacyHTTPHandlerDeps) Copy(w io.Writer, r io.Reader) error {
   228  	s.AddCall("Copy", w, r)
   229  	if err := s.NextErr(); err != nil {
   230  		return err
   231  	}
   232  
   233  	return nil
   234  }
   235  
   236  type stubResponseWriter struct {
   237  	*testing.Stub
   238  	io.Writer
   239  	buf *bytes.Buffer
   240  
   241  	ReturnHeader http.Header
   242  }
   243  
   244  func newStubResponseWriter(stub *testing.Stub) *stubResponseWriter {
   245  	writer, buf := filetesting.NewStubWriter(stub)
   246  	return &stubResponseWriter{
   247  		Stub:   stub,
   248  		Writer: writer,
   249  		buf:    buf,
   250  
   251  		ReturnHeader: make(http.Header),
   252  	}
   253  }
   254  
   255  func (s *stubResponseWriter) Header() http.Header {
   256  	s.AddCall("Header")
   257  	s.NextErr() // Pop one off.
   258  
   259  	return s.ReturnHeader
   260  }
   261  
   262  func (s *stubResponseWriter) WriteHeader(code int) {
   263  	s.AddCall("WriteHeader", code)
   264  	s.NextErr() // Pop one off.
   265  }
   266  
   267  type fakeResponseWriter struct {
   268  	*stubResponseWriter
   269  
   270  	writeCalled   bool
   271  	writtenHeader http.Header
   272  }
   273  
   274  func (f *fakeResponseWriter) checkWritten(c *gc.C, body string, header http.Header) {
   275  	if !c.Check(f.writeCalled, jc.IsTrue) {
   276  		return
   277  	}
   278  	c.Check(f.buf.String(), gc.Equals, body)
   279  	c.Check(f.writtenHeader, jc.DeepEquals, header)
   280  	c.Check(f.writtenHeader.Get("Content-Length"), gc.Equals, fmt.Sprint(len(body)))
   281  }
   282  
   283  func (f *fakeResponseWriter) WriteHeader(code int) {
   284  	f.stubResponseWriter.WriteHeader(code)
   285  
   286  	// See http.Header.clone() in the stdlib (net/http/header.go).
   287  	header := make(http.Header)
   288  	for k, vv := range f.ReturnHeader {
   289  		vv2 := make([]string, len(vv))
   290  		copy(vv2, vv)
   291  		header[k] = vv2
   292  	}
   293  	f.writtenHeader = header
   294  }
   295  
   296  func (f *fakeResponseWriter) Write(data []byte) (int, error) {
   297  	f.writeCalled = true
   298  	if f.writtenHeader == nil {
   299  		f.WriteHeader(http.StatusOK)
   300  	}
   301  	return f.stubResponseWriter.Write(data)
   302  }