~ubuntu-branches/ubuntu/vivid/juju-core/vivid-updates

« back to all changes in this revision

Viewing changes to src/github.com/juju/juju/worker/uniter/uniter_test.go

  • Committer: Package Import Robot
  • Author(s): Curtis C. Hovey
  • Date: 2015-09-29 19:43:29 UTC
  • mfrom: (47.1.4 wily-proposed)
  • Revision ID: package-import@ubuntu.com-20150929194329-9y496tbic30hc7vp
Tags: 1.24.6-0ubuntu1~15.04.1
Backport of 1.24.6 from wily. (LP: #1500916, #1497087)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
// Copyright 2012-2014 Canonical Ltd.
 
1
// Copyright 2012-2015 Canonical Ltd.
2
2
// Licensed under the AGPLv3, see LICENCE file for details.
3
3
 
4
4
package uniter_test
5
5
 
6
6
import (
7
7
        "fmt"
 
8
        "io"
8
9
        "io/ioutil"
9
10
        "os"
10
11
        "os/exec"
11
12
        "path/filepath"
 
13
        "runtime"
 
14
        "strings"
 
15
        "syscall"
 
16
        "time"
12
17
 
 
18
        "github.com/juju/errors"
13
19
        jc "github.com/juju/testing/checkers"
14
20
        ft "github.com/juju/testing/filetesting"
15
21
        gc "gopkg.in/check.v1"
16
 
        corecharm "gopkg.in/juju/charm.v4"
 
22
        corecharm "gopkg.in/juju/charm.v5"
17
23
 
18
24
        "github.com/juju/juju/agent/tools"
19
25
        "github.com/juju/juju/apiserver/params"
20
26
        "github.com/juju/juju/juju/testing"
21
27
        "github.com/juju/juju/state"
 
28
        "github.com/juju/juju/state/lease"
22
29
        "github.com/juju/juju/testcharms"
23
30
        coretesting "github.com/juju/juju/testing"
24
31
        "github.com/juju/juju/worker/uniter"
 
32
        "github.com/juju/juju/worker/uniter/operation"
25
33
)
26
34
 
27
35
type UniterSuite struct {
36
44
 
37
45
var _ = gc.Suite(&UniterSuite{})
38
46
 
 
47
var leaseClock *coretesting.Clock
 
48
 
 
49
// This guarantees that we get proper platform
 
50
// specific error directly from their source
 
51
// This works on both windows and unix
 
52
var errNotDir = syscall.ENOTDIR.Error()
 
53
 
39
54
func (s *UniterSuite) SetUpSuite(c *gc.C) {
40
55
        s.GitSuite.SetUpSuite(c)
41
56
        s.JujuConnSuite.SetUpSuite(c)
52
67
        s.oldLcAll = os.Getenv("LC_ALL")
53
68
        os.Setenv("LC_ALL", "en_US")
54
69
        s.unitDir = filepath.Join(s.dataDir, "agents", "unit-u-0")
 
70
 
 
71
        zone, err := time.LoadLocation("")
 
72
        c.Assert(err, jc.ErrorIsNil)
 
73
        now := time.Date(2030, 11, 11, 11, 11, 11, 11, zone)
 
74
        leaseClock = coretesting.NewClock(now)
 
75
        oldGetClock := state.GetClock
 
76
        state.GetClock = func() lease.Clock {
 
77
                return leaseClock
 
78
        }
 
79
        s.AddSuiteCleanup(func(*gc.C) { state.GetClock = oldGetClock })
55
80
}
56
81
 
57
82
func (s *UniterSuite) TearDownSuite(c *gc.C) {
65
90
        s.JujuConnSuite.SetUpTest(c)
66
91
        s.ticker = uniter.NewManualTicker()
67
92
        s.PatchValue(uniter.ActiveMetricsTimer, s.ticker.ReturnTimer)
 
93
        s.PatchValue(uniter.IdleWaitTime, 1*time.Millisecond)
68
94
}
69
95
 
70
96
func (s *UniterSuite) TearDownTest(c *gc.C) {
113
139
                        createCharm{},
114
140
                        createServiceAndUnit{},
115
141
                        startUniter{},
116
 
                        waitUniterDead{`failed to initialize uniter for "unit-u-0": .*not a directory`},
 
142
                        waitUniterDead{`failed to initialize uniter for "unit-u-0": .*` + errNotDir},
117
143
                ), ut(
118
144
                        "unknown unit",
119
145
                        // We still need to create a unit, because that's when we also
121
147
                        // (and hence unit) name.
122
148
                        createCharm{},
123
149
                        createServiceAndUnit{serviceName: "w"},
124
 
                        startUniter{"unit-u-0"},
 
150
                        startUniter{unitTag: "unit-u-0"},
125
151
                        waitUniterDead{`failed to initialize uniter for "unit-u-0": permission denied`},
126
152
                ),
127
153
        })
128
154
}
129
155
 
