github.com/altoros/juju-vmware@v0.0.0-20150312064031-f19ae857ccca/worker/envworkermanager/envworkermanager_test.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package envworkermanager_test 5 6 import ( 7 stdtesting "testing" 8 "time" 9 10 "github.com/juju/errors" 11 jc "github.com/juju/testing/checkers" 12 gc "gopkg.in/check.v1" 13 "launchpad.net/tomb" 14 15 "github.com/juju/juju/state" 16 statetesting "github.com/juju/juju/state/testing" 17 "github.com/juju/juju/testing" 18 "github.com/juju/juju/testing/factory" 19 "github.com/juju/juju/worker" 20 "github.com/juju/juju/worker/envworkermanager" 21 ) 22 23 func TestPackage(t *stdtesting.T) { 24 testing.MgoTestPackage(t) 25 } 26 27 var _ = gc.Suite(&suite{}) 28 29 type suite struct { 30 statetesting.StateSuite 31 factory *factory.Factory 32 runnerC chan *fakeRunner 33 startErr error 34 } 35 36 func (s *suite) SetUpTest(c *gc.C) { 37 s.StateSuite.SetUpTest(c) 38 s.factory = factory.NewFactory(s.State) 39 s.runnerC = make(chan *fakeRunner, 1) 40 s.startErr = nil 41 } 42 43 func (s *suite) makeEnvironment(c *gc.C) *state.State { 44 st := s.factory.MakeEnvironment(c, nil) 45 s.AddCleanup(func(*gc.C) { st.Close() }) 46 return st 47 } 48 49 func (s *suite) TestStartsWorkersForPreExistingEnvs(c *gc.C) { 50 moreState := s.makeEnvironment(c) 51 52 var seenEnvs []string 53 m := envworkermanager.NewEnvWorkerManager(s.State, s.startEnvWorkers) 54 defer m.Kill() 55 for _, r := range s.seeRunnersStart(c, 2) { 56 seenEnvs = append(seenEnvs, r.envUUID) 57 } 58 c.Assert(seenEnvs, jc.SameContents, 59 []string{s.State.EnvironUUID(), moreState.EnvironUUID()}) 60 } 61 62 func (s *suite) TestStartsWorkersForNewEnv(c *gc.C) { 63 m := envworkermanager.NewEnvWorkerManager(s.State, s.startEnvWorkers) 64 defer m.Kill() 65 s.seeRunnersStart(c, 1) // Runner for state server env 66 67 // Create another environment and watch a runner be created for it. 68 st2 := s.makeEnvironment(c) 69 runner := s.seeRunnersStart(c, 1)[0] 70 c.Assert(runner.envUUID, gc.Equals, st2.EnvironUUID()) 71 } 72 73 func (s *suite) TestStopsWorkersWhenEnvGoesAway(c *gc.C) { 74 m := envworkermanager.NewEnvWorkerManager(s.State, s.startEnvWorkers) 75 defer m.Kill() 76 runner0 := s.seeRunnersStart(c, 1)[0] 77 78 // Create an environment and grab the runner for it. 79 otherState := s.makeEnvironment(c) 80 runner1 := s.seeRunnersStart(c, 1)[0] 81 82 // Destroy the new environment. 83 env, err := otherState.Environment() 84 c.Assert(err, jc.ErrorIsNil) 85 err = env.Destroy() 86 c.Assert(err, jc.ErrorIsNil) 87 88 // See that the first runner is still running but the runner for 89 // the new environment is stopped. 90 s.State.StartSync() 91 select { 92 case <-runner0.tomb.Dying(): 93 c.Fatal("first runner should not die here") 94 case <-runner1.tomb.Dying(): 95 break 96 case <-time.After(testing.LongWait): 97 c.Fatal("timed out waiting for runner to die") 98 } 99 100 // Make sure the first runner doesn't get stopped. 101 s.State.StartSync() 102 select { 103 case <-runner0.tomb.Dying(): 104 c.Fatal("first runner should not die here") 105 case <-time.After(testing.ShortWait): 106 break 107 } 108 } 109 110 func (s *suite) TestKillPropogates(c *gc.C) { 111 s.makeEnvironment(c) 112 113 m := envworkermanager.NewEnvWorkerManager(s.State, s.startEnvWorkers) 114 runners := s.seeRunnersStart(c, 2) 115 c.Assert(runners[0].killed, jc.IsFalse) 116 c.Assert(runners[1].killed, jc.IsFalse) 117 118 m.Kill() 119 err := waitOrPanic(m.Wait) 120 c.Assert(err, jc.ErrorIsNil) 121 122 c.Assert(runners[0].killed, jc.IsTrue) 123 c.Assert(runners[1].killed, jc.IsTrue) 124 } 125 126 func (s *suite) TestNothingHappensWhenEnvIsSeenAgain(c *gc.C) { 127 // This could happen if there's a change to an environment doc but 128 // it's otherwise still alive (unlikely but possible). 129 st := newStateWithFakeWatcher(s.State) 130 uuid := st.EnvironUUID() 131 132 m := envworkermanager.NewEnvWorkerManager(st, s.startEnvWorkers) 133 defer m.Kill() 134 135 // First time: runners started 136 st.sendEnvChange(uuid) 137 s.seeRunnersStart(c, 1) 138 139 // Second time: no runners started 140 st.sendEnvChange(uuid) 141 s.checkNoRunnersStart(c) 142 } 143 144 func (s *suite) TestNothingHappensWhenUnknownEnvReported(c *gc.C) { 145 // This could perhaps happen when an environment is dying just as 146 // the EnvWorkerManager is coming up (unlikely but possible). 147 st := newStateWithFakeWatcher(s.State) 148 149 m := envworkermanager.NewEnvWorkerManager(st, s.startEnvWorkers) 150 defer m.Kill() 151 152 st.sendEnvChange("unknown-env-uuid") 153 s.checkNoRunnersStart(c) 154 155 // Existing environment still works. 156 st.sendEnvChange(st.EnvironUUID()) 157 s.seeRunnersStart(c, 1) 158 } 159 160 func (s *suite) TestFatalErrorKillsEnvWorkerManager(c *gc.C) { 161 m := envworkermanager.NewEnvWorkerManager(s.State, s.startEnvWorkers) 162 runner := s.seeRunnersStart(c, 1)[0] 163 164 runner.tomb.Kill(worker.ErrTerminateAgent) 165 runner.tomb.Done() 166 167 err := waitOrPanic(m.Wait) 168 c.Assert(errors.Cause(err), gc.Equals, worker.ErrTerminateAgent) 169 } 170 171 func (s *suite) TestNonFatalErrorCausesRunnerRestart(c *gc.C) { 172 s.PatchValue(&worker.RestartDelay, time.Millisecond) 173 174 m := envworkermanager.NewEnvWorkerManager(s.State, s.startEnvWorkers) 175 defer m.Kill() 176 runner0 := s.seeRunnersStart(c, 1)[0] 177 178 runner0.tomb.Kill(errors.New("trivial")) 179 runner0.tomb.Done() 180 181 s.seeRunnersStart(c, 1) 182 } 183 184 func (s *suite) TestStateIsClosedIfStartEnvWorkersFails(c *gc.C) { 185 // If State is not closed when startEnvWorkers errors, MgoSuite's 186 // dirty socket detection will pick up the leaked socket and 187 // panic. 188 s.startErr = worker.ErrTerminateAgent // This will make envWorkerManager exit. 189 m := envworkermanager.NewEnvWorkerManager(s.State, s.startEnvWorkers) 190 waitOrPanic(m.Wait) 191 } 192 193 func (s *suite) seeRunnersStart(c *gc.C, expectedCount int) []*fakeRunner { 194 if expectedCount < 1 { 195 panic("expectedCount must be >= 1") 196 } 197 s.State.StartSync() 198 runners := make([]*fakeRunner, 0, expectedCount) 199 for { 200 select { 201 case r := <-s.runnerC: 202 c.Assert(r.ssEnvUUID, gc.Equals, s.State.EnvironUUID()) 203 204 runners = append(runners, r) 205 if len(runners) == expectedCount { 206 s.checkNoRunnersStart(c) // Check no more runners start 207 return runners 208 } 209 case <-time.After(testing.LongWait): 210 c.Fatal("timed out waiting for runners to be started") 211 } 212 } 213 } 214 215 func (s *suite) checkNoRunnersStart(c *gc.C) { 216 s.State.StartSync() 217 for { 218 select { 219 case <-s.runnerC: 220 c.Fatal("saw runner creation when expecting none") 221 case <-time.After(testing.ShortWait): 222 return 223 } 224 } 225 } 226 227 // startEnvWorkers is passed to NewEnvWorkerManager in these tests. It 228 // creates fake Runner instances when envWorkerManager starts workers 229 // for an environment. 230 func (s *suite) startEnvWorkers(ssSt envworkermanager.InitialState, st *state.State) (worker.Runner, error) { 231 if s.startErr != nil { 232 return nil, s.startErr 233 } 234 runner := &fakeRunner{ 235 ssEnvUUID: ssSt.EnvironUUID(), 236 envUUID: st.EnvironUUID(), 237 } 238 s.runnerC <- runner 239 return runner, nil 240 } 241 242 func waitOrPanic(wait func() error) error { 243 errC := make(chan error) 244 go func() { 245 errC <- wait() 246 }() 247 248 select { 249 case err := <-errC: 250 return err 251 case <-time.After(testing.LongWait): 252 panic("waited too long") 253 } 254 } 255 256 // fakeRunner minimally implements the worker.Runner interface. It 257 // doesn't actually run anything, recording some execution details for 258 // testing. 259 type fakeRunner struct { 260 worker.Runner 261 tomb tomb.Tomb 262 ssEnvUUID string 263 envUUID string 264 killed bool 265 } 266 267 func (r *fakeRunner) Kill() { 268 r.killed = true 269 r.tomb.Done() 270 } 271 272 func (r *fakeRunner) Wait() error { 273 e := r.tomb.Wait() 274 return e 275 } 276 277 func newStateWithFakeWatcher(realSt *state.State) *stateWithFakeWatcher { 278 return &stateWithFakeWatcher{ 279 State: realSt, 280 envWatcher: &fakeEnvWatcher{ 281 changes: make(chan []string), 282 }, 283 } 284 } 285 286 // stateWithFakeWatcher wraps a *state.State, overriding the 287 // WatchEnvironments method to allow control over the reported 288 // environment lifecycle events for testing. 289 // 290 // Use sendEnvChange to cause an environment event to be emitted by 291 // the watcher returned by WatchEnvironments. 292 type stateWithFakeWatcher struct { 293 *state.State 294 envWatcher *fakeEnvWatcher 295 } 296 297 func (s *stateWithFakeWatcher) WatchEnvironments() state.StringsWatcher { 298 return s.envWatcher 299 } 300 301 func (s *stateWithFakeWatcher) sendEnvChange(uuids ...string) { 302 s.envWatcher.changes <- uuids 303 } 304 305 type fakeEnvWatcher struct { 306 state.StringsWatcher 307 changes chan []string 308 } 309 310 func (w *fakeEnvWatcher) Stop() error { 311 return nil 312 } 313 314 func (w *fakeEnvWatcher) Changes() <-chan []string { 315 return w.changes 316 }