github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/worker/controller/manifold_test.go (about)

     1  // Copyright 2017 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package controller_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  	"gopkg.in/juju/worker.v1"
    14  	"gopkg.in/juju/worker.v1/dependency"
    15  	dt "gopkg.in/juju/worker.v1/dependency/testing"
    16  
    17  	coreagent "github.com/juju/juju/agent"
    18  	"github.com/juju/juju/state"
    19  	statetesting "github.com/juju/juju/state/testing"
    20  	coretesting "github.com/juju/juju/testing"
    21  	workercontroller "github.com/juju/juju/worker/controller"
    22  )
    23  
    24  type ManifoldSuite struct {
    25  	statetesting.StateSuite
    26  	manifold             dependency.Manifold
    27  	openControllerCalled bool
    28  	openControllerErr    error
    29  	config               workercontroller.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.openControllerCalled = false
    40  	s.openControllerErr = nil
    41  
    42  	s.config = workercontroller.ManifoldConfig{
    43  		AgentName:              "agent",
    44  		StateConfigWatcherName: "state-config-watcher",
    45  		OpenController:         s.fakeOpenController,
    46  		MongoPingInterval:      10 * time.Millisecond,
    47  	}
    48  	s.manifold = workercontroller.Manifold(s.config)
    49  	s.resources = dt.StubResources{
    50  		"agent":                dt.NewStubResource(new(mockAgent)),
    51  		"state-config-watcher": dt.NewStubResource(true),
    52  	}
    53  }
    54  
    55  func (s *ManifoldSuite) fakeOpenController(coreagent.Config) (*state.Controller, error) {
    56  	s.openControllerCalled = true
    57  	if s.openControllerErr != nil {
    58  		return nil, s.openControllerErr
    59  	}
    60  	// Here's one we prepared earlier...
    61  	return s.Controller, 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) TestStartOpenControllerNil(c *gc.C) {
    86  	s.config.OpenController = nil
    87  	manifold := workercontroller.Manifold(s.config)
    88  	w, err := manifold.Start(s.resources.Context())
    89  	c.Check(w, gc.IsNil)
    90  	c.Check(err, gc.ErrorMatches, "OpenController is nil in config")
    91  }
    92  
    93  func (s *ManifoldSuite) TestStartNotController(c *gc.C) {
    94  	s.resources["state-config-watcher"] = dt.NewStubResource(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) TestStartOpenControllerFails(c *gc.C) {
   101  	s.openControllerErr = 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.openControllerCalled, jc.IsTrue)
   110  	checkNotExiting(c, w)
   111  	checkStop(c, w)
   112  }
   113  
   114  func (s *ManifoldSuite) TestPinging(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, "database ping failed: .+")
   122  }
   123  
   124  func (s *ManifoldSuite) TestOutputBadWorker(c *gc.C) {
   125  	var st *state.Controller
   126  	err := s.manifold.Output(dummyWorker{}, &st)
   127  	c.Check(st, gc.IsNil)
   128  	c.Check(err, gc.ErrorMatches, `in should be a \*controller.controllerWorker; .+`)
   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 \*Tracker; got .+`)
   138  }
   139  
   140  func (s *ManifoldSuite) TestOutputSuccess(c *gc.C) {
   141  	w := s.mustStartManifold(c)
   142  
   143  	var tracker workercontroller.Tracker
   144  	err := s.manifold.Output(w, &tracker)
   145  	c.Assert(err, jc.ErrorIsNil)
   146  
   147  	ctlr, err := tracker.Use()
   148  	c.Assert(err, jc.ErrorIsNil)
   149  	c.Check(ctlr, gc.Equals, s.Controller)
   150  	c.Assert(tracker.Done(), jc.ErrorIsNil)
   151  
   152  	// Ensure Controller is closed when the worker is done.
   153  	checkStop(c, w)
   154  	assertControllerClosed(c, s.Controller)
   155  }
   156  
   157  func (s *ManifoldSuite) TestControllerStillInUse(c *gc.C) {
   158  	w := s.mustStartManifold(c)
   159  
   160  	var tracker workercontroller.Tracker
   161  	err := s.manifold.Output(w, &tracker)
   162  	c.Assert(err, jc.ErrorIsNil)
   163  
   164  	ctlr, err := tracker.Use()
   165  	c.Assert(err, jc.ErrorIsNil)
   166  
   167  	// Close the worker while the State is still in use.
   168  	checkStop(c, w)
   169  	assertControllerNotClosed(c, ctlr)
   170  
   171  	// Now signal that the Controller is no longer needed.
   172  	c.Assert(tracker.Done(), jc.ErrorIsNil)
   173  	assertControllerClosed(c, ctlr)
   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  }