~juju-qa/ubuntu/xenial/juju/xenial-2.0-beta3

« back to all changes in this revision

Viewing changes to src/gopkg.in/juju/charmstore.v5-unstable/internal/v5/common_test.go

  • Committer: Martin Packman
  • Date: 2016-03-30 19:31:08 UTC
  • mfrom: (1.1.41)
  • Revision ID: martin.packman@canonical.com-20160330193108-h9iz3ak334uk0z5r
Merge new upstream source 2.0~beta3

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
package v5_test // import "gopkg.in/juju/charmstore.v5-unstable/internal/v5"
2
2
 
3
3
import (
 
4
        "bytes"
4
5
        "encoding/json"
5
6
        "io"
6
7
        "net/http"
9
10
 
10
11
        "github.com/juju/loggo"
11
12
        jujutesting "github.com/juju/testing"
 
13
        "github.com/juju/testing/httptesting"
12
14
        "github.com/julienschmidt/httprouter"
13
15
        gc "gopkg.in/check.v1"
14
16
        "gopkg.in/errgo.v1"
 
17
        "gopkg.in/juju/charm.v6-unstable"
 
18
        "gopkg.in/juju/charmrepo.v2-unstable/csclient/params"
15
19
        "gopkg.in/macaroon-bakery.v1/bakery"
16
20
        "gopkg.in/macaroon-bakery.v1/bakery/checkers"
17
21
        "gopkg.in/macaroon-bakery.v1/bakerytest"
18
22
        "gopkg.in/macaroon-bakery.v1/httpbakery"
 
23
        "gopkg.in/macaroon.v1"
19
24
        "gopkg.in/mgo.v2"
20
25
 
21
26
        "gopkg.in/juju/charmstore.v5-unstable/internal/charmstore"
 
27
        "gopkg.in/juju/charmstore.v5-unstable/internal/router"
22
28
        "gopkg.in/juju/charmstore.v5-unstable/internal/storetesting"
23
29
        "gopkg.in/juju/charmstore.v5-unstable/internal/v5"
24
30
)
188
194
        }
189
195
        db := s.Session.DB("charmstore")
190
196
        var err error
191
 
        s.srv, err = charmstore.NewServer(db, si, config, map[string]charmstore.NewAPIHandlerFunc{"v4": v5.NewAPIHandler})
 
197
        s.srv, err = charmstore.NewServer(db, si, config, map[string]charmstore.NewAPIHandlerFunc{"v5": v5.NewAPIHandler})
192
198
        c.Assert(err, gc.IsNil)
193
199
        s.srvParams = config
194
200
 
196
202
                config.IdentityLocation = ""
197
203
                config.PublicKeyLocator = nil
198
204
                config.IdentityAPIURL = ""
199
 
                s.noMacaroonSrv, err = charmstore.NewServer(db, si, config, map[string]charmstore.NewAPIHandlerFunc{"v4": v5.NewAPIHandler})
 
205
                s.noMacaroonSrv, err = charmstore.NewServer(db, si, config, map[string]charmstore.NewAPIHandlerFunc{"v5": v5.NewAPIHandler})
200
206
                c.Assert(err, gc.IsNil)
201
207
        } else {
202
208
                s.noMacaroonSrv = s.srv
205
211
        s.store = s.srv.Pool().Store()
206
212
}
207
213
 
 
214
func (s *commonSuite) addPublicCharmFromRepo(c *gc.C, charmName string, rurl *router.ResolvedURL) (*router.ResolvedURL, charm.Charm) {
 
215
        return s.addPublicCharm(c, storetesting.Charms.CharmDir(charmName), rurl)
 
216
}
 
217
 
 
218
func (s *commonSuite) addPublicCharm(c *gc.C, ch charm.Charm, rurl *router.ResolvedURL) (*router.ResolvedURL, charm.Charm) {
 
219
        err := s.store.AddCharmWithArchive(rurl, ch)
 
220
        c.Assert(err, gc.IsNil)
 
221
        s.setPublic(c, rurl)
 
222
        return rurl, ch
 
223
}
 
224
 
 
225
func (s *commonSuite) setPublic(c *gc.C, rurl *router.ResolvedURL) {
 
226
        err := s.store.SetPerms(&rurl.URL, "stable.read", params.Everyone)
 
227
        c.Assert(err, gc.IsNil)
 
228
        err = s.store.Publish(rurl, params.StableChannel)
 
229
        c.Assert(err, gc.IsNil)
 
230
}
 
231
 
 
232
func (s *commonSuite) addPublicBundleFromRepo(c *gc.C, bundleName string, rurl *router.ResolvedURL, addRequiredCharms bool) (*router.ResolvedURL, charm.Bundle) {
 
233
        return s.addPublicBundle(c, storetesting.Charms.BundleDir(bundleName), rurl, addRequiredCharms)
 
234
}
 
