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 }