launchpad.net/~rogpeppe/juju-core/500-errgo-fix@v0.0.0-20140213181702-000000002356/state/life_test.go (about) 1 // Copyright 2012, 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package state_test 5 6 import ( 7 gc "launchpad.net/gocheck" 8 9 "launchpad.net/juju-core/state" 10 ) 11 12 type LifeSuite struct { 13 ConnSuite 14 charm *state.Charm 15 svc *state.Service 16 } 17 18 func (s *LifeSuite) SetUpTest(c *gc.C) { 19 s.ConnSuite.SetUpTest(c) 20 s.charm = s.AddTestingCharm(c, "dummy") 21 s.svc = s.AddTestingService(c, "dummysvc", s.charm) 22 } 23 24 var _ = gc.Suite(&LifeSuite{}) 25 26 var stateChanges = []struct { 27 cached, desired state.Life 28 dbinitial, dbfinal state.Life 29 }{ 30 { 31 state.Alive, state.Dying, 32 state.Alive, state.Dying, 33 }, 34 { 35 state.Alive, state.Dying, 36 state.Dying, state.Dying, 37 }, 38 { 39 state.Alive, state.Dying, 40 state.Dead, state.Dead, 41 }, 42 { 43 state.Alive, state.Dead, 44 state.Alive, state.Dead, 45 }, 46 { 47 state.Alive, state.Dead, 48 state.Dying, state.Dead, 49 }, 50 { 51 state.Alive, state.Dead, 52 state.Dead, state.Dead, 53 }, 54 { 55 state.Dying, state.Dying, 56 state.Dying, state.Dying, 57 }, 58 { 59 state.Dying, state.Dying, 60 state.Dead, state.Dead, 61 }, 62 { 63 state.Dying, state.Dead, 64 state.Dying, state.Dead, 65 }, 66 { 67 state.Dying, state.Dead, 68 state.Dead, state.Dead, 69 }, 70 { 71 state.Dead, state.Dying, 72 state.Dead, state.Dead, 73 }, 74 { 75 state.Dead, state.Dead, 76 state.Dead, state.Dead, 77 }, 78 } 79 80 type lifeFixture interface { 81 id() (coll string, id interface{}) 82 setup(s *LifeSuite, c *gc.C) state.AgentLiving 83 } 84 85 type unitLife struct { 86 unit *state.Unit 87 } 88 89 func (l *unitLife) id() (coll string, id interface{}) { 90 return "units", l.unit.Name() 91 } 92 93 func (l *unitLife) setup(s *LifeSuite, c *gc.C) state.AgentLiving { 94 unit, err := s.svc.AddUnit() 95 c.Assert(err, gc.IsNil) 96 preventUnitDestroyRemove(c, unit) 97 l.unit = unit 98 return l.unit 99 } 100 101 type machineLife struct { 102 machine *state.Machine 103 } 104 105 func (l *machineLife) id() (coll string, id interface{}) { 106 return "machines", l.machine.Id() 107 } 108 109 func (l *machineLife) setup(s *LifeSuite, c *gc.C) state.AgentLiving { 110 var err error 111 l.machine, err = s.State.AddMachine("quantal", state.JobHostUnits) 112 c.Assert(err, gc.IsNil) 113 return l.machine 114 } 115 116 func (s *LifeSuite) prepareFixture(living state.Living, lfix lifeFixture, cached, dbinitial state.Life, c *gc.C) { 117 collName, id := lfix.id() 118 coll := s.MgoSuite.Session.DB("juju").C(collName) 119 120 err := coll.UpdateId(id, D{{"$set", D{ 121 {"life", cached}, 122 }}}) 123 c.Assert(err, gc.IsNil) 124 err = living.Refresh() 125 c.Assert(err, gc.IsNil) 126 127 err = coll.UpdateId(id, D{{"$set", D{ 128 {"life", dbinitial}, 129 }}}) 130 c.Assert(err, gc.IsNil) 131 } 132 133 func (s *LifeSuite) TestLifecycleStateChanges(c *gc.C) { 134 for i, lfix := range []lifeFixture{&unitLife{}, &machineLife{}} { 135 c.Logf("fixture %d", i) 136 for j, v := range stateChanges { 137 c.Logf("sequence %d", j) 138 living := lfix.setup(s, c) 139 s.prepareFixture(living, lfix, v.cached, v.dbinitial, c) 140 switch v.desired { 141 case state.Dying: 142 err := living.Destroy() 143 c.Assert(err, gc.IsNil) 144 case state.Dead: 145 err := living.EnsureDead() 146 c.Assert(err, gc.IsNil) 147 default: 148 panic("desired lifecycle can only be dying or dead") 149 } 150 err := living.Refresh() 151 c.Assert(err, gc.IsNil) 152 c.Assert(living.Life(), gc.Equals, v.dbfinal) 153 err = living.EnsureDead() 154 c.Assert(err, gc.IsNil) 155 err = living.Remove() 156 c.Assert(err, gc.IsNil) 157 } 158 } 159 } 160 161 const ( 162 notAliveErr = ".*: not found or not alive" 163 deadErr = ".*: not found or dead" 164 noErr = "" 165 ) 166 167 type lifer interface { 168 EnsureDead() error 169 Destroy() error 170 Life() state.Life 171 } 172 173 func runLifeChecks(c *gc.C, obj lifer, expectErr string, checks []func() error) { 174 for i, check := range checks { 175 c.Logf("check %d when %v", i, obj.Life()) 176 err := check() 177 if expectErr == noErr { 178 c.Assert(err, gc.IsNil) 179 } else { 180 c.Assert(err, gc.ErrorMatches, expectErr) 181 } 182 } 183 } 184 185 // testWhenDying sets obj to Dying and Dead in turn, and asserts 186 // that the errors from the given checks match aliveErr, dyingErr and deadErr 187 // in each respective life state. 188 func testWhenDying(c *gc.C, obj lifer, dyingErr, deadErr string, checks ...func() error) { 189 c.Logf("checking life of %v (%T)", obj, obj) 190 err := obj.Destroy() 191 c.Assert(err, gc.IsNil) 192 runLifeChecks(c, obj, dyingErr, checks) 193 err = obj.EnsureDead() 194 c.Assert(err, gc.IsNil) 195 runLifeChecks(c, obj, deadErr, checks) 196 }