130
156
func (s *UniterSuite) TestUniterBootstrap(c *gc.C) {
 
157
        //TODO(bogdanteleaga): Fix this on windows
 
158
        if runtime.GOOS == "windows" {
 
159
                c.Skip("bug 1403084: currently does not work on windows")
 
160
        }
131
161
        s.runUniterTests(c, []uniterTest{
132
162
                // Check error conditions during unit bootstrap phase.
133
163
                ut(
136
166
                        serveCharm{},
137
167
                        writeFile{"charm", 0644},
138
168
                        createUniter{},
139
 
                        waitUniterDead{`ModeInstalling cs:quantal/wordpress-0: executing operation "install cs:quantal/wordpress-0": open .*: not a directory`},
 
169
                        waitUniterDead{`ModeInstalling cs:quantal/wordpress-0: executing operation "install cs:quantal/wordpress-0": open .*` + errNotDir},
140
170
                ), ut(
141
171
                        "charm cannot be downloaded",
142
172
                        createCharm{},
155
185
                        verifyWaiting{},
156
186
 
157
187
                        resolveError{state.ResolvedNoHooks},
158
 
                        waitUnit{
159
 
                                status: params.StatusActive,
160
 
                        },
161
 
                        waitHooks{"config-changed", "start"},
 
188
                        waitUnitAgent{
 
189
                                status: params.StatusIdle,
 
190
                        },
 
191
                        waitUnitAgent{
 
192
                                statusGetter: unitStatusGetter,
 
193
                                status:       params.StatusUnknown,
 
194
                        },
 
195
                        waitHooks{"leader-elected", "config-changed", "start"},
162
196
                ), ut(
163
197
                        "install hook fail and retry",
164
198
                        startupError{"install"},
165
199
                        verifyWaiting{},
166
200
 
167
201
                        resolveError{state.ResolvedRetryHooks},
168
 
                        waitUnit{
169
 
                                status: params.StatusError,
170
 
                                info:   `hook failed: "install"`,
 
202
                        waitUnitAgent{
 
203
                                statusGetter: unitStatusGetter,
 
204
                                status:       params.StatusError,
 
205
                                info:         `hook failed: "install"`,
171
206
                                data: map[string]interface{}{
172
207
                                        "hook": "install",
173
208
                                },
177
212
                        verifyWaiting{},
178
213
 
179
214
                        resolveError{state.ResolvedRetryHooks},
180
 
                        waitUnit{
181
 
                                status: params.StatusActive,
 
215
                        waitUnitAgent{
 
216
                                status: params.StatusIdle,
182
217
                        },
183
 
                        waitHooks{"install", "config-changed", "start"},
 
218
                        waitHooks{"install", "leader-elected", "config-changed", "start"},
184
219
                ),
185
220
        })
186
221
}
193
228
                        verifyWaiting{},
194
229
 
195
230
                        resolveError{state.ResolvedNoHooks},
196
 
                        waitUnit{
197
 
                                status: params.StatusActive,
 
231
                        waitUnitAgent{
 
232
                                status: params.StatusIdle,
 
233
                        },
 
234
                        waitUnitAgent{
 
235
                                statusGetter: unitStatusGetter,
 
236
                                status:       params.StatusMaintenance,
 
237
                                info:         "installing charm software",
198
238
                        },
199
239
                        waitHooks{"config-changed"},
200
240
                        verifyRunning{},
204
244
                        verifyWaiting{},
205
245
 
206
246
                        resolveError{state.ResolvedRetryHooks},
207
 
                        waitUnit{
208
 
                                status: params.StatusError,
209
 
                                info:   `hook failed: "start"`,
 
247
                        waitUnitAgent{
 
248
                                statusGetter: unitStatusGetter,
 
249
                                status:       params.StatusError,
 
250
                                info:         `hook failed: "start"`,
210
251
                                data: map[string]interface{}{
211
252
                                        "hook": "start",
212
253
                                },
216
257
 
217
258
                        fixHook{"start"},
218
259
                        resolveError{state.ResolvedRetryHooks},
219
 
                        waitUnit{
220
 
                                status: params.StatusActive,
 
260
                        waitUnitAgent{
 
261
                                status: params.StatusIdle,
221
262
                        },
222
263
                        waitHooks{"start", "config-changed"},
223
264
                        verifyRunning{},
229
270
        s.runUniterTests(c, []uniterTest{
230
271
                ut(
231
272
                        "resolved is cleared before moving on to next hook",
232
 
                        createCharm{badHooks: []string{"install", "config-changed", "start"}},
 
273
                        createCharm{badHooks: []string{"install", "leader-elected", "config-changed", "start"}},
233
274
                        serveCharm{},
234
275
                        createUniter{},
235
 
                        waitUnit{
236
 
                                status: params.StatusError,
237
 
                                info:   `hook failed: "install"`,
 
276
                        waitUnitAgent{
 
277
                                statusGetter: unitStatusGetter,
 
278
                                status:       params.StatusError,
 
279
                                info:         `hook failed: "install"`,
238
280
                                data: map[string]interface{}{
239
281
                                        "hook": "install",
240
282
                                },
241
283
                        },
242
284
                        resolveError{state.ResolvedNoHooks},
243
 
                        waitUnit{
244
 
                                status: params.StatusError,
245
 
                                info:   `hook failed: "config-changed"`,
 
285
                        waitUnitAgent{
 
286
                                statusGetter: unitStatusGetter,
 
287
                                status:       params.StatusError,
 
288
                                info:         `hook failed: "leader-elected"`,
 
289
                                data: map[string]interface{}{
 
290
                                        "hook": "leader-elected",
 
291
                                },
 
292
                        },
 
293
                        resolveError{state.ResolvedNoHooks},
 
294
                        waitUnitAgent{
 
295
                                statusGetter: unitStatusGetter,
 
296
                                status:       params.StatusError,
 
297
                                info:         `hook failed: "config-changed"`,
246
298
                                data: map[string]interface{}{
247
299
                                        "hook": "config-changed",
248
300
                                },
249
301
                        },
250
302
                        resolveError{state.ResolvedNoHooks},
251
 
                        waitUnit{
252
 
                                status: params.StatusError,
253
 
                                info:   `hook failed: "start"`,
 
303
                        waitUnitAgent{
 
304
                                statusGetter: unitStatusGetter,
 
305
                                status:       params.StatusError,
 
306
                                info:         `hook failed: "start"`,
254
307
                                data: map[string]interface{}{
255
308
                                        "hook": "start",
256
309
                                },
271
324
                        // from advancing at all if we didn't fix it.
272
325
                        fixHook{"config-changed"},
273
326
                        resolveError{state.ResolvedNoHooks},
274
 
                        waitUnit{
275
 
                                status: params.StatusActive,
 
327
                        waitUnitAgent{
 
328
                                status: params.StatusIdle,
 
329
                        },
 
330
                        waitUnitAgent{
 
331
                                statusGetter: unitStatusGetter,
 
332
                                status:       params.StatusUnknown,
276
333
                        },
277
334
                        waitHooks{"start", "config-changed"},
278
335
                        // If we'd accidentally retried that hook, somehow, we would get
285
342
                        verifyWaiting{},
286
343
 
287
344
                        resolveError{state.ResolvedRetryHooks},
288
 
                        waitUnit{
289
 
                                status: params.StatusError,
290
 
                                info:   `hook failed: "config-changed"`,
 
345
                        waitUnitAgent{
 
346
                                statusGetter: unitStatusGetter,
 
347
                                status:       params.StatusError,
 
348
                                info:         `hook failed: "config-changed"`,
291
349
                                data: map[string]interface{}{
292
350
                                        "hook": "config-changed",
293
351
                                },
297
355
 
298
356
                        fixHook{"config-changed"},
299
357
                        resolveError{state.ResolvedRetryHooks},
300
 
                        waitUnit{
301
 
                                status: params.StatusActive,
 
358
                        waitUnitAgent{
 
359
                                status: params.StatusIdle,
302
360
                        },
303
361
                        waitHooks{"config-changed", "start"},
304
362
                        verifyRunning{},
306
364
                        "steady state config change with config-get verification",
307
365
                        createCharm{
308
366
                                customize: func(c *gc.C, ctx *context, path string) {
309
 
                                        appendHook(c, path, "config-changed", "config-get --format yaml --output config.out")
 
367
                                        appendHook(c, path, "config-changed", appendConfigChanged)
310
368
                                },
311
369
                        },
312
370
                        serveCharm{},
313
371
                        createUniter{},
314
 
                        waitUnit{
315
 
                                status: params.StatusActive,
 
372
                        waitUnitAgent{
 
373
                                status: params.StatusIdle,
316
374
                        },
317
 
                        waitHooks{"install", "config-changed", "start"},
 
375
                        waitHooks{"install", "leader-elected", "config-changed", "start"},
318
376
                        assertYaml{"charm/config.out", map[string]interface{}{
319
377
                                "blog-title": "My Title",
320
378
                        }},
356
414
                        waitHooks{},
357
415
                        verifyHookSyncLockLocked,
358
416
                        releaseHookSyncLock,
359
 
                        waitUnit{status: params.StatusActive},
360
 
                        waitHooks{"install", "config-changed", "start"},
 
417
                        waitUnitAgent{status: params.StatusIdle},
 
418
                        waitHooks{"install", "leader-elected", "config-changed", "start"},
361
419
                ),
362
420
        })
363
421
}
419
477
                        quickStart{},
420
478
                        createCharm{revision: 1},
421
479
                        upgradeCharm{revision: 1},
422
 
                        waitUnit{
423
 
                                status: params.StatusActive,
 
480
                        waitUnitAgent{
 
481
                                status: params.StatusIdle,
424
482
                                charm:  1,
425
483
                        },
 
484
                        waitUnitAgent{
 
485
                                statusGetter: unitStatusGetter,
 
486
                                status:       params.StatusUnknown,
 
487
                                charm:        1,
 
488
                        },
426
489
                        waitHooks{"upgrade-charm", "config-changed"},
427
490
                        verifyCharm{revision: 1},
428
491
                        verifyRunning{},
431
494
                        quickStart{},
432
495
                        createCharm{revision: 1},
433
496
                        upgradeCharm{revision: 1, forced: true},
434
 
                        waitUnit{
435
 
                                status: params.StatusActive,
 
497
                        waitUnitAgent{
 
498
                                status: params.StatusIdle,
436
499
                                charm:  1,
437
500
                        },
 
501
                        waitUnitAgent{
 
502
                                statusGetter: unitStatusGetter,
 
503
                                status:       params.StatusUnknown,
 
504
                                charm:        1,
 
505
                        },
438
506
                        waitHooks{"upgrade-charm", "config-changed"},
439
507
                        verifyCharm{revision: 1},
440
508
                        verifyRunning{},
443
511
                        quickStart{},
444
512
                        createCharm{revision: 1, badHooks: []string{"upgrade-charm"}},
445
513
                        upgradeCharm{revision: 1},
446
 
                        waitUnit{
447
 
                                status: params.StatusError,
448
 
                                info:   `hook failed: "upgrade-charm"`,
 
514
                        waitUnitAgent{
 
515
                                statusGetter: unitStatusGetter,
 
516
                                status:       params.StatusError,
 
517
                                info:         `hook failed: "upgrade-charm"`,
449
518
                                data: map[string]interface{}{
450
519
                                        "hook": "upgrade-charm",
451
520
                                },
456
525
                        verifyWaiting{},
457
526
 
458
527
                        resolveError{state.ResolvedNoHooks},
459
 
                        waitUnit{
460
 
                                status: params.StatusActive,
 
528
                        waitUnitAgent{
 
529
                                status: params.StatusIdle,
461
530
                                charm:  1,
462
531
                        },
 
532
                        waitUnitAgent{
 
533
                                statusGetter: unitStatusGetter,
 
534
                                status:       params.StatusUnknown,
 
535
                                charm:        1,
 
536
                        },
463
537
                        waitHooks{"config-changed"},
464
538
                        verifyRunning{},
465
539
                ), ut(
467
541
                        quickStart{},
468
542
                        createCharm{revision: 1, badHooks: []string{"upgrade-charm"}},
469
543
                        upgradeCharm{revision: 1},
470
 
                        waitUnit{
471
 
                                status: params.StatusError,
472
 
                                info:   `hook failed: "upgrade-charm"`,
 
544
                        waitUnitAgent{
 
545
                                statusGetter: unitStatusGetter,
 
546
                                status:       params.StatusError,
 
547
                                info:         `hook failed: "upgrade-charm"`,
473
548
                                data: map[string]interface{}{
474
549
                                        "hook": "upgrade-charm",
475
550
                                },
480
555
                        verifyWaiting{},
481
556
 
482
557
                        resolveError{state.ResolvedRetryHooks},
483
 
                        waitUnit{
484
 
                                status: params.StatusError,
485
 
                                info:   `hook failed: "upgrade-charm"`,
 
558
                        waitUnitAgent{
 
559
                                statusGetter: unitStatusGetter,
 
560
                                status:       params.StatusError,
 
561
                                info:         `hook failed: "upgrade-charm"`,
486
562
                                data: map[string]interface{}{
487
563
                                        "hook": "upgrade-charm",
488
564
                                },
493
569
 
494
570
                        fixHook{"upgrade-charm"},
495
571
                        resolveError{state.ResolvedRetryHooks},
496
 
                        waitUnit{
497
 
                                status: params.StatusActive,
 
572
                        waitUnitAgent{
 
573
                                status: params.StatusIdle,
498
574
                                charm:  1,
499
575
                        },
500
576
                        waitHooks{"upgrade-charm", "config-changed"},
525
601
}
526
602
 
527
603
func (s *UniterSuite) TestUniterUpgradeOverwrite(c *gc.C) {
 
604
        //TODO(bogdanteleaga): Fix this on windows
 
605
        if runtime.GOOS == "windows" {
 
606
                c.Skip("bug 1403084: currently does not work on windows")
 
607
        }
528
608
        makeTest := func(description string, content, extraChecks ft.Entries) uniterTest {
529
609
                return ut(description,
530
610
                        createCharm{
543
623
                        },
544
624
                        serveCharm{},
545
625
                        createUniter{},
546
 
                        waitUnit{
547
 
                                status: params.StatusActive,
548
 
                        },
549
 
                        waitHooks{"install", "config-changed", "start"},
 
626
                        waitUnitAgent{
 
627
                                status: params.StatusIdle,
 
628
                        },
 
629
                        waitUnitAgent{
 
630
                                statusGetter: unitStatusGetter,
 
631
                                status:       params.StatusUnknown,
 
632
                        },
 
633
                        waitHooks{"install", "leader-elected", "config-changed", "start"},
550
634
 
551
635
                        createCharm{
552
636
                                revision: 1,
556
640
                        },
557
641
                        serveCharm{},
558
642
                        upgradeCharm{revision: 1},
559
 
                        waitUnit{
560
 
                                status: params.StatusActive,
 
643
                        waitUnitAgent{
 
644
                                status: params.StatusIdle,
561
645
                                charm:  1,
562
646
                        },
 
647
                        waitUnitAgent{
 
648
                                statusGetter: unitStatusGetter,
 
649
                                status:       params.StatusUnknown,
 
650
                                charm:        1,
 
651
                        },
563
652
                        waitHooks{"upgrade-charm", "config-changed"},
564
653
                        verifyCharm{revision: 1},
565
654
                        custom{func(c *gc.C, ctx *context) {
615
704
                        startupError{"start"},
616
705
                        createCharm{revision: 1},
617
706
                        upgradeCharm{revision: 1},
618
 
                        waitUnit{
619
 
                                status: params.StatusError,
620
 
                                info:   `hook failed: "start"`,
 
707
                        waitUnitAgent{
 
708
                                statusGetter: unitStatusGetter,
 
709
                                status:       params.StatusError,
 
710
                                info:         `hook failed: "start"`,
621
711
                                data: map[string]interface{}{
622
712
                                        "hook": "start",
623
713
                                },
627
717
                        verifyWaiting{},
628
718
 
629
719
                        resolveError{state.ResolvedNoHooks},
630
 
                        waitUnit{
631
 
                                status: params.StatusActive,
 
720
                        waitUnitAgent{
 
721
                                status: params.StatusIdle,
632
722
                                charm:  1,
633
723
                        },
 
724
                        waitUnitAgent{
 
725
                                statusGetter: unitStatusGetter,
 
726
                                status:       params.StatusMaintenance,
 
727
                                info:         "installing charm software",
 
728
                                charm:        1,
 
729
                        },
634
730
                        waitHooks{"config-changed", "upgrade-charm", "config-changed"},
635
731
                        verifyCharm{revision: 1},
636
732
                        verifyRunning{},
644
740
                        // process's point of no return (before actually deploying, but after
645
741
                        // the charm has been downloaded and verified). However, it's still
646
742
                        // useful to wait until that point...
647
 
                        waitUnit{
648
 
                                status: params.StatusError,
649
 
                                info:   `hook failed: "start"`,
 
743
                        waitUnitAgent{
 
744
                                statusGetter: unitStatusGetter,
 
745
                                status:       params.StatusError,
 
746
                                info:         `hook failed: "start"`,
650
747
                                data: map[string]interface{}{
651
748
                                        "hook": "start",
652
749
                                },
660
757
                        verifyCharm{revision: 1},
661
758
 
662
759
                        resolveError{state.ResolvedNoHooks},
663
 
                        waitUnit{
664
 
                                status: params.StatusActive,
 
760
                        waitUnitAgent{
 
761
                                status: params.StatusIdle,
665
762
                                charm:  1,
666
763
                        },
667
764
                        waitHooks{"config-changed"},
671
768
}
672
769
 
673
770
func (s *UniterSuite) TestUniterDeployerConversion(c *gc.C) {
 
771
        coretesting.SkipIfGitNotAvailable(c)
 
772
 
674
773
        deployerConversionTests := []uniterTest{
675
774
                ut(
676
775
                        "install normally, check not using git",
695
794
                        createCharm{revision: 1},
696
795
                        upgradeCharm{revision: 1},
697
796
                        waitHooks{"upgrade-charm", "config-changed"},
698
 
                        waitUnit{
699
 
                                status: params.StatusActive,
 
797
                        waitUnitAgent{
 
798
                                status: params.StatusIdle,
700
799
                                charm:  1,
701
800
                        },
 
801
                        waitUnitAgent{
 
802
                                statusGetter: unitStatusGetter,
 
803
                                status:       params.StatusUnknown,
 
804
                                charm:        1,
 
805
                        },
702
806
                        verifyCharm{
703
807
                                revision:   1,
704
808
                                checkFiles: ft.Entries{ft.Removed{".git"}},
714
818
 
715
819
                        resolveError{state.ResolvedNoHooks},
716
820
                        waitHooks{"upgrade-charm", "config-changed"},
717
 
                        waitUnit{
718
 
                                status: params.StatusActive,
 
821
                        waitUnitAgent{
 
822
                                status: params.StatusIdle,
719
823
                                charm:  1,
720
824
                        },
 
825
                        waitUnitAgent{
 
826
                                statusGetter: unitStatusGetter,
 
827
                                status:       params.StatusUnknown,
 
828
                                charm:        1,
 
829
                        },
721
830
                        verifyCharm{revision: 1},
722
831
                        verifyRunning{},
723
832
 
728
837
                        createCharm{revision: 2},
729
838
                        upgradeCharm{revision: 2},
730
839
                        waitHooks{"upgrade-charm", "config-changed"},
731
 
                        waitUnit{
732
 
                                status: params.StatusActive,
 
840
                        waitUnitAgent{
 
841
                                status: params.StatusIdle,
733
842
                                charm:  2,
734
843
                        },
 
844
                        waitUnitAgent{
 
845
                                statusGetter: unitStatusGetter,
 
846
                                status:       params.StatusUnknown,
 
847
                                charm:        2,
 
848
                        },
735
849
                        verifyCharm{
736
850
                                revision:   2,
737
851
                                checkFiles: ft.Entries{ft.Removed{".git"}},
754
868
                        serveCharm{},
755
869
                        upgradeCharm{revision: 2, forced: true},
756
870
                        waitHooks{"upgrade-charm", "config-changed"},
757
 
                        waitUnit{
758
 
                                status: params.StatusActive,
 
871
                        waitUnitAgent{
 
872
                                status: params.StatusIdle,
759
873
                                charm:  2,
760
874
                        },
761
875
 
775
889
}
776
890
 
777
891
func (s *UniterSuite) TestUniterUpgradeConflicts(c *gc.C) {
 
892
        coretesting.SkipIfPPC64EL(c, "lp:1448308")
 
893
        coretesting.SkipIfI386(c, "lp:1442149")
 
894
        //TODO(bogdanteleaga): Fix this on windows
 
895
        if runtime.GOOS == "windows" {
 
896
                c.Skip("bug 1403084: currently does not work on windows")
 
897
        }
778
898
        s.runUniterTests(c, []uniterTest{
779
899
                // Upgrade scenarios - handling conflicts.
780
900
                ut(
785
905
                        fixUpgradeError{},
786
906
                        resolveError{state.ResolvedNoHooks},
787
907
                        waitHooks{"upgrade-charm", "config-changed"},
788
 
                        waitUnit{
789
 
                                status: params.StatusActive,
 
908
                        waitUnitAgent{
 
909
                                status: params.StatusIdle,
790
910
                                charm:  1,
791
911
                        },
 
912
                        waitUnitAgent{
 
913
                                statusGetter: unitStatusGetter,
 
914
                                status:       params.StatusUnknown,
 
915
                                charm:        1,
 
916
                        },
792
917
                        verifyCharm{revision: 1},
793
918
                ), ut(
794
919
                        `upgrade: forced upgrade does work without explicit resolution if underlying problem was fixed`,
800
925
                        serveCharm{},
801
926
                        upgradeCharm{revision: 2, forced: true},
802
927
                        waitHooks{"upgrade-charm", "config-changed"},
803
 
                        waitUnit{
804
 
                                status: params.StatusActive,
 
928
                        waitUnitAgent{
 
929
                                status: params.StatusIdle,
805
930
                                charm:  2,
806
931
                        },
 
932
                        waitUnitAgent{
 
933
                                statusGetter: unitStatusGetter,
 
934
                                status:       params.StatusUnknown,
 
935
                                charm:        2,
 
936
                        },
807
937
                        verifyCharm{revision: 2},
808
938
                ), ut(
809
939
                        "upgrade conflict service dying",
835
965
}
836
966
 
837
967
func (s *UniterSuite) TestUniterUpgradeGitConflicts(c *gc.C) {
 
968
        coretesting.SkipIfGitNotAvailable(c)
 
969
 
838
970
        // These tests are copies of the old git-deployer-related tests, to test that
839
971
        // the uniter with the manifest-deployer work patched out still works how it
840
972
        // used to; thus demonstrating that the *other* tests that verify manifest
855
987
                        // we have to take their word for it.
856
988
                        resolveError{state.ResolvedNoHooks},
857
989
                        waitHooks{"upgrade-charm", "config-changed"},
858
 
                        waitUnit{
859
 
                                status: params.StatusActive,
 
990
                        waitUnitAgent{
 
991
                                status: params.StatusIdle,
860
992
                                charm:  1,
861
993
                        },
 
994
                        waitUnitAgent{
 
995
                                statusGetter: unitStatusGetter,
 
996
                                status:       params.StatusUnknown,
 
997
                                charm:        1,
 
998
                        },
862
999
                        verifyGitCharm{revision: 1},
863
1000
                ), ugt(
864
1001
                        `upgrade: conflicting directories`,
871
1008
                        },
872
1009
                        serveCharm{},
873
1010
                        createUniter{},
874
 
                        waitUnit{
875
 
                                status: params.StatusActive,
876
 
                        },
877
 
                        waitHooks{"install", "config-changed", "start"},
 
1011
                        waitUnitAgent{
 
1012
                                status: params.StatusIdle,
 
1013
                        },
 
1014
                        waitUnitAgent{
 
1015
                                statusGetter: unitStatusGetter,
 
1016
                                status:       params.StatusUnknown,
 
1017
                        },
 
1018
                        waitHooks{"install", "leader-elected", "config-changed", "start"},
878
1019
                        verifyGitCharm{dirty: true},
879
1020
 
880
1021
                        createCharm{
887
1028
                        },
888
1029
                        serveCharm{},
889
1030
                        upgradeCharm{revision: 1},
890
 
                        waitUnit{
891
 
                                status: params.StatusError,
892
 
                                info:   "upgrade failed",
893
 
                                charm:  1,
 
1031
                        waitUnitAgent{
 
1032
                                statusGetter: unitStatusGetter,
 
1033
                                status:       params.StatusError,
 
1034
                                info:         "upgrade failed",
 
1035
                                charm:        1,
894
1036
                        },
895
1037
                        verifyWaiting{},
896
1038
                        verifyGitCharm{dirty: true},
897
1039
 
898
1040
                        resolveError{state.ResolvedNoHooks},
899
1041
                        waitHooks{"upgrade-charm", "config-changed"},
900
 
                        waitUnit{
901
 
                                status: params.StatusActive,
 
1042
                        waitUnitAgent{
 
1043
                                status: params.StatusIdle,
902
1044
                                charm:  1,
903
1045
                        },
904
1046
                        verifyGitCharm{revision: 1},
915
1057
                        },
916
1058
                        serveCharm{},
917
1059
                        upgradeCharm{revision: 2, forced: true},
918
 
                        waitUnit{
919
 
                                status: params.StatusActive,
 
1060
                        waitUnitAgent{
 
1061
                                status: params.StatusIdle,
920
1062
                                charm:  2,
 
1063
                        }, waitUnitAgent{
 
1064
                                statusGetter: unitStatusGetter,
 
1065
                                status:       params.StatusUnknown,
 
1066
                                charm:        2,
921
1067
                        },
922
1068
                        waitHooks{"upgrade-charm", "config-changed"},
923
1069
                        verifyGitCharm{revision: 2},
962
1108
        })
963
1109
}
964
1110
 
965
 
func (s *UniterSuite) TestRunCommand(c *gc.C) {
966
 
        testDir := c.MkDir()
967
 
        testFile := func(name string) string {
968
 
                return filepath.Join(testDir, name)
969
 
        }
970
 
        echoUnitNameToFile := func(name string) string {
971
 
                path := filepath.Join(testDir, name)
972
 
                template := "echo juju run ${JUJU_UNIT_NAME} > %s.tmp; mv %s.tmp %s"
973
 
                return fmt.Sprintf(template, path, path, path)
974
 
        }
975
 
        adminTag := s.AdminUserTag(c)
976
 
 
977
 
        s.runUniterTests(c, []uniterTest{
978
 
                ut(
979
 
                        "run commands: environment",
980
 
                        quickStart{},
981
 
                        runCommands{echoUnitNameToFile("run.output")},
982
 
                        verifyFile{filepath.Join(testDir, "run.output"), "juju run u/0\n"},
983
 
                ), ut(
984
 
                        "run commands: jujuc commands",
985
 
                        quickStartRelation{},
986
 
                        runCommands{
987
 
                                fmt.Sprintf("owner-get tag > %s", testFile("jujuc.output")),
988
 
                                fmt.Sprintf("unit-get private-address >> %s", testFile("jujuc.output")),
989
 
                                fmt.Sprintf("unit-get public-address >> %s", testFile("jujuc.output")),
990
 
                        },
991
 
                        verifyFile{
992
 
                                testFile("jujuc.output"),
993
 
                                adminTag.String() + "\nprivate.address.example.com\npublic.address.example.com\n",
994
 
                        },
995
 
                ), ut(
996
 
                        "run commands: jujuc environment",
997
 
                        quickStartRelation{},
998
 
                        relationRunCommands{
999
 
                                fmt.Sprintf("echo $JUJU_RELATION_ID > %s", testFile("jujuc-env.output")),
1000
 
                                fmt.Sprintf("echo $JUJU_REMOTE_UNIT >> %s", testFile("jujuc-env.output")),
1001
 
                        },
1002
 
                        verifyFile{
1003
 
                                testFile("jujuc-env.output"),
1004
 
                                "db:0\nmysql/0\n",
1005
 
                        },
1006
 
                ), ut(
1007
 
                        "run commands: proxy settings set",
1008
 
                        quickStartRelation{},
1009
 
                        setProxySettings{Http: "http", Https: "https", Ftp: "ftp", NoProxy: "localhost"},
1010
 
                        runCommands{
1011
 
                                fmt.Sprintf("echo $http_proxy > %s", testFile("proxy.output")),
1012
 
                                fmt.Sprintf("echo $HTTP_PROXY >> %s", testFile("proxy.output")),
1013
 
                                fmt.Sprintf("echo $https_proxy >> %s", testFile("proxy.output")),
1014
 
                                fmt.Sprintf("echo $HTTPS_PROXY >> %s", testFile("proxy.output")),
1015
 
                                fmt.Sprintf("echo $ftp_proxy >> %s", testFile("proxy.output")),
1016
 
                                fmt.Sprintf("echo $FTP_PROXY >> %s", testFile("proxy.output")),
1017
 
                                fmt.Sprintf("echo $no_proxy >> %s", testFile("proxy.output")),
1018
 
                                fmt.Sprintf("echo $NO_PROXY >> %s", testFile("proxy.output")),
1019
 
                        },
1020
 
                        verifyFile{
1021
 
                                testFile("proxy.output"),
1022
 
                                "http\nhttp\nhttps\nhttps\nftp\nftp\nlocalhost\nlocalhost\n",
1023
 
                        },
1024
 
                ), ut(
1025
 
                        "run commands: async using rpc client",
1026
 
                        quickStart{},
1027
 
                        asyncRunCommands{echoUnitNameToFile("run.output")},
1028
 
                        verifyFile{testFile("run.output"), "juju run u/0\n"},
1029
 
                ), ut(
1030
 
                        "run commands: waits for lock",
1031
 
                        quickStart{},
1032
 
                        acquireHookSyncLock{},
1033
 
                        asyncRunCommands{echoUnitNameToFile("wait.output")},
1034
 
                        verifyNoFile{testFile("wait.output")},
1035
 
                        releaseHookSyncLock,
1036
 
                        verifyFile{testFile("wait.output"), "juju run u/0\n"},
1037
 
                ),
1038
 
        })
1039
 
}
1040
 
 
1041
1111
func (s *UniterSuite) TestUniterRelations(c *gc.C) {
 
1112
        waitDyingHooks := custom{func(c *gc.C, ctx *context) {
 
1113
                // There is no ordering relationship between relation hooks and
 
1114
                // leader-settings-changed hooks; and while we're dying we may
 
1115
                // never get to leader-settings-changed before it's time to run
 
1116
                // the stop (as we might not react to a config change in time).
 
1117
                // It's actually clearer to just list the possible orders:
 
1118
                possibles := [][]string{{
 
1119
                        "leader-settings-changed",
 
1120
                        "db-relation-departed mysql/0 db:0",
 
1121
                        "db-relation-broken db:0",
 
1122
                        "stop",
 
1123
                }, {
 
1124
                        "db-relation-departed mysql/0 db:0",
 
1125
                        "leader-settings-changed",
 
1126
                        "db-relation-broken db:0",
 
1127
                        "stop",
 
1128
                }, {
 
1129
                        "db-relation-departed mysql/0 db:0",
 
1130
                        "db-relation-broken db:0",
 
1131
                        "leader-settings-changed",
 
1132
                        "stop",
 
1133
                }, {
 
1134
                        "db-relation-departed mysql/0 db:0",
 
1135
                        "db-relation-broken db:0",
 
1136
                        "stop",
 
1137
                }}
 
1138
                unchecked := ctx.hooksCompleted[len(ctx.hooks):]
 
1139
                for _, possible := range possibles {
 
1140
                        if ok, _ := jc.DeepEqual(unchecked, possible); ok {
 
1141
                                return
 
1142
                        }
 
1143
                }
 
1144
                c.Fatalf("unexpected hooks: %v", unchecked)
 
1145
        }}
1042
1146
        s.runUniterTests(c, []uniterTest{
1043
1147
                // Relations.
1044
1148
                ut(
1045
1149
                        "simple joined/changed/departed",
1046
1150
                        quickStartRelation{},
1047
1151
                        addRelationUnit{},
1048
 
                        waitHooks{"db-relation-joined mysql/1 db:0", "db-relation-changed mysql/1 db:0"},
 
1152
                        waitHooks{
 
1153
                                "db-relation-joined mysql/1 db:0",
 
1154
                                "db-relation-changed mysql/1 db:0",
 
1155
                        },
1049
1156
                        changeRelationUnit{"mysql/0"},
1050
1157
                        waitHooks{"db-relation-changed mysql/0 db:0"},
1051
1158
                        removeRelationUnit{"mysql/1"},
1055
1162
                        "relation becomes dying; unit is not last remaining member",
1056
1163
                        quickStartRelation{},
1057
1164
                        relationDying,
1058
 
                        waitHooks{"db-relation-departed mysql/0 db:0", "db-relation-broken db:0"},
 
1165
                        waitHooks{
 
1166
                                "db-relation-departed mysql/0 db:0",
 
1167
                                "db-relation-broken db:0",
 
1168
                        },
1059
1169
                        verifyRunning{},
1060
1170
                        relationState{life: state.Dying},
1061
1171
                        removeRelationUnit{"mysql/0"},
1076
1186
                        "service becomes dying while in a relation",
1077
1187
                        quickStartRelation{},
1078
1188
                        serviceDying,
1079
 
                        waitHooks{"db-relation-departed mysql/0 db:0", "db-relation-broken db:0", "stop"},
1080
1189
                        waitUniterDead{},
 
1190
                        waitDyingHooks,
1081
1191
                        relationState{life: state.Dying},
1082
1192
                        removeRelationUnit{"mysql/0"},
1083
1193
                        relationState{removed: true},
1085
1195
                        "unit becomes dying while in a relation",
1086
1196
                        quickStartRelation{},
1087
1197
                        unitDying,
1088
 
                        waitHooks{"db-relation-departed mysql/0 db:0", "db-relation-broken db:0", "stop"},
1089
1198
                        waitUniterDead{},
 
1199
                        waitDyingHooks,
1090
1200
                        relationState{life: state.Alive},
1091
1201
                        removeRelationUnit{"mysql/0"},
1092
1202
                        relationState{life: state.Alive},
1117
1227
                        "all relations are available to config-changed on bounce, even if state dir is missing",
1118
1228
                        createCharm{
1119
1229
                                customize: func(c *gc.C, ctx *context, path string) {
1120
 
                                        script := "relation-ids db > relations.out && chmod 644 relations.out"
 
1230
                                        script := uniterRelationsCustomizeScript
1121
1231
                                        appendHook(c, path, "config-changed", script)
1122
1232
                                },
1123
1233
                        },
1124
1234
                        serveCharm{},
1125
1235
                        createUniter{},
1126
 
                        waitUnit{
1127
 
                                status: params.StatusActive,
1128
 
                        },
1129
 
                        waitHooks{"install", "config-changed", "start"},
 
1236
                        waitUnitAgent{
 
1237
                                status: params.StatusIdle,
 
1238
                        },
 
1239
                        waitUnitAgent{
 
1240
                                statusGetter: unitStatusGetter,
 
1241
                                status:       params.StatusUnknown,
 
1242
                        },
 
1243
                        waitHooks{"install", "leader-elected", "config-changed", "start"},
1130
1244
                        addRelation{waitJoin: true},
1131
1245
                        stopUniter{},
1132
1246
                        custom{func(c *gc.C, ctx *context) {
1159
1273
                ut(
1160
1274
                        "hook error during join of a relation",
1161
1275
                        startupRelationError{"db-relation-joined"},
1162
 
                        waitUnit{
1163
 
                                status: params.StatusError,
1164
 
                                info:   `hook failed: "db-relation-joined"`,
 
1276
                        waitUnitAgent{
 
1277
                                statusGetter: unitStatusGetter,
 
1278
                                status:       params.StatusError,
 
1279
                                info:         `hook failed: "db-relation-joined"`,
1165
1280
                                data: map[string]interface{}{
1166
1281
                                        "hook":        "db-relation-joined",
1167
1282
                                        "relation-id": 0,
1171
1286
                ), ut(
1172
1287
                        "hook error during change of a relation",
1173
1288
                        startupRelationError{"db-relation-changed"},
1174
 
                        waitUnit{
1175
 
                                status: params.StatusError,
1176
 
                                info:   `hook failed: "db-relation-changed"`,
 
1289
                        waitUnitAgent{
 
1290
                                statusGetter: unitStatusGetter,
 
1291
                                status:       params.StatusError,
 
1292
                                info:         `hook failed: "db-relation-changed"`,
1177
1293
                                data: map[string]interface{}{
1178
1294
                                        "hook":        "db-relation-changed",
1179
1295
                                        "relation-id": 0,
1185
1301
                        startupRelationError{"db-relation-departed"},
1186
1302
                        waitHooks{"db-relation-joined mysql/0 db:0", "db-relation-changed mysql/0 db:0"},
1187
1303
                        removeRelationUnit{"mysql/0"},
1188
 
                        waitUnit{
1189
 
                                status: params.StatusError,
1190
 
                                info:   `hook failed: "db-relation-departed"`,
 
1304
                        waitUnitAgent{
 
1305
                                statusGetter: unitStatusGetter,
 
1306
                                status:       params.StatusError,
 
1307
                                info:         `hook failed: "db-relation-departed"`,
1191
1308
                                data: map[string]interface{}{
1192
1309
                                        "hook":        "db-relation-departed",
1193
1310
                                        "relation-id": 0,
1200
1317
                        startupRelationError{"db-relation-broken"},
1201
1318
                        waitHooks{"db-relation-joined mysql/0 db:0", "db-relation-changed mysql/0 db:0"},
1202
1319
                        relationDying,
1203
 
                        waitUnit{
1204
 
                                status: params.StatusError,
1205
 
                                info:   `hook failed: "db-relation-broken"`,
 
1320
                        waitUnitAgent{
 
1321
                                statusGetter: unitStatusGetter,
 
1322
                                status:       params.StatusError,
 
1323
                                info:         `hook failed: "db-relation-broken"`,
1206
1324
                                data: map[string]interface{}{
1207
1325
                                        "hook":        "db-relation-broken",
1208
1326
                                        "relation-id": 0,
1234
1352
                        },
1235
1353
                        serveCharm{},
1236
1354
                        createUniter{},
1237
 
                        waitUnit{status: params.StatusActive},
1238
 
                        waitHooks{"install", "config-changed", "start"},
 
1355
                        waitUnitAgent{status: params.StatusIdle},
 
1356
                        waitUnitAgent{
 
1357
                                statusGetter: unitStatusGetter,
 
1358
                                status:       params.StatusUnknown,
 
1359
                        },
 
1360
                        waitHooks{"install", "leader-elected", "config-changed", "start"},
1239
1361
                        verifyCharm{},
1240
1362
                        metricsTick{},
1241
1363
                        waitHooks{"collect-metrics"},
1251
1373
                        metricsTick{},
1252
1374
                        fixHook{"config-changed"},
1253
1375
                        resolveError{state.ResolvedRetryHooks},
1254
 
                        waitUnit{
1255
 
                                status: params.StatusActive,
 
1376
                        waitUnitAgent{
 
1377
                                status: params.StatusIdle,
 
1378
                        },
 
1379
                        waitUnitAgent{
 
1380
                                statusGetter: unitStatusGetter,
 
1381
                                status:       params.StatusUnknown,
1256
1382
                        },
1257
1383
                        waitHooks{"config-changed", "start", "collect-metrics"},
1258
1384
                        verifyRunning{},
1270
1396
                        stopUniter{},
1271
1397
                        startUniter{},
1272
1398
                        resolveError{state.ResolvedRetryHooks},
1273
 
                        waitUnit{
1274
 
                                status: params.StatusActive,
 
1399
                        waitUnitAgent{
 
1400
                                status: params.StatusIdle,
 
1401
                        },
 
1402
                        waitUnitAgent{
 
1403
                                statusGetter: unitStatusGetter,
 
1404
                                status:       params.StatusUnknown,
1275
1405
                        },
1276
1406
                        waitHooks{"config-changed", "start", "collect-metrics"},
1277
1407
                        verifyRunning{},
1300
1430
                        createServiceAndUnit{},
1301
1431
                        startUniter{},
1302
1432
                        waitAddresses{},
1303
 
                        waitUnit{status: params.StatusActive},
1304
 
                        waitHooks{"install", "config-changed", "start"},
 
1433
                        waitUnitAgent{status: params.StatusIdle},
 
1434
                        waitUnitAgent{
 
1435
                                statusGetter: unitStatusGetter,
 
1436
                                status:       params.StatusUnknown,
 
1437
                        },
 
1438
                        waitHooks{"install", "leader-elected", "config-changed", "start"},
1305
1439
                        verifyCharm{},
1306
1440
                        addAction{"action-log", nil},
1307
1441
                        waitActionResults{[]actionResult{{
1309
1443
                                results: map[string]interface{}{},
1310
1444
                                status:  params.ActionCompleted,
1311
1445
                        }}},
1312
 
                        waitUnit{status: params.StatusActive},
 
1446
                        waitUnitAgent{status: params.StatusIdle},
 
1447
                        waitUnitAgent{
 
1448
                                statusGetter: unitStatusGetter,
 
1449
                                status:       params.StatusUnknown,
 
1450
                        },
1313
1451
                ), ut(
1314
1452
                        "action-fail causes the action to fail with a message",
1315
1453
                        createCharm{
1323
1461
                        createServiceAndUnit{},
1324
1462
                        startUniter{},
1325
1463
                        waitAddresses{},
1326
 
                        waitUnit{status: params.StatusActive},
1327
 
                        waitHooks{"install", "config-changed", "start"},
 
1464
                        waitUnitAgent{status: params.StatusIdle},
 
1465
                        waitUnitAgent{
 
1466
                                statusGetter: unitStatusGetter,
 
1467
                                status:       params.StatusUnknown,
 
1468
                        },
 
1469
                        waitHooks{"install", "leader-elected", "config-changed", "start"},
1328
1470
                        verifyCharm{},
1329
1471
                        addAction{"action-log-fail", nil},
1330
1472
                        waitActionResults{[]actionResult{{
1335
1477
                                message: "I'm afraid I can't let you do that, Dave.",
1336
1478
                                status:  params.ActionFailed,
1337
1479
                        }}},
1338
 
                        waitUnit{status: params.StatusActive},
 
1480
                        waitUnitAgent{status: params.StatusIdle}, waitUnitAgent{
 
1481
                                statusGetter: unitStatusGetter,
 
1482
                                status:       params.StatusUnknown,
 
1483
                        },
1339
1484
                ), ut(
1340
1485
                        "action-fail with the wrong arguments fails but is not an error",
1341
1486
                        createCharm{
1349
1494
                        createServiceAndUnit{},
1350
1495
                        startUniter{},
1351
1496
                        waitAddresses{},
1352
 
                        waitUnit{status: params.StatusActive},
1353
 
                        waitHooks{"install", "config-changed", "start"},
 
1497
                        waitUnitAgent{status: params.StatusIdle},
 
1498
                        waitUnitAgent{
 
1499
                                statusGetter: unitStatusGetter,
 
1500
                                status:       params.StatusUnknown,
 
1501
                        },
 
1502
                        waitHooks{"install", "leader-elected", "config-changed", "start"},
1354
1503
                        verifyCharm{},
1355
1504
                        addAction{"action-log-fail-error", nil},
1356
1505
                        waitActionResults{[]actionResult{{
1361
1510
                                message: "A real message",
1362
1511
                                status:  params.ActionFailed,
1363
1512
                        }}},
1364
 
                        waitUnit{status: params.StatusActive},
 
1513
                        waitUnitAgent{status: params.StatusIdle},
 
1514
                        waitUnitAgent{
 
1515
                                statusGetter: unitStatusGetter,
 
1516
                                status:       params.StatusUnknown,
 
1517
                        },
1365
1518
                ), ut(
1366
1519
                        "actions with correct params passed are not an error",
1367
1520
                        createCharm{
1375
1528
                        createServiceAndUnit{},
1376
1529
                        startUniter{},
1377
1530
                        waitAddresses{},
1378
 
                        waitUnit{status: params.StatusActive},
1379
 
                        waitHooks{"install", "config-changed", "start"},
 
1531
                        waitUnitAgent{status: params.StatusIdle},
 
1532
                        waitUnitAgent{
 
1533
                                statusGetter: unitStatusGetter,
 
1534
                                status:       params.StatusUnknown,
 
1535
                        },
 
1536
                        waitHooks{"install", "leader-elected", "config-changed", "start"},
1380
1537
                        verifyCharm{},
1381
1538
                        addAction{
1382
1539
                                name:   "snapshot",
1396
1553
                                },
1397
1554
                                status: params.ActionCompleted,
1398
1555
                        }}},
1399
 
                        waitUnit{status: params.StatusActive},
 
1556
                        waitUnitAgent{status: params.StatusIdle},
 
1557
                        waitUnitAgent{
 
1558
                                statusGetter: unitStatusGetter,
 
1559
                                status:       params.StatusUnknown,
 
1560
                        },
1400
1561
                ), ut(
1401
1562
                        "actions with incorrect params passed are not an error but fail",
1402
1563
                        createCharm{
1410
1571
                        createServiceAndUnit{},
1411
1572
                        startUniter{},
1412
1573
                        waitAddresses{},
1413
 
                        waitUnit{status: params.StatusActive},
1414
 
                        waitHooks{"install", "config-changed", "start"},
 
1574
                        waitUnitAgent{status: params.StatusIdle},
 
1575
                        waitUnitAgent{
 
1576
                                statusGetter: unitStatusGetter,
 
1577
                                status:       params.StatusUnknown,
 
1578
                        },
 
1579
                        waitHooks{"install", "leader-elected", "config-changed", "start"},
1415
1580
                        verifyCharm{},
1416
1581
                        addAction{
1417
1582
                                name:   "snapshot",
1421
1586
                                name:    "snapshot",
1422
1587
                                results: map[string]interface{}{},
1423
1588
                                status:  params.ActionFailed,
1424
 
                                message: `cannot run "snapshot" action: JSON validation failed: (root).outfile : must be of type string, given 2`,
 
1589
                                message: `cannot run "snapshot" action: validation failed: (root).outfile : must be of type string, given 2`,
1425
1590
                        }}},
1426
 
                        waitUnit{status: params.StatusActive},
 
1591
                        waitUnitAgent{status: params.StatusIdle},
 
1592
                        waitUnitAgent{
 
1593
                                statusGetter: unitStatusGetter,
 
1594
                                status:       params.StatusUnknown,
 
1595
                        },
1427
1596
                ), ut(
1428
1597
                        "actions not defined in actions.yaml fail without causing a uniter error",
1429
1598
                        createCharm{
1436
1605
                        createServiceAndUnit{},
1437
1606
                        startUniter{},
1438
1607
                        waitAddresses{},
1439
 
                        waitUnit{status: params.StatusActive},
1440
 
                        waitHooks{"install", "config-changed", "start"},
 
1608
                        waitUnitAgent{status: params.StatusIdle},
 
1609
                        waitUnitAgent{
 
1610
                                statusGetter: unitStatusGetter,
 
1611
                                status:       params.StatusUnknown,
 
1612
                        },
 
1613
                        waitHooks{"install", "leader-elected", "config-changed", "start"},
1441
1614
                        verifyCharm{},
1442
1615
                        addAction{"snapshot", map[string]interface{}{"outfile": "foo.bar"}},
1443
1616
                        waitActionResults{[]actionResult{{
1446
1619
                                status:  params.ActionFailed,
1447
1620
                                message: `cannot run "snapshot" action: not defined`,
1448
1621
                        }}},
1449
 
                        waitUnit{status: params.StatusActive},
 
1622
                        waitUnitAgent{status: params.StatusIdle},
 
1623
                        waitUnitAgent{
 
1624
                                statusGetter: unitStatusGetter,
 
1625
                                status:       params.StatusUnknown,
 
1626
                        },
1450
1627
                ), ut(
1451
1628
                        "pending actions get consumed",
1452
1629
                        createCharm{
1463
1640
                        addAction{"action-log", nil},
1464
1641
                        startUniter{},
1465
1642
                        waitAddresses{},
1466
 
                        waitUnit{status: params.StatusActive},
1467
 
                        waitHooks{"install", "config-changed", "start"},
 
1643
                        waitUnitAgent{status: params.StatusIdle},
 
1644
                        waitUnitAgent{
 
1645
                                statusGetter: unitStatusGetter,
 
1646
                                status:       params.StatusUnknown,
 
1647
                        },
 
1648
                        waitHooks{"install", "leader-elected", "config-changed", "start"},
1468
1649
                        verifyCharm{},
1469
1650
                        waitActionResults{[]actionResult{{
1470
1651
                                name:    "action-log",
1479
1660
                                results: map[string]interface{}{},
1480
1661
                                status:  params.ActionCompleted,
1481
1662
                        }}},
1482
 
                        waitUnit{status: params.StatusActive},
 
1663
                        waitUnitAgent{status: params.StatusIdle},
 
1664
                        waitUnitAgent{
 
1665
                                statusGetter: unitStatusGetter,
 
1666
                                status:       params.StatusUnknown,
 
1667
                        },
1483
1668
                ), ut(
1484
1669
                        "actions not implemented fail but are not errors",
1485
1670
                        createCharm{
1492
1677
                        createServiceAndUnit{},
1493
1678
                        startUniter{},
1494
1679
                        waitAddresses{},
1495
 
                        waitUnit{status: params.StatusActive},
1496
 
                        waitHooks{"install", "config-changed", "start"},
 
1680
                        waitUnitAgent{status: params.StatusIdle},
 
1681
                        waitUnitAgent{
 
1682
                                statusGetter: unitStatusGetter,
 
1683
                                status:       params.StatusUnknown,
 
1684
                        },
 
1685
                        waitHooks{"install", "leader-elected", "config-changed", "start"},
1497
1686
                        verifyCharm{},
1498
1687
                        addAction{"action-log", nil},
1499
1688
                        waitActionResults{[]actionResult{{
1502
1691
                                status:  params.ActionFailed,
1503
1692
                                message: `action not implemented on unit "u/0"`,
1504
1693
                        }}},
1505
 
                        waitUnit{status: params.StatusActive},
 
1694
                        waitUnitAgent{status: params.StatusIdle},
 
1695
                        waitUnitAgent{
 
1696
                                statusGetter: unitStatusGetter,
 
1697
                                status:       params.StatusUnknown,
 
1698
                        },
1506
1699
                ), ut(
1507
 
                        "actions are not attempted from ModeHookError and do not clear the error",
 
1700
                        "actions may run from ModeHookError, but do not clear the error",
1508
1701
                        startupErrorWithCustomCharm{
1509
1702
                                badHook: "start",
1510
1703
                                customize: func(c *gc.C, ctx *context, path string) {
1513
1706
                                },
1514
1707
                        },
1515
1708
                        addAction{"action-log", nil},
1516
 
                        waitUnit{
1517
 
                                status: params.StatusError,
1518
 
                                info:   `hook failed: "start"`,
 
1709
                        waitUnitAgent{
 
1710
                                statusGetter: unitStatusGetter,
 
1711
                                status:       params.StatusError,
 
1712
                                info:         `hook failed: "start"`,
1519
1713
                                data: map[string]interface{}{
1520
1714
                                        "hook": "start",
1521
1715
                                },
1522
1716
                        },
1523
 
                        verifyNoActionResults{},
1524
 
                        verifyWaiting{},
1525
 
                        resolveError{state.ResolvedNoHooks},
1526
 
                        waitUnit{status: params.StatusActive},
1527
1717
                        waitActionResults{[]actionResult{{
1528
1718
                                name:    "action-log",
1529
1719
                                results: map[string]interface{}{},
1530
1720
                                status:  params.ActionCompleted,
1531
1721
                        }}},
1532
 
                        waitUnit{status: params.StatusActive},
 
1722
                        waitUnitAgent{
 
1723
                                statusGetter: unitStatusGetter,
 
1724
                                status:       params.StatusError,
 
1725
                                info:         `hook failed: "start"`,
 
1726
                                data:         map[string]interface{}{"hook": "start"},
 
1727
                        },
 
1728
                        verifyWaiting{},
 
1729
                        resolveError{state.ResolvedNoHooks},
 
1730
                        waitUnitAgent{status: params.StatusIdle},
 
1731
                        waitUnitAgent{
 
1732
                                statusGetter: unitStatusGetter,
 
1733
                                status:       params.StatusMaintenance,
 
1734
                                info:         "installing charm software",
 
1735
                        },
1533
1736
                ),
1534
1737
        })
1535
1738
}
1631
1834
                        addAction{"action-reboot", nil},
1632
1835
                        startUniter{},
1633
1836
                        waitAddresses{},
1634
 
                        waitUnit{
1635
 
                                status: params.StatusActive,
 
1837
                        waitUnitAgent{
 
1838
                                status: params.StatusIdle,
 
1839
                        },
 
1840
                        waitUnitAgent{
 
1841
                                statusGetter: unitStatusGetter,
 
1842
                                status:       params.StatusUnknown,
1636
1843
                        },
1637
1844
                        waitActionResults{[]actionResult{{
1638
1845
                                name: "action-reboot",
1658
1865
                        waitUniterDead{"machine needs to reboot"},
1659
1866
                        waitHooks{"install"},
1660
1867
                        startUniter{},
1661
 
                        waitUnit{
1662
 
                                status: params.StatusActive,
1663
 
                        },
1664
 
                        waitHooks{"config-changed", "start"},
 
1868
                        waitUnitAgent{
 
1869
                                status: params.StatusIdle,
 
1870
                        },
 
1871
                        waitUnitAgent{
 
1872
                                statusGetter: unitStatusGetter,
 
1873
                                status:       params.StatusUnknown,
 
1874
                        },
 
1875
                        waitHooks{"leader-elected", "config-changed", "start"},
1665
1876
                ), ut(
1666
1877
                        "test that juju-reboot --now kills hook and exits",
1667
1878
                        createCharm{
1678
1889
                        waitUniterDead{"machine needs to reboot"},
1679
1890
                        waitHooks{"install"},
1680
1891
                        startUniter{},
1681
 
                        waitUnit{
1682
 
                                status: params.StatusActive,
1683
 
                        },
1684
 
                        waitHooks{"install", "config-changed", "start"},
 
1892
                        waitUnitAgent{
 
1893
                                status: params.StatusIdle,
 
1894
                        },
 
1895
                        waitUnitAgent{
 
1896
                                statusGetter: unitStatusGetter,
 
1897
                                status:       params.StatusUnknown,
 
1898
                        },
 
1899
                        waitHooks{"install", "leader-elected", "config-changed", "start"},
1685
1900
                ), ut(
1686
1901
                        "test juju-reboot will not happen if hook errors out",
1687
1902
                        createCharm{
1695
1910
                        createServiceAndUnit{},
1696
1911
                        startUniter{},
1697
1912
                        waitAddresses{},
1698
 
                        waitUnit{
1699
 
                                status: params.StatusError,
1700
 
                                info:   fmt.Sprintf(`hook failed: "install"`),
 
1913
                        waitUnitAgent{
 
1914
                                statusGetter: unitStatusGetter,
 
1915
                                status:       params.StatusError,
 
1916
                                info:         fmt.Sprintf(`hook failed: "install"`),
1701
1917
                        },
1702
1918
                ),
1703
1919
        })
1704
1920
}
1705
1921
 
1706
1922
func (s *UniterSuite) TestRebootFromJujuRun(c *gc.C) {
 
1923
        //TODO(bogdanteleaga): Fix this on windows
 
1924
        if runtime.GOOS == "windows" {
 
1925
                c.Skip("bug 1403084: currently does not work on windows")
 
1926
        }
1707
1927
        s.runUniterTests(c, []uniterTest{
1708
1928
                ut(
1709
1929
                        "test juju-reboot",
1736
1956
                ),
1737
1957
        })
1738
1958
}
 
1959
 
 
1960
func (s *UniterSuite) TestLeadership(c *gc.C) {
 
1961
        s.runUniterTests(c, []uniterTest{
 
1962
                ut(
 
1963
                        "hook tools when leader",
 
1964
                        quickStart{},
 
1965
                        runCommands{"leader-set foo=bar baz=qux"},
 
1966
                        verifyLeaderSettings{"foo": "bar", "baz": "qux"},
 
1967
                ), ut(
 
1968
                        "hook tools when not leader",
 
1969
                        quickStart{minion: true},
 
1970
                        runCommands{leadershipScript},
 
1971
                ), ut(
 
1972
                        "leader-elected triggers when elected",
 
1973
                        quickStart{minion: true},
 
1974
                        forceLeader{},
 
1975
                        waitHooks{"leader-elected"},
 
1976
                ), ut(
 
1977
                        "leader-settings-changed triggers when leader settings change",
 
1978
                        quickStart{minion: true},
 
1979
                        setLeaderSettings{"ping": "pong"},
 
1980
                        waitHooks{"leader-settings-changed"},
 
1981
                ), ut(
 
1982
                        "leader-settings-changed triggers when bounced",
 
1983
                        quickStart{minion: true},
 
1984
                        verifyRunning{minion: true},
 
1985
                ), ut(
 
1986
                        "leader-settings-changed triggers when deposed (while stopped)",
 
1987
                        quickStart{},
 
1988
                        stopUniter{},
 
1989
                        forceMinion{},
 
1990
                        verifyRunning{minion: true},
 
1991
                ),
 
1992
        })
 
1993
}
 
1994
 
 
1995
func (s *UniterSuite) TestLeadershipUnexpectedDepose(c *gc.C) {
 
1996
        s.PatchValue(uniter.LeadershipGuarantee, 2*coretesting.ShortWait)
 
1997
        s.runUniterTests(c, []uniterTest{
 
1998
                ut(
 
1999
                        // NOTE: this is a strange and ugly test, intended to detect what
 
2000
                        // *would* happen if the uniter suddenly failed to renew its lease;
 
2001
                        // it depends on an artificially shortened tracker refresh time to
 
2002
                        // run in a reasonable amount of time.
 
2003
                        "leader-settings-changed triggers when deposed (while running)",
 
2004
                        quickStart{},
 
2005
                        forceMinion{},
 
2006
                        waitHooks{"leader-settings-changed"},
 
2007
                ),
 
2008
        })
 
2009
}
 
2010
 
 
2011
func (s *UniterSuite) TestStorage(c *gc.C) {
 
2012
        // appendStorageMetadata customises the wordpress charm's metadata,
 
2013
        // adding a "wp-content" filesystem store. We do it here rather
 
2014
        // than in the charm itself to avoid modifying all of the other
 
2015
        // scenarios.
 
2016
        appendStorageMetadata := func(c *gc.C, ctx *context, path string) {
 
2017
                f, err := os.OpenFile(filepath.Join(path, "metadata.yaml"), os.O_RDWR|os.O_APPEND, 0644)
 
2018
                c.Assert(err, jc.ErrorIsNil)
 
2019
                defer func() {
 
2020
                        err := f.Close()
 
2021
                        c.Assert(err, jc.ErrorIsNil)
 
2022
                }()
 
2023
                _, err = io.WriteString(f, "storage:\n  wp-content:\n    type: filesystem\n")
 
2024
                c.Assert(err, jc.ErrorIsNil)
 
2025
        }
 
2026
        s.runUniterTests(c, []uniterTest{
 
2027
                ut(
 
2028
                        "test that storage-attached is called",
 
2029
                        createCharm{customize: appendStorageMetadata},
 
2030
                        serveCharm{},
 
2031
                        ensureStateWorker{},
 
2032
                        createServiceAndUnit{},
 
2033
                        provisionStorage{},
 
2034
                        startUniter{},
 
2035
                        waitAddresses{},
 
2036
                        waitHooks{"wp-content-storage-attached"},
 
2037
                        waitHooks(startupHooks(false)),
 
2038
                ), ut(
 
2039
                        "test that storage-detaching is called before stop",
 
2040
                        createCharm{customize: appendStorageMetadata},
 
2041
                        serveCharm{},
 
2042
                        ensureStateWorker{},
 
2043
                        createServiceAndUnit{},
 
2044
                        provisionStorage{},
 
2045
                        startUniter{},
 
2046
                        waitAddresses{},
 
2047
                        waitHooks{"wp-content-storage-attached"},
 
2048
                        waitHooks(startupHooks(false)),
 
2049
                        unitDying,
 
2050
                        waitHooks{"leader-settings-changed"},
 
2051
                        // "stop" hook is not called until storage is detached
 
2052
                        waitHooks{"wp-content-storage-detaching", "stop"},
 
2053
                        verifyStorageDetached{},
 
2054
                        waitUniterDead{},
 
2055
                ), ut(
 
2056
                        "test that storage-detaching is called only if previously attached",
 
2057
                        createCharm{customize: appendStorageMetadata},
 
2058
                        serveCharm{},
 
2059
                        ensureStateWorker{},
 
2060
                        createServiceAndUnit{},
 
2061
                        // provision and destroy the storage before the uniter starts,
 
2062
                        // to ensure it never sees the storage as attached
 
2063
                        provisionStorage{},
 
2064
                        destroyStorageAttachment{},
 
2065
                        startUniter{},
 
2066
                        waitHooks(startupHooks(false)),
 
2067
                        unitDying,
 
2068
                        // storage-detaching is not called because it was never attached
 
2069
                        waitHooks{"stop"},
 
2070
                        verifyStorageDetached{},
 
2071
                        waitUniterDead{},
 
2072
                ), ut(
 
2073
                        "test that delay-provisioned storage does not block forever",
 
2074
                        createCharm{customize: appendStorageMetadata},
 
2075
                        serveCharm{},
 
2076
                        ensureStateWorker{},
 
2077
                        createServiceAndUnit{},
 
2078
                        startUniter{},
 
2079
                        // no hooks should be run, as storage isn't provisioned
 
2080
                        waitHooks{},
 
2081
                        provisionStorage{},
 
2082
                        waitHooks{"wp-content-storage-attached"},
 
2083
                        waitHooks(startupHooks(false)),
 
2084
                ), ut(
 
2085
                        "test that unprovisioned storage does not block unit termination",
 
2086
                        createCharm{customize: appendStorageMetadata},
 
2087
                        serveCharm{},
 
2088
                        ensureStateWorker{},
 
2089
                        createServiceAndUnit{},
 
2090
                        startUniter{},
 
2091
                        // no hooks should be run, as storage isn't provisioned
 
2092
                        waitHooks{},
 
2093
                        unitDying,
 
2094
                        // TODO(axw) should we really be running startup hooks
 
2095
                        // when the unit is dying?
 
2096
                        waitHooks(startupHooks(true)),
 
2097
                        waitHooks{"stop"},
 
2098
                        waitUniterDead{},
 
2099
                ),
 
2100
                // TODO(axw) test that storage-attached is run for new
 
2101
                // storage attachments before upgrade-charm is run. This
 
2102
                // requires additions to state to add storage when a charm
 
2103
                // is upgraded.
 
2104
        })
 
2105
}
 
2106
 
 
2107
type mockExecutor struct {
 
2108
        operation.Executor
 
2109
}
 
2110
 
 
2111
func (m *mockExecutor) Run(op operation.Operation) error {
 
2112
        // want to allow charm unpacking to occur
 
2113
        if strings.HasPrefix(op.String(), "install") {
 
2114
                return m.Executor.Run(op)
 
2115
        }
 
2116
        // but hooks should error
 
2117
        return errors.New("some error occurred")
 
2118
}
 
2119
 
 
2120
func (s *UniterSuite) TestOperationErrorReported(c *gc.C) {
 
2121
        executorFunc := func(u *uniter.Uniter) (operation.Executor, error) {
 
2122
                e, err := uniter.NewExecutor(u)
 
2123
                c.Assert(err, jc.ErrorIsNil)
 
2124
                return &mockExecutor{e}, nil
 
2125
        }
 
2126
        s.runUniterTests(c, []uniterTest{
 
2127
                ut(
 
2128
                        "error running operations are reported",
 
2129
                        createCharm{},
 
2130
                        serveCharm{},
 
2131
                        createUniter{executorFunc: executorFunc},
 
2132
                        waitUnitAgent{
 
2133
                                status: params.StatusFailed,
 
2134
                                info:   "run install hook",
 
2135
                        },
 
2136
                        expectError{".*some error occurred.*"},
 
2137
                ),
 
2138
        })
 
2139
}