~nskaggs/+junk/xenial-test

« back to all changes in this revision

Viewing changes to src/github.com/juju/juju/worker/upgrader/upgrader_test.go

  • Committer: Nicholas Skaggs
  • Date: 2016-10-24 20:56:05 UTC
  • Revision ID: nicholas.skaggs@canonical.com-20161024205605-z8lta0uvuhtxwzwl
Initi with beta15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright 2012, 2013 Canonical Ltd.
 
2
// Licensed under the AGPLv3, see LICENCE file for details.
 
3
 
 
4
package upgrader_test
 
5
 
 
6
import (
 
7
        "fmt"
 
8
        "os"
 
9
        "path/filepath"
 
10
        stdtesting "testing"
 
11
        "time"
 
12
 
 
13
        "github.com/juju/errors"
 
14
        jc "github.com/juju/testing/checkers"
 
15
        "github.com/juju/utils"
 
16
        "github.com/juju/utils/arch"
 
17
        "github.com/juju/utils/series"
 
18
        "github.com/juju/utils/symlink"
 
19
        "github.com/juju/version"
 
20
        gc "gopkg.in/check.v1"
 
21
        "gopkg.in/juju/names.v2"
 
22
 
 
23
        "github.com/juju/juju/agent"
 
24
        agenttools "github.com/juju/juju/agent/tools"
 
25
        "github.com/juju/juju/api"
 
26
        envtesting "github.com/juju/juju/environs/testing"
 
27
        envtools "github.com/juju/juju/environs/tools"
 
28
        jujutesting "github.com/juju/juju/juju/testing"
 
29
        "github.com/juju/juju/state"
 
30
        statetesting "github.com/juju/juju/state/testing"
 
31
        coretesting "github.com/juju/juju/testing"
 
32
        coretools "github.com/juju/juju/tools"
 
33
        jujuversion "github.com/juju/juju/version"
 
34
        "github.com/juju/juju/worker/gate"
 
35
        "github.com/juju/juju/worker/upgrader"
 
36
)
 
37
 
 
38
func TestPackage(t *stdtesting.T) {
 
39
        coretesting.MgoTestPackage(t)
 
40
}
 
41
 
 
42
type UpgraderSuite struct {
 
43
        jujutesting.JujuConnSuite
 
44
 
 
45
        machine              *state.Machine
 
46
        state                api.Connection
 
47
        oldRetryAfter        func() <-chan time.Time
 
48
        confVersion          version.Number
 
49
        upgradeStepsComplete gate.Lock
 
50
        initialCheckComplete gate.Lock
 
51
}
 
52
 
 
53
type AllowedTargetVersionSuite struct{}
 
54
 
 
55
var _ = gc.Suite(&UpgraderSuite{})
 
56
var _ = gc.Suite(&AllowedTargetVersionSuite{})
 
57
 
 
58
func (s *UpgraderSuite) SetUpTest(c *gc.C) {
 
59
        s.JujuConnSuite.SetUpTest(c)
 
60
        // s.machine needs to have IsManager() so that it can get the actual
 
61
        // current revision to upgrade to.
 
62
        s.state, s.machine = s.OpenAPIAsNewMachine(c, state.JobManageModel)
 
63
        // Capture the value of RetryAfter, and use that captured
 
64
        // value in the cleanup lambda.
 
65
        oldRetryAfter := *upgrader.RetryAfter
 
66
        s.AddCleanup(func(*gc.C) {
 
67
                *upgrader.RetryAfter = oldRetryAfter
 
68
        })
 
69
        s.upgradeStepsComplete = gate.NewLock()
 
70
        s.initialCheckComplete = gate.NewLock()
 
71
}
 
72
 
 
73
func (s *UpgraderSuite) patchVersion(v version.Binary) {
 
74
        s.PatchValue(&arch.HostArch, func() string { return v.Arch })
 
75
        s.PatchValue(&series.HostSeries, func() string { return v.Series })
 
76
        s.PatchValue(&jujuversion.Current, v.Number)
 
77
}
 
78
 
 
79
type mockConfig struct {
 
80
        agent.Config
 
81
        tag     names.Tag
 
82
        datadir string
 
83
        version version.Number
 
84
}
 
