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 }