github.com/altoros/juju-vmware@v0.0.0-20150312064031-f19ae857ccca/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 jujucmd "github.com/juju/cmd" 15 jc "github.com/juju/testing/checkers" 16 gc "gopkg.in/check.v1" 17 18 "github.com/juju/juju/apiserver/params" 19 "github.com/juju/juju/cmd/envcmd" 20 "github.com/juju/juju/environs/config" 21 "github.com/juju/juju/environs/filestorage" 22 "github.com/juju/juju/environs/sync" 23 envtesting "github.com/juju/juju/environs/testing" 24 "github.com/juju/juju/environs/tools" 25 toolstesting "github.com/juju/juju/environs/tools/testing" 26 "github.com/juju/juju/juju/testing" 27 "github.com/juju/juju/network" 28 "github.com/juju/juju/state" 29 coretesting "github.com/juju/juju/testing" 30 coretools "github.com/juju/juju/tools" 31 "github.com/juju/juju/version" 32 ) 33 34 type UpgradeJujuSuite struct { 35 testing.JujuConnSuite 36 toolsDir string 37 } 38 39 var _ = gc.Suite(&UpgradeJujuSuite{}) 40 41 var upgradeJujuTests = []struct { 42 about string 43 tools []string 44 currentVersion string 45 agentVersion string 46 47 args []string 48 expectInitErr string 49 expectErr string 50 expectVersion string 51 expectUploaded []string 52 }{{ 53 about: "unwanted extra argument", 54 currentVersion: "1.0.0-quantal-amd64", 55 args: []string{"foo"}, 56 expectInitErr: "unrecognized args:.*", 57 }, { 58 about: "removed arg --dev specified", 59 currentVersion: "1.0.0-quantal-amd64", 60 args: []string{"--dev"}, 61 expectInitErr: "flag provided but not defined: --dev", 62 }, { 63 about: "invalid --version value", 64 currentVersion: "1.0.0-quantal-amd64", 65 args: []string{"--version", "invalid-version"}, 66 expectInitErr: "invalid version .*", 67 }, { 68 about: "just major version, no minor specified", 69 currentVersion: "4.2.0-quantal-amd64", 70 args: []string{"--version", "4"}, 71 expectInitErr: `invalid version "4"`, 72 }, { 73 about: "major version upgrade to incompatible version", 74 currentVersion: "2.0.0-quantal-amd64", 75 args: []string{"--version", "5.2.0"}, 76 expectInitErr: "cannot upgrade to version incompatible with CLI", 77 }, { 78 about: "major version downgrade to incompatible version", 79 currentVersion: "4.2.0-quantal-amd64", 80 args: []string{"--version", "3.2.0"}, 81 expectInitErr: "cannot upgrade to version incompatible with CLI", 82 }, { 83 about: "invalid --series", 84 currentVersion: "4.2.0-quantal-amd64", 85 args: []string{"--series", "precise&quantal"}, 86 expectInitErr: `invalid value "precise&quantal" for flag --series: .*`, 87 }, { 88 about: "--series without --upload-tools", 89 currentVersion: "4.2.0-quantal-amd64", 90 args: []string{"--series", "precise,quantal"}, 91 expectInitErr: "--series requires --upload-tools", 92 }, { 93 about: "--upload-tools with inappropriate version 1", 94 currentVersion: "4.2.0-quantal-amd64", 95 args: []string{"--upload-tools", "--version", "3.1.0"}, 96 expectInitErr: "cannot upgrade to version incompatible with CLI", 97 }, { 98 about: "--upload-tools with inappropriate version 2", 99 currentVersion: "3.2.7-quantal-amd64", 100 args: []string{"--upload-tools", "--version", "3.2.8.4"}, 101 expectInitErr: "cannot specify build number when uploading tools", 102 }, { 103 about: "latest supported stable release", 104 tools: []string{"2.1.0-quantal-amd64", "2.1.2-quantal-i386", "2.1.3-quantal-amd64", "2.1-dev1-quantal-amd64"}, 105 currentVersion: "2.0.0-quantal-amd64", 106 agentVersion: "2.0.0", 107 expectVersion: "2.1.3", 108 }, { 109 about: "latest current release", 110 tools: []string{"2.0.5-quantal-amd64", "2.0.1-quantal-i386", "2.3.3-quantal-amd64"}, 111 currentVersion: "2.0.0-quantal-amd64", 112 agentVersion: "2.0.0", 113 expectVersion: "2.0.5", 114 }, { 115 about: "latest current release matching CLI, major version", 116 tools: []string{"3.2.0-quantal-amd64"}, 117 currentVersion: "3.2.0-quantal-amd64", 118 agentVersion: "2.8.2", 119 expectVersion: "3.2.0", 120 }, { 121 about: "latest current release matching CLI, major version, no matching major tools", 122 tools: []string{"2.8.2-quantal-amd64"}, 123 currentVersion: "3.2.0-quantal-amd64", 124 agentVersion: "2.8.2", 125 expectErr: "no matching tools available", 126 }, { 127 about: "latest current release matching CLI, major version, no matching tools", 128 tools: []string{"3.3.0-quantal-amd64"}, 129 currentVersion: "3.2.0-quantal-amd64", 130 agentVersion: "2.8.2", 131 expectErr: "no compatible tools available", 132 }, { 133 about: "no next supported available", 134 tools: []string{"2.2.0-quantal-amd64", "2.2.5-quantal-i386", "2.3.3-quantal-amd64", "2.1-dev1-quantal-amd64"}, 135 currentVersion: "2.0.0-quantal-amd64", 136 agentVersion: "2.0.0", 137 expectErr: "no more recent supported versions available", 138 }, { 139 about: "latest supported stable, when client is dev", 140 tools: []string{"2.1-dev1-quantal-amd64", "2.1.0-quantal-amd64", "2.3-dev0-quantal-amd64", "3.0.1-quantal-amd64"}, 141 currentVersion: "2.1-dev0-quantal-amd64", 142 agentVersion: "2.0.0", 143 expectVersion: "2.1.0", 144 }, { 145 about: "latest current, when agent is dev", 146 tools: []string{"2.1-dev1-quantal-amd64", "2.2.0-quantal-amd64", "2.3-dev0-quantal-amd64", "3.0.1-quantal-amd64"}, 147 currentVersion: "2.0.0-quantal-amd64", 148 agentVersion: "2.1-dev0", 149 expectVersion: "2.2.0", 150 }, { 151 about: "specified version", 152 tools: []string{"2.3-dev0-quantal-amd64"}, 153 currentVersion: "2.0.0-quantal-amd64", 154 agentVersion: "2.0.0", 155 args: []string{"--version", "2.3-dev0"}, 156 expectVersion: "2.3-dev0", 157 }, { 158 about: "specified major version", 159 tools: []string{"3.2.0-quantal-amd64"}, 160 currentVersion: "3.2.0-quantal-amd64", 161 agentVersion: "2.8.2", 162 args: []string{"--version", "3.2.0"}, 163 expectVersion: "3.2.0", 164 }, { 165 about: "specified version missing, but already set", 166 currentVersion: "3.0.0-quantal-amd64", 167 agentVersion: "3.0.0", 168 args: []string{"--version", "3.0.0"}, 169 expectVersion: "3.0.0", 170 }, { 171 about: "specified version, no tools", 172 currentVersion: "3.0.0-quantal-amd64", 173 agentVersion: "3.0.0", 174 args: []string{"--version", "3.2.0"}, 175 expectErr: "no tools available", 176 }, { 177 about: "specified version, no matching major version", 178 tools: []string{"4.2.0-quantal-amd64"}, 179 currentVersion: "3.0.0-quantal-amd64", 180 agentVersion: "3.0.0", 181 args: []string{"--version", "3.2.0"}, 182 expectErr: "no matching tools available", 183 }, { 184 about: "specified version, no matching minor version", 185 tools: []string{"3.4.0-quantal-amd64"}, 186 currentVersion: "3.0.0-quantal-amd64", 187 agentVersion: "3.0.0", 188 args: []string{"--version", "3.2.0"}, 189 expectErr: "no matching tools available", 190 }, { 191 about: "specified version, no matching patch version", 192 tools: []string{"3.2.5-quantal-amd64"}, 193 currentVersion: "3.0.0-quantal-amd64", 194 agentVersion: "3.0.0", 195 args: []string{"--version", "3.2.0"}, 196 expectErr: "no matching tools available", 197 }, { 198 about: "specified version, no matching build version", 199 tools: []string{"3.2.0.2-quantal-amd64"}, 200 currentVersion: "3.0.0-quantal-amd64", 201 agentVersion: "3.0.0", 202 args: []string{"--version", "3.2.0"}, 203 expectErr: "no matching tools available", 204 }, { 205 about: "major version downgrade to incompatible version", 206 tools: []string{"3.2.0-quantal-amd64"}, 207 currentVersion: "3.2.0-quantal-amd64", 208 agentVersion: "4.2.0", 209 args: []string{"--version", "3.2.0"}, 210 expectErr: "cannot change version from 4.2.0 to 3.2.0", 211 }, { 212 about: "minor version downgrade to incompatible version", 213 tools: []string{"3.2.0-quantal-amd64"}, 214 currentVersion: "3.2.0-quantal-amd64", 215 agentVersion: "3.3-dev0", 216 args: []string{"--version", "3.2.0"}, 217 expectErr: "cannot change version from 3.3-dev0 to 3.2.0", 218 }, { 219 about: "nothing available", 220 currentVersion: "2.0.0-quantal-amd64", 221 agentVersion: "2.0.0", 222 expectVersion: "2.0.0", 223 }, { 224 about: "nothing available 2", 225 currentVersion: "2.0.0-quantal-amd64", 226 tools: []string{"3.2.0-quantal-amd64"}, 227 agentVersion: "2.0.0", 228 expectVersion: "2.0.0", 229 }, { 230 about: "upload with default series", 231 currentVersion: "2.2.0-quantal-amd64", 232 agentVersion: "2.0.0", 233 args: []string{"--upload-tools"}, 234 expectVersion: "2.2.0.1", 235 expectUploaded: []string{"2.2.0.1-quantal-amd64", "2.2.0.1-%LTS%-amd64", "2.2.0.1-raring-amd64"}, 236 }, { 237 about: "upload with explicit version", 238 currentVersion: "2.2.0-quantal-amd64", 239 agentVersion: "2.0.0", 240 args: []string{"--upload-tools", "--version", "2.7.3"}, 241 expectVersion: "2.7.3.1", 242 expectUploaded: []string{"2.7.3.1-quantal-amd64", "2.7.3.1-%LTS%-amd64", "2.7.3.1-raring-amd64"}, 243 }, { 244 about: "upload with explicit series", 245 currentVersion: "2.2.0-quantal-amd64", 246 agentVersion: "2.0.0", 247 args: []string{"--upload-tools", "--series", "raring"}, 248 expectVersion: "2.2.0.1", 249 expectUploaded: []string{"2.2.0.1-quantal-amd64", "2.2.0.1-raring-amd64"}, 250 }, { 251 about: "upload dev version, currently on release version", 252 currentVersion: "2.1.0-quantal-amd64", 253 agentVersion: "2.0.0", 254 args: []string{"--upload-tools"}, 255 expectVersion: "2.1.0.1", 256 expectUploaded: []string{"2.1.0.1-quantal-amd64", "2.1.0.1-%LTS%-amd64", "2.1.0.1-raring-amd64"}, 257 }, { 258 about: "upload bumps version when necessary", 259 tools: []string{"2.4.6-quantal-amd64", "2.4.8-quantal-amd64"}, 260 currentVersion: "2.4.6-quantal-amd64", 261 agentVersion: "2.4.0", 262 args: []string{"--upload-tools"}, 263 expectVersion: "2.4.6.1", 264 expectUploaded: []string{"2.4.6.1-quantal-amd64", "2.4.6.1-%LTS%-amd64", "2.4.6.1-raring-amd64"}, 265 }, { 266 about: "upload re-bumps version when necessary", 267 tools: []string{"2.4.6-quantal-amd64", "2.4.6.2-saucy-i386", "2.4.8-quantal-amd64"}, 268 currentVersion: "2.4.6-quantal-amd64", 269 agentVersion: "2.4.6.2", 270 args: []string{"--upload-tools"}, 271 expectVersion: "2.4.6.3", 272 expectUploaded: []string{"2.4.6.3-quantal-amd64", "2.4.6.3-%LTS%-amd64", "2.4.6.3-raring-amd64"}, 273 }, { 274 about: "upload with explicit version bumps when necessary", 275 currentVersion: "2.2.0-quantal-amd64", 276 tools: []string{"2.7.3.1-quantal-amd64"}, 277 agentVersion: "2.0.0", 278 args: []string{"--upload-tools", "--version", "2.7.3"}, 279 expectVersion: "2.7.3.2", 280 expectUploaded: []string{"2.7.3.2-quantal-amd64", "2.7.3.2-%LTS%-amd64", "2.7.3.2-raring-amd64"}, 281 }} 282 283 func (s *UpgradeJujuSuite) TestUpgradeJuju(c *gc.C) { 284 oldVersion := version.Current 285 defer func() { 286 version.Current = oldVersion 287 }() 288 289 for i, test := range upgradeJujuTests { 290 c.Logf("\ntest %d: %s", i, test.about) 291 s.Reset(c) 292 tools.DefaultBaseURL = "" 293 294 // Set up apparent CLI version and initialize the command. 295 version.Current = version.MustParseBinary(test.currentVersion) 296 com := &UpgradeJujuCommand{} 297 if err := coretesting.InitCommand(envcmd.Wrap(com), test.args); err != nil { 298 if test.expectInitErr != "" { 299 c.Check(err, gc.ErrorMatches, test.expectInitErr) 300 } else { 301 c.Check(err, jc.ErrorIsNil) 302 } 303 continue 304 } 305 306 // Set up state and environ, and run the command. 307 toolsDir := c.MkDir() 308 updateAttrs := map[string]interface{}{ 309 "agent-version": test.agentVersion, 310 "agent-metadata-url": "file://" + toolsDir + "/tools", 311 } 312 err := s.State.UpdateEnvironConfig(updateAttrs, nil, nil) 313 c.Assert(err, jc.ErrorIsNil) 314 versions := make([]version.Binary, len(test.tools)) 315 for i, v := range test.tools { 316 versions[i] = version.MustParseBinary(v) 317 } 318 if len(versions) > 0 { 319 stor, err := filestorage.NewFileStorageWriter(toolsDir) 320 c.Assert(err, jc.ErrorIsNil) 321 envtesting.MustUploadFakeToolsVersions(stor, s.Environ.Config().AgentStream(), versions...) 322 } 323 324 err = com.Run(coretesting.Context(c)) 325 if test.expectErr != "" { 326 c.Check(err, gc.ErrorMatches, test.expectErr) 327 continue 328 } else if !c.Check(err, jc.ErrorIsNil) { 329 continue 330 } 331 332 // Check expected changes to environ/state. 333 cfg, err := s.State.EnvironConfig() 334 c.Check(err, jc.ErrorIsNil) 335 agentVersion, ok := cfg.AgentVersion() 336 c.Check(ok, jc.IsTrue) 337 c.Check(agentVersion, gc.Equals, version.MustParse(test.expectVersion)) 338 339 for _, uploaded := range test.expectUploaded { 340 // Substitute latest LTS for placeholder in expected series for uploaded tools 341 uploaded = strings.Replace(uploaded, "%LTS%", config.LatestLtsSeries(), 1) 342 vers := version.MustParseBinary(uploaded) 343 s.checkToolsUploaded(c, vers, agentVersion) 344 } 345 } 346 } 347 348 func (s *UpgradeJujuSuite) checkToolsUploaded(c *gc.C, vers version.Binary, agentVersion version.Number) { 349 storage, err := s.State.ToolsStorage() 350 c.Assert(err, jc.ErrorIsNil) 351 defer storage.Close() 352 _, r, err := storage.Tools(vers) 353 if !c.Check(err, jc.ErrorIsNil) { 354 return 355 } 356 data, err := ioutil.ReadAll(r) 357 r.Close() 358 c.Check(err, jc.ErrorIsNil) 359 expectContent := version.Current 360 expectContent.Number = agentVersion 361 checkToolsContent(c, data, "jujud contents "+expectContent.String()) 362 } 363 364 func checkToolsContent(c *gc.C, data []byte, uploaded string) { 365 zr, err := gzip.NewReader(bytes.NewReader(data)) 366 c.Check(err, jc.ErrorIsNil) 367 defer zr.Close() 368 tr := tar.NewReader(zr) 369 found := false 370 for { 371 hdr, err := tr.Next() 372 if err == io.EOF { 373 break 374 } 375 c.Check(err, jc.ErrorIsNil) 376 if strings.ContainsAny(hdr.Name, "/\\") { 377 c.Fail() 378 } 379 if hdr.Typeflag != tar.TypeReg { 380 c.Fail() 381 } 382 content, err := ioutil.ReadAll(tr) 383 c.Check(err, jc.ErrorIsNil) 384 c.Check(string(content), gc.Equals, uploaded) 385 found = true 386 } 387 c.Check(found, jc.IsTrue) 388 } 389 390 // JujuConnSuite very helpfully uploads some default 391 // tools to the environment's storage. We don't want 392 // 'em there; but we do want a consistent default-series 393 // in the environment state. 394 func (s *UpgradeJujuSuite) Reset(c *gc.C) { 395 s.JujuConnSuite.Reset(c) 396 envtesting.RemoveTools(c, s.DefaultToolsStorage, s.Environ.Config().AgentStream()) 397 updateAttrs := map[string]interface{}{ 398 "default-series": "raring", 399 "agent-version": "1.2.3", 400 } 401 err := s.State.UpdateEnvironConfig(updateAttrs, nil, nil) 402 c.Assert(err, jc.ErrorIsNil) 403 s.PatchValue(&sync.BuildToolsTarball, toolstesting.GetMockBuildTools(c)) 404 405 // Set API host ports so FindTools works. 406 hostPorts := [][]network.HostPort{{{ 407 Address: network.NewAddress("0.1.2.3", network.ScopeUnknown), 408 Port: 1234, 409 }}} 410 err = s.State.SetAPIHostPorts(hostPorts) 411 c.Assert(err, jc.ErrorIsNil) 412 } 413 414 func (s *UpgradeJujuSuite) TestUpgradeJujuWithRealUpload(c *gc.C) { 415 s.Reset(c) 416 cmd := envcmd.Wrap(&UpgradeJujuCommand{}) 417 _, err := coretesting.RunCommand(c, cmd, "--upload-tools") 418 c.Assert(err, jc.ErrorIsNil) 419 vers := version.Current 420 vers.Build = 1 421 s.checkToolsUploaded(c, vers, vers.Number) 422 //_, err = envtools.FindExactTools(s.Environ, vers.Number, vers.Series, vers.Arch) 423 //c.Assert(err, jc.ErrorIsNil) 424 } 425 426 func (s *UpgradeJujuSuite) TestBlockUpgradeJujuWithRealUpload(c *gc.C) { 427 s.Reset(c) 428 cmd := envcmd.Wrap(&UpgradeJujuCommand{}) 429 // Block operation 430 s.AssertConfigParameterUpdated(c, "block-all-changes", true) 431 _, err := coretesting.RunCommand(c, cmd, "--upload-tools") 432 c.Assert(err, gc.ErrorMatches, jujucmd.ErrSilent.Error()) 433 // msg is logged 434 stripped := strings.Replace(c.GetTestLog(), "\n", "", -1) 435 c.Check(stripped, gc.Matches, ".*To unblock changes.*") 436 } 437 438 type DryRunTest struct { 439 about string 440 cmdArgs []string 441 tools []string 442 currentVersion string 443 agentVersion string 444 expectedCmdOutput string 445 } 446 447 func (s *UpgradeJujuSuite) TestUpgradeDryRun(c *gc.C) { 448 tests := []DryRunTest{ 449 { 450 about: "dry run outputs and doesn't change anything when uploading tools", 451 cmdArgs: []string{"--upload-tools", "--dry-run"}, 452 tools: []string{"2.1.0-quantal-amd64", "2.1.2-quantal-i386", "2.1.3-quantal-amd64", "2.1-dev1-quantal-amd64", "2.2.3-quantal-amd64"}, 453 currentVersion: "2.0.0-quantal-amd64", 454 agentVersion: "2.0.0", 455 expectedCmdOutput: `available tools: 456 2.1-dev1-quantal-amd64 457 2.1.0-quantal-amd64 458 2.1.2-quantal-i386 459 2.1.3-quantal-amd64 460 2.2.3-quantal-amd64 461 best version: 462 2.1.3 463 upgrade to this version by running 464 juju upgrade-juju --version="2.1.3" 465 `, 466 }, 467 { 468 about: "dry run outputs and doesn't change anything", 469 cmdArgs: []string{"--dry-run"}, 470 tools: []string{"2.1.0-quantal-amd64", "2.1.2-quantal-i386", "2.1.3-quantal-amd64", "2.1-dev1-quantal-amd64", "2.2.3-quantal-amd64"}, 471 currentVersion: "2.0.0-quantal-amd64", 472 agentVersion: "2.0.0", 473 expectedCmdOutput: `available tools: 474 2.1-dev1-quantal-amd64 475 2.1.0-quantal-amd64 476 2.1.2-quantal-i386 477 2.1.3-quantal-amd64 478 2.2.3-quantal-amd64 479 best version: 480 2.1.3 481 upgrade to this version by running 482 juju upgrade-juju --version="2.1.3" 483 `, 484 }, 485 } 486 487 for i, test := range tests { 488 c.Logf("\ntest %d: %s", i, test.about) 489 s.Reset(c) 490 tools.DefaultBaseURL = "" 491 492 s.PatchValue(&version.Current, version.MustParseBinary(test.currentVersion)) 493 com := &UpgradeJujuCommand{} 494 err := coretesting.InitCommand(envcmd.Wrap(com), test.cmdArgs) 495 c.Assert(err, jc.ErrorIsNil) 496 toolsDir := c.MkDir() 497 updateAttrs := map[string]interface{}{ 498 "agent-version": test.agentVersion, 499 "agent-metadata-url": "file://" + toolsDir + "/tools", 500 } 501 502 err = s.State.UpdateEnvironConfig(updateAttrs, nil, nil) 503 c.Assert(err, jc.ErrorIsNil) 504 versions := make([]version.Binary, len(test.tools)) 505 for i, v := range test.tools { 506 versions[i] = version.MustParseBinary(v) 507 } 508 if len(versions) > 0 { 509 stor, err := filestorage.NewFileStorageWriter(toolsDir) 510 c.Assert(err, jc.ErrorIsNil) 511 envtesting.MustUploadFakeToolsVersions(stor, s.Environ.Config().AgentStream(), versions...) 512 } 513 514 ctx := coretesting.Context(c) 515 err = com.Run(ctx) 516 c.Assert(err, jc.ErrorIsNil) 517 518 // Check agent version doesn't change 519 cfg, err := s.State.EnvironConfig() 520 c.Assert(err, jc.ErrorIsNil) 521 agentVer, ok := cfg.AgentVersion() 522 c.Assert(ok, jc.IsTrue) 523 c.Assert(agentVer, gc.Equals, version.MustParse(test.agentVersion)) 524 output := coretesting.Stderr(ctx) 525 c.Assert(output, gc.Equals, test.expectedCmdOutput) 526 } 527 } 528 529 func (s *UpgradeJujuSuite) TestUpgradeInProgress(c *gc.C) { 530 fakeAPI := NewFakeUpgradeJujuAPI(c, s.State) 531 fakeAPI.setVersionErr = ¶ms.Error{ 532 Message: "a message from the server about the problem", 533 Code: params.CodeUpgradeInProgress, 534 } 535 fakeAPI.patch(s) 536 cmd := &UpgradeJujuCommand{} 537 err := coretesting.InitCommand(envcmd.Wrap(cmd), []string{}) 538 c.Assert(err, jc.ErrorIsNil) 539 540 err = cmd.Run(coretesting.Context(c)) 541 c.Assert(err, gc.ErrorMatches, "a message from the server about the problem\n"+ 542 "\n"+ 543 "Please wait for the upgrade to complete or if there was a problem with\n"+ 544 "the last upgrade that has been resolved, consider running the\n"+ 545 "upgrade-juju command with the --reset-previous-upgrade flag.", 546 ) 547 } 548 549 func (s *UpgradeJujuSuite) TestBlockUpgradeInProgress(c *gc.C) { 550 fakeAPI := NewFakeUpgradeJujuAPI(c, s.State) 551 fakeAPI.setVersionErr = ¶ms.Error{ 552 Code: params.CodeOperationBlocked, 553 Message: "The operation has been blocked.", 554 } 555 fakeAPI.patch(s) 556 cmd := &UpgradeJujuCommand{} 557 err := coretesting.InitCommand(envcmd.Wrap(cmd), []string{}) 558 c.Assert(err, jc.ErrorIsNil) 559 560 // Block operation 561 s.AssertConfigParameterUpdated(c, "block-all-changes", true) 562 err = cmd.Run(coretesting.Context(c)) 563 c.Assert(err, gc.ErrorMatches, jujucmd.ErrSilent.Error()) 564 // msg is logged 565 stripped := strings.Replace(c.GetTestLog(), "\n", "", -1) 566 c.Check(stripped, gc.Matches, ".*To unblock changes.*") 567 } 568 569 func (s *UpgradeJujuSuite) TestResetPreviousUpgrade(c *gc.C) { 570 fakeAPI := NewFakeUpgradeJujuAPI(c, s.State) 571 fakeAPI.patch(s) 572 573 ctx := coretesting.Context(c) 574 var stdin bytes.Buffer 575 ctx.Stdin = &stdin 576 577 run := func(answer string, expect bool, args ...string) { 578 stdin.Reset() 579 if answer != "" { 580 stdin.WriteString(answer) 581 } 582 583 fakeAPI.reset() 584 585 cmd := &UpgradeJujuCommand{} 586 err := coretesting.InitCommand(envcmd.Wrap(cmd), 587 append([]string{"--reset-previous-upgrade"}, args...)) 588 c.Assert(err, jc.ErrorIsNil) 589 err = cmd.Run(ctx) 590 if expect { 591 c.Assert(err, jc.ErrorIsNil) 592 } else { 593 c.Assert(err, gc.ErrorMatches, "previous upgrade not reset and no new upgrade triggered") 594 } 595 596 c.Assert(fakeAPI.abortCurrentUpgradeCalled, gc.Equals, expect) 597 expectedVersion := version.Number{} 598 if expect { 599 expectedVersion = fakeAPI.nextVersion.Number 600 } 601 c.Assert(fakeAPI.setVersionCalledWith, gc.Equals, expectedVersion) 602 } 603 604 const expectUpgrade = true 605 const expectNoUpgrade = false 606 607 // EOF on stdin - equivalent to answering no. 608 run("", expectNoUpgrade) 609 610 // -y on command line - no confirmation required 611 run("", expectUpgrade, "-y") 612 613 // --yes on command line - no confirmation required 614 run("", expectUpgrade, "--yes") 615 616 // various ways of saying "yes" to the prompt 617 for _, answer := range []string{"y", "Y", "yes", "YES"} { 618 run(answer, expectUpgrade) 619 } 620 621 // various ways of saying "no" to the prompt 622 for _, answer := range []string{"n", "N", "no", "foo"} { 623 run(answer, expectNoUpgrade) 624 } 625 } 626 627 func NewFakeUpgradeJujuAPI(c *gc.C, st *state.State) *fakeUpgradeJujuAPI { 628 nextVersion := version.Current 629 nextVersion.Minor++ 630 return &fakeUpgradeJujuAPI{ 631 c: c, 632 st: st, 633 nextVersion: nextVersion, 634 } 635 } 636 637 type fakeUpgradeJujuAPI struct { 638 c *gc.C 639 st *state.State 640 nextVersion version.Binary 641 setVersionErr error 642 abortCurrentUpgradeCalled bool 643 setVersionCalledWith version.Number 644 } 645 646 func (a *fakeUpgradeJujuAPI) reset() { 647 a.setVersionErr = nil 648 a.abortCurrentUpgradeCalled = false 649 a.setVersionCalledWith = version.Number{} 650 } 651 652 func (a *fakeUpgradeJujuAPI) patch(s *UpgradeJujuSuite) { 653 s.PatchValue(&getUpgradeJujuAPI, func(*UpgradeJujuCommand) (upgradeJujuAPI, error) { 654 return a, nil 655 }) 656 } 657 658 func (a *fakeUpgradeJujuAPI) EnvironmentGet() (map[string]interface{}, error) { 659 config, err := a.st.EnvironConfig() 660 if err != nil { 661 return make(map[string]interface{}), err 662 } 663 return config.AllAttrs(), nil 664 } 665 666 func (a *fakeUpgradeJujuAPI) FindTools(majorVersion, minorVersion int, series, arch string) ( 667 result params.FindToolsResult, err error, 668 ) { 669 tools := toolstesting.MakeTools(a.c, a.c.MkDir(), "released", []string{a.nextVersion.String()}) 670 return params.FindToolsResult{ 671 List: tools, 672 Error: nil, 673 }, nil 674 } 675 676 func (a *fakeUpgradeJujuAPI) UploadTools(r io.Reader, vers version.Binary, additionalSeries ...string) ( 677 *coretools.Tools, error, 678 ) { 679 panic("not implemented") 680 } 681 682 func (a *fakeUpgradeJujuAPI) AbortCurrentUpgrade() error { 683 a.abortCurrentUpgradeCalled = true 684 return nil 685 } 686 687 func (a *fakeUpgradeJujuAPI) SetEnvironAgentVersion(v version.Number) error { 688 a.setVersionCalledWith = v 689 return a.setVersionErr 690 } 691 692 func (a *fakeUpgradeJujuAPI) Close() error { 693 return nil 694 }