85
 
 
86
func (mock *mockConfig) Tag() names.Tag {
 
87
        return mock.tag
 
88
}
 
89
 
 
90
func (mock *mockConfig) DataDir() string {
 
91
        return mock.datadir
 
92
}
 
93
 
 
94
func agentConfig(tag names.Tag, datadir string) agent.Config {
 
95
        return &mockConfig{
 
96
                tag:     tag,
 
97
                datadir: datadir,
 
98
        }
 
99
}
 
100
 
 
101
func (s *UpgraderSuite) makeUpgrader(c *gc.C) *upgrader.Upgrader {
 
102
        w, err := upgrader.NewAgentUpgrader(
 
103
                s.state.Upgrader(),
 
104
                agentConfig(s.machine.Tag(), s.DataDir()),
 
105
                s.confVersion,
 
106
                s.upgradeStepsComplete,
 
107
                s.initialCheckComplete,
 
108
        )
 
109
        c.Assert(err, jc.ErrorIsNil)
 
110
        return w
 
111
}
 
112
 
 
113
func (s *UpgraderSuite) TestUpgraderSetsTools(c *gc.C) {
 
114
        vers := version.MustParseBinary("5.4.3-precise-amd64")
 
115
        err := statetesting.SetAgentVersion(s.State, vers.Number)
 
116
        c.Assert(err, jc.ErrorIsNil)
 
117
        stor := s.DefaultToolsStorage
 
118
        agentTools := envtesting.PrimeTools(c, stor, s.DataDir(), s.Environ.Config().AgentStream(), vers)
 
119
        s.patchVersion(agentTools.Version)
 
120
        err = envtools.MergeAndWriteMetadata(stor, "released", "released", coretools.List{agentTools}, envtools.DoNotWriteMirrors)
 
121
        _, err = s.machine.AgentTools()
 
122
        c.Assert(err, jc.Satisfies, errors.IsNotFound)
 
123
 
 
124
        u := s.makeUpgrader(c)
 
125
        statetesting.AssertStop(c, u)
 
126
        s.expectInitialUpgradeCheckDone(c)
 
127
        s.machine.Refresh()
 
128
        gotTools, err := s.machine.AgentTools()
 
129
        c.Assert(err, jc.ErrorIsNil)
 
130
        envtesting.CheckTools(c, gotTools, agentTools)
 
131
}
 
132
 
 
133
func (s *UpgraderSuite) TestUpgraderSetVersion(c *gc.C) {
 
134
        vers := version.MustParseBinary("5.4.3-precise-amd64")
 
135
        agentTools := envtesting.PrimeTools(c, s.DefaultToolsStorage, s.DataDir(), s.Environ.Config().AgentStream(), vers)
 
136
        s.patchVersion(agentTools.Version)
 
137
        err := os.RemoveAll(filepath.Join(s.DataDir(), "tools"))
 
138
        c.Assert(err, jc.ErrorIsNil)
 
139
 
 
140
        _, err = s.machine.AgentTools()
 
141
        c.Assert(err, jc.Satisfies, errors.IsNotFound)
 
142
        err = statetesting.SetAgentVersion(s.State, vers.Number)
 
143
        c.Assert(err, jc.ErrorIsNil)
 
144
 
 
145
        u := s.makeUpgrader(c)
 
146
        statetesting.AssertStop(c, u)
 
147
        s.expectInitialUpgradeCheckDone(c)
 
148
        s.machine.Refresh()
 
149
        gotTools, err := s.machine.AgentTools()
 
150
        c.Assert(err, jc.ErrorIsNil)
 
151
        c.Assert(gotTools, gc.DeepEquals, &coretools.Tools{Version: vers})
 
152
}
 
153
 
 
154
func (s *UpgraderSuite) expectInitialUpgradeCheckDone(c *gc.C) {
 
155
        c.Assert(s.initialCheckComplete.IsUnlocked(), jc.IsTrue)
 
156
}
 
157
 
 
158
func (s *UpgraderSuite) expectInitialUpgradeCheckNotDone(c *gc.C) {
 
159
        c.Assert(s.initialCheckComplete.IsUnlocked(), jc.IsFalse)
 
160
}
 
