github.com/mattyw/juju@v0.0.0-20140610034352-732aecd63861/cmd/juju/upgradejuju_test.go (about) 1 // Copyright 2012, 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package main 5 6 import ( 7 "archive/tar" 8 "bytes" 9 "compress/gzip" 10 "io" 11 "io/ioutil" 12 "strings" 13 14 jc "github.com/juju/testing/checkers" 15 gc "launchpad.net/gocheck" 16 17 "github.com/juju/juju/cmd/envcmd" 18 "github.com/juju/juju/environs/config" 19 "github.com/juju/juju/environs/filestorage" 20 "github.com/juju/juju/environs/storage" 21 "github.com/juju/juju/environs/sync" 22 envtesting "github.com/juju/juju/environs/testing" 23 envtools "github.com/juju/juju/environs/tools" 24 toolstesting "github.com/juju/juju/environs/tools/testing" 25 "github.com/juju/juju/juju/testing" 26 coretesting "github.com/juju/juju/testing" 27 "github.com/juju/juju/version" 28 ) 29 30 type UpgradeJujuSuite struct { 31 testing.JujuConnSuite 32 toolsDir string 33 } 34 35 var _ = gc.Suite(&UpgradeJujuSuite{}) 36 37 var upgradeJujuTests = []struct { 38 about string 39 tools []string 40 currentVersion string 41 agentVersion string 42 43 args []string 44 expectInitErr string 45 expectErr string 46 expectVersion string 47 expectUploaded []string 48 }{{ 49 about: "unwanted extra argument", 50 currentVersion: "1.0.0-quantal-amd64", 51 args: []string{"foo"}, 52 expectInitErr: "unrecognized args:.*", 53 }, { 54 about: "removed arg --dev specified", 55 currentVersion: "1.0.0-quantal-amd64", 56 args: []string{"--dev"}, 57 expectInitErr: "flag provided but not defined: --dev", 58 }, { 59 about: "invalid --version value", 60 currentVersion: "1.0.0-quantal-amd64", 61 args: []string{"--version", "invalid-version"}, 62 expectInitErr: "invalid version .*", 63 }, { 64 about: "just major version, no minor specified", 65 currentVersion: "4.2.0-quantal-amd64", 66 args: []string{"--version", "4"}, 67 expectInitErr: `invalid version "4"`, 68 }, { 69 about: "major version upgrade to incompatible version", 70 currentVersion: "2.0.0-quantal-amd64", 71 args: []string{"--version", "5.2.0"}, 72 expectInitErr: "cannot upgrade to version incompatible with CLI", 73 }, { 74 about: "major version downgrade to incompatible version", 75 currentVersion: "4.2.0-quantal-amd64", 76 args: []string{"--version", "3.2.0"}, 77 expectInitErr: "cannot upgrade to version incompatible with CLI", 78 }, { 79 about: "invalid --series", 80 currentVersion: "4.2.0-quantal-amd64", 81 args: []string{"--series", "precise&quantal"}, 82 expectInitErr: `invalid value "precise&quantal" for flag --series: .*`, 83 }, { 84 about: "--series without --upload-tools", 85 currentVersion: "4.2.0-quantal-amd64", 86 args: []string{"--series", "precise,quantal"}, 87 expectInitErr: "--series requires --upload-tools", 88 }, { 89 about: "--upload-tools with inappropriate version 1", 90 currentVersion: "4.2.0-quantal-amd64", 91 args: []string{"--upload-tools", "--version", "3.1.0"}, 92 expectInitErr: "cannot upgrade to version incompatible with CLI", 93 }, { 94 about: "--upload-tools with inappropriate version 2", 95 currentVersion: "3.2.7-quantal-amd64", 96 args: []string{"--upload-tools", "--version", "3.2.8.4"}, 97 expectInitErr: "cannot specify build number when uploading tools", 98 }, { 99 about: "latest supported stable release", 100 tools: []string{"2.2.0-quantal-amd64", "2.2.2-quantal-i386", "2.2.3-quantal-amd64"}, 101 currentVersion: "2.0.0-quantal-amd64", 102 agentVersion: "2.0.0", 103 expectVersion: "2.2.3", 104 }, { 105 about: "latest current release", 106 tools: []string{"2.0.5-quantal-amd64", "2.0.1-quantal-i386", "2.3.3-quantal-amd64"}, 107 currentVersion: "2.0.0-quantal-amd64", 108 agentVersion: "2.0.0", 109 expectVersion: "2.0.5", 110 }, { 111 about: "latest current release matching CLI, major version", 112 tools: []string{"3.2.0-quantal-amd64"}, 113 currentVersion: "3.2.0-quantal-amd64", 114 agentVersion: "2.8.2", 115 expectVersion: "3.2.0", 116 }, { 117 about: "latest current release matching CLI, major version, no matching major tools", 118 tools: []string{"2.8.2-quantal-amd64"}, 119 currentVersion: "3.2.0-quantal-amd64", 120 agentVersion: "2.8.2", 121 expectErr: "no matching tools available", 122 }, { 123 about: "latest current release matching CLI, major version, no matching tools", 124 tools: []string{"3.3.0-quantal-amd64"}, 125 currentVersion: "3.2.0-quantal-amd64", 126 agentVersion: "2.8.2", 127 expectErr: "no compatible tools available", 128 }, { 129 about: "no next supported available", 130 tools: []string{"2.1.0-quantal-amd64", "2.1.5-quantal-i386", "2.3.3-quantal-amd64"}, 131 currentVersion: "2.0.0-quantal-amd64", 132 agentVersion: "2.0.0", 133 expectErr: "no more recent supported versions available", 134 }, { 135 about: "latest supported stable, when client is dev", 136 tools: []string{"2.1-dev1-quantal-amd64", "2.2.0-quantal-amd64", "2.3-dev0-quantal-amd64", "3.0.1-quantal-amd64"}, 137 currentVersion: "2.1-dev0-quantal-amd64", 138 agentVersion: "2.0.0", 139 expectVersion: "2.2.0", 140 }, { 141 about: "latest current, when agent is dev", 142 tools: []string{"2.1-dev1-quantal-amd64", "2.2.0-quantal-amd64", "2.3-dev0-quantal-amd64", "3.0.1-quantal-amd64"}, 143 currentVersion: "2.0.0-quantal-amd64", 144 agentVersion: "2.1-dev0", 145 expectVersion: "2.2.0", 146 }, { 147 about: "specified version", 148 tools: []string{"2.3-dev0-quantal-amd64"}, 149 currentVersion: "2.0.0-quantal-amd64", 150 agentVersion: "2.0.0", 151 args: []string{"--version", "2.3-dev0"}, 152 expectVersion: "2.3-dev0", 153 }, { 154 about: "specified major version", 155 tools: []string{"3.2.0-quantal-amd64"}, 156 currentVersion: "3.2.0-quantal-amd64", 157 agentVersion: "2.8.2", 158 args: []string{"--version", "3.2.0"}, 159 expectVersion: "3.2.0", 160 }, { 161 about: "specified version missing, but already set", 162 currentVersion: "3.0.0-quantal-amd64", 163 agentVersion: "3.0.0", 164 args: []string{"--version", "3.0.0"}, 165 expectVersion: "3.0.0", 166 }, { 167 about: "specified version, no tools", 168 currentVersion: "3.0.0-quantal-amd64", 169 agentVersion: "3.0.0", 170 args: []string{"--version", "3.2.0"}, 171 expectErr: "no tools available", 172 }, { 173 about: "specified version, no matching major version", 174 tools: []string{"4.2.0-quantal-amd64"}, 175 currentVersion: "3.0.0-quantal-amd64", 176 agentVersion: "3.0.0", 177 args: []string{"--version", "3.2.0"}, 178 expectErr: "no matching tools available", 179 }, { 180 about: "specified version, no matching minor version", 181 tools: []string{"3.4.0-quantal-amd64"}, 182 currentVersion: "3.0.0-quantal-amd64", 183 agentVersion: "3.0.0", 184 args: []string{"--version", "3.2.0"}, 185 expectErr: "no matching tools available", 186 }, { 187 about: "specified version, no matching patch version", 188 tools: []string{"3.2.5-quantal-amd64"}, 189 currentVersion: "3.0.0-quantal-amd64", 190 agentVersion: "3.0.0", 191 args: []string{"--version", "3.2.0"}, 192 expectErr: "no matching tools available", 193 }, { 194 about: "specified version, no matching build version", 195 tools: []string{"3.2.0.2-quantal-amd64"}, 196 currentVersion: "3.0.0-quantal-amd64", 197 agentVersion: "3.0.0", 198 args: []string{"--version", "3.2.0"}, 199 expectErr: "no matching tools available", 200 }, { 201 about: "major version downgrade to incompatible version", 202 tools: []string{"3.2.0-quantal-amd64"}, 203 currentVersion: "3.2.0-quantal-amd64", 204 agentVersion: "4.2.0", 205 args: []string{"--version", "3.2.0"}, 206 expectErr: "cannot change version from 4.2.0 to 3.2.0", 207 }, { 208 about: "minor version downgrade to incompatible version", 209 tools: []string{"3.2.0-quantal-amd64"}, 210 currentVersion: "3.2.0-quantal-amd64", 211 agentVersion: "3.3-dev0", 212 args: []string{"--version", "3.2.0"}, 213 expectErr: "cannot change version from 3.3-dev0 to 3.2.0", 214 }, { 215 about: "nothing available", 216 currentVersion: "2.0.0-quantal-amd64", 217 agentVersion: "2.0.0", 218 expectVersion: "2.0.0", 219 }, { 220 about: "nothing available 2", 221 currentVersion: "2.0.0-quantal-amd64", 222 tools: []string{"3.2.0-quantal-amd64"}, 223 agentVersion: "2.0.0", 224 expectVersion: "2.0.0", 225 }, { 226 about: "upload with default series", 227 currentVersion: "2.2.0-quantal-amd64", 228 agentVersion: "2.0.0", 229 args: []string{"--upload-tools"}, 230 expectVersion: "2.2.0.1", 231 expectUploaded: []string{"2.2.0.1-quantal-amd64", "2.2.0.1-%LTS%-amd64", "2.2.0.1-raring-amd64"}, 232 }, { 233 about: "upload with explicit version", 234 currentVersion: "2.2.0-quantal-amd64", 235 agentVersion: "2.0.0", 236 args: []string{"--upload-tools", "--version", "2.7.3"}, 237 expectVersion: "2.7.3.1", 238 expectUploaded: []string{"2.7.3.1-quantal-amd64", "2.7.3.1-%LTS%-amd64", "2.7.3.1-raring-amd64"}, 239 }, { 240 about: "upload with explicit series", 241 currentVersion: "2.2.0-quantal-amd64", 242 agentVersion: "2.0.0", 243 args: []string{"--upload-tools", "--series", "raring"}, 244 expectVersion: "2.2.0.1", 245 expectUploaded: []string{"2.2.0.1-quantal-amd64", "2.2.0.1-raring-amd64"}, 246 }, { 247 about: "upload dev version, currently on release version", 248 currentVersion: "2.1.0-quantal-amd64", 249 agentVersion: "2.0.0", 250 args: []string{"--upload-tools"}, 251 expectVersion: "2.1.0.1", 252 expectUploaded: []string{"2.1.0.1-quantal-amd64", "2.1.0.1-%LTS%-amd64", "2.1.0.1-raring-amd64"}, 253 }, { 254 about: "upload bumps version when necessary", 255 tools: []string{"2.4.6-quantal-amd64", "2.4.8-quantal-amd64"}, 256 currentVersion: "2.4.6-quantal-amd64", 257 agentVersion: "2.4.0", 258 args: []string{"--upload-tools"}, 259 expectVersion: "2.4.6.1", 260 expectUploaded: []string{"2.4.6.1-quantal-amd64", "2.4.6.1-%LTS%-amd64", "2.4.6.1-raring-amd64"}, 261 }, { 262 about: "upload re-bumps version when necessary", 263 tools: []string{"2.4.6-quantal-amd64", "2.4.6.2-saucy-i386", "2.4.8-quantal-amd64"}, 264 currentVersion: "2.4.6-quantal-amd64", 265 agentVersion: "2.4.6.2", 266 args: []string{"--upload-tools"}, 267 expectVersion: "2.4.6.3", 268 expectUploaded: []string{"2.4.6.3-quantal-amd64", "2.4.6.3-%LTS%-amd64", "2.4.6.3-raring-amd64"}, 269 }, { 270 about: "upload with explicit version bumps when necessary", 271 currentVersion: "2.2.0-quantal-amd64", 272 tools: []string{"2.7.3.1-quantal-amd64"}, 273 agentVersion: "2.0.0", 274 args: []string{"--upload-tools", "--version", "2.7.3"}, 275 expectVersion: "2.7.3.2", 276 expectUploaded: []string{"2.7.3.2-quantal-amd64", "2.7.3.2-%LTS%-amd64", "2.7.3.2-raring-amd64"}, 277 }} 278 279 func (s *UpgradeJujuSuite) TestUpgradeJuju(c *gc.C) { 280 oldVersion := version.Current 281 defer func() { 282 version.Current = oldVersion 283 }() 284 285 for i, test := range upgradeJujuTests { 286 c.Logf("\ntest %d: %s", i, test.about) 287 s.Reset(c) 288 289 // Set up apparent CLI version and initialize the command. 290 version.Current = version.MustParseBinary(test.currentVersion) 291 com := &UpgradeJujuCommand{} 292 if err := coretesting.InitCommand(envcmd.Wrap(com), test.args); err != nil { 293 if test.expectInitErr != "" { 294 c.Check(err, gc.ErrorMatches, test.expectInitErr) 295 } else { 296 c.Check(err, gc.IsNil) 297 } 298 continue 299 } 300 301 // Set up state and environ, and run the command. 302 toolsDir := c.MkDir() 303 updateAttrs := map[string]interface{}{ 304 "agent-version": test.agentVersion, 305 "tools-metadata-url": "file://" + toolsDir, 306 } 307 err := s.State.UpdateEnvironConfig(updateAttrs, nil, nil) 308 c.Assert(err, gc.IsNil) 309 versions := make([]version.Binary, len(test.tools)) 310 for i, v := range test.tools { 311 versions[i] = version.MustParseBinary(v) 312 } 313 if len(versions) > 0 { 314 envtesting.MustUploadFakeToolsVersions(s.Conn.Environ.Storage(), versions...) 315 stor, err := filestorage.NewFileStorageWriter(toolsDir) 316 c.Assert(err, gc.IsNil) 317 envtesting.MustUploadFakeToolsVersions(stor, versions...) 318 } 319 320 err = com.Run(coretesting.Context(c)) 321 if test.expectErr != "" { 322 c.Check(err, gc.ErrorMatches, test.expectErr) 323 continue 324 } else if !c.Check(err, gc.IsNil) { 325 continue 326 } 327 328 // Check expected changes to environ/state. 329 cfg, err := s.State.EnvironConfig() 330 c.Check(err, gc.IsNil) 331 agentVersion, ok := cfg.AgentVersion() 332 c.Check(ok, gc.Equals, true) 333 c.Check(agentVersion, gc.Equals, version.MustParse(test.expectVersion)) 334 335 for _, uploaded := range test.expectUploaded { 336 // Substitute latest LTS for placeholder in expected series for uploaded tools 337 uploaded = strings.Replace(uploaded, "%LTS%", config.LatestLtsSeries(), 1) 338 339 vers := version.MustParseBinary(uploaded) 340 r, err := storage.Get(s.Conn.Environ.Storage(), envtools.StorageName(vers)) 341 if !c.Check(err, gc.IsNil) { 342 continue 343 } 344 data, err := ioutil.ReadAll(r) 345 r.Close() 346 c.Check(err, gc.IsNil) 347 expectContent := version.Current 348 expectContent.Number = agentVersion 349 checkToolsContent(c, data, "jujud contents "+expectContent.String()) 350 } 351 } 352 } 353 354 func checkToolsContent(c *gc.C, data []byte, uploaded string) { 355 zr, err := gzip.NewReader(bytes.NewReader(data)) 356 c.Check(err, gc.IsNil) 357 defer zr.Close() 358 tr := tar.NewReader(zr) 359 found := false 360 for { 361 hdr, err := tr.Next() 362 if err == io.EOF { 363 break 364 } 365 c.Check(err, gc.IsNil) 366 if strings.ContainsAny(hdr.Name, "/\\") { 367 c.Fail() 368 } 369 if hdr.Typeflag != tar.TypeReg { 370 c.Fail() 371 } 372 content, err := ioutil.ReadAll(tr) 373 c.Check(err, gc.IsNil) 374 c.Check(string(content), gc.Equals, uploaded) 375 found = true 376 } 377 c.Check(found, jc.IsTrue) 378 } 379 380 // JujuConnSuite very helpfully uploads some default 381 // tools to the environment's storage. We don't want 382 // 'em there; but we do want a consistent default-series 383 // in the environment state. 384 func (s *UpgradeJujuSuite) Reset(c *gc.C) { 385 s.JujuConnSuite.Reset(c) 386 envtesting.RemoveTools(c, s.Conn.Environ.Storage()) 387 updateAttrs := map[string]interface{}{ 388 "default-series": "raring", 389 "agent-version": "1.2.3", 390 } 391 err := s.State.UpdateEnvironConfig(updateAttrs, nil, nil) 392 c.Assert(err, gc.IsNil) 393 s.PatchValue(&sync.BuildToolsTarball, toolstesting.GetMockBuildTools(c)) 394 } 395 396 func (s *UpgradeJujuSuite) TestUpgradeJujuWithRealUpload(c *gc.C) { 397 s.Reset(c) 398 _, err := coretesting.RunCommand(c, &UpgradeJujuCommand{}, "--upload-tools") 399 c.Assert(err, gc.IsNil) 400 vers := version.Current 401 vers.Build = 1 402 tools, err := envtools.FindInstanceTools(s.Conn.Environ, vers.Number, vers.Series, &vers.Arch) 403 c.Assert(err, gc.IsNil) 404 c.Assert(len(tools), gc.Equals, 1) 405 }