279
283
waitHooks{"config-changed"},
288
"steady state upgrade",
290
createCharm{revision: 1},
291
upgradeCharm{revision: 1},
293
status: state.UnitStarted,
295
waitHooks{"upgrade-charm", "config-changed"},
296
verifyCharm{revision: 1},
299
"steady state forced upgrade (identical behaviour)",
301
createCharm{revision: 1},
302
upgradeCharm{revision: 1, forced: true},
304
status: state.UnitStarted,
307
waitHooks{"upgrade-charm", "config-changed"},
308
verifyCharm{revision: 1},
311
"steady state upgrade hook fail and resolve",
313
createCharm{revision: 1, badHooks: []string{"upgrade-charm"}},
314
upgradeCharm{revision: 1},
316
status: state.UnitError,
317
info: `hook failed: "upgrade-charm"`,
320
waitHooks{"fail-upgrade-charm"},
321
verifyCharm{revision: 1},
324
resolveError{state.ResolvedNoHooks},
326
status: state.UnitStarted,
329
waitHooks{"config-changed"},
332
"steady state upgrade hook fail and retry",
334
createCharm{revision: 1, badHooks: []string{"upgrade-charm"}},
335
upgradeCharm{revision: 1},
337
status: state.UnitError,
338
info: `hook failed: "upgrade-charm"`,
341
waitHooks{"fail-upgrade-charm"},
342
verifyCharm{revision: 1},
345
resolveError{state.ResolvedRetryHooks},
347
status: state.UnitError,
348
info: `hook failed: "upgrade-charm"`,
351
waitHooks{"fail-upgrade-charm"},
354
fixHook{"upgrade-charm"},
355
resolveError{state.ResolvedRetryHooks},
357
status: state.UnitStarted,
360
waitHooks{"upgrade-charm", "config-changed"},
363
"error state unforced upgrade (ignored until started state)",
364
startupError{"start"},
365
createCharm{revision: 1},
366
upgradeCharm{revision: 1},
368
status: state.UnitError,
369
info: `hook failed: "start"`,
375
resolveError{state.ResolvedNoHooks},
377
status: state.UnitStarted,
380
waitHooks{"config-changed", "upgrade-charm", "config-changed"},
381
verifyCharm{revision: 1},
384
"error state forced upgrade",
385
startupError{"start"},
386
createCharm{revision: 1},
387
upgradeCharm{revision: 1, forced: true},
389
status: state.UnitError,
390
info: `hook failed: "start"`,
394
verifyCharm{revision: 1},
397
resolveError{state.ResolvedNoHooks},
399
status: state.UnitStarted,
402
waitHooks{"config-changed"},
405
"upgrade: conflicting files",
407
customize: func(c *C, path string) {
408
start := filepath.Join(path, "hooks", "start")
409
f, err := os.OpenFile(start, os.O_WRONLY|os.O_APPEND, 0755)
412
_, err = f.Write([]byte("echo USERDATA > data"))
419
status: state.UnitStarted,
421
waitHooks{"install", "start", "config-changed"},
426
customize: func(c *C, path string) {
427
data := filepath.Join(path, "data")
428
err := ioutil.WriteFile(data, []byte("<nelson>ha ha</nelson>"), 0644)
433
upgradeCharm{revision: 1},
435
status: state.UnitError,
436
info: "upgrade failed",
439
verifyCharm{dirty: true},
441
// NOTE: this is just dumbly committing the conflicts, but AFAICT this
442
// is the only reasonable solution; if the user tells us it's resolved
443
// we have to take their word for it.
444
resolveError{state.ResolvedNoHooks},
445
waitHooks{"upgrade-charm", "config-changed"},
447
status: state.UnitStarted,
450
verifyCharm{revision: 1},
452
`upgrade: conflicting directories`,
454
customize: func(c *C, path string) {
455
err := os.Mkdir(filepath.Join(path, "data"), 0755)
457
start := filepath.Join(path, "hooks", "start")
458
f, err := os.OpenFile(start, os.O_WRONLY|os.O_APPEND, 0755)
461
_, err = f.Write([]byte("echo DATA > data/newfile"))
468
status: state.UnitStarted,
470
waitHooks{"install", "start", "config-changed"},
475
customize: func(c *C, path string) {
476
data := filepath.Join(path, "data")
477
err := ioutil.WriteFile(data, []byte("<nelson>ha ha</nelson>"), 0644)
482
upgradeCharm{revision: 1},
484
status: state.UnitError,
485
info: "upgrade failed",
488
verifyCharm{dirty: true},
490
resolveError{state.ResolvedNoHooks},
491
waitHooks{"upgrade-charm", "config-changed"},
493
status: state.UnitStarted,
496
verifyCharm{revision: 1},
498
"upgrade conflict resolved with forced upgrade",
500
customize: func(c *C, path string) {
501
start := filepath.Join(path, "hooks", "start")
502
f, err := os.OpenFile(start, os.O_WRONLY|os.O_APPEND, 0755)
505
_, err = f.Write([]byte("echo STARTDATA > data"))
512
status: state.UnitStarted,
514
waitHooks{"install", "start", "config-changed"},
519
customize: func(c *C, path string) {
520
data := filepath.Join(path, "data")
521
err := ioutil.WriteFile(data, []byte("<nelson>ha ha</nelson>"), 0644)
523
ignore := filepath.Join(path, "ignore")
524
err = ioutil.WriteFile(ignore, []byte("anything"), 0644)
529
upgradeCharm{revision: 1},
531
status: state.UnitError,
532
info: "upgrade failed",
535
verifyCharm{dirty: true},
539
customize: func(c *C, path string) {
540
otherdata := filepath.Join(path, "otherdata")
541
err := ioutil.WriteFile(otherdata, []byte("blah"), 0644)
546
upgradeCharm{revision: 2, forced: true},
548
status: state.UnitStarted,
551
verifyCharm{revision: 2},
552
custom{func(c *C, ctx *context) {
553
// otherdata should exist (in v2)
554
otherdata, err := ioutil.ReadFile(filepath.Join(ctx.path, "charm", "otherdata"))
556
c.Assert(string(otherdata), Equals, "blah")
558
// ignore should not (only in v1)
559
_, err = os.Stat(filepath.Join(ctx.path, "charm", "ignore"))
560
c.Assert(os.IsNotExist(err), Equals, true)
562
// data should contain what was written in the start hook
563
data, err := ioutil.ReadFile(filepath.Join(ctx.path, "charm", "data"))
565
c.Assert(string(data), Equals, "STARTDATA\n")
284
570
func (s *UniterSuite) TestUniter(c *C) {
635
925
type verifyCharm struct {
639
930
func (s verifyCharm) step(c *C, ctx *context) {
640
path := filepath.Join(ctx.path, "charm", "revision")
641
content, err := ioutil.ReadFile(path)
643
c.Assert(string(content), Equals, strconv.Itoa(s.revision))
644
ch, err := ctx.unit.Charm()
646
c.Assert(ch.URL(), DeepEquals, curl(s.revision))
932
path := filepath.Join(ctx.path, "charm", "revision")
933
content, err := ioutil.ReadFile(path)
935
c.Assert(string(content), Equals, strconv.Itoa(s.revision))
936
ch, err := ctx.unit.Charm()
938
c.Assert(ch.URL(), DeepEquals, curl(s.revision))
941
// Even if the charm itself has been updated correctly, it is possible that
942
// a hook has run and is being committed by git; which will cause all manner
943
// of bad stuff to happen when we try to get the status below. There's no
944
// general way to guarantee that this is not happening, but the following
945
// voodoo sleep has been observed to be sufficient in practice.
946
time.Sleep(500 * time.Millisecond)
948
cmd := exec.Command("git", "status")
949
cmd.Dir = filepath.Join(ctx.path, "charm")
950
out, err := cmd.CombinedOutput()
957
c.Assert(string(out), cmp, "# On branch master\nnothing to commit (working directory clean)\n")
649
960
type writeFile struct {