161
 
 
162
func (s *UpgraderSuite) TestUpgraderUpgradesImmediately(c *gc.C) {
 
163
        stor := s.DefaultToolsStorage
 
164
        oldTools := envtesting.PrimeTools(c, stor, s.DataDir(), s.Environ.Config().AgentStream(), version.MustParseBinary("5.4.3-precise-amd64"))
 
165
        s.patchVersion(oldTools.Version)
 
166
        newTools := envtesting.AssertUploadFakeToolsVersions(
 
167
                c, stor, s.Environ.Config().AgentStream(), s.Environ.Config().AgentStream(), version.MustParseBinary("5.4.5-precise-amd64"))[0]
 
168
        err := statetesting.SetAgentVersion(s.State, newTools.Version.Number)
 
169
        c.Assert(err, jc.ErrorIsNil)
 
170
 
 
171
        u := s.makeUpgrader(c)
 
172
        err = u.Stop()
 
173
        s.expectInitialUpgradeCheckNotDone(c)
 
174
        envtesting.CheckUpgraderReadyError(c, err, &upgrader.UpgradeReadyError{
 
175
                AgentName: s.machine.Tag().String(),
 
176
                OldTools:  oldTools.Version,
 
177
                NewTools:  newTools.Version,
 
178
                DataDir:   s.DataDir(),
 
179
        })
 
180
        foundTools, err := agenttools.ReadTools(s.DataDir(), newTools.Version)
 
181
        c.Assert(err, jc.ErrorIsNil)
 
182
        newTools.URL = fmt.Sprintf("https://%s/model/%s/tools/5.4.5-precise-amd64",
 
183
                s.APIState.Addr(), coretesting.ModelTag.Id())
 
184
        envtesting.CheckTools(c, foundTools, newTools)
 
185
}
 
186
 
 
187
func (s *UpgraderSuite) TestUpgraderRetryAndChanged(c *gc.C) {
 
188
        stor := s.DefaultToolsStorage
 
189
        oldTools := envtesting.PrimeTools(c, stor, s.DataDir(), s.Environ.Config().AgentStream(), version.MustParseBinary("5.4.3-precise-amd64"))
 
190
        s.patchVersion(oldTools.Version)
 
191
        newTools := envtesting.AssertUploadFakeToolsVersions(
 
192
                c, stor, s.Environ.Config().AgentStream(), s.Environ.Config().AgentStream(), version.MustParseBinary("5.4.5-precise-amd64"))[0]
 
193
        err := statetesting.SetAgentVersion(s.State, newTools.Version.Number)
 
194
        c.Assert(err, jc.ErrorIsNil)
 
195
 
 
196
        retryc := make(chan time.Time)
 
197
        *upgrader.RetryAfter = func() <-chan time.Time {
 
198
                c.Logf("replacement retry after")
 
199
                return retryc
 
200
        }
 
201
        err = stor.Remove(envtools.StorageName(newTools.Version, "released"))
 
202
        c.Assert(err, jc.ErrorIsNil)
 
203
        u := s.makeUpgrader(c)
 
204
        defer u.Stop()
 
205
        s.expectInitialUpgradeCheckNotDone(c)
 
206
 
 
207
        for i := 0; i < 3; i++ {
 
208
                select {
 
209
                case retryc <- time.Now():
 
210
                case <-time.After(coretesting.LongWait):
 
211
                        c.Fatalf("upgrader did not retry (attempt %d)", i)
 
212
                }
 
213
        }
 
214
 
 
215
        // Make it upgrade to some newer tools that can be
 
216
        // downloaded ok; it should stop retrying, download
 
217
        // the newer tools and exit.
 
218
        newerTools := envtesting.AssertUploadFakeToolsVersions(
 
219
                c, stor, s.Environ.Config().AgentStream(), s.Environ.Config().AgentStream(), version.MustParseBinary("5.4.6-precise-amd64"))[0]
 
220
 
 
221
        err = statetesting.SetAgentVersion(s.State, newerTools.Version.Number)
 
222
        c.Assert(err, jc.ErrorIsNil)
 
223
 
 
224
        s.BackingState.StartSync()
 
225
        done := make(chan error)
 
226
        go func() {
 
227
                done <- u.Wait()
 
228
        }()
 
229
        select {
 
230
        case err := <-done:
 
231
                envtesting.CheckUpgraderReadyError(c, err, &upgrader.UpgradeReadyError{
 
232
                        AgentName: s.machine.Tag().String(),
 
233
                        OldTools:  oldTools.Version,
 
234
                        NewTools:  newerTools.Version,
 
235
                        DataDir:   s.DataDir(),
 
236
                })
 
237
        case <-time.After(coretesting.LongWait):
 
238
                c.Fatalf("upgrader did not quit after upgrading")
 
239
        }
 
240
}
 
