~sinzui/ubuntu/wily/juju-core/wily-1.24.7

« back to all changes in this revision

Viewing changes to src/github.com/juju/juju/cmd/juju/deploy_test.go

  • Committer: Package Import Robot
  • Author(s): Curtis C. Hovey
  • Date: 2015-09-22 15:27:01 UTC
  • mfrom: (1.1.36)
  • Revision ID: package-import@ubuntu.com-20150922152701-lzq2yhn2uaahrdqu
Tags: 1.24.6-0ubuntu1
* New upstream release (LP: #1481556).
* d/copyright updated for Juju 1.24.6 (Last verified commit changes).
* d/tests/* Run tests with upstart when Juju version before 1.23.
* Prefer gccgo-5 for ppc64el and arm64 in build-deps.

Show diffs side-by-side

added added

removed removed

Lines of Context:
4
4
package main
5
5
 
6
6
import (
 
7
        "fmt"
 
8
        "io/ioutil"
 
9
        "net/http"
 
10
        "net/url"
7
11
        "strings"
8
12
 
9
 
        "github.com/juju/cmd"
10
13
        "github.com/juju/errors"
11
14
        jc "github.com/juju/testing/checkers"
12
15
        "github.com/juju/utils"
13
16
        gc "gopkg.in/check.v1"
14
 
        "gopkg.in/juju/charm.v4"
 
17
        "gopkg.in/juju/charm.v5"
 
18
        "gopkg.in/juju/charm.v5/charmrepo"
 
19
        "gopkg.in/juju/charmstore.v4"
 
20
        "gopkg.in/juju/charmstore.v4/charmstoretesting"
 
21
        "gopkg.in/juju/charmstore.v4/csclient"
 
22
        "gopkg.in/macaroon-bakery.v0/bakery/checkers"
 
23
        "gopkg.in/macaroon-bakery.v0/bakerytest"
15
24
 
16
 
        "github.com/juju/juju/api"
17
25
        "github.com/juju/juju/cmd/envcmd"
 
26
        "github.com/juju/juju/cmd/juju/service"
18
27
        "github.com/juju/juju/constraints"
19
28
        "github.com/juju/juju/environs/config"
20
29
        "github.com/juju/juju/instance"
21
30
        "github.com/juju/juju/juju/testing"
22
31
        "github.com/juju/juju/state"
 
32
        "github.com/juju/juju/storage/poolmanager"
 
33
        "github.com/juju/juju/storage/provider"
23
34
        "github.com/juju/juju/testcharms"
24
35
        coretesting "github.com/juju/juju/testing"
25
36
)
26
37
 
27
38
type DeploySuite struct {
28
39
        testing.RepoSuite
 
40
        CmdBlockHelper
 
41
}
 
42
 
 
43
func (s *DeploySuite) SetUpTest(c *gc.C) {
 
44
        s.RepoSuite.SetUpTest(c)
 
45
        s.CmdBlockHelper = NewCmdBlockHelper(s.APIState)
 
46
        c.Assert(s.CmdBlockHelper, gc.NotNil)
 
47
        s.AddCleanup(func(*gc.C) { s.CmdBlockHelper.Close() })
29
48
}
30
49
 
31
50
var _ = gc.Suite(&DeploySuite{})
81
100
 
82
101
func (s *DeploySuite) TestBlockDeploy(c *gc.C) {
83
102
        // Block operation
84
 
        s.AssertConfigParameterUpdated(c, "block-all-changes", true)
 
103
        s.BlockAllChanges(c, "TestBlockDeploy")
85
104
        testcharms.Repo.CharmArchivePath(s.SeriesPath, "dummy")
86
105
        err := runDeploy(c, "local:dummy", "some-service-name")
87
 
        c.Assert(err, gc.ErrorMatches, cmd.ErrSilent.Error())
88
 
 
89
 
        // msg is logged
90
 
        stripped := strings.Replace(c.GetTestLog(), "\n", "", -1)
91
 
        c.Check(stripped, gc.Matches, ".*To unblock changes.*")
 
106
        s.AssertBlocked(c, err, ".*TestBlockDeploy.*")
92
107
}
93
108
 
94
109
func (s *DeploySuite) TestCharmDir(c *gc.C) {
200
215
        c.Assert(cons, jc.DeepEquals, constraints.MustParse("mem=2G cpu-cores=2 networks=net1,net0,^net3,^net4"))
201
216
}
202
217
 
 
218
// TODO(wallyworld) - add another test that deploy with storage fails for older environments
 
219
// (need deploy client to be refactored to use API stub)
 
220
func (s *DeploySuite) TestStorage(c *gc.C) {
 
221
        pm := poolmanager.New(state.NewStateSettings(s.State))
 
222
        _, err := pm.Create("loop-pool", provider.LoopProviderType, map[string]interface{}{"foo": "bar"})
 
223
        c.Assert(err, jc.ErrorIsNil)
 
224
 
 
225
        testcharms.Repo.CharmArchivePath(s.SeriesPath, "storage-block")
 
226
        err = runDeploy(c, "local:storage-block", "--storage", "data=loop-pool,1G")
 
227
        c.Assert(err, jc.ErrorIsNil)
 
228
        curl := charm.MustParseURL("local:trusty/storage-block-1")
 
229
        service, _ := s.AssertService(c, "storage-block", curl, 1, 0)
 
230
 
 
231
        cons, err := service.StorageConstraints()
 
232
        c.Assert(err, jc.ErrorIsNil)
 
233
        c.Assert(cons, jc.DeepEquals, map[string]state.StorageConstraints{
 
234
                "data": {
 
235
                        Pool:  "loop-pool",
 
236
                        Count: 1,
 
237
                        Size:  1024,
 
238
                },
 
239
                "allecto": {
 
240
                        Pool:  "loop",
 
241
                        Count: 0,
 
242
                        Size:  1024,
 
243
                },
 
244
        })
 
245
}
 
246
 
203
247
func (s *DeploySuite) TestSubordinateConstraints(c *gc.C) {
204
248
        testcharms.Repo.CharmArchivePath(s.SeriesPath, "logging")
205
249
        err := runDeploy(c, "local:logging", "--constraints", "mem=1G")
303
347
        s.RepoSuite.SetUpTest(c)
304
348
 
305
349
        // override provider type
306
 
        s.PatchValue(&getClientConfig, func(client *api.Client) (*config.Config, error) {
 
350
        s.PatchValue(&service.GetClientConfig, func(client service.ServiceAddUnitAPI) (*config.Config, error) {
307
351
                attrs, err := client.EnvironmentGet()
308
352
                if err != nil {
309
353
                        return nil, err
318
362
        err := runDeploy(c, "--to", "0", "local:dummy", "portlandia")
319
363
        c.Assert(err, gc.ErrorMatches, "machine 0 is the state server for a local environment and cannot host units")
320
364
}
 
365
 
 
366
// setupConfigFile creates a configuration file for testing set
 
367
// with the --config argument specifying a configuration file.
 
368
func setupConfigFile(c *gc.C, dir string) string {
 
369
        ctx := coretesting.ContextForDir(c, dir)
 
370
        path := ctx.AbsPath("testconfig.yaml")
 
371
        content := []byte("dummy-service:\n  skill-level: 9000\n  username: admin001\n\n")
 
372
        err := ioutil.WriteFile(path, content, 0666)
 
373
        c.Assert(err, jc.ErrorIsNil)
 
374
        return path
 
375
}
 
376
 
 
377
type DeployCharmStoreSuite struct {
 
378
        charmStoreSuite
 
379
}
 
380
 
 
381
var _ = gc.Suite(&DeployCharmStoreSuite{})
 
382
 
 
383
var deployAuthorizationTests = []struct {
 
384
        about        string
 
385
        uploadURL    string
 
386
        deployURL    string
 
387
        readPermUser string
 
388
        expectError  string
 
389
        expectOutput string
 
390
}{{
 
391
        about:        "public charm, success",
 
392
        uploadURL:    "cs:~bob/trusty/wordpress1-10",
 
393
        deployURL:    "cs:~bob/trusty/wordpress1",
 
394
        expectOutput: `Added charm "cs:~bob/trusty/wordpress1-10" to the environment.`,
 
395
}, {
 
396
        about:        "public charm, fully resolved, success",
 
397
        uploadURL:    "cs:~bob/trusty/wordpress2-10",
 
398
        deployURL:    "cs:~bob/trusty/wordpress2-10",
 
399
        expectOutput: `Added charm "cs:~bob/trusty/wordpress2-10" to the environment.`,
 
400
}, {
 
401
        about:        "non-public charm, success",
 
402
        uploadURL:    "cs:~bob/trusty/wordpress3-10",
 
403
        deployURL:    "cs:~bob/trusty/wordpress3",
 
404
        readPermUser: clientUserName,
 
405
        expectOutput: `Added charm "cs:~bob/trusty/wordpress3-10" to the environment.`,
 
406
}, {
 
407
        about:        "non-public charm, fully resolved, success",
 
408
        uploadURL:    "cs:~bob/trusty/wordpress4-10",
 
409
        deployURL:    "cs:~bob/trusty/wordpress4-10",
 
410
        readPermUser: clientUserName,
 
411
        expectOutput: `Added charm "cs:~bob/trusty/wordpress4-10" to the environment.`,
 
412
}, {
 
413
        about:        "non-public charm, access denied",
 
414
        uploadURL:    "cs:~bob/trusty/wordpress5-10",
 
415
        deployURL:    "cs:~bob/trusty/wordpress5",
 
416
        readPermUser: "bob",
 
417
        expectError:  `cannot resolve charm URL "cs:~bob/trusty/wordpress5": cannot get "/~bob/trusty/wordpress5/meta/any\?include=id": unauthorized: access denied for user "client-username"`,
 
418
}, {
 
419
        about:        "non-public charm, fully resolved, access denied",
 
420
        uploadURL:    "cs:~bob/trusty/wordpress6-47",
 
421
        deployURL:    "cs:~bob/trusty/wordpress6-47",
 
422
        readPermUser: "bob",
 
423
        expectError:  `cannot retrieve charm "cs:~bob/trusty/wordpress6-47": cannot get archive: unauthorized: access denied for user "client-username"`,
 
424
}}
 
425
 
 
426
func (s *DeployCharmStoreSuite) TestDeployAuthorization(c *gc.C) {
 
427
        for i, test := range deployAuthorizationTests {
 
428
                c.Logf("test %d: %s", i, test.about)
 
429
                url, _ := s.uploadCharm(c, test.uploadURL, "wordpress")
 
430
                if test.readPermUser != "" {
 
431
                        s.changeReadPerm(c, url, test.readPermUser)
 
432
                }
 
433
                ctx, err := coretesting.RunCommand(c, envcmd.Wrap(&DeployCommand{}), test.deployURL, fmt.Sprintf("wordpress%d", i))
 
434
                if test.expectError != "" {
 
435
                        c.Assert(err, gc.ErrorMatches, test.expectError)
 
436
                        continue
 
437
                }
 
438
                c.Assert(err, jc.ErrorIsNil)
 
439
                output := strings.Trim(coretesting.Stderr(ctx), "\n")
 
440
                c.Assert(output, gc.Equals, test.expectOutput)
 
441
        }
 
442
}
 
443
 
 
444
const (
 
445
        // clientUserCookie is the name of the cookie which is
 
446
        // used to signal to the charmStoreSuite macaroon discharger
 
447
        // that the client is a juju client rather than the juju environment.
 
448
        clientUserCookie = "client"
 
449
 
 
450
        // clientUserName is the name chosen for the juju client
 
451
        // when it has authorized.
 
452
        clientUserName = "client-username"
 
453
)
 
454
 
 
455
// charmStoreSuite is a suite fixture that puts the machinery in
 
456
// place to allow testing code that calls addCharmViaAPI.
 
457
type charmStoreSuite struct {
 
458
        testing.JujuConnSuite
 
459
        srv        *charmstoretesting.Server
 
460
        discharger *bakerytest.Discharger
 
461
}
 
462
 
 
463
func (s *charmStoreSuite) SetUpTest(c *gc.C) {
 
464
        s.JujuConnSuite.SetUpTest(c)
 
465
 
 
466
        // Set up the third party discharger.
 
467
        s.discharger = bakerytest.NewDischarger(nil, func(req *http.Request, cond string, arg string) ([]checkers.Caveat, error) {
 
468
                cookie, err := req.Cookie(clientUserCookie)
 
469
                if err != nil {
 
470
                        return nil, errors.New("discharge denied to non-clients")
 
471
                }
 
472
                return []checkers.Caveat{
 
473
                        checkers.DeclaredCaveat("username", cookie.Value),
 
474
                }, nil
 
475
        })
 
476
 
 
477
        // Set up the charm store testing server.
 
478
        s.srv = charmstoretesting.OpenServer(c, s.Session, charmstore.ServerParams{
 
479
                IdentityLocation: s.discharger.Location(),
 
480
                PublicKeyLocator: s.discharger,
 
481
        })
 
482
 
 
483
        // Initialize the charm cache dir.
 
484
        s.PatchValue(&charmrepo.CacheDir, c.MkDir())
 
485
 
 
486
        // Point the CLI to the charm store testing server.
 
487
        original := newCharmStoreClient
 
488
        s.PatchValue(&newCharmStoreClient, func() (*csClient, error) {
 
489
                csclient, err := original()
 
490
                if err != nil {
 
491
                        return nil, err
 
492
                }
 
493
                csclient.params.URL = s.srv.URL()
 
494
                // Add a cookie so that the discharger can detect whether the
 
495
                // HTTP client is the juju environment or the juju client.
 
496
                lurl, err := url.Parse(s.discharger.Location())
 
497
                if err != nil {
 
498
                        panic(err)
 
499
                }
 
500
                csclient.params.HTTPClient.Jar.SetCookies(lurl, []*http.Cookie{{
 
501
                        Name:  clientUserCookie,
 
502
                        Value: clientUserName,
 
503
                }})
 
504
                return csclient, nil
 
505
        })
 
506
 
 
507
        // Point the Juju API server to the charm store testing server.
 
508
        s.PatchValue(&csclient.ServerURL, s.srv.URL())
 
509
}
 
510
 
 
511
func (s *charmStoreSuite) TearDownTest(c *gc.C) {
 
512
        s.discharger.Close()
 
513
        s.srv.Close()
 
514
        s.JujuConnSuite.TearDownTest(c)
 
515
}
 
516
 
 
517
// uploadCharm adds a charm with the given URL and name to the charm store.
 
518
func (s *charmStoreSuite) uploadCharm(c *gc.C, url, name string) (*charm.URL, charm.Charm) {
 
519
        id := charm.MustParseReference(url)
 
520
        promulgated := false
 
521
        if id.User == "" {
 
522
                id.User = "who"
 
523
                promulgated = true
 
524
        }
 
525
        ch := testcharms.Repo.CharmArchive(c.MkDir(), name)
 
526
        id = s.srv.UploadCharm(c, ch, id, promulgated)
 
527
        return (*charm.URL)(id), ch
 
528
}
 
529
 
 
530
// changeReadPerm changes the read permission of the given charm URL.
 
531
// The charm must be present in the testing charm store.
 
532
func (s *charmStoreSuite) changeReadPerm(c *gc.C, url *charm.URL, perms ...string) {
 
533
        err := s.srv.NewClient().Put("/"+url.Path()+"/meta/perm/read", perms)
 
534
        c.Assert(err, jc.ErrorIsNil)
 
535
}