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 }