241
 
 
242
func (s *UpgraderSuite) TestChangeAgentTools(c *gc.C) {
 
243
        oldTools := &coretools.Tools{
 
244
                Version: version.MustParseBinary("1.2.3-quantal-amd64"),
 
245
        }
 
246
        stor := s.DefaultToolsStorage
 
247
        newToolsBinary := "5.4.3-precise-amd64"
 
248
        newTools := envtesting.PrimeTools(c, stor, s.DataDir(), s.Environ.Config().AgentStream(), version.MustParseBinary(newToolsBinary))
 
249
        s.patchVersion(newTools.Version)
 
250
        err := envtools.MergeAndWriteMetadata(stor, "released", "released", coretools.List{newTools}, envtools.DoNotWriteMirrors)
 
251
        c.Assert(err, jc.ErrorIsNil)
 
252
        ugErr := &upgrader.UpgradeReadyError{
 
253
                AgentName: "anAgent",
 
254
                OldTools:  oldTools.Version,
 
255
                NewTools:  newTools.Version,
 
256
                DataDir:   s.DataDir(),
 
257
        }
 
258
        err = ugErr.ChangeAgentTools()
 
259
        c.Assert(err, jc.ErrorIsNil)
 
260
        target := agenttools.ToolsDir(s.DataDir(), newToolsBinary)
 
261
        link, err := symlink.Read(agenttools.ToolsDir(s.DataDir(), "anAgent"))
 
262
        c.Assert(err, jc.ErrorIsNil)
 
263
        c.Assert(link, jc.SamePath, target)
 
264
}
 
265
 
 
266
func (s *UpgraderSuite) TestUsesAlreadyDownloadedToolsIfAvailable(c *gc.C) {
 
267
        oldVersion := version.MustParseBinary("1.2.3-quantal-amd64")
 
268
        s.patchVersion(oldVersion)
 
269
 
 
270
        newVersion := version.MustParseBinary("5.4.3-quantal-amd64")
 
271
        err := statetesting.SetAgentVersion(s.State, newVersion.Number)
 
272
        c.Assert(err, jc.ErrorIsNil)
 
273
 
 
274
        // Install tools matching the new version in the data directory
 
275
        // but *not* in environment storage. The upgrader should find the
 
276
        // downloaded tools without looking in environment storage.
 
277
        envtesting.InstallFakeDownloadedTools(c, s.DataDir(), newVersion)
 
278
 
 
279
        u := s.makeUpgrader(c)
 
280
        err = u.Stop()
 
281
        s.expectInitialUpgradeCheckNotDone(c)
 
282
 
 
283
        envtesting.CheckUpgraderReadyError(c, err, &upgrader.UpgradeReadyError{
 
284
                AgentName: s.machine.Tag().String(),
 
285
                OldTools:  oldVersion,
 
286
                NewTools:  newVersion,
 
287
                DataDir:   s.DataDir(),
 
288
        })
 
289
}
 
