~rogpeppe/juju-core/066-rename-mstate

« back to all changes in this revision

Viewing changes to worker/uniter/uniter_test.go

  • Committer: William Reade
  • Author(s): William Reade
  • Date: 2012-09-13 09:35:37 UTC
  • mfrom: (460.10.6 juju-core)
  • Revision ID: fwereade@gmail.com-20120913093537-ib0td1wi8vgawar5
implementĀ charmĀ upgrades

R=niemeyer
CC=
https://codereview.appspot.com/6503072

Show diffs side-by-side

added added

removed removed

Lines of Context:
33
33
type UniterSuite struct {
34
34
        testing.JujuConnSuite
35
35
        coretesting.HTTPSuite
36
 
        dataDir string
37
 
        oldPath string
 
36
        dataDir  string
 
37
        oldPath  string
 
38
        oldLcAll string
38
39
}
39
40
 
40
41
var _ = Suite(&UniterSuite{})
53
54
        c.Assert(err, IsNil)
54
55
        s.oldPath = os.Getenv("PATH")
55
56
        os.Setenv("PATH", toolsDir+":"+s.oldPath)
 
57
        s.oldLcAll = os.Getenv("LC_ALL")
 
58
        os.Setenv("LC_ALL", "en_US")
56
59
}
57
60
 
58
61
func (s *UniterSuite) TearDownSuite(c *C) {
59
62
        os.Setenv("PATH", s.oldPath)
 
63
        os.Setenv("LC_ALL", s.oldLcAll)
60
64
}
61
65
 
62
66
func (s *UniterSuite) SetUpTest(c *C) {
279
283
                waitHooks{"config-changed"},
280
284
                verifyRunning{},
281
285
        ),
 
286
        // Upgrade tests
 
287
        ut(
 
288
                "steady state upgrade",
 
289
                quickStart{},
 
290
                createCharm{revision: 1},
 
291
                upgradeCharm{revision: 1},
 
292
                waitUnit{
 
293
                        status: state.UnitStarted,
 
294
                },
 
295
                waitHooks{"upgrade-charm", "config-changed"},
 
296
                verifyCharm{revision: 1},
 
297
                verifyRunning{},
 
298
        ), ut(
 
299
                "steady state forced upgrade (identical behaviour)",
 
300
                quickStart{},
 
301
                createCharm{revision: 1},
 
302
                upgradeCharm{revision: 1, forced: true},
 
303
                waitUnit{
 
304
                        status: state.UnitStarted,
 
305
                        charm:  1,
 
306
                },
 
307
                waitHooks{"upgrade-charm", "config-changed"},
 
308
                verifyCharm{revision: 1},
 
309
                verifyRunning{},
 
310
        ), ut(
 
311
                "steady state upgrade hook fail and resolve",
 
312
                quickStart{},
 
313
                createCharm{revision: 1, badHooks: []string{"upgrade-charm"}},
 
314
                upgradeCharm{revision: 1},
 
315
                waitUnit{
 
316
                        status: state.UnitError,
 
317
                        info:   `hook failed: "upgrade-charm"`,
 
318
                        charm:  1,
 
319
                },
 
320
                waitHooks{"fail-upgrade-charm"},
 
321
                verifyCharm{revision: 1},
 
322
                verifyWaiting{},
 
323
 
 
324
                resolveError{state.ResolvedNoHooks},
 
325
                waitUnit{
 
326
                        status: state.UnitStarted,
 
327
                        charm:  1,
 
328
                },
 
329
                waitHooks{"config-changed"},
 
330
                verifyRunning{},
 
331
        ), ut(
 
332
                "steady state upgrade hook fail and retry",
 
333
                quickStart{},
 
334
                createCharm{revision: 1, badHooks: []string{"upgrade-charm"}},
 
335
                upgradeCharm{revision: 1},
 
336
                waitUnit{
 
337
                        status: state.UnitError,
 
338
                        info:   `hook failed: "upgrade-charm"`,
 
339
                        charm:  1,
 
340
                },
 
341
                waitHooks{"fail-upgrade-charm"},
 
342
                verifyCharm{revision: 1},
 
343
                verifyWaiting{},
 
344
 
 
345
                resolveError{state.ResolvedRetryHooks},
 
346
                waitUnit{
 
347
                        status: state.UnitError,
 
348
                        info:   `hook failed: "upgrade-charm"`,
 
349
                        charm:  1,
 
350
                },
 
351
                waitHooks{"fail-upgrade-charm"},
 
352
                verifyWaiting{},
 
353
 
 
354
                fixHook{"upgrade-charm"},
 
355
                resolveError{state.ResolvedRetryHooks},
 
356
                waitUnit{
 
357
                        status: state.UnitStarted,
 
358
                        charm:  1,
 
359
                },
 
360
                waitHooks{"upgrade-charm", "config-changed"},
 
361
                verifyRunning{},
 
362
        ), ut(
 
363
                "error state unforced upgrade (ignored until started state)",
 
364
                startupError{"start"},
 
365
                createCharm{revision: 1},
 
366
                upgradeCharm{revision: 1},
 
367
                waitUnit{
 
368
                        status: state.UnitError,
 
369
                        info:   `hook failed: "start"`,
 
370
                },
 
371
                waitHooks{},
 
372
                verifyCharm{},
 
373
                verifyWaiting{},
 
374
 
 
375
                resolveError{state.ResolvedNoHooks},
 
376
                waitUnit{
 
377
                        status: state.UnitStarted,
 
378
                        charm:  1,
 
379
                },
 
380
                waitHooks{"config-changed", "upgrade-charm", "config-changed"},
 
381
                verifyCharm{revision: 1},
 
382
                verifyRunning{},
 
383
        ), ut(
 
384
                "error state forced upgrade",
 
385
                startupError{"start"},
 
386
                createCharm{revision: 1},
 
387
                upgradeCharm{revision: 1, forced: true},
 
388
                waitUnit{
 
389
                        status: state.UnitError,
 
390
                        info:   `hook failed: "start"`,
 
391
                        charm:  1,
 
392
                },
 
393
                waitHooks{},
 
394
                verifyCharm{revision: 1},
 
395
                verifyWaiting{},
 
396
 
 
397
                resolveError{state.ResolvedNoHooks},
 
398
                waitUnit{
 
399
                        status: state.UnitStarted,
 
400
                        charm:  1,
 
401
                },
 
402
                waitHooks{"config-changed"},
 
403
                verifyRunning{},
 
404
        ), ut(
 
405
                "upgrade: conflicting files",
 
406
                createCharm{
 
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)
 
410
                                c.Assert(err, IsNil)
 
411
                                defer f.Close()
 
412
                                _, err = f.Write([]byte("echo USERDATA > data"))
 
413
                                c.Assert(err, IsNil)
 
414
                        },
 