235
 
 
236
func (s *commonSuite) addPublicBundle(c *gc.C, bundle charm.Bundle, rurl *router.ResolvedURL, addRequiredCharms bool) (*router.ResolvedURL, charm.Bundle) {
 
237
        if addRequiredCharms {
 
238
                s.addRequiredCharms(c, bundle)
 
239
        }
 
240
        err := s.store.AddBundleWithArchive(rurl, bundle)
 
241
        c.Assert(err, gc.IsNil)
 
242
        s.setPublic(c, rurl)
 
243
        return rurl, bundle
 
244
}
 
245
 
 
246
// addCharms adds all the given charms to s.store. The
 
247
// map key is the id of the charm.
 
248
func (s *commonSuite) addCharms(c *gc.C, charms map[string]charm.Charm) {
 
249
        for id, ch := range charms {
 
250
                s.addPublicCharm(c, storetesting.NewCharm(ch.Meta()), mustParseResolvedURL(id))
 
251
        }
 
252
}
 
253
 
 
254
// setPerms sets the stable channel read permissions of a set of
 
255
// entities. The map key is the is the id of each entity; its associated
 
256
// value is its read ACL.
 
257
func (s *commonSuite) setPerms(c *gc.C, readACLs map[string][]string) {
 
258
        for url, acl := range readACLs {
 
259
                err := s.store.SetPerms(charm.MustParseURL(url), "stable.read", acl...)
 
260
                c.Assert(err, gc.IsNil)
 
261
        }
 
262
}
 
263
 
208
264
// handler returns a request handler that can be
209
265
// used to invoke private methods. The caller
210
266
// is responsible for calling Put on the returned handler.
211
267
func (s *commonSuite) handler(c *gc.C) *v5.ReqHandler {
212
 
        h := v5.New(s.store.Pool(), s.srvParams)
 
268
        h := v5.New(s.store.Pool(), s.srvParams, "")
213
269
        defer h.Close()
214
 
        rh, err := h.NewReqHandler()
 
270
        rh, err := h.NewReqHandler(new(http.Request))
215
271
        c.Assert(err, gc.IsNil)
216
272
        // It would be nice if we could call s.AddCleanup here
217
273
        // to call rh.Put when the test has completed, but
221
277
}
222
278
 
223
279
func storeURL(path string) string {
224
 
        return "/v4/" + path
 
280
        return "/v5/" + path
 
281
}
 
282
 
 
283
func (s *commonSuite) bakeryDoAsUser(c *gc.C, user string) func(*http.Request) (*http.Response, error) {
 
284
        bclient := httpbakery.NewClient()
 
285
        m, err := s.store.Bakery.NewMacaroon("", nil, []checkers.Caveat{
 
286
                checkers.DeclaredCaveat("username", user),
 
287
        })
 
288
        c.Assert(err, gc.IsNil)
 
289
        macaroonCookie, err := httpbakery.NewCookie(macaroon.Slice{m})
 
290
        c.Assert(err, gc.IsNil)
 
291
        return func(req *http.Request) (*http.Response, error) {
 
292
                req.AddCookie(macaroonCookie)
 
293
                if req.Body == nil {
 
294
                        return bclient.Do(req)
 
295
                }
 
296
                body := req.Body.(io.ReadSeeker)
 
297
                req.Body = nil
 
298
                return bclient.DoWithBody(req, body)
 
299
        }
 
300
}
 
301
 
 
302
// addRequiredCharms adds any charms required by the given
 
303
// bundle that are not already in the store.
 
304
func (s *commonSuite) addRequiredCharms(c *gc.C, bundle charm.Bundle) {
 
305
        for _, svc := range bundle.Data().Services {
 
306
                u := charm.MustParseURL(svc.Charm)
 
307
                if _, err := s.store.FindBestEntity(u, params.StableChannel, nil); err == nil {
 
308
                        continue
 
309
                }
 
310
                if u.Revision == -1 {
 
311
                        u.Revision = 0
 
312
                }
 
313
                var rurl router.ResolvedURL
 
314
                rurl.URL = *u
 
315
                chDir, err := charm.ReadCharmDir(storetesting.Charms.CharmDirPath(u.Name))
 
316
                ch := charm.Charm(chDir)
 
317
                if err != nil {
 
318
                        // The charm doesn't exist in the local charm repo; make one up.
 
319
                        ch = storetesting.NewCharm(nil)
 
320
                }
 
321
                if len(ch.Meta().Series) == 0 && u.Series == "" {
 
322
                        rurl.URL.Series = "trusty"
 
323
                }
 
324
                if u.User == "" {
 
325
                        rurl.URL.User = "charmers"
 
326
                        rurl.PromulgatedRevision = rurl.URL.Revision
 
327
                } else {
 
328
                        rurl.PromulgatedRevision = -1
 
329
                }
 
330
                c.Logf("adding charm %v %d required by bundle to fulfil %v", &rurl.URL, rurl.PromulgatedRevision, svc.Charm)
 
331
                s.addPublicCharm(c, ch, &rurl)
 
332
        }
 
333
}
 