290
 
 
291
func (s *UpgraderSuite) TestUpgraderRefusesToDowngradeMinorVersions(c *gc.C) {
 
292
        stor := s.DefaultToolsStorage
 
293
        origTools := envtesting.PrimeTools(c, stor, s.DataDir(), s.Environ.Config().AgentStream(), version.MustParseBinary("5.4.3-precise-amd64"))
 
294
        s.patchVersion(origTools.Version)
 
295
        downgradeTools := envtesting.AssertUploadFakeToolsVersions(
 
296
                c, stor, s.Environ.Config().AgentStream(), s.Environ.Config().AgentStream(), version.MustParseBinary("5.3.3-precise-amd64"))[0]
 
297
        err := statetesting.SetAgentVersion(s.State, downgradeTools.Version.Number)
 
298
        c.Assert(err, jc.ErrorIsNil)
 
299
 
 
300
        u := s.makeUpgrader(c)
 
301
        err = u.Stop()
 
302
        s.expectInitialUpgradeCheckDone(c)
 
303
        // If the upgrade would have triggered, we would have gotten an
 
304
        // UpgradeReadyError, since it was skipped, we get no error
 
305
        c.Check(err, jc.ErrorIsNil)
 
306
        _, err = agenttools.ReadTools(s.DataDir(), downgradeTools.Version)
 
307
        // TODO: ReadTools *should* be returning some form of errors.NotFound,
 
308
        // however, it just passes back a fmt.Errorf so we live with it
 
309
        // c.Assert(err, jc.Satisfies, errors.IsNotFound)
 
310
        c.Check(err, gc.ErrorMatches, "cannot read tools metadata in tools directory.*"+utils.NoSuchFileErrRegexp)
 
311
}
 
312
 
 
313
func (s *UpgraderSuite) TestUpgraderAllowsDowngradingPatchVersions(c *gc.C) {
 
314
        stor := s.DefaultToolsStorage
 
315
        origTools := envtesting.PrimeTools(c, stor, s.DataDir(), s.Environ.Config().AgentStream(), version.MustParseBinary("5.4.3-precise-amd64"))
 
316
        s.patchVersion(origTools.Version)
 
317
        downgradeTools := envtesting.AssertUploadFakeToolsVersions(
 
318
                c, stor, s.Environ.Config().AgentStream(), s.Environ.Config().AgentStream(), version.MustParseBinary("5.4.2-precise-amd64"))[0]
 
319
        err := statetesting.SetAgentVersion(s.State, downgradeTools.Version.Number)
 
320
        c.Assert(err, jc.ErrorIsNil)
 
321
 
 
322
        u := s.makeUpgrader(c)
 
323
        err = u.Stop()
 
324
        s.expectInitialUpgradeCheckNotDone(c)
 
325
        envtesting.CheckUpgraderReadyError(c, err, &upgrader.UpgradeReadyError{
 
326
                AgentName: s.machine.Tag().String(),
 
327
                OldTools:  origTools.Version,
 
328
                NewTools:  downgradeTools.Version,
 
329
                DataDir:   s.DataDir(),
 
330
        })
 
331
        foundTools, err := agenttools.ReadTools(s.DataDir(), downgradeTools.Version)
 
332
        c.Assert(err, jc.ErrorIsNil)
 
333
        downgradeTools.URL = fmt.Sprintf("https://%s/model/%s/tools/5.4.2-precise-amd64",
 
334
                s.APIState.Addr(), coretesting.ModelTag.Id())
 
335
        envtesting.CheckTools(c, foundTools, downgradeTools)
 
336
}
 
337
 
 
338
func (s *UpgraderSuite) TestUpgraderAllowsDowngradeToOrigVersionIfUpgradeInProgress(c *gc.C) {
 
339
        // note: otherwise illegal version jump
 
340
        downgradeVersion := version.MustParseBinary("5.3.0-precise-amd64")
 
341
        s.confVersion = downgradeVersion.Number
 
342
 
 
343
        stor := s.DefaultToolsStorage
 
344
        origTools := envtesting.PrimeTools(c, stor, s.DataDir(), s.Environ.Config().AgentStream(), version.MustParseBinary("5.4.3-precise-amd64"))
 
345
        s.patchVersion(origTools.Version)
 
346
        downgradeTools := envtesting.AssertUploadFakeToolsVersions(
 
347
                c, stor, s.Environ.Config().AgentStream(), s.Environ.Config().AgentStream(), downgradeVersion)[0]
 
348
        err := statetesting.SetAgentVersion(s.State, downgradeVersion.Number)
 
349
        c.Assert(err, jc.ErrorIsNil)
 
350
 
 
351
        u := s.makeUpgrader(c)
 
352
        err = u.Stop()
 
353
        s.expectInitialUpgradeCheckNotDone(c)
 
354
        envtesting.CheckUpgraderReadyError(c, err, &upgrader.UpgradeReadyError{
 
355
                AgentName: s.machine.Tag().String(),
 
356
                OldTools:  origTools.Version,
 
357
                NewTools:  downgradeVersion,
 
358
                DataDir:   s.DataDir(),
 
359
        })
 
360
        foundTools, err := agenttools.ReadTools(s.DataDir(), downgradeTools.Version)
 
361
        c.Assert(err, jc.ErrorIsNil)
 
362
        downgradeTools.URL = fmt.Sprintf("https://%s/model/%s/tools/5.3.0-precise-amd64",
 
363
                s.APIState.Addr(), coretesting.ModelTag.Id())
 
364
        envtesting.CheckTools(c, foundTools, downgradeTools)
 
365
}
 
