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 }