415
                },
 
416
                serveCharm{},
 
417
                createUniter{},
 
418
                waitUnit{
 
419
                        status: state.UnitStarted,
 
420
                },
 
421
                waitHooks{"install", "start", "config-changed"},
 
422
                verifyCharm{},
 
423
 
 
424
                createCharm{
 
425
                        revision: 1,
 
426
                        customize: func(c *C, path string) {
 
427
                                data := filepath.Join(path, "data")
 
428
                                err := ioutil.WriteFile(data, []byte("<nelson>ha ha</nelson>"), 0644)
 
429
                                c.Assert(err, IsNil)
 
430
                        },
 
431
                },
 
432
                serveCharm{},
 
433
                upgradeCharm{revision: 1},
 
434
                waitUnit{
 
435
                        status: state.UnitError,
 
436
                        info:   "upgrade failed",
 
437
                },
 
438
                verifyWaiting{},
 
439
                verifyCharm{dirty: true},
 
440
 
 
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"},
 
446
                waitUnit{
 
447
                        status: state.UnitStarted,
 
448
                        charm:  1,
 
449
                },
 
450
                verifyCharm{revision: 1},
 
451
        ), ut(
 
452
                `upgrade: conflicting directories`,
 
453
                createCharm{
 
454
                        customize: func(c *C, path string) {
 
455
                                err := os.Mkdir(filepath.Join(path, "data"), 0755)
 
456
                                c.Assert(err, IsNil)
 
457
                                start := filepath.Join(path, "hooks", "start")
 
458
                                f, err := os.OpenFile(start, os.O_WRONLY|os.O_APPEND, 0755)
 
459
                                c.Assert(err, IsNil)
 
460
                                defer f.Close()
 
461
                                _, err = f.Write([]byte("echo DATA > data/newfile"))
 
462
                                c.Assert(err, IsNil)
 
463
                        },
 
464
                },
 
465
                serveCharm{},
 
466
                createUniter{},
 
467
                waitUnit{
 
468
                        status: state.UnitStarted,
 
469
                },
 
470
                waitHooks{"install", "start", "config-changed"},
 
471
                verifyCharm{},
 
472
 
 
473
                createCharm{
 
474
                        revision: 1,
 
475
                        customize: func(c *C, path string) {
 
476
                                data := filepath.Join(path, "data")
 
477
                                err := ioutil.WriteFile(data, []byte("<nelson>ha ha</nelson>"), 0644)
 
478
                                c.Assert(err, IsNil)
 
479
                        },
 
480
                },
 
481
                serveCharm{},
 
482
                upgradeCharm{revision: 1},
 
483
                waitUnit{
 
484
                        status: state.UnitError,
 
485
                        info:   "upgrade failed",
 
486
                },
 
487
                verifyWaiting{},
 
488
                verifyCharm{dirty: true},
 
489
 
 
490
                resolveError{state.ResolvedNoHooks},
 
491
                waitHooks{"upgrade-charm", "config-changed"},
 
492
                waitUnit{
 
493
                        status: state.UnitStarted,
 
494
                        charm:  1,
 
495
                },
 
496
                verifyCharm{revision: 1},
 
497
        ), ut(
 
498
                "upgrade conflict resolved with forced upgrade",
 
499
                createCharm{
 
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)
 
503
                                c.Assert(err, IsNil)
 
504
                                defer f.Close()
 
505
                                _, err = f.Write([]byte("echo STARTDATA > data"))
 
506
                                c.Assert(err, IsNil)
 
507
                        },
 