366
 
 
367
func (s *UpgraderSuite) TestUpgraderRefusesDowngradeToOrigVersionIfUpgradeNotInProgress(c *gc.C) {
 
368
        downgradeVersion := version.MustParseBinary("5.3.0-precise-amd64")
 
369
        s.confVersion = downgradeVersion.Number
 
370
        s.upgradeStepsComplete.Unlock()
 
371
 
 
372
        stor := s.DefaultToolsStorage
 
373
        origTools := envtesting.PrimeTools(c, stor, s.DataDir(), s.Environ.Config().AgentStream(), version.MustParseBinary("5.4.3-precise-amd64"))
 
374
        s.patchVersion(origTools.Version)
 
375
        envtesting.AssertUploadFakeToolsVersions(
 
376
                c, stor, s.Environ.Config().AgentStream(), s.Environ.Config().AgentStream(), downgradeVersion)
 
377
        err := statetesting.SetAgentVersion(s.State, downgradeVersion.Number)
 
378
        c.Assert(err, jc.ErrorIsNil)
 
379
 
 
380
        u := s.makeUpgrader(c)
 
381
        err = u.Stop()
 
382
        s.expectInitialUpgradeCheckDone(c)
 
383
 
 
384
        // If the upgrade would have triggered, we would have gotten an
 
385
        // UpgradeReadyError, since it was skipped, we get no error
 
386
        c.Check(err, jc.ErrorIsNil)
 
387
}
 
388
 
 
389
type allowedTest struct {
 
390
        original       string
 
391
        current        string
 
392
        target         string
 
393
        upgradeRunning bool
 
394
        allowed        bool
 
395
}
 
396
 
 
397
func (s *AllowedTargetVersionSuite) TestAllowedTargetVersionSuite(c *gc.C) {
 
398
        cases := []allowedTest{
 
399
                {original: "1.2.3", current: "1.2.3", upgradeRunning: false, target: "1.3.3", allowed: true},
 
400
                {original: "1.2.3", current: "1.2.3", upgradeRunning: false, target: "1.2.3", allowed: true},
 
401
                {original: "1.2.3", current: "1.2.3", upgradeRunning: false, target: "2.2.3", allowed: true},
 
402
                {original: "1.2.3", current: "1.2.3", upgradeRunning: false, target: "1.1.3", allowed: false},
 
403
                {original: "1.2.3", current: "1.2.3", upgradeRunning: false, target: "1.2.2", allowed: true}, // downgrade between builds
 
404
                {original: "1.2.3", current: "1.2.3", upgradeRunning: false, target: "0.2.3", allowed: false},
 
405
                {original: "0.2.3", current: "1.2.3", upgradeRunning: false, target: "0.2.3", allowed: false},
 
406
                {original: "0.2.3", current: "1.2.3", upgradeRunning: true, target: "0.2.3", allowed: true}, // downgrade during upgrade
 
407
        }
 
408
        for i, test := range cases {
 
409
                c.Logf("test case %d, %#v", i, test)
 
410
                original := version.MustParse(test.original)
 
411
                current := version.MustParse(test.current)
 
412
                target := version.MustParse(test.target)
 
413
                result := upgrader.AllowedTargetVersion(original, current, test.upgradeRunning, target)
 
414
                c.Check(result, gc.Equals, test.allowed)
 
415
        }
 
416
}