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

     1  // Copyright 2018 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package featureflag_test
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  	"github.com/juju/testing"
     9  	jc "github.com/juju/testing/checkers"
    10  	gc "gopkg.in/check.v1"
    11  	"gopkg.in/juju/worker.v1"
    12  	"gopkg.in/juju/worker.v1/dependency"
    13  	dt "gopkg.in/juju/worker.v1/dependency/testing"
    14  	"gopkg.in/juju/worker.v1/workertest"
    15  
    16  	"github.com/juju/juju/cmd/jujud/agent/engine"
    17  	"github.com/juju/juju/state"
    18  	statetesting "github.com/juju/juju/state/testing"
    19  	"github.com/juju/juju/worker/featureflag"
    20  )
    21  
    22  type ValidationSuite struct {
    23  	testing.IsolationSuite
    24  	config featureflag.ManifoldConfig
    25  }
    26  
    27  var _ = gc.Suite(&ValidationSuite{})
    28  
    29  func (s *ValidationSuite) SetUpTest(c *gc.C) {
    30  	s.IsolationSuite.SetUpTest(c)
    31  	s.config.StateName = "state"
    32  	s.config.FlagName = "new-hotness"
    33  	s.config.NewWorker = func(featureflag.Config) (worker.Worker, error) {
    34  		return nil, nil
    35  	}
    36  }
    37  
    38  func (s *ValidationSuite) TestMissingStateName(c *gc.C) {
    39  	s.config.StateName = ""
    40  	c.Assert(s.config.Validate(), gc.ErrorMatches, "empty StateName not valid")
    41  }
    42  
    43  func (s *ValidationSuite) TestMissingFlagName(c *gc.C) {
    44  	s.config.FlagName = ""
    45  	c.Assert(s.config.Validate(), gc.ErrorMatches, "empty FlagName not valid")
    46  }
    47  
    48  func (s *ValidationSuite) TestMissingNewWorker(c *gc.C) {
    49  	s.config.NewWorker = nil
    50  	c.Assert(s.config.Validate(), gc.ErrorMatches, "nil NewWorker not valid")
    51  }
    52  
    53  type ManifoldSuite struct {
    54  	statetesting.StateSuite
    55  
    56  	manifold     dependency.Manifold
    57  	context      dependency.Context
    58  	stateTracker stubStateTracker
    59  	worker       *mockWorker
    60  
    61  	stub testing.Stub
    62  }
    63  
    64  var _ = gc.Suite(&ManifoldSuite{})
    65  
    66  func (s *ManifoldSuite) SetUpTest(c *gc.C) {
    67  	s.StateSuite.SetUpTest(c)
    68  
    69  	s.stub.ResetCalls()
    70  	s.worker = &mockWorker{}
    71  	s.stateTracker.ResetCalls()
    72  	s.stateTracker.pool = s.StatePool
    73  
    74  	s.context = s.newContext(nil)
    75  	s.manifold = featureflag.Manifold(featureflag.ManifoldConfig{
    76  		StateName: "state",
    77  		FlagName:  "new-hotness",
    78  		Invert:    true,
    79  		NewWorker: s.newWorker,
    80  	})
    81  }
    82  
    83  func (s *ManifoldSuite) newContext(overlay map[string]interface{}) dependency.Context {
    84  	resources := map[string]interface{}{
    85  		"state": &s.stateTracker,
    86  	}
    87  	for k, v := range overlay {
    88  		resources[k] = v
    89  	}
    90  	return dt.StubContext(nil, resources)
    91  }
    92  
    93  func (s *ManifoldSuite) newWorker(config featureflag.Config) (worker.Worker, error) {
    94  	s.stub.MethodCall(s, "NewWorker", config)
    95  	if err := s.stub.NextErr(); err != nil {
    96  		return nil, err
    97  	}
    98  	return s.worker, nil
    99  }
   100  
   101  var expectedInputs = []string{"state"}
   102  
   103  func (s *ManifoldSuite) TestInputs(c *gc.C) {
   104  	c.Assert(s.manifold.Inputs, jc.SameContents, expectedInputs)
   105  }
   106  
   107  func (s *ManifoldSuite) TestMissingInputs(c *gc.C) {
   108  	for _, input := range expectedInputs {
   109  		context := s.newContext(map[string]interface{}{
   110  			input: dependency.ErrMissing,
   111  		})
   112  		_, err := s.manifold.Start(context)
   113  		c.Assert(errors.Cause(err), gc.Equals, dependency.ErrMissing)
   114  	}
   115  }
   116  
   117  func (s *ManifoldSuite) TestStart(c *gc.C) {
   118  	s.startWorkerClean(c)
   119  
   120  	s.stub.CheckCallNames(c, "NewWorker")
   121  	args := s.stub.Calls()[0].Args
   122  	c.Assert(args, gc.HasLen, 1)
   123  	c.Assert(args[0], jc.DeepEquals, featureflag.Config{
   124  		Source:   s.State,
   125  		FlagName: "new-hotness",
   126  		Invert:   true,
   127  	})
   128  }
   129  
   130  func (s *ManifoldSuite) TestErrRefresh(c *gc.C) {
   131  	w := s.startWorkerClean(c)
   132  
   133  	s.worker.SetErrors(featureflag.ErrRefresh)
   134  	err := w.Wait()
   135  	c.Assert(s.manifold.Filter(err), gc.Equals, dependency.ErrBounce)
   136  }
   137  
   138  func (s *ManifoldSuite) TestOutput(c *gc.C) {
   139  	s.worker.result = true
   140  	w := s.startWorkerClean(c)
   141  
   142  	var flag engine.Flag
   143  	err := s.manifold.Output(w, &flag)
   144  	c.Assert(err, jc.ErrorIsNil)
   145  	c.Assert(flag.Check(), jc.IsTrue)
   146  }
   147  
   148  func (s *ManifoldSuite) TestStopWorkerClosesState(c *gc.C) {
   149  	w, err := s.manifold.Start(s.context)
   150  	c.Assert(err, jc.ErrorIsNil)
   151  	defer workertest.CleanKill(c, w)
   152  
   153  	s.stateTracker.CheckCallNames(c, "Use")
   154  
   155  	workertest.CleanKill(c, w)
   156  	s.stateTracker.CheckCallNames(c, "Use", "Done")
   157  }
   158  
   159  func (s *ManifoldSuite) TestClosesStateOnWorkerError(c *gc.C) {
   160  	s.stub.SetErrors(errors.Errorf("splat"))
   161  	w, err := s.manifold.Start(s.context)
   162  	c.Assert(err, gc.ErrorMatches, "splat")
   163  	c.Assert(w, gc.IsNil)
   164  
   165  	s.stateTracker.CheckCallNames(c, "Use", "Done")
   166  }
   167  
   168  func (s *ManifoldSuite) startWorkerClean(c *gc.C) worker.Worker {
   169  	w, err := s.manifold.Start(s.context)
   170  	c.Assert(err, jc.ErrorIsNil)
   171  	return w
   172  }
   173  
   174  type mockWorker struct {
   175  	testing.Stub
   176  	result bool
   177  }
   178  
   179  func (w *mockWorker) Check() bool {
   180  	return w.result
   181  }
   182  
   183  func (w *mockWorker) Kill() {}
   184  
   185  func (w *mockWorker) Wait() error {
   186  	return w.NextErr()
   187  }
   188  
   189  type stubStateTracker struct {
   190  	testing.Stub
   191  	pool *state.StatePool
   192  }
   193  
   194  func (s *stubStateTracker) Use() (*state.StatePool, error) {
   195  	s.MethodCall(s, "Use")
   196  	return s.pool, s.NextErr()
   197  }
   198  
   199  func (s *stubStateTracker) Done() error {
   200  	s.MethodCall(s, "Done")
   201  	return s.NextErr()
   202  }
   203  
   204  func (s *stubStateTracker) Report() map[string]interface{} {
   205  	s.MethodCall(s, "Report")
   206  	return nil
   207  }