github.com/altoros/juju-vmware@v0.0.0-20150312064031-f19ae857ccca/worker/uniter/relation/hooksender_test.go (about) 1 // Copyright 2012-2014 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package relation_test 5 6 import ( 7 "time" 8 9 jc "github.com/juju/testing/checkers" 10 gc "gopkg.in/check.v1" 11 "gopkg.in/juju/charm.v4/hooks" 12 13 "github.com/juju/juju/state/multiwatcher" 14 statetesting "github.com/juju/juju/state/testing" 15 coretesting "github.com/juju/juju/testing" 16 "github.com/juju/juju/worker/uniter/hook" 17 "github.com/juju/juju/worker/uniter/relation" 18 ) 19 20 type HookSenderSuite struct{} 21 22 var _ = gc.Suite(&HookSenderSuite{}) 23 24 func assertNext(c *gc.C, out chan hook.Info, expect hook.Info) { 25 select { 26 case <-time.After(coretesting.LongWait): 27 c.Fatalf("timed out waiting for %#v", expect) 28 case actual, ok := <-out: 29 c.Assert(ok, jc.IsTrue) 30 c.Assert(actual, gc.Equals, expect) 31 } 32 } 33 34 func assertEmpty(c *gc.C, out chan hook.Info) { 35 select { 36 case <-time.After(coretesting.ShortWait): 37 case actual, ok := <-out: 38 c.Fatalf("got unexpected %#v %#v", actual, ok) 39 } 40 } 41 42 func (s *HookSenderSuite) TestSendsHooks(c *gc.C) { 43 expect := hookList(hooks.Install, hooks.ConfigChanged, hooks.Start) 44 source := relation.NewListSource(expect) 45 out := make(chan hook.Info) 46 sender := relation.NewHookSender(out, source) 47 defer statetesting.AssertStop(c, sender) 48 49 for i := range expect { 50 assertNext(c, out, expect[i]) 51 } 52 assertEmpty(c, out) 53 statetesting.AssertStop(c, sender) 54 c.Assert(source.Empty(), jc.IsTrue) 55 } 56 57 func (s *HookSenderSuite) TestStopsHooks(c *gc.C) { 58 expect := hookList(hooks.Install, hooks.ConfigChanged, hooks.Start) 59 source := relation.NewListSource(expect) 60 out := make(chan hook.Info) 61 sender := relation.NewHookSender(out, source) 62 defer statetesting.AssertStop(c, sender) 63 64 assertNext(c, out, expect[0]) 65 assertNext(c, out, expect[1]) 66 statetesting.AssertStop(c, sender) 67 assertEmpty(c, out) 68 c.Assert(source.Next(), gc.Equals, expect[2]) 69 } 70 71 func (s *HookSenderSuite) TestHandlesUpdatesFullQueue(c *gc.C) { 72 source := newFullUnbufferedSource() 73 defer statetesting.AssertStop(c, source) 74 75 out := make(chan hook.Info) 76 sender := relation.NewHookSender(out, source) 77 defer statetesting.AssertStop(c, sender) 78 79 // Check we're being sent hooks but not updates. 80 assertActive := func() { 81 assertNext(c, out, hook.Info{Kind: hooks.Install}) 82 select { 83 case update, ok := <-source.updates: 84 c.Fatalf("got unexpected update: %#v %#v", update, ok) 85 case <-time.After(coretesting.ShortWait): 86 } 87 } 88 assertActive() 89 90 // Send an event on the Changes() chan. 91 sent := multiwatcher.RelationUnitsChange{Departed: []string{"sent"}} 92 select { 93 case source.changes <- sent: 94 case <-time.After(coretesting.LongWait): 95 c.Fatalf("could not send change") 96 } 97 98 // Now that a change has been delivered, nothing should be sent on the out 99 // chan, or read from the changes chan, until the Update method has completed. 100 notSent := multiwatcher.RelationUnitsChange{Departed: []string{"notSent"}} 101 select { 102 case source.changes <- notSent: 103 c.Fatalf("sent extra change while updating queue") 104 case hi, ok := <-out: 105 c.Fatalf("got unexpected hook while updating queue: %#v %#v", hi, ok) 106 case got, ok := <-source.updates: 107 c.Assert(ok, jc.IsTrue) 108 c.Assert(got, gc.DeepEquals, sent) 109 case <-time.After(coretesting.LongWait): 110 c.Fatalf("timed out") 111 } 112 113 // Check we're still being sent hooks and not updates. 114 assertActive() 115 } 116 117 func (s *HookSenderSuite) TestHandlesUpdatesFullQueueSpam(c *gc.C) { 118 source := newFullBufferedSource() 119 defer statetesting.AssertStop(c, source) 120 121 out := make(chan hook.Info) 122 sender := relation.NewHookSender(out, source) 123 defer statetesting.AssertStop(c, sender) 124 125 // Spam all channels continuously for a bit. 126 timeout := time.After(coretesting.LongWait) 127 hookCount := 0 128 changeCount := 0 129 updateCount := 0 130 for i := 0; i < 100; i++ { 131 select { 132 case hi, ok := <-out: 133 c.Assert(ok, jc.IsTrue) 134 c.Assert(hi, gc.DeepEquals, hook.Info{Kind: hooks.Install}) 135 hookCount++ 136 case source.changes <- multiwatcher.RelationUnitsChange{}: 137 changeCount++ 138 case update, ok := <-source.updates: 139 c.Assert(ok, jc.IsTrue) 140 c.Assert(update, gc.DeepEquals, multiwatcher.RelationUnitsChange{}) 141 updateCount++ 142 case <-timeout: 143 c.Fatalf("not enough things happened in time") 144 } 145 } 146 147 // Once we've finished sending, exhaust the updates... 148 for i := updateCount; i < changeCount && updateCount < changeCount; i++ { 149 select { 150 case update, ok := <-source.updates: 151 c.Assert(ok, jc.IsTrue) 152 c.Assert(update, gc.DeepEquals, multiwatcher.RelationUnitsChange{}) 153 updateCount++ 154 case <-timeout: 155 c.Fatalf("expected %d updates, got %d", changeCount, updateCount) 156 } 157 } 158 159 // ...and check sane end state to validate the foregoing. 160 c.Check(hookCount, gc.Not(gc.Equals), 0) 161 c.Check(changeCount, gc.Not(gc.Equals), 0) 162 } 163 164 func (s *HookSenderSuite) TestHandlesUpdatesEmptyQueue(c *gc.C) { 165 source := newEmptySource() 166 defer statetesting.AssertStop(c, source) 167 168 out := make(chan hook.Info) 169 sender := relation.NewHookSender(out, source) 170 defer statetesting.AssertStop(c, sender) 171 172 // Check no hooks are sent and no updates delivered. 173 assertIdle := func() { 174 select { 175 case hi, ok := <-out: 176 c.Fatalf("got unexpected hook: %#v %#v", hi, ok) 177 case update, ok := <-source.updates: 178 c.Fatalf("got unexpected update: %#v %#v", update, ok) 179 case <-time.After(coretesting.ShortWait): 180 } 181 } 182 assertIdle() 183 184 // Send an event on the Changes() chan. 185 sent := multiwatcher.RelationUnitsChange{Departed: []string{"sent"}} 186 timeout := time.After(coretesting.LongWait) 187 select { 188 case source.changes <- sent: 189 case <-timeout: 190 c.Fatalf("timed out") 191 } 192 193 // Now that a change has been delivered, nothing should be sent on the out 194 // chan, or read from the changes chan, until the Update method has completed. 195 notSent := multiwatcher.RelationUnitsChange{Departed: []string{"notSent"}} 196 select { 197 case source.changes <- notSent: 198 c.Fatalf("sent extra update while updating queue") 199 case hi, ok := <-out: 200 c.Fatalf("got unexpected hook while updating queue: %#v %#v", hi, ok) 201 case got, ok := <-source.updates: 202 c.Assert(ok, jc.IsTrue) 203 c.Assert(got, gc.DeepEquals, sent) 204 case <-timeout: 205 c.Fatalf("timed out") 206 } 207 208 // Now the change has been delivered, nothing should be happening. 209 assertIdle() 210 } 211 212 func (s *HookSenderSuite) TestHandlesUpdatesEmptyQueueSpam(c *gc.C) { 213 source := newEmptySource() 214 defer statetesting.AssertStop(c, source) 215 216 out := make(chan hook.Info) 217 sender := relation.NewHookSender(out, source) 218 defer statetesting.AssertStop(c, sender) 219 220 // Spam all channels continuously for a bit. 221 timeout := time.After(coretesting.LongWait) 222 changeCount := 0 223 updateCount := 0 224 for i := 0; i < 100; i++ { 225 select { 226 case hi, ok := <-out: 227 c.Fatalf("got unexpected hook: %#v %#v", hi, ok) 228 case source.changes <- multiwatcher.RelationUnitsChange{}: 229 changeCount++ 230 case update, ok := <-source.updates: 231 c.Assert(ok, jc.IsTrue) 232 c.Assert(update, gc.DeepEquals, multiwatcher.RelationUnitsChange{}) 233 updateCount++ 234 case <-timeout: 235 c.Fatalf("not enough things happened in time") 236 } 237 } 238 239 // Check sane end state. 240 c.Check(changeCount, gc.Equals, 50) 241 c.Check(updateCount, gc.Equals, 50) 242 }