1
// Copyright 2016 Canonical Ltd.
2
// Licensed under the AGPLv3, see LICENCE file for details.
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"
19
"github.com/juju/juju/resource"
20
"github.com/juju/juju/resource/api"
21
"github.com/juju/juju/resource/api/server"
22
"github.com/juju/juju/resource/resourcetesting"
25
var _ = gc.Suite(&UnitResourceHandlerSuite{})
27
type UnitResourceHandlerSuite struct {
28
testing.IsolationSuite
31
opener *stubResourceOpener
32
deps *stubUnitResourceHandlerDeps
33
resp *stubResponseWriter
36
func (s *UnitResourceHandlerSuite) SetUpTest(c *gc.C) {
37
s.IsolationSuite.SetUpTest(c)
39
s.stub = &testing.Stub{}
40
s.opener = &stubResourceOpener{Stub: s.stub}
41
s.deps = &stubUnitResourceHandlerDeps{Stub: s.stub}
42
s.resp = newStubResponseWriter(s.stub)
45
func (s *UnitResourceHandlerSuite) TestIntegration(c *gc.C) {
46
opened := resourcetesting.NewResource(c, s.stub, "spam", "a-service", "some data")
47
s.opener.ReturnOpenResource = opened
48
s.deps.ReturnNewResourceOpener = s.opener
49
deps := server.NewUnitResourceHandlerDeps(s.deps)
50
h := server.NewUnitResourceHandler(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,
59
c.Logf("%#v", opened.ReadCloser)
60
h.ServeHTTP(resp, req)
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()},
69
func (s *UnitResourceHandlerSuite) TestNewUnitResourceHandler(c *gc.C) {
70
h := server.NewUnitResourceHandler(s.deps)
72
s.stub.CheckNoCalls(c)
76
func (s *UnitResourceHandlerSuite) TestServeHTTPDownloadOkay(c *gc.C) {
77
s.deps.ReturnNewResourceOpener = s.opener
78
opened := resourcetesting.NewResource(c, s.stub, "spam", "a-service", "some data")
79
s.deps.ReturnHandleDownload = opened
80
h := &server.UnitResourceHandler{
81
UnitResourceHandlerDeps: s.deps,
83
req, err := http.NewRequest("GET", "...", nil)
84
c.Assert(err, jc.ErrorIsNil)
86
h.ServeHTTP(s.resp, req)
88
s.stub.CheckCallNames(c,
91
"UpdateDownloadResponse",
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)
103
func (s *UnitResourceHandlerSuite) TestServeHTTPDownloadHandlerFailed(c *gc.C) {
104
h := &server.UnitResourceHandler{
105
UnitResourceHandlerDeps: s.deps,
107
failure := errors.New("<failure>")
108
s.stub.SetErrors(nil, failure)
109
req, err := http.NewRequest("GET", "...", nil)
110
c.Assert(err, jc.ErrorIsNil)
112
h.ServeHTTP(s.resp, req)
114
s.stub.CheckCallNames(c,
119
s.stub.CheckCall(c, 2, "SendHTTPError", s.resp, failure)
122
func (s *UnitResourceHandlerSuite) TestServeHTTPDownloadCopyFailed(c *gc.C) {
123
s.deps.ReturnHandleDownload = resourcetesting.NewResource(c, s.stub, "spam", "a-service", "some data")
124
h := &server.UnitResourceHandler{
125
UnitResourceHandlerDeps: s.deps,
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)
132
h.ServeHTTP(s.resp, req)
134
s.stub.CheckCallNames(c,
137
"UpdateDownloadResponse",
144
func (s *UnitResourceHandlerSuite) TestServeHTTPConnectFailed(c *gc.C) {
145
h := &server.UnitResourceHandler{
146
UnitResourceHandlerDeps: s.deps,
148
failure := errors.New("<failure>")
149
s.stub.SetErrors(failure)
150
req, err := http.NewRequest("GET", "...", nil)
151
c.Assert(err, jc.ErrorIsNil)
153
h.ServeHTTP(s.resp, req)
155
s.stub.CheckCallNames(c,
159
s.stub.CheckCall(c, 1, "SendHTTPError", s.resp, failure)
162
func (s *UnitResourceHandlerSuite) TestServeHTTPUnsupportedMethod(c *gc.C) {
163
h := &server.UnitResourceHandler{
164
UnitResourceHandlerDeps: s.deps,
166
req, err := http.NewRequest("HEAD", "...", nil)
167
c.Assert(err, jc.ErrorIsNil)
169
h.ServeHTTP(s.resp, req)
171
s.stub.CheckCallNames(c,
177
type stubUnitResourceHandlerDeps struct {
180
ReturnNewResourceOpener resource.Opener
181
ReturnHandleDownload resource.Opened
184
func (s *stubUnitResourceHandlerDeps) NewResourceOpener(req *http.Request) (resource.Opener, error) {
185
s.AddCall("NewResourceOpener", req)
186
if err := s.NextErr(); err != nil {
190
return s.ReturnNewResourceOpener, nil
193
func (s *stubUnitResourceHandlerDeps) SendHTTPError(resp http.ResponseWriter, err error) {
194
s.AddCall("SendHTTPError", resp, err)
195
s.NextErr() // Pop one off.
198
func (s *stubUnitResourceHandlerDeps) UpdateDownloadResponse(resp http.ResponseWriter, info resource.Resource) {
199
s.AddCall("UpdateDownloadResponse", resp, info)
200
s.NextErr() // Pop one off.
203
func (s *stubUnitResourceHandlerDeps) 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
209
return s.ReturnHandleDownload, nil
212
type stubResourceOpener struct {
215
ReturnOpenResource resource.Opened
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
224
return s.ReturnOpenResource, nil
227
func (s *stubUnitResourceHandlerDeps) Copy(w io.Writer, r io.Reader) error {
228
s.AddCall("Copy", w, r)
229
if err := s.NextErr(); err != nil {
236
type stubResponseWriter struct {
241
ReturnHeader http.Header
244
func newStubResponseWriter(stub *testing.Stub) *stubResponseWriter {
245
writer, buf := filetesting.NewStubWriter(stub)
246
return &stubResponseWriter{
251
ReturnHeader: make(http.Header),
255
func (s *stubResponseWriter) Header() http.Header {
257
s.NextErr() // Pop one off.
259
return s.ReturnHeader
262
func (s *stubResponseWriter) WriteHeader(code int) {
263
s.AddCall("WriteHeader", code)
264
s.NextErr() // Pop one off.
267
type fakeResponseWriter struct {
271
writtenHeader http.Header
274
func (f *fakeResponseWriter) checkWritten(c *gc.C, body string, header http.Header) {
275
if !c.Check(f.writeCalled, jc.IsTrue) {
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)))
283
func (f *fakeResponseWriter) WriteHeader(code int) {
284
f.stubResponseWriter.WriteHeader(code)
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))
293
f.writtenHeader = header
296
func (f *fakeResponseWriter) Write(data []byte) (int, error) {
298
if f.writtenHeader == nil {
299
f.WriteHeader(http.StatusOK)
301
return f.stubResponseWriter.Write(data)