334
 
 
335
func (s *commonSuite) assertPut(c *gc.C, url string, val interface{}) {
 
336
        s.assertPut0(c, url, val, false)
 
337
}
 
338
 
 
339
func (s *commonSuite) assertPutAsAdmin(c *gc.C, url string, val interface{}) {
 
340
        s.assertPut0(c, url, val, true)
 
341
}
 
342
 
 
343
func (s *commonSuite) assertPut0(c *gc.C, url string, val interface{}, asAdmin bool) {
 
344
        body, err := json.Marshal(val)
 
345
        c.Assert(err, gc.IsNil)
 
346
        p := httptesting.JSONCallParams{
 
347
                Handler: s.srv,
 
348
                URL:     storeURL(url),
 
349
                Method:  "PUT",
 
350
                Do:      bakeryDo(nil),
 
351
                Header: http.Header{
 
352
                        "Content-Type": {"application/json"},
 
353
                },
 
354
                Body: bytes.NewReader(body),
 
355
        }
 
356
        if asAdmin {
 
357
                p.Username = testUsername
 
358
                p.Password = testPassword
 
359
        }
 
360
        httptesting.AssertJSONCall(c, p)
 
361
}
 
362
 
 
363
func (s *commonSuite) assertGet(c *gc.C, url string, expectVal interface{}) {
 
364
        httptesting.AssertJSONCall(c, httptesting.JSONCallParams{
 
365
                Handler:    s.srv,
 
366
                Do:         bakeryDo(nil),
 
367
                URL:        storeURL(url),
 
368
                ExpectBody: expectVal,
 
369
        })
 
370
}
 
371
 
 
372
// assertGetIsUnauthorized asserts that a GET to the given URL results
 
373
// in an ErrUnauthorized response with the given error message.
 
374
func (s *commonSuite) assertGetIsUnauthorized(c *gc.C, url, expectMessage string) {
 
375
        httptesting.AssertJSONCall(c, httptesting.JSONCallParams{
 
376
                Handler:      s.srv,
 
377
                Do:           bakeryDo(nil),
 
378
                Method:       "GET",
 
379
                URL:          storeURL(url),
 
380
                ExpectStatus: http.StatusUnauthorized,
 
381
                ExpectBody: params.Error{
 
382
                        Code:    params.ErrUnauthorized,
 
383
                        Message: expectMessage,
 
384
                },
 
385
        })
 
386
}
 
387
 
 
388
// assertGetIsUnauthorized asserts that a PUT to the given URL with the
 
389
// given body value results in an ErrUnauthorized response with the given
 
390
// error message.
 
391
func (s *commonSuite) assertPutIsUnauthorized(c *gc.C, url string, val interface{}, expectMessage string) {
 
392
        body, err := json.Marshal(val)
 
393
        c.Assert(err, gc.IsNil)
 
394
        httptesting.AssertJSONCall(c, httptesting.JSONCallParams{
 
395
                Handler: s.srv,
 
396
                URL:     storeURL(url),
 
397
                Method:  "PUT",
 
398
                Do:      bakeryDo(nil),
 
399
                Header: http.Header{
 
400
                        "Content-Type": {"application/json"},
 
401
                },
 
402
                Body:         bytes.NewReader(body),
 
403
                ExpectStatus: http.StatusUnauthorized,
 
404
                ExpectBody: params.Error{
 
405
                        Code:    params.ErrUnauthorized,
 
406
                        Message: expectMessage,
 
407
                },
 
408
        })
 
409
}
 
410
 
 
411
// doAsUser calls the given function, discharging any authorization
 
412
// request as the given user name.
 
413
func (s *commonSuite) doAsUser(user string, f func()) {
 
414
        old := s.discharge
 
415
        s.discharge = dischargeForUser(user)
 
416
        defer func() {
 
417
                s.discharge = old
 
418
        }()
 
419
        f()
225
420
}
226
421
 
227
422
func bakeryDo(client *http.Client) func(*http.Request) (*http.Response, error) {
231
426
        bclient := httpbakery.NewClient()
232
427
        bclient.Client = client
233
428
        return func(req *http.Request) (*http.Response, error) {
234
 
                if req.Body != nil {
235
 
                        body := req.Body.(io.ReadSeeker)
236
 
                        req.Body = nil
237
 
                        return bclient.DoWithBody(req, body)
 
429
                if req.Body == nil {
 
430
                        return bclient.Do(req)
238
431
                }
239
 
                return bclient.Do(req)
 
432
                body := req.Body.(io.ReadSeeker)
 
433
                req.Body = nil
 
434
                return bclient.DoWithBody(req, body)
240
435
        }
241
436
}
242
437