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  }