launchpad.net/~rogpeppe/juju-core/500-errgo-fix@v0.0.0-20140213181702-000000002356/state/cleanup_test.go (about) 1 package state_test 2 3 import ( 4 "fmt" 5 gc "launchpad.net/gocheck" 6 7 "launchpad.net/juju-core/charm" 8 "launchpad.net/juju-core/errors" 9 "launchpad.net/juju-core/instance" 10 "launchpad.net/juju-core/state" 11 jc "launchpad.net/juju-core/testing/checkers" 12 ) 13 14 type CleanupSuite struct { 15 ConnSuite 16 } 17 18 var _ = gc.Suite(&CleanupSuite{}) 19 20 func (s *CleanupSuite) TestCleanupDyingServiceUnits(c *gc.C) { 21 s.assertDoesNotNeedCleanup(c) 22 23 // Create a service with some units. 24 mysql := s.AddTestingService(c, "mysql", s.AddTestingCharm(c, "mysql")) 25 units := make([]*state.Unit, 3) 26 for i := range units { 27 unit, err := mysql.AddUnit() 28 c.Assert(err, gc.IsNil) 29 units[i] = unit 30 } 31 preventUnitDestroyRemove(c, units[0]) 32 s.assertDoesNotNeedCleanup(c) 33 34 // Destroy the service and check the units are unaffected, but a cleanup 35 // has been scheduled. 36 err := mysql.Destroy() 37 c.Assert(err, gc.IsNil) 38 for _, unit := range units { 39 err := unit.Refresh() 40 c.Assert(err, gc.IsNil) 41 } 42 s.assertNeedsCleanup(c) 43 44 // Run the cleanup, and check that units are all destroyed as appropriate. 45 s.assertCleanupRuns(c) 46 s.assertDoesNotNeedCleanup(c) 47 err = units[0].Refresh() 48 c.Assert(err, gc.IsNil) 49 c.Assert(units[0].Life(), gc.Equals, state.Dying) 50 err = units[1].Refresh() 51 c.Assert(err, jc.Satisfies, errors.IsNotFoundError) 52 err = units[2].Refresh() 53 c.Assert(err, jc.Satisfies, errors.IsNotFoundError) 54 } 55 56 func (s *CleanupSuite) TestCleanupEnvironmentServices(c *gc.C) { 57 s.assertDoesNotNeedCleanup(c) 58 59 // Create a service with some units. 60 mysql := s.AddTestingService(c, "mysql", s.AddTestingCharm(c, "mysql")) 61 units := make([]*state.Unit, 3) 62 for i := range units { 63 unit, err := mysql.AddUnit() 64 c.Assert(err, gc.IsNil) 65 units[i] = unit 66 } 67 s.assertDoesNotNeedCleanup(c) 68 69 // Destroy the environment and check the service and units are 70 // unaffected, but a cleanup for the service has been scheduled. 71 env, err := s.State.Environment() 72 c.Assert(err, gc.IsNil) 73 err = env.Destroy() 74 c.Assert(err, gc.IsNil) 75 s.assertNeedsCleanup(c) 76 s.assertCleanupRuns(c) 77 err = mysql.Refresh() 78 c.Assert(err, gc.IsNil) 79 c.Assert(mysql.Life(), gc.Equals, state.Dying) 80 for _, unit := range units { 81 err = unit.Refresh() 82 c.Assert(err, gc.IsNil) 83 c.Assert(unit.Life(), gc.Equals, state.Alive) 84 } 85 86 // The first cleanup Destroys the service, which 87 // schedules another cleanup to destroy the units. 88 s.assertNeedsCleanup(c) 89 s.assertCleanupRuns(c) 90 for _, unit := range units { 91 err = unit.Refresh() 92 c.Assert(err, jc.Satisfies, errors.IsNotFoundError) 93 } 94 s.assertDoesNotNeedCleanup(c) 95 } 96 97 func (s *CleanupSuite) TestCleanupRelationSettings(c *gc.C) { 98 s.assertDoesNotNeedCleanup(c) 99 100 // Create a relation with a unit in scope. 101 pr := NewPeerRelation(c, s.State) 102 rel := pr.ru0.Relation() 103 err := pr.ru0.EnterScope(map[string]interface{}{"some": "settings"}) 104 c.Assert(err, gc.IsNil) 105 s.assertDoesNotNeedCleanup(c) 106 107 // Destroy the service, check the relation's still around. 108 err = pr.svc.Destroy() 109 c.Assert(err, gc.IsNil) 110 s.assertNeedsCleanup(c) 111 s.assertCleanupRuns(c) 112 err = rel.Refresh() 113 c.Assert(err, gc.IsNil) 114 c.Assert(rel.Life(), gc.Equals, state.Dying) 115 s.assertDoesNotNeedCleanup(c) 116 117 // The unit leaves scope, triggering relation removal. 118 err = pr.ru0.LeaveScope() 119 c.Assert(err, gc.IsNil) 120 s.assertNeedsCleanup(c) 121 122 // Settings are not destroyed yet... 123 settings, err := pr.ru1.ReadSettings("riak/0") 124 c.Assert(err, gc.IsNil) 125 c.Assert(settings, gc.DeepEquals, map[string]interface{}{"some": "settings"}) 126 127 // ...but they are on cleanup. 128 s.assertCleanupRuns(c) 129 s.assertDoesNotNeedCleanup(c) 130 _, err = pr.ru1.ReadSettings("riak/0") 131 c.Assert(err, gc.ErrorMatches, `cannot read settings for unit "riak/0" in relation "riak:ring": settings not found`) 132 } 133 134 func (s *CleanupSuite) TestForceDestroyMachineErrors(c *gc.C) { 135 manager, err := s.State.AddMachine("quantal", state.JobManageEnviron) 136 c.Assert(err, gc.IsNil) 137 s.assertDoesNotNeedCleanup(c) 138 err = manager.ForceDestroy() 139 expect := fmt.Sprintf("machine %s is required by the environment", manager.Id()) 140 c.Assert(err, gc.ErrorMatches, expect) 141 s.assertDoesNotNeedCleanup(c) 142 assertLife(c, manager, state.Alive) 143 } 144 145 func (s *CleanupSuite) TestCleanupForceDestroyedMachineUnit(c *gc.C) { 146 s.assertDoesNotNeedCleanup(c) 147 148 // Create a machine. 149 machine, err := s.State.AddMachine("quantal", state.JobHostUnits) 150 c.Assert(err, gc.IsNil) 151 152 // Create a relation with a unit in scope and assigned to the machine. 153 pr := NewPeerRelation(c, s.State) 154 err = pr.u0.AssignToMachine(machine) 155 c.Assert(err, gc.IsNil) 156 err = pr.ru0.EnterScope(nil) 157 c.Assert(err, gc.IsNil) 158 s.assertDoesNotNeedCleanup(c) 159 160 // Force machine destruction, check cleanup queued. 161 err = machine.ForceDestroy() 162 c.Assert(err, gc.IsNil) 163 s.assertNeedsCleanup(c) 164 165 // Clean up, and check that the unit has been removed... 166 s.assertCleanupRuns(c) 167 s.assertDoesNotNeedCleanup(c) 168 assertRemoved(c, pr.u0) 169 170 // ...and the unit has departed relation scope... 171 assertNotInScope(c, pr.ru0) 172 173 // ...but that the machine remains, and is Dead, ready for removal by the 174 // provisioner. 175 assertLife(c, machine, state.Dead) 176 } 177 178 func (s *CleanupSuite) TestCleanupForceDestroyedMachineWithContainer(c *gc.C) { 179 s.assertDoesNotNeedCleanup(c) 180 181 // Create a machine with a container. 182 machine, err := s.State.AddMachine("quantal", state.JobHostUnits) 183 c.Assert(err, gc.IsNil) 184 container, err := s.State.AddMachineInsideMachine(state.MachineTemplate{ 185 Series: "quantal", 186 Jobs: []state.MachineJob{state.JobHostUnits}, 187 }, machine.Id(), instance.LXC) 188 c.Assert(err, gc.IsNil) 189 190 // Create active units (in relation scope, with subordinates). 191 prr := NewProReqRelation(c, &s.ConnSuite, charm.ScopeContainer) 192 err = prr.pru0.EnterScope(nil) 193 c.Assert(err, gc.IsNil) 194 err = prr.pru1.EnterScope(nil) 195 c.Assert(err, gc.IsNil) 196 err = prr.rru0.EnterScope(nil) 197 c.Assert(err, gc.IsNil) 198 err = prr.rru1.EnterScope(nil) 199 c.Assert(err, gc.IsNil) 200 201 // Assign the various units to machines. 202 err = prr.pu0.AssignToMachine(machine) 203 c.Assert(err, gc.IsNil) 204 err = prr.pu1.AssignToMachine(container) 205 c.Assert(err, gc.IsNil) 206 s.assertDoesNotNeedCleanup(c) 207 208 // Force removal of the top-level machine. 209 err = machine.ForceDestroy() 210 c.Assert(err, gc.IsNil) 211 s.assertNeedsCleanup(c) 212 213 // And do it again, just to check that the second cleanup doc for the same 214 // machine doesn't cause problems down the line. 215 err = machine.ForceDestroy() 216 c.Assert(err, gc.IsNil) 217 s.assertNeedsCleanup(c) 218 219 // Clean up, and check that the container has been removed... 220 s.assertCleanupRuns(c) 221 s.assertDoesNotNeedCleanup(c) 222 err = container.Refresh() 223 c.Assert(err, jc.Satisfies, errors.IsNotFoundError) 224 225 // ...and so have all the units... 226 assertRemoved(c, prr.pu0) 227 assertRemoved(c, prr.pu1) 228 assertRemoved(c, prr.ru0) 229 assertRemoved(c, prr.ru1) 230 231 // ...and none of the units have left relation scopes occupied... 232 assertNotInScope(c, prr.pru0) 233 assertNotInScope(c, prr.pru1) 234 assertNotInScope(c, prr.rru0) 235 assertNotInScope(c, prr.rru1) 236 237 // ...but that the machine remains, and is Dead, ready for removal by the 238 // provisioner. 239 assertLife(c, machine, state.Dead) 240 } 241 242 func (s *CleanupSuite) TestNothingToCleanup(c *gc.C) { 243 s.assertDoesNotNeedCleanup(c) 244 s.assertCleanupRuns(c) 245 s.assertDoesNotNeedCleanup(c) 246 } 247 248 func (s *CleanupSuite) assertCleanupRuns(c *gc.C) { 249 err := s.State.Cleanup() 250 c.Assert(err, gc.IsNil) 251 } 252 253 func (s *CleanupSuite) assertNeedsCleanup(c *gc.C) { 254 actual, err := s.State.NeedsCleanup() 255 c.Assert(err, gc.IsNil) 256 c.Assert(actual, jc.IsTrue) 257 } 258 259 func (s *CleanupSuite) assertDoesNotNeedCleanup(c *gc.C) { 260 actual, err := s.State.NeedsCleanup() 261 c.Assert(err, gc.IsNil) 262 c.Assert(actual, jc.IsFalse) 263 }