github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/worker/state/manifold_test.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package state_test
     5  
     6  import (
     7  	"errors"
     8  	"time"
     9  
    10  	jujutesting "github.com/juju/testing"
    11  	jc "github.com/juju/testing/checkers"
    12  	gc "gopkg.in/check.v1"
    13  
    14  	coreagent "github.com/juju/juju/agent"
    15  	"github.com/juju/juju/state"
    16  	statetesting "github.com/juju/juju/state/testing"
    17  	coretesting "github.com/juju/juju/testing"
    18  	"github.com/juju/juju/worker"
    19  	"github.com/juju/juju/worker/dependency"
    20  	dt "github.com/juju/juju/worker/dependency/testing"
    21  	workerstate "github.com/juju/juju/worker/state"
    22  )
    23  
    24  type ManifoldSuite struct {
    25  	statetesting.StateSuite
    26  	manifold        dependency.Manifold
    27  	openStateCalled bool
    28  	openStateErr    error
    29  	config          workerstate.ManifoldConfig
    30  	agent           *mockAgent
    31  	resources       dt.StubResources
    32  }
    33  
    34  var _ = gc.Suite(&ManifoldSuite{})
    35  
    36  func (s *ManifoldSuite) SetUpTest(c *gc.C) {
    37  	s.StateSuite.SetUpTest(c)
    38  
    39  	s.openStateCalled = false
    40  	s.openStateErr = nil
    41  
    42  	s.config = workerstate.ManifoldConfig{
    43  		AgentName:              "agent",
    44  		StateConfigWatcherName: "state-config-watcher",
    45  		OpenState:              s.fakeOpenState,
    46  		PingInterval:           10 * time.Millisecond,
    47  	}
    48  	s.manifold = workerstate.Manifold(s.config)
    49  	s.resources = dt.StubResources{
    50  		"agent":                dt.StubResource{Output: new(mockAgent)},
    51  		"state-config-watcher": dt.StubResource{Output: true},
    52  	}
    53  }
    54  
    55  func (s *ManifoldSuite) fakeOpenState(coreagent.Config) (*state.State, error) {
    56  	s.openStateCalled = true
    57  	if s.openStateErr != nil {
    58  		return nil, s.openStateErr
    59  	}
    60  	// Here's one we prepared earlier...
    61  	return s.State, nil
    62  }
    63  
    64  func (s *ManifoldSuite) TestInputs(c *gc.C) {
    65  	c.Assert(s.manifold.Inputs, jc.SameContents, []string{
    66  		"agent",
    67  		"state-config-watcher",
    68  	})
    69  }
    70  
    71  func (s *ManifoldSuite) TestStartAgentMissing(c *gc.C) {
    72  	s.resources["agent"] = dt.StubResource{Error: dependency.ErrMissing}
    73  	w, err := s.startManifold(c)
    74  	c.Check(w, gc.IsNil)
    75  	c.Check(err, gc.Equals, dependency.ErrMissing)
    76  }
    77  
    78  func (s *ManifoldSuite) TestStateConfigWatcherMissing(c *gc.C) {
    79  	s.resources["state-config-watcher"] = dt.StubResource{Error: dependency.ErrMissing}
    80  	w, err := s.startManifold(c)
    81  	c.Check(w, gc.IsNil)
    82  	c.Check(err, gc.Equals, dependency.ErrMissing)
    83  }
    84  
    85  func (s *ManifoldSuite) TestStartOpenStateNil(c *gc.C) {
    86  	s.config.OpenState = nil
    87  	manifold := workerstate.Manifold(s.config)
    88  	w, err := manifold.Start(s.resources.Context())
    89  	c.Check(w, gc.IsNil)
    90  	c.Check(err, gc.ErrorMatches, "OpenState is nil in config")
    91  }
    92  
    93  func (s *ManifoldSuite) TestStartNotStateServer(c *gc.C) {
    94  	s.resources["state-config-watcher"] = dt.StubResource{Output: false}
    95  	w, err := s.startManifold(c)
    96  	c.Check(w, gc.IsNil)
    97  	c.Check(err, gc.Equals, dependency.ErrMissing)
    98  }
    99  
   100  func (s *ManifoldSuite) TestStartOpenStateFails(c *gc.C) {
   101  	s.openStateErr = errors.New("boom")
   102  	w, err := s.startManifold(c)
   103  	c.Check(w, gc.IsNil)
   104  	c.Check(err, gc.ErrorMatches, "boom")
   105  }
   106  
   107  func (s *ManifoldSuite) TestStartSuccess(c *gc.C) {
   108  	w := s.mustStartManifold(c)
   109  	c.Check(s.openStateCalled, jc.IsTrue)
   110  	checkNotExiting(c, w)
   111  	checkStop(c, w)
   112  }
   113  
   114  func (s *ManifoldSuite) TestStatePinging(c *gc.C) {
   115  	w := s.mustStartManifold(c)
   116  	checkNotExiting(c, w)
   117  
   118  	// Kill the mongod to cause pings to fail.
   119  	jujutesting.MgoServer.Destroy()
   120  
   121  	checkExitsWithError(c, w, "state ping failed: .+")
   122  }
   123  
   124  func (s *ManifoldSuite) TestOutputBadWorker(c *gc.C) {
   125  	var st *state.State
   126  	err := s.manifold.Output(dummyWorker{}, &st)
   127  	c.Check(st, gc.IsNil)
   128  	c.Check(err, gc.ErrorMatches, `in should be a \*state.stateWorker; .+`)
   129  }
   130  
   131  func (s *ManifoldSuite) TestOutputWrongType(c *gc.C) {
   132  	w := s.mustStartManifold(c)
   133  
   134  	var wrong int
   135  	err := s.manifold.Output(w, &wrong)
   136  	c.Check(wrong, gc.Equals, 0)
   137  	c.Check(err, gc.ErrorMatches, `out should be \*state.State; got .+`)
   138  }
   139  
   140  func (s *ManifoldSuite) TestOutputSuccess(c *gc.C) {
   141  	w := s.mustStartManifold(c)
   142  
   143  	var stTracker workerstate.StateTracker
   144  	err := s.manifold.Output(w, &stTracker)
   145  	c.Assert(err, jc.ErrorIsNil)
   146  
   147  	st, err := stTracker.Use()
   148  	c.Assert(err, jc.ErrorIsNil)
   149  	c.Check(st, gc.Equals, s.State)
   150  	c.Assert(stTracker.Done(), jc.ErrorIsNil)
   151  
   152  	// Ensure State is closed when the worker is done.
   153  	checkStop(c, w)
   154  	assertStateClosed(c, s.State)
   155  }
   156  
   157  func (s *ManifoldSuite) TestStateStillInUse(c *gc.C) {
   158  	w := s.mustStartManifold(c)
   159  
   160  	var stTracker workerstate.StateTracker
   161  	err := s.manifold.Output(w, &stTracker)
   162  	c.Assert(err, jc.ErrorIsNil)
   163  
   164  	st, err := stTracker.Use()
   165  	c.Assert(err, jc.ErrorIsNil)
   166  
   167  	// Close the worker while the State is still in use.
   168  	checkStop(c, w)
   169  	assertStateNotClosed(c, st)
   170  
   171  	// Now signal that the State is no longer needed.
   172  	c.Assert(stTracker.Done(), jc.ErrorIsNil)
   173  	assertStateClosed(c, st)
   174  }
   175  
   176  func (s *ManifoldSuite) mustStartManifold(c *gc.C) worker.Worker {
   177  	w, err := s.startManifold(c)
   178  	c.Assert(err, jc.ErrorIsNil)
   179  	return w
   180  }
   181  
   182  func (s *ManifoldSuite) startManifold(c *gc.C) (worker.Worker, error) {
   183  	w, err := s.manifold.Start(s.resources.Context())
   184  	if w != nil {
   185  		s.AddCleanup(func(*gc.C) { worker.Stop(w) })
   186  	}
   187  	return w, err
   188  }
   189  
   190  func checkStop(c *gc.C, w worker.Worker) {
   191  	err := worker.Stop(w)
   192  	c.Check(err, jc.ErrorIsNil)
   193  }
   194  
   195  func checkNotExiting(c *gc.C, w worker.Worker) {
   196  	exited := make(chan bool)
   197  	go func() {
   198  		w.Wait()
   199  		close(exited)
   200  	}()
   201  
   202  	select {
   203  	case <-exited:
   204  		c.Fatal("worker exited unexpectedly")
   205  	case <-time.After(coretesting.ShortWait):
   206  		// Worker didn't exit (good)
   207  	}
   208  }
   209  
   210  func checkExitsWithError(c *gc.C, w worker.Worker, expectedErr string) {
   211  	errCh := make(chan error)
   212  	go func() {
   213  		errCh <- w.Wait()
   214  	}()
   215  	select {
   216  	case err := <-errCh:
   217  		c.Check(err, gc.ErrorMatches, expectedErr)
   218  	case <-time.After(coretesting.LongWait):
   219  		c.Fatal("timed out waiting for worker to exit")
   220  	}
   221  }
   222  
   223  type mockAgent struct {
   224  	coreagent.Agent
   225  }
   226  
   227  func (ma *mockAgent) CurrentConfig() coreagent.Config {
   228  	return new(mockConfig)
   229  }
   230  
   231  type mockConfig struct {
   232  	coreagent.Config
   233  }
   234  
   235  type dummyWorker struct {
   236  	worker.Worker
   237  }