508
                },
 
509
                serveCharm{},
 
510
                createUniter{},
 
511
                waitUnit{
 
512
                        status: state.UnitStarted,
 
513
                },
 
514
                waitHooks{"install", "start", "config-changed"},
 
515
                verifyCharm{},
 
516
 
 
517
                createCharm{
 
518
                        revision: 1,
 
519
                        customize: func(c *C, path string) {
 
520
                                data := filepath.Join(path, "data")
 
521
                                err := ioutil.WriteFile(data, []byte("<nelson>ha ha</nelson>"), 0644)
 
522
                                c.Assert(err, IsNil)
 
523
                                ignore := filepath.Join(path, "ignore")
 
524
                                err = ioutil.WriteFile(ignore, []byte("anything"), 0644)
 
525
                                c.Assert(err, IsNil)
 
526
                        },
 
527
                },
 
528
                serveCharm{},
 
529
                upgradeCharm{revision: 1},
 
530
                waitUnit{
 
531
                        status: state.UnitError,
 
532
                        info:   "upgrade failed",
 
533
                },
 
534
                verifyWaiting{},
 
535
                verifyCharm{dirty: true},
 
536
 
 
537
                createCharm{
 
538
                        revision: 2,
 
539
                        customize: func(c *C, path string) {
 
540
                                otherdata := filepath.Join(path, "otherdata")
 
541
                                err := ioutil.WriteFile(otherdata, []byte("blah"), 0644)
 
542
                                c.Assert(err, IsNil)
 
543
                        },
 
544
                },
 
545
                serveCharm{},
 
546
                upgradeCharm{revision: 2, forced: true},
 
547
                waitUnit{
 
548
                        status: state.UnitStarted,
 
549
                        charm:  2,
 
550
                },
 
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"))
 
555
                        c.Assert(err, IsNil)
 
556
                        c.Assert(string(otherdata), Equals, "blah")
 
557
 
 
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)
 
561
 
 
562
                        // data should contain what was written in the start hook
 
563
                        data, err := ioutil.ReadFile(filepath.Join(ctx.path, "charm", "data"))
 
564
                        c.Assert(err, IsNil)
 
565
                        c.Assert(string(data), Equals, "STARTDATA\n")
 
566
                }},
 
567
        ),
282
568
}
283
569
 
284
570
func (s *UniterSuite) TestUniter(c *C) {
315
601
}
316
602
 
317
603
type createCharm struct {
318
 
        revision int
319
 
        badHooks []string
 
604
        revision  int
 
605
        badHooks  []string
 
606
        customize func(*C, string)
320
607
}
321
608
 
322
609
func (s createCharm) step(c *C, ctx *context) {
331
618
                }
332
619
                ctx.writeHook(c, path, good)
333
620
        }
 
621
        if s.customize != nil {
 
622
                s.customize(c, base)
 
623
        }
334
624
        dir, err := charm.ReadDir(base)
335
625
        c.Assert(err, IsNil)
336
626
        err = dir.SetDiskRevision(s.revision)
634
924
 
635
925
type verifyCharm struct {
636
926
        revision int
 
927
        dirty    bool
637
928
}
638
929
 
639
930
func (s verifyCharm) step(c *C, ctx *context) {
640
 
        path := filepath.Join(ctx.path, "charm", "revision")
641
 
        content, err := ioutil.ReadFile(path)
642
 
        c.Assert(err, IsNil)
643
 
        c.Assert(string(content), Equals, strconv.Itoa(s.revision))
644
 
        ch, err := ctx.unit.Charm()
645
 
        c.Assert(err, IsNil)
646
 
        c.Assert(ch.URL(), DeepEquals, curl(s.revision))
 
931
        if !s.dirty {
 
932
                path := filepath.Join(ctx.path, "charm", "revision")
 
933
                content, err := ioutil.ReadFile(path)
 
934
                c.Assert(err, IsNil)
 
935
                c.Assert(string(content), Equals, strconv.Itoa(s.revision))
 
936
                ch, err := ctx.unit.Charm()
 
937
                c.Assert(err, IsNil)
 
938
                c.Assert(ch.URL(), DeepEquals, curl(s.revision))
 
939
        }
 
940
 
 
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)
 
947
 
 
948
        cmd := exec.Command("git", "status")
 
949
        cmd.Dir = filepath.Join(ctx.path, "charm")
 
950
        out, err := cmd.CombinedOutput()
 
951
        c.Assert(err, IsNil)
 
952
 
 
953
        cmp := Equals
 
954
        if s.dirty {
 
955
                cmp = Not(Equals)
 
956
        }
 
957
        c.Assert(string(out), cmp, "# On branch master\nnothing to commit (working directory clean)\n")
647
958
}
648
959
 
649
960
type writeFile struct {