github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/cmd/juju/commands/upgradecharm_test.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package commands
     5  
     6  import (
     7  	"bytes"
     8  	"io/ioutil"
     9  	"net/http/httptest"
    10  	"os"
    11  	"path"
    12  
    13  	jc "github.com/juju/testing/checkers"
    14  	gc "gopkg.in/check.v1"
    15  	"gopkg.in/juju/charm.v6-unstable"
    16  	"gopkg.in/juju/charmrepo.v1"
    17  	"gopkg.in/juju/charmstore.v5-unstable"
    18  
    19  	"github.com/juju/juju/cmd/envcmd"
    20  	jujutesting "github.com/juju/juju/juju/testing"
    21  	"github.com/juju/juju/state"
    22  	"github.com/juju/juju/testcharms"
    23  	"github.com/juju/juju/testing"
    24  )
    25  
    26  type UpgradeCharmErrorsSuite struct {
    27  	jujutesting.RepoSuite
    28  	handler charmstore.HTTPCloseHandler
    29  	srv     *httptest.Server
    30  }
    31  
    32  func (s *UpgradeCharmErrorsSuite) SetUpTest(c *gc.C) {
    33  	s.RepoSuite.SetUpTest(c)
    34  	// Set up the charm store testing server.
    35  	handler, err := charmstore.NewServer(s.Session.DB("juju-testing"), nil, "", charmstore.ServerParams{
    36  		AuthUsername: "test-user",
    37  		AuthPassword: "test-password",
    38  	}, charmstore.V4)
    39  	c.Assert(err, jc.ErrorIsNil)
    40  	s.handler = handler
    41  	s.srv = httptest.NewServer(handler)
    42  
    43  	s.PatchValue(&charmrepo.CacheDir, c.MkDir())
    44  	original := newCharmStoreClient
    45  	s.PatchValue(&newCharmStoreClient, func() (*csClient, error) {
    46  		csclient, err := original()
    47  		c.Assert(err, jc.ErrorIsNil)
    48  		csclient.params.URL = s.srv.URL
    49  		return csclient, nil
    50  	})
    51  }
    52  
    53  func (s *UpgradeCharmErrorsSuite) TearDownTest(c *gc.C) {
    54  	s.handler.Close()
    55  	s.srv.Close()
    56  	s.RepoSuite.TearDownTest(c)
    57  }
    58  
    59  var _ = gc.Suite(&UpgradeCharmErrorsSuite{})
    60  
    61  func runUpgradeCharm(c *gc.C, args ...string) error {
    62  	_, err := testing.RunCommand(c, envcmd.Wrap(&UpgradeCharmCommand{}), args...)
    63  	return err
    64  }
    65  
    66  func (s *UpgradeCharmErrorsSuite) TestInvalidArgs(c *gc.C) {
    67  	err := runUpgradeCharm(c)
    68  	c.Assert(err, gc.ErrorMatches, "no service specified")
    69  	err = runUpgradeCharm(c, "invalid:name")
    70  	c.Assert(err, gc.ErrorMatches, `invalid service name "invalid:name"`)
    71  	err = runUpgradeCharm(c, "foo", "bar")
    72  	c.Assert(err, gc.ErrorMatches, `unrecognized args: \["bar"\]`)
    73  }
    74  
    75  func (s *UpgradeCharmErrorsSuite) TestWithInvalidRepository(c *gc.C) {
    76  	testcharms.Repo.ClonedDirPath(s.SeriesPath, "riak")
    77  	err := runDeploy(c, "local:riak", "riak")
    78  	c.Assert(err, jc.ErrorIsNil)
    79  
    80  	err = runUpgradeCharm(c, "riak", "--repository=blah")
    81  	c.Assert(err, gc.ErrorMatches, `no repository found at ".*blah"`)
    82  	// Reset JUJU_REPOSITORY explicitly, because repoSuite.SetUpTest
    83  	// overwrites it (TearDownTest will revert it again).
    84  	os.Setenv("JUJU_REPOSITORY", "")
    85  	err = runUpgradeCharm(c, "riak", "--repository=")
    86  	c.Assert(err, gc.ErrorMatches, `entity not found in ".*": local:trusty/riak`)
    87  }
    88  
    89  func (s *UpgradeCharmErrorsSuite) TestInvalidService(c *gc.C) {
    90  	err := runUpgradeCharm(c, "phony")
    91  	c.Assert(err, gc.ErrorMatches, `service "phony" not found`)
    92  }
    93  
    94  func (s *UpgradeCharmErrorsSuite) deployService(c *gc.C) {
    95  	testcharms.Repo.ClonedDirPath(s.SeriesPath, "riak")
    96  	err := runDeploy(c, "local:riak", "riak")
    97  	c.Assert(err, jc.ErrorIsNil)
    98  }
    99  
   100  func (s *UpgradeCharmErrorsSuite) TestInvalidSwitchURL(c *gc.C) {
   101  	s.deployService(c)
   102  	err := runUpgradeCharm(c, "riak", "--switch=blah")
   103  	c.Assert(err, gc.ErrorMatches, `cannot resolve URL "cs:trusty/blah": charm not found`)
   104  	err = runUpgradeCharm(c, "riak", "--switch=cs:missing/one")
   105  	c.Assert(err, gc.ErrorMatches, `cannot resolve URL "cs:missing/one": charm not found`)
   106  	// TODO(dimitern): add tests with incompatible charms
   107  }
   108  
   109  func (s *UpgradeCharmErrorsSuite) TestSwitchAndRevisionFails(c *gc.C) {
   110  	s.deployService(c)
   111  	err := runUpgradeCharm(c, "riak", "--switch=riak", "--revision=2")
   112  	c.Assert(err, gc.ErrorMatches, "--switch and --revision are mutually exclusive")
   113  }
   114  
   115  func (s *UpgradeCharmErrorsSuite) TestInvalidRevision(c *gc.C) {
   116  	s.deployService(c)
   117  	err := runUpgradeCharm(c, "riak", "--revision=blah")
   118  	c.Assert(err, gc.ErrorMatches, `invalid value "blah" for flag --revision: strconv.ParseInt: parsing "blah": invalid syntax`)
   119  }
   120  
   121  type UpgradeCharmSuccessSuite struct {
   122  	jujutesting.RepoSuite
   123  	CmdBlockHelper
   124  	path string
   125  	riak *state.Service
   126  }
   127  
   128  var _ = gc.Suite(&UpgradeCharmSuccessSuite{})
   129  
   130  func (s *UpgradeCharmSuccessSuite) SetUpTest(c *gc.C) {
   131  	s.RepoSuite.SetUpTest(c)
   132  	s.path = testcharms.Repo.ClonedDirPath(s.SeriesPath, "riak")
   133  	err := runDeploy(c, "local:riak", "riak")
   134  	c.Assert(err, jc.ErrorIsNil)
   135  	s.riak, err = s.State.Service("riak")
   136  	c.Assert(err, jc.ErrorIsNil)
   137  	ch, forced, err := s.riak.Charm()
   138  	c.Assert(err, jc.ErrorIsNil)
   139  	c.Assert(ch.Revision(), gc.Equals, 7)
   140  	c.Assert(forced, jc.IsFalse)
   141  
   142  	s.CmdBlockHelper = NewCmdBlockHelper(s.APIState)
   143  	c.Assert(s.CmdBlockHelper, gc.NotNil)
   144  	s.AddCleanup(func(*gc.C) { s.CmdBlockHelper.Close() })
   145  }
   146  
   147  func (s *UpgradeCharmSuccessSuite) assertUpgraded(c *gc.C, revision int, forced bool) *charm.URL {
   148  	err := s.riak.Refresh()
   149  	c.Assert(err, jc.ErrorIsNil)
   150  	ch, force, err := s.riak.Charm()
   151  	c.Assert(err, jc.ErrorIsNil)
   152  	c.Assert(ch.Revision(), gc.Equals, revision)
   153  	c.Assert(force, gc.Equals, forced)
   154  	s.AssertCharmUploaded(c, ch.URL())
   155  	return ch.URL()
   156  }
   157  
   158  func (s *UpgradeCharmSuccessSuite) assertLocalRevision(c *gc.C, revision int, path string) {
   159  	dir, err := charm.ReadCharmDir(path)
   160  	c.Assert(err, jc.ErrorIsNil)
   161  	c.Assert(dir.Revision(), gc.Equals, revision)
   162  }
   163  
   164  func (s *UpgradeCharmSuccessSuite) TestLocalRevisionUnchanged(c *gc.C) {
   165  	err := runUpgradeCharm(c, "riak")
   166  	c.Assert(err, jc.ErrorIsNil)
   167  	s.assertUpgraded(c, 8, false)
   168  	// Even though the remote revision is bumped, the local one should
   169  	// be unchanged.
   170  	s.assertLocalRevision(c, 7, s.path)
   171  }
   172  
   173  func (s *UpgradeCharmSuccessSuite) TestBlockUpgradeCharm(c *gc.C) {
   174  	// Block operation
   175  	s.BlockAllChanges(c, "TestBlockUpgradeCharm")
   176  	err := runUpgradeCharm(c, "riak")
   177  	s.AssertBlocked(c, err, ".*TestBlockUpgradeCharm.*")
   178  }
   179  
   180  func (s *UpgradeCharmSuccessSuite) TestRespectsLocalRevisionWhenPossible(c *gc.C) {
   181  	dir, err := charm.ReadCharmDir(s.path)
   182  	c.Assert(err, jc.ErrorIsNil)
   183  	err = dir.SetDiskRevision(42)
   184  	c.Assert(err, jc.ErrorIsNil)
   185  
   186  	err = runUpgradeCharm(c, "riak")
   187  	c.Assert(err, jc.ErrorIsNil)
   188  	s.assertUpgraded(c, 42, false)
   189  	s.assertLocalRevision(c, 42, s.path)
   190  }
   191  
   192  func (s *UpgradeCharmSuccessSuite) TestUpgradesWithBundle(c *gc.C) {
   193  	dir, err := charm.ReadCharmDir(s.path)
   194  	c.Assert(err, jc.ErrorIsNil)
   195  	dir.SetRevision(42)
   196  	buf := &bytes.Buffer{}
   197  	err = dir.ArchiveTo(buf)
   198  	c.Assert(err, jc.ErrorIsNil)
   199  	bundlePath := path.Join(s.SeriesPath, "riak.charm")
   200  	err = ioutil.WriteFile(bundlePath, buf.Bytes(), 0644)
   201  	c.Assert(err, jc.ErrorIsNil)
   202  
   203  	err = runUpgradeCharm(c, "riak")
   204  	c.Assert(err, jc.ErrorIsNil)
   205  	s.assertUpgraded(c, 42, false)
   206  	s.assertLocalRevision(c, 7, s.path)
   207  }
   208  
   209  func (s *UpgradeCharmSuccessSuite) TestBlockUpgradesWithBundle(c *gc.C) {
   210  	dir, err := charm.ReadCharmDir(s.path)
   211  	c.Assert(err, jc.ErrorIsNil)
   212  	dir.SetRevision(42)
   213  	buf := &bytes.Buffer{}
   214  	err = dir.ArchiveTo(buf)
   215  	c.Assert(err, jc.ErrorIsNil)
   216  	bundlePath := path.Join(s.SeriesPath, "riak.charm")
   217  	err = ioutil.WriteFile(bundlePath, buf.Bytes(), 0644)
   218  	c.Assert(err, jc.ErrorIsNil)
   219  
   220  	// Block operation
   221  	s.BlockAllChanges(c, "TestBlockUpgradesWithBundle")
   222  	err = runUpgradeCharm(c, "riak")
   223  	s.AssertBlocked(c, err, ".*TestBlockUpgradesWithBundle.*")
   224  }
   225  
   226  func (s *UpgradeCharmSuccessSuite) TestForcedUpgrade(c *gc.C) {
   227  	err := runUpgradeCharm(c, "riak", "--force")
   228  	c.Assert(err, jc.ErrorIsNil)
   229  	s.assertUpgraded(c, 8, true)
   230  	// Local revision is not changed.
   231  	s.assertLocalRevision(c, 7, s.path)
   232  }
   233  
   234  func (s *UpgradeCharmSuccessSuite) TestBlockForcedUpgrade(c *gc.C) {
   235  	// Block operation
   236  	s.BlockAllChanges(c, "TestBlockForcedUpgrade")
   237  	err := runUpgradeCharm(c, "riak", "--force")
   238  	c.Assert(err, jc.ErrorIsNil)
   239  	s.assertUpgraded(c, 8, true)
   240  	// Local revision is not changed.
   241  	s.assertLocalRevision(c, 7, s.path)
   242  }
   243  
   244  var myriakMeta = []byte(`
   245  name: myriak
   246  summary: "K/V storage engine"
   247  description: "Scalable K/V Store in Erlang with Clocks :-)"
   248  provides:
   249    endpoint:
   250      interface: http
   251    admin:
   252      interface: http
   253  peers:
   254    ring:
   255      interface: riak
   256  `)
   257  
   258  func (s *UpgradeCharmSuccessSuite) TestSwitch(c *gc.C) {
   259  	myriakPath := testcharms.Repo.RenamedClonedDirPath(s.SeriesPath, "riak", "myriak")
   260  	err := ioutil.WriteFile(path.Join(myriakPath, "metadata.yaml"), myriakMeta, 0644)
   261  	c.Assert(err, jc.ErrorIsNil)
   262  
   263  	// Test with local repo and no explicit revsion.
   264  	err = runUpgradeCharm(c, "riak", "--switch=local:myriak")
   265  	c.Assert(err, jc.ErrorIsNil)
   266  	curl := s.assertUpgraded(c, 7, false)
   267  	c.Assert(curl.String(), gc.Equals, "local:trusty/myriak-7")
   268  	s.assertLocalRevision(c, 7, myriakPath)
   269  
   270  	// Now try the same with explicit revision - should fail.
   271  	err = runUpgradeCharm(c, "riak", "--switch=local:myriak-7")
   272  	c.Assert(err, gc.ErrorMatches, `already running specified charm "local:trusty/myriak-7"`)
   273  
   274  	// Change the revision to 42 and upgrade to it with explicit revision.
   275  	err = ioutil.WriteFile(path.Join(myriakPath, "revision"), []byte("42"), 0644)
   276  	c.Assert(err, jc.ErrorIsNil)
   277  	err = runUpgradeCharm(c, "riak", "--switch=local:myriak-42")
   278  	c.Assert(err, jc.ErrorIsNil)
   279  	curl = s.assertUpgraded(c, 42, false)
   280  	c.Assert(curl.String(), gc.Equals, "local:trusty/myriak-42")
   281  	s.assertLocalRevision(c, 42, myriakPath)
   282  }
   283  
   284  type UpgradeCharmCharmStoreSuite struct {
   285  	charmStoreSuite
   286  }
   287  
   288  var _ = gc.Suite(&UpgradeCharmCharmStoreSuite{})
   289  
   290  var upgradeCharmAuthorizationTests = []struct {
   291  	about        string
   292  	uploadURL    string
   293  	switchURL    string
   294  	readPermUser string
   295  	expectError  string
   296  }{{
   297  	about:     "public charm, success",
   298  	uploadURL: "cs:~bob/trusty/wordpress1-10",
   299  	switchURL: "cs:~bob/trusty/wordpress1",
   300  }, {
   301  	about:     "public charm, fully resolved, success",
   302  	uploadURL: "cs:~bob/trusty/wordpress2-10",
   303  	switchURL: "cs:~bob/trusty/wordpress2-10",
   304  }, {
   305  	about:        "non-public charm, success",
   306  	uploadURL:    "cs:~bob/trusty/wordpress3-10",
   307  	switchURL:    "cs:~bob/trusty/wordpress3",
   308  	readPermUser: clientUserName,
   309  }, {
   310  	about:        "non-public charm, fully resolved, success",
   311  	uploadURL:    "cs:~bob/trusty/wordpress4-10",
   312  	switchURL:    "cs:~bob/trusty/wordpress4-10",
   313  	readPermUser: clientUserName,
   314  }, {
   315  	about:        "non-public charm, access denied",
   316  	uploadURL:    "cs:~bob/trusty/wordpress5-10",
   317  	switchURL:    "cs:~bob/trusty/wordpress5",
   318  	readPermUser: "bob",
   319  	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"`,
   320  }, {
   321  	about:        "non-public charm, fully resolved, access denied",
   322  	uploadURL:    "cs:~bob/trusty/wordpress6-47",
   323  	switchURL:    "cs:~bob/trusty/wordpress6-47",
   324  	readPermUser: "bob",
   325  	expectError:  `cannot retrieve charm "cs:~bob/trusty/wordpress6-47": cannot get archive: unauthorized: access denied for user "client-username"`,
   326  }}
   327  
   328  func (s *UpgradeCharmCharmStoreSuite) TestUpgradeCharmAuthorization(c *gc.C) {
   329  	testcharms.UploadCharm(c, s.client, "cs:~other/trusty/wordpress-0", "wordpress")
   330  	err := runDeploy(c, "cs:~other/trusty/wordpress-0")
   331  	c.Assert(err, jc.ErrorIsNil)
   332  	for i, test := range upgradeCharmAuthorizationTests {
   333  		c.Logf("test %d: %s", i, test.about)
   334  		url, _ := testcharms.UploadCharm(c, s.client, test.uploadURL, "wordpress")
   335  		if test.readPermUser != "" {
   336  			s.changeReadPerm(c, url, test.readPermUser)
   337  		}
   338  		err := runUpgradeCharm(c, "wordpress", "--switch", test.switchURL)
   339  		if test.expectError != "" {
   340  			c.Assert(err, gc.ErrorMatches, test.expectError)
   341  			continue
   342  		}
   343  		c.Assert(err, jc.ErrorIsNil)
   344  	}
   345  }