github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/worker/dependency/util_test.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package dependency_test 5 6 import ( 7 "time" 8 9 "github.com/juju/errors" 10 "github.com/juju/testing" 11 jc "github.com/juju/testing/checkers" 12 gc "gopkg.in/check.v1" 13 "launchpad.net/tomb" 14 15 coretesting "github.com/juju/juju/testing" 16 "github.com/juju/juju/worker" 17 "github.com/juju/juju/worker/dependency" 18 ) 19 20 type engineFixture struct { 21 testing.IsolationSuite 22 engine dependency.Engine 23 } 24 25 func (s *engineFixture) SetUpTest(c *gc.C) { 26 s.IsolationSuite.SetUpTest(c) 27 s.startEngine(c, nothingFatal) 28 } 29 30 func (s *engineFixture) TearDownTest(c *gc.C) { 31 s.stopEngine(c) 32 s.IsolationSuite.TearDownTest(c) 33 } 34 35 func (s *engineFixture) startEngine(c *gc.C, isFatal dependency.IsFatalFunc) { 36 if s.engine != nil { 37 c.Fatalf("original engine not stopped") 38 } 39 config := dependency.EngineConfig{ 40 IsFatal: isFatal, 41 WorstError: func(err0, err1 error) error { return err0 }, 42 ErrorDelay: coretesting.ShortWait / 2, 43 BounceDelay: coretesting.ShortWait / 10, 44 } 45 46 e, err := dependency.NewEngine(config) 47 c.Assert(err, jc.ErrorIsNil) 48 s.engine = e 49 } 50 51 func (s *engineFixture) stopEngine(c *gc.C) { 52 if s.engine != nil { 53 err := worker.Stop(s.engine) 54 s.engine = nil 55 c.Check(err, jc.ErrorIsNil) 56 } 57 } 58 59 type manifoldHarness struct { 60 inputs []string 61 errors chan error 62 starts chan struct{} 63 ignoreExternalKill bool 64 } 65 66 func newManifoldHarness(inputs ...string) *manifoldHarness { 67 return &manifoldHarness{ 68 inputs: inputs, 69 errors: make(chan error, 1000), 70 starts: make(chan struct{}, 1000), 71 ignoreExternalKill: false, 72 } 73 } 74 75 // newErrorIgnoringManifoldHarness starts a minimal worker that ignores 76 // fatal errors - and will never die. 77 // This is potentially nasty, but it's useful in tests where we want 78 // to generate fatal errors but not race on which one the engine see first. 79 func newErrorIgnoringManifoldHarness(inputs ...string) *manifoldHarness { 80 return &manifoldHarness{ 81 inputs: inputs, 82 errors: make(chan error, 1000), 83 starts: make(chan struct{}, 1000), 84 ignoreExternalKill: true, 85 } 86 } 87 88 func (ews *manifoldHarness) Manifold() dependency.Manifold { 89 return dependency.Manifold{ 90 Inputs: ews.inputs, 91 Start: ews.start, 92 } 93 } 94 95 func (ews *manifoldHarness) start(getResource dependency.GetResourceFunc) (worker.Worker, error) { 96 for _, resourceName := range ews.inputs { 97 if err := getResource(resourceName, nil); err != nil { 98 return nil, err 99 } 100 } 101 w := &minimalWorker{tomb.Tomb{}, ews.ignoreExternalKill} 102 go func() { 103 defer w.tomb.Done() 104 ews.starts <- struct{}{} 105 select { 106 case <-w.tombDying(): 107 case err := <-ews.errors: 108 w.tomb.Kill(err) 109 } 110 }() 111 return w, nil 112 } 113 114 func (ews *manifoldHarness) AssertOneStart(c *gc.C) { 115 ews.AssertStart(c) 116 ews.AssertNoStart(c) 117 } 118 119 func (ews *manifoldHarness) AssertStart(c *gc.C) { 120 select { 121 case <-ews.starts: 122 case <-time.After(coretesting.LongWait): 123 c.Fatalf("never started") 124 } 125 } 126 127 func (ews *manifoldHarness) AssertNoStart(c *gc.C) { 128 select { 129 case <-time.After(coretesting.ShortWait): 130 case <-ews.starts: 131 c.Fatalf("started unexpectedly") 132 } 133 } 134 135 func (ews *manifoldHarness) InjectError(c *gc.C, err error) { 136 select { 137 case ews.errors <- err: 138 case <-time.After(coretesting.LongWait): 139 c.Fatalf("never sent") 140 } 141 } 142 143 func newTracedManifoldHarness(inputs ...string) *tracedManifoldHarness { 144 return &tracedManifoldHarness{ 145 &manifoldHarness{ 146 inputs: inputs, 147 errors: make(chan error, 1000), 148 starts: make(chan struct{}, 1000), 149 ignoreExternalKill: false, 150 }, 151 } 152 } 153 154 type tracedManifoldHarness struct { 155 *manifoldHarness 156 } 157 158 func (ews *tracedManifoldHarness) Manifold() dependency.Manifold { 159 return dependency.Manifold{ 160 Inputs: ews.inputs, 161 Start: ews.start, 162 } 163 } 164 165 func (ews *tracedManifoldHarness) start(getResource dependency.GetResourceFunc) (worker.Worker, error) { 166 for _, resourceName := range ews.inputs { 167 if err := getResource(resourceName, nil); err != nil { 168 return nil, errors.Trace(err) 169 } 170 } 171 w := &minimalWorker{tomb.Tomb{}, ews.ignoreExternalKill} 172 go func() { 173 defer w.tomb.Done() 174 ews.starts <- struct{}{} 175 select { 176 case <-w.tombDying(): 177 case err := <-ews.errors: 178 w.tomb.Kill(err) 179 } 180 }() 181 return w, nil 182 } 183 184 type minimalWorker struct { 185 tomb tomb.Tomb 186 ignoreExternalKill bool 187 } 188 189 func (w *minimalWorker) tombDying() <-chan struct{} { 190 if w.ignoreExternalKill { 191 return nil 192 } 193 return w.tomb.Dying() 194 } 195 196 func (w *minimalWorker) Kill() { 197 w.tomb.Kill(nil) 198 } 199 200 func (w *minimalWorker) Wait() error { 201 return w.tomb.Wait() 202 } 203 204 func (w *minimalWorker) Report() map[string]interface{} { 205 return map[string]interface{}{ 206 "key1": "hello there", 207 } 208 } 209 210 func startMinimalWorker(_ dependency.GetResourceFunc) (worker.Worker, error) { 211 w := &minimalWorker{} 212 go func() { 213 <-w.tomb.Dying() 214 w.tomb.Done() 215 }() 216 return w, nil 217 } 218 219 func nothingFatal(_ error) bool { 220 return false 221 }