github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/resource/api/server/upload_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  	"fmt"
     8  	"io"
     9  	"io/ioutil"
    10  	"net/http"
    11  	"strings"
    12  
    13  	"github.com/juju/errors"
    14  	jc "github.com/juju/testing/checkers"
    15  	gc "gopkg.in/check.v1"
    16  	charmresource "gopkg.in/juju/charm.v6-unstable/resource"
    17  
    18  	"github.com/juju/juju/resource/api"
    19  	"github.com/juju/juju/resource/api/server"
    20  )
    21  
    22  type UploadSuite struct {
    23  	BaseSuite
    24  
    25  	req    *http.Request
    26  	header http.Header
    27  	resp   *stubHTTPResponseWriter
    28  }
    29  
    30  var _ = gc.Suite(&UploadSuite{})
    31  
    32  func (s *UploadSuite) SetUpTest(c *gc.C) {
    33  	s.BaseSuite.SetUpTest(c)
    34  
    35  	method := "..."
    36  	urlStr := "..."
    37  	body := strings.NewReader("...")
    38  	req, err := http.NewRequest(method, urlStr, body)
    39  	c.Assert(err, jc.ErrorIsNil)
    40  
    41  	s.req = req
    42  	s.header = make(http.Header)
    43  	s.resp = &stubHTTPResponseWriter{
    44  		stub:         s.stub,
    45  		returnHeader: s.header,
    46  	}
    47  }
    48  
    49  func (s *UploadSuite) TestHandleRequestOkay(c *gc.C) {
    50  	content := "<some data>"
    51  	res, _ := newResource(c, "spam", "a-user", content)
    52  	stored, _ := newResource(c, "spam", "", "")
    53  	s.data.ReturnGetResource = stored
    54  	s.data.ReturnSetResource = res
    55  	uh := server.UploadHandler{
    56  		Username: "a-user",
    57  		Store:    s.data,
    58  	}
    59  	req, body := newUploadRequest(c, "spam", "a-application", content)
    60  
    61  	result, err := uh.HandleRequest(req)
    62  	c.Assert(err, jc.ErrorIsNil)
    63  
    64  	s.stub.CheckCallNames(c, "GetResource", "SetResource")
    65  	s.stub.CheckCall(c, 0, "GetResource", "a-application", "spam")
    66  	s.stub.CheckCall(c, 1, "SetResource", "a-application", "a-user", res.Resource, ioutil.NopCloser(body))
    67  	c.Check(result, jc.DeepEquals, &api.UploadResult{
    68  		Resource: api.Resource2API(res),
    69  	})
    70  }
    71  
    72  func (s *UploadSuite) TestExtensionMismatch(c *gc.C) {
    73  	content := "<some data>"
    74  
    75  	// newResource returns a resource with a Path = name + ".tgz"
    76  	res, _ := newResource(c, "spam", "a-user", content)
    77  	stored, _ := newResource(c, "spam", "", "")
    78  	s.data.ReturnGetResource = stored
    79  	s.data.ReturnSetResource = res
    80  	uh := server.UploadHandler{
    81  		Username: "a-user",
    82  		Store:    s.data,
    83  	}
    84  	req, _ := newUploadRequest(c, "spam", "a-application", content)
    85  	req.Header.Set("Content-Disposition", "form-data; filename=different.ext")
    86  
    87  	_, err := uh.HandleRequest(req)
    88  	c.Assert(err, gc.ErrorMatches, `incorrect extension on resource upload "different.ext", expected ".tgz"`)
    89  }
    90  
    91  func (s *UploadSuite) TestHandleRequestPending(c *gc.C) {
    92  	content := "<some data>"
    93  	res, _ := newResource(c, "spam", "a-user", content)
    94  	res.PendingID = "some-unique-id"
    95  	stored, _ := newResource(c, "spam", "", "")
    96  	stored.PendingID = "some-unique-id"
    97  	s.data.ReturnGetPendingResource = stored
    98  	s.data.ReturnUpdatePendingResource = res
    99  	uh := server.UploadHandler{
   100  		Username: "a-user",
   101  		Store:    s.data,
   102  	}
   103  	req, body := newUploadRequest(c, "spam", "a-application", content)
   104  	req.URL.RawQuery += "&pendingid=some-unique-id"
   105  
   106  	result, err := uh.HandleRequest(req)
   107  	c.Assert(err, jc.ErrorIsNil)
   108  
   109  	s.stub.CheckCallNames(c, "GetPendingResource", "UpdatePendingResource")
   110  	s.stub.CheckCall(c, 0, "GetPendingResource", "a-application", "spam", "some-unique-id")
   111  	s.stub.CheckCall(c, 1, "UpdatePendingResource", "a-application", "some-unique-id", "a-user", res.Resource, ioutil.NopCloser(body))
   112  	c.Check(result, jc.DeepEquals, &api.UploadResult{
   113  		Resource: api.Resource2API(res),
   114  	})
   115  }
   116  
   117  func (s *UploadSuite) TestHandleRequestSetResourceFailure(c *gc.C) {
   118  	content := "<some data>"
   119  	stored, _ := newResource(c, "spam", "", "")
   120  	s.data.ReturnGetResource = stored
   121  	uh := server.UploadHandler{
   122  		Username: "a-user",
   123  		Store:    s.data,
   124  	}
   125  	req, _ := newUploadRequest(c, "spam", "a-application", content)
   126  	failure := errors.New("<failure>")
   127  	s.stub.SetErrors(nil, failure)
   128  
   129  	_, err := uh.HandleRequest(req)
   130  
   131  	c.Check(errors.Cause(err), gc.Equals, failure)
   132  	s.stub.CheckCallNames(c, "GetResource", "SetResource")
   133  }
   134  
   135  func (s *UploadSuite) TestReadResourceOkay(c *gc.C) {
   136  	content := "<some data>"
   137  	expected, _ := newResource(c, "spam", "a-user", content)
   138  	stored, _ := newResource(c, "spam", "", "")
   139  	s.data.ReturnGetResource = stored
   140  	uh := server.UploadHandler{
   141  		Username: "a-user",
   142  		Store:    s.data,
   143  	}
   144  	req, body := newUploadRequest(c, "spam", "a-application", content)
   145  
   146  	uploaded, err := uh.ReadResource(req)
   147  	c.Assert(err, jc.ErrorIsNil)
   148  
   149  	s.stub.CheckCallNames(c, "GetResource")
   150  	s.stub.CheckCall(c, 0, "GetResource", "a-application", "spam")
   151  	c.Check(uploaded, jc.DeepEquals, &server.UploadedResource{
   152  		Service:  "a-application",
   153  		Resource: expected.Resource,
   154  		Data:     ioutil.NopCloser(body),
   155  	})
   156  }
   157  
   158  func (s *UploadSuite) TestReadResourcePending(c *gc.C) {
   159  	content := "<some data>"
   160  	expected, _ := newResource(c, "spam", "a-user", content)
   161  	stored, _ := newResource(c, "spam", "", "")
   162  	s.data.ReturnGetPendingResource = stored
   163  	uh := server.UploadHandler{
   164  		Username: "a-user",
   165  		Store:    s.data,
   166  	}
   167  	req, body := newUploadRequest(c, "spam", "a-application", content)
   168  	req.URL.RawQuery += "&pendingid=some-unique-id"
   169  
   170  	uploaded, err := uh.ReadResource(req)
   171  	c.Assert(err, jc.ErrorIsNil)
   172  
   173  	s.stub.CheckCallNames(c, "GetPendingResource")
   174  	s.stub.CheckCall(c, 0, "GetPendingResource", "a-application", "spam", "some-unique-id")
   175  	c.Check(uploaded, jc.DeepEquals, &server.UploadedResource{
   176  		Service:   "a-application",
   177  		PendingID: "some-unique-id",
   178  		Resource:  expected.Resource,
   179  		Data:      ioutil.NopCloser(body),
   180  	})
   181  }
   182  
   183  func (s *UploadSuite) TestReadResourceBadContentType(c *gc.C) {
   184  	uh := server.UploadHandler{
   185  		Username: "a-user",
   186  		Store:    s.data,
   187  	}
   188  	req, _ := newUploadRequest(c, "spam", "a-application", "<some data>")
   189  	req.Header.Set("Content-Type", "text/plain")
   190  
   191  	_, err := uh.ReadResource(req)
   192  
   193  	c.Check(err, gc.ErrorMatches, "unsupported content type .*")
   194  	s.stub.CheckNoCalls(c)
   195  }
   196  
   197  func (s *UploadSuite) TestReadResourceGetResourceFailure(c *gc.C) {
   198  	uh := server.UploadHandler{
   199  		Username: "a-user",
   200  		Store:    s.data,
   201  	}
   202  	req, _ := newUploadRequest(c, "spam", "a-application", "<some data>")
   203  	failure := errors.New("<failure>")
   204  	s.stub.SetErrors(failure)
   205  
   206  	_, err := uh.ReadResource(req)
   207  
   208  	c.Check(errors.Cause(err), gc.Equals, failure)
   209  	s.stub.CheckCallNames(c, "GetResource")
   210  }
   211  
   212  func (s *UploadSuite) TestReadResourceBadFingerprint(c *gc.C) {
   213  	stored, _ := newResource(c, "spam", "", "")
   214  	s.data.ReturnGetResource = stored
   215  	uh := server.UploadHandler{
   216  		Username: "a-user",
   217  		Store:    s.data,
   218  	}
   219  	req, _ := newUploadRequest(c, "spam", "a-application", "<some data>")
   220  	req.Header.Set("Content-SHA384", "bogus")
   221  
   222  	_, err := uh.ReadResource(req)
   223  
   224  	c.Check(err, gc.ErrorMatches, "invalid fingerprint.*")
   225  	s.stub.CheckNoCalls(c)
   226  }
   227  
   228  func (s *UploadSuite) TestReadResourceBadSize(c *gc.C) {
   229  	stored, _ := newResource(c, "spam", "", "")
   230  	s.data.ReturnGetResource = stored
   231  	uh := server.UploadHandler{
   232  		Username: "a-user",
   233  		Store:    s.data,
   234  	}
   235  	req, _ := newUploadRequest(c, "spam", "a-application", "<some data>")
   236  	req.Header.Set("Content-Length", "should-be-an-int")
   237  
   238  	_, err := uh.ReadResource(req)
   239  
   240  	c.Check(err, gc.ErrorMatches, "invalid size.*")
   241  	s.stub.CheckNoCalls(c)
   242  }
   243  
   244  func newUploadRequest(c *gc.C, name, service, content string) (*http.Request, io.Reader) {
   245  	fp, err := charmresource.GenerateFingerprint(strings.NewReader(content))
   246  	c.Assert(err, jc.ErrorIsNil)
   247  
   248  	method := "PUT"
   249  	urlStr := "https://api:17017/applications/%s/resources/%s"
   250  	urlStr += "?:application=%s&:resource=%s" // ...added by the mux.
   251  	urlStr = fmt.Sprintf(urlStr, service, name, service, name)
   252  	body := strings.NewReader(content)
   253  	req, err := http.NewRequest(method, urlStr, body)
   254  	c.Assert(err, jc.ErrorIsNil)
   255  
   256  	req.Header.Set("Content-Type", "application/octet-stream")
   257  	req.Header.Set("Content-Length", fmt.Sprint(len(content)))
   258  	req.Header.Set("Content-SHA384", fp.String())
   259  	req.Header.Set("Content-Disposition", "form-data; filename="+name+".tgz")
   260  
   261  	return req, body
   262  }