LEFT | RIGHT |
1 // Copyright 2012, 2013 Canonical Ltd. | 1 // Copyright 2012, 2013 Canonical Ltd. |
2 // Licensed under the AGPLv3, see LICENCE file for details. | 2 // Licensed under the AGPLv3, see LICENCE file for details. |
3 | 3 |
4 package main | 4 package main |
5 | 5 |
6 import ( | 6 import ( |
7 "archive/tar" | 7 "archive/tar" |
8 "bytes" | 8 "bytes" |
9 "compress/gzip" | 9 "compress/gzip" |
10 "io" | 10 "io" |
11 "io/ioutil" | 11 "io/ioutil" |
12 "strings" | 12 "strings" |
13 | 13 |
| 14 jc "github.com/juju/testing/checkers" |
14 gc "launchpad.net/gocheck" | 15 gc "launchpad.net/gocheck" |
15 | 16 |
16 "launchpad.net/juju-core/environs/filestorage" | 17 "launchpad.net/juju-core/environs/filestorage" |
17 "launchpad.net/juju-core/environs/storage" | 18 "launchpad.net/juju-core/environs/storage" |
18 "launchpad.net/juju-core/environs/sync" | 19 "launchpad.net/juju-core/environs/sync" |
19 envtesting "launchpad.net/juju-core/environs/testing" | 20 envtesting "launchpad.net/juju-core/environs/testing" |
20 envtools "launchpad.net/juju-core/environs/tools" | 21 envtools "launchpad.net/juju-core/environs/tools" |
21 "launchpad.net/juju-core/juju/testing" | 22 "launchpad.net/juju-core/juju/testing" |
22 coretesting "launchpad.net/juju-core/testing" | 23 coretesting "launchpad.net/juju-core/testing" |
23 jc "launchpad.net/juju-core/testing/checkers" | |
24 coretools "launchpad.net/juju-core/tools" | |
25 "launchpad.net/juju-core/version" | 24 "launchpad.net/juju-core/version" |
26 ) | 25 ) |
27 | 26 |
28 type UpgradeJujuSuite struct { | 27 type UpgradeJujuSuite struct { |
29 testing.JujuConnSuite | 28 testing.JujuConnSuite |
| 29 toolsDir string |
30 } | 30 } |
31 | 31 |
32 var _ = gc.Suite(&UpgradeJujuSuite{}) | 32 var _ = gc.Suite(&UpgradeJujuSuite{}) |
33 | 33 |
34 var upgradeJujuTests = []struct { | 34 var upgradeJujuTests = []struct { |
35 about string | 35 about string |
36 tools []string | 36 tools []string |
37 currentVersion string | 37 currentVersion string |
38 agentVersion string | 38 agentVersion string |
39 | 39 |
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
158 about: "specified version missing, but already set", | 158 about: "specified version missing, but already set", |
159 currentVersion: "3.0.0-quantal-amd64", | 159 currentVersion: "3.0.0-quantal-amd64", |
160 agentVersion: "3.0.0", | 160 agentVersion: "3.0.0", |
161 args: []string{"--version", "3.0.0"}, | 161 args: []string{"--version", "3.0.0"}, |
162 expectVersion: "3.0.0", | 162 expectVersion: "3.0.0", |
163 }, { | 163 }, { |
164 about: "specified version, no tools", | 164 about: "specified version, no tools", |
165 currentVersion: "3.0.0-quantal-amd64", | 165 currentVersion: "3.0.0-quantal-amd64", |
166 agentVersion: "3.0.0", | 166 agentVersion: "3.0.0", |
167 args: []string{"--version", "3.2.0"}, | 167 args: []string{"--version", "3.2.0"}, |
168 » expectErr: "no matching tools available", | 168 » expectErr: "no tools available", |
169 }, { | 169 }, { |
170 about: "specified version, no matching major version", | 170 about: "specified version, no matching major version", |
171 tools: []string{"4.2.0-quantal-amd64"}, | 171 tools: []string{"4.2.0-quantal-amd64"}, |
172 currentVersion: "3.0.0-quantal-amd64", | 172 currentVersion: "3.0.0-quantal-amd64", |
173 agentVersion: "3.0.0", | 173 agentVersion: "3.0.0", |
174 args: []string{"--version", "3.2.0"}, | 174 args: []string{"--version", "3.2.0"}, |
175 expectErr: "no matching tools available", | 175 expectErr: "no matching tools available", |
176 }, { | 176 }, { |
177 about: "specified version, no matching minor version", | 177 about: "specified version, no matching minor version", |
178 tools: []string{"3.4.0-quantal-amd64"}, | 178 tools: []string{"3.4.0-quantal-amd64"}, |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
266 }, { | 266 }, { |
267 about: "upload with explicit version bumps when necessary", | 267 about: "upload with explicit version bumps when necessary", |
268 currentVersion: "2.2.0-quantal-amd64", | 268 currentVersion: "2.2.0-quantal-amd64", |
269 tools: []string{"2.7.3.1-quantal-amd64"}, | 269 tools: []string{"2.7.3.1-quantal-amd64"}, |
270 agentVersion: "2.0.0", | 270 agentVersion: "2.0.0", |
271 args: []string{"--upload-tools", "--version", "2.7.3"}, | 271 args: []string{"--upload-tools", "--version", "2.7.3"}, |
272 expectVersion: "2.7.3.2", | 272 expectVersion: "2.7.3.2", |
273 expectUploaded: []string{"2.7.3.2-quantal-amd64", "2.7.3.2-precise-amd64
", "2.7.3.2-raring-amd64"}, | 273 expectUploaded: []string{"2.7.3.2-quantal-amd64", "2.7.3.2-precise-amd64
", "2.7.3.2-raring-amd64"}, |
274 }} | 274 }} |
275 | 275 |
276 // mockUploadTools simulates the effect of tools.Upload, but skips the time- | 276 // getMockBuildTools returns a sync.BuildToolsTarballFunc implementation which g
enerates |
277 // consuming build from source. | 277 // a fake tools tarball. |
278 // TODO(fwereade) better factor agent/tools such that build logic is | 278 func (s *UpgradeJujuSuite) getMockBuildTools(c *gc.C) sync.BuildToolsTarballFunc
{ |
279 // exposed and can itself be neatly mocked? | 279 » return func(forceVersion *version.Number) (*sync.BuiltTools, error) { |
280 func mockUploadTools(stor storage.Storage, forceVersion *version.Number, series
...string) (*coretools.Tools, error) { | 280 » » // UploadFakeToolsVersions requires a storage to write to. |
281 » vers := version.Current | 281 » » stor, err := filestorage.NewFileStorageWriter(s.toolsDir) |
282 » if forceVersion != nil { | 282 » » c.Assert(err, gc.IsNil) |
283 » » vers.Number = *forceVersion | 283 » » vers := version.Current |
| 284 » » if forceVersion != nil { |
| 285 » » » vers.Number = *forceVersion |
| 286 » » } |
| 287 » » versions := []version.Binary{vers} |
| 288 » » uploadedTools, err := envtesting.UploadFakeToolsVersions(stor, v
ersions...) |
| 289 » » c.Assert(err, gc.IsNil) |
| 290 » » agentTools := uploadedTools[0] |
| 291 » » return &sync.BuiltTools{ |
| 292 » » » Dir: s.toolsDir, |
| 293 » » » StorageName: envtools.StorageName(vers), |
| 294 » » » Version: vers, |
| 295 » » » Size: agentTools.Size, |
| 296 » » » Sha256Hash: agentTools.SHA256, |
| 297 » » }, nil |
284 } | 298 } |
285 versions := []version.Binary{vers} | |
286 for _, series := range series { | |
287 if series != version.Current.Series { | |
288 newVers := vers | |
289 newVers.Series = series | |
290 versions = append(versions, newVers) | |
291 } | |
292 } | |
293 agentTools, err := envtesting.UploadFakeToolsVersions(stor, versions...) | |
294 if err != nil { | |
295 return nil, err | |
296 } | |
297 return agentTools[0], nil | |
298 } | 299 } |
299 | 300 |
300 func (s *UpgradeJujuSuite) TestUpgradeJuju(c *gc.C) { | 301 func (s *UpgradeJujuSuite) TestUpgradeJuju(c *gc.C) { |
301 » s.PatchValue(&sync.Upload, mockUploadTools) | 302 » s.PatchValue(&sync.BuildToolsTarball, s.getMockBuildTools(c)) |
302 oldVersion := version.Current | 303 oldVersion := version.Current |
303 defer func() { | 304 defer func() { |
304 version.Current = oldVersion | 305 version.Current = oldVersion |
305 }() | 306 }() |
306 | 307 |
307 for i, test := range upgradeJujuTests { | 308 for i, test := range upgradeJujuTests { |
308 c.Logf("\ntest %d: %s", i, test.about) | 309 c.Logf("\ntest %d: %s", i, test.about) |
309 s.Reset(c) | 310 s.Reset(c) |
310 | 311 |
311 // Set up apparent CLI version and initialize the command. | 312 // Set up apparent CLI version and initialize the command. |
312 version.Current = version.MustParseBinary(test.currentVersion) | 313 version.Current = version.MustParseBinary(test.currentVersion) |
313 com := &UpgradeJujuCommand{} | 314 com := &UpgradeJujuCommand{} |
314 if err := coretesting.InitCommand(com, test.args); err != nil { | 315 if err := coretesting.InitCommand(com, test.args); err != nil { |
315 if test.expectInitErr != "" { | 316 if test.expectInitErr != "" { |
316 c.Check(err, gc.ErrorMatches, test.expectInitErr
) | 317 c.Check(err, gc.ErrorMatches, test.expectInitErr
) |
317 } else { | 318 } else { |
318 c.Check(err, gc.IsNil) | 319 c.Check(err, gc.IsNil) |
319 } | 320 } |
320 continue | 321 continue |
321 } | 322 } |
322 | 323 |
323 // Set up state and environ, and run the command. | 324 // Set up state and environ, and run the command. |
324 toolsDir := c.MkDir() | 325 toolsDir := c.MkDir() |
325 updateAttrs := map[string]interface{}{ | 326 updateAttrs := map[string]interface{}{ |
326 "agent-version": test.agentVersion, | 327 "agent-version": test.agentVersion, |
327 "tools-metadata-url": "file://" + toolsDir, | 328 "tools-metadata-url": "file://" + toolsDir, |
328 } | 329 } |
329 » » err := s.State.UpdateEnvironConfig(updateAttrs, []string{}) | 330 » » err := s.State.UpdateEnvironConfig(updateAttrs, nil, nil) |
330 c.Assert(err, gc.IsNil) | 331 c.Assert(err, gc.IsNil) |
331 versions := make([]version.Binary, len(test.tools)) | 332 versions := make([]version.Binary, len(test.tools)) |
332 for i, v := range test.tools { | 333 for i, v := range test.tools { |
333 versions[i] = version.MustParseBinary(v) | 334 versions[i] = version.MustParseBinary(v) |
334 } | 335 } |
335 » » envtesting.MustUploadFakeToolsVersions(s.Conn.Environ.Storage(),
versions...) | 336 » » if len(versions) > 0 { |
336 » » stor, err := filestorage.NewFileStorageWriter(toolsDir) | 337 » » » envtesting.MustUploadFakeToolsVersions(s.Conn.Environ.St
orage(), versions...) |
337 » » c.Assert(err, gc.IsNil) | 338 » » » stor, err := filestorage.NewFileStorageWriter(toolsDir) |
338 » » envtesting.MustUploadFakeToolsVersions(stor, versions...) | 339 » » » c.Assert(err, gc.IsNil) |
| 340 » » » envtesting.MustUploadFakeToolsVersions(stor, versions...
) |
| 341 » » } |
| 342 |
339 err = com.Run(coretesting.Context(c)) | 343 err = com.Run(coretesting.Context(c)) |
340 if test.expectErr != "" { | 344 if test.expectErr != "" { |
341 c.Check(err, gc.ErrorMatches, test.expectErr) | 345 c.Check(err, gc.ErrorMatches, test.expectErr) |
342 continue | 346 continue |
343 } else if !c.Check(err, gc.IsNil) { | 347 } else if !c.Check(err, gc.IsNil) { |
344 continue | 348 continue |
345 } | 349 } |
346 | 350 |
347 // Check expected changes to environ/state. | 351 // Check expected changes to environ/state. |
348 cfg, err := s.State.EnvironConfig() | 352 cfg, err := s.State.EnvironConfig() |
349 c.Check(err, gc.IsNil) | 353 c.Check(err, gc.IsNil) |
350 agentVersion, ok := cfg.AgentVersion() | 354 agentVersion, ok := cfg.AgentVersion() |
351 c.Check(ok, gc.Equals, true) | 355 c.Check(ok, gc.Equals, true) |
352 c.Check(agentVersion, gc.Equals, version.MustParse(test.expectVe
rsion)) | 356 c.Check(agentVersion, gc.Equals, version.MustParse(test.expectVe
rsion)) |
353 | 357 |
354 for _, uploaded := range test.expectUploaded { | 358 for _, uploaded := range test.expectUploaded { |
355 vers := version.MustParseBinary(uploaded) | 359 vers := version.MustParseBinary(uploaded) |
356 r, err := storage.Get(s.Conn.Environ.Storage(), envtools
.StorageName(vers)) | 360 r, err := storage.Get(s.Conn.Environ.Storage(), envtools
.StorageName(vers)) |
357 if !c.Check(err, gc.IsNil) { | 361 if !c.Check(err, gc.IsNil) { |
358 continue | 362 continue |
359 } | 363 } |
360 data, err := ioutil.ReadAll(r) | 364 data, err := ioutil.ReadAll(r) |
361 r.Close() | 365 r.Close() |
362 c.Check(err, gc.IsNil) | 366 c.Check(err, gc.IsNil) |
363 » » » checkToolsContent(c, data, "jujud contents "+uploaded) | 367 » » » expectContent := version.Current |
| 368 » » » expectContent.Number = agentVersion |
| 369 » » » checkToolsContent(c, data, "jujud contents "+expectConte
nt.String()) |
364 } | 370 } |
365 } | 371 } |
366 } | 372 } |
367 | 373 |
368 func checkToolsContent(c *gc.C, data []byte, uploaded string) { | 374 func checkToolsContent(c *gc.C, data []byte, uploaded string) { |
369 zr, err := gzip.NewReader(bytes.NewReader(data)) | 375 zr, err := gzip.NewReader(bytes.NewReader(data)) |
370 c.Check(err, gc.IsNil) | 376 c.Check(err, gc.IsNil) |
371 defer zr.Close() | 377 defer zr.Close() |
372 tr := tar.NewReader(zr) | 378 tr := tar.NewReader(zr) |
373 found := false | 379 found := false |
(...skipping 21 matching lines...) Expand all Loading... |
395 // tools to the environment's storage. We don't want | 401 // tools to the environment's storage. We don't want |
396 // 'em there; but we do want a consistent default-series | 402 // 'em there; but we do want a consistent default-series |
397 // in the environment state. | 403 // in the environment state. |
398 func (s *UpgradeJujuSuite) Reset(c *gc.C) { | 404 func (s *UpgradeJujuSuite) Reset(c *gc.C) { |
399 s.JujuConnSuite.Reset(c) | 405 s.JujuConnSuite.Reset(c) |
400 envtesting.RemoveTools(c, s.Conn.Environ.Storage()) | 406 envtesting.RemoveTools(c, s.Conn.Environ.Storage()) |
401 updateAttrs := map[string]interface{}{ | 407 updateAttrs := map[string]interface{}{ |
402 "default-series": "raring", | 408 "default-series": "raring", |
403 "agent-version": "1.2.3", | 409 "agent-version": "1.2.3", |
404 } | 410 } |
405 » err := s.State.UpdateEnvironConfig(updateAttrs, []string{}) | 411 » err := s.State.UpdateEnvironConfig(updateAttrs, nil, nil) |
406 c.Assert(err, gc.IsNil) | 412 c.Assert(err, gc.IsNil) |
| 413 s.toolsDir = c.MkDir() |
407 } | 414 } |
408 | 415 |
409 func (s *UpgradeJujuSuite) TestUpgradeJujuWithRealUpload(c *gc.C) { | 416 func (s *UpgradeJujuSuite) TestUpgradeJujuWithRealUpload(c *gc.C) { |
410 s.Reset(c) | 417 s.Reset(c) |
411 _, err := coretesting.RunCommand(c, &UpgradeJujuCommand{}, []string{"--u
pload-tools"}) | 418 _, err := coretesting.RunCommand(c, &UpgradeJujuCommand{}, []string{"--u
pload-tools"}) |
412 c.Assert(err, gc.IsNil) | 419 c.Assert(err, gc.IsNil) |
413 vers := version.Current | 420 vers := version.Current |
414 vers.Build = 1 | 421 vers.Build = 1 |
415 tools, err := envtools.FindInstanceTools(s.Conn.Environ, vers.Number, ve
rs.Series, &vers.Arch) | 422 tools, err := envtools.FindInstanceTools(s.Conn.Environ, vers.Number, ve
rs.Series, &vers.Arch) |
416 c.Assert(err, gc.IsNil) | 423 c.Assert(err, gc.IsNil) |
417 c.Assert(len(tools), gc.Equals, 1) | 424 c.Assert(len(tools), gc.Equals, 1) |
418 } | 425 } |
LEFT | RIGHT |