github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/worker/uniter/hook/peeker_test.go (about) 1 // Copyright 2014-2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package hook_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.v6-unstable/hooks" 12 13 statetesting "github.com/juju/juju/state/testing" 14 coretesting "github.com/juju/juju/testing" 15 "github.com/juju/juju/worker/uniter/hook" 16 "github.com/juju/juju/worker/uniter/hook/hooktesting" 17 ) 18 19 type PeekerSuite struct { 20 } 21 22 var _ = gc.Suite(&PeekerSuite{}) 23 24 func (s *PeekerSuite) TestPeeks(c *gc.C) { 25 expect := hooktesting.HookList(hooks.Install, hooks.ConfigChanged, hooks.Start) 26 source := hook.NewListSource(expect) 27 peeker := hook.NewPeeker(source) 28 defer statetesting.AssertStop(c, peeker) 29 30 timeout := time.After(coretesting.LongWait) 31 for _, expectInfo := range expect { 32 select { 33 case peek, ok := <-peeker.Peeks(): 34 c.Assert(ok, jc.IsTrue) 35 c.Assert(peek.HookInfo(), gc.Equals, expectInfo) 36 peek.Reject() 37 case <-timeout: 38 c.Fatalf("ran out of time") 39 } 40 select { 41 case peek, ok := <-peeker.Peeks(): 42 c.Assert(ok, jc.IsTrue) 43 c.Assert(peek.HookInfo(), gc.Equals, expectInfo) 44 peek.Consume() 45 case <-timeout: 46 c.Fatalf("ran out of time") 47 } 48 } 49 select { 50 case <-time.After(coretesting.ShortWait): 51 case peek, ok := <-peeker.Peeks(): 52 c.Fatalf("unexpected peek from empty queue: %#v, %#v", peek, ok) 53 } 54 } 55 56 func (s *PeekerSuite) TestStopWhileRunning(c *gc.C) { 57 source := hooktesting.NewFullUnbufferedSource() 58 defer statetesting.AssertStop(c, source) 59 60 peeker := hook.NewPeeker(source) 61 defer statetesting.AssertStop(c, peeker) 62 63 // Grab and reject a peek to check we're running. 64 select { 65 case peek, ok := <-peeker.Peeks(): 66 c.Assert(ok, jc.IsTrue) 67 c.Assert(peek.HookInfo(), gc.Equals, hook.Info{Kind: hooks.Install}) 68 peek.Reject() 69 assertStopPeeker(c, peeker, source) 70 case <-time.After(coretesting.LongWait): 71 c.Fatalf("timed out") 72 } 73 } 74 75 func (s *PeekerSuite) TestStopWhilePeeking(c *gc.C) { 76 source := hooktesting.NewFullUnbufferedSource() 77 defer statetesting.AssertStop(c, source) 78 79 peeker := hook.NewPeeker(source) 80 defer statetesting.AssertStop(c, peeker) 81 82 select { 83 case peek, ok := <-peeker.Peeks(): 84 c.Assert(ok, jc.IsTrue) 85 c.Assert(peek.HookInfo(), gc.Equals, hook.Info{Kind: hooks.Install}) 86 assertStopPeeker(c, peeker, source) 87 case <-time.After(coretesting.LongWait): 88 c.Fatalf("timed out") 89 } 90 } 91 92 func (s *PeekerSuite) TestStopWhileUpdating(c *gc.C) { 93 source := hooktesting.NewFullBufferedSource() 94 defer statetesting.AssertStop(c, source) 95 96 peeker := hook.NewPeeker(source) 97 defer statetesting.AssertStop(c, peeker) 98 99 // Deliver a change; do not accept updates. 100 select { 101 case source.ChangesC <- source.NewChange(nil): 102 assertStopPeeker(c, peeker, source) 103 case <-time.After(coretesting.LongWait): 104 c.Fatalf("timed out") 105 } 106 } 107 108 func (s *PeekerSuite) TestUpdatesFullQueue(c *gc.C) { 109 source := hooktesting.NewFullUnbufferedSource() 110 defer statetesting.AssertStop(c, source) 111 112 peeker := hook.NewPeeker(source) 113 defer statetesting.AssertStop(c, peeker) 114 115 // Check we're being sent peeks but not updates. 116 timeout := time.After(coretesting.LongWait) 117 assertActive := func() { 118 select { 119 case peek, ok := <-peeker.Peeks(): 120 c.Assert(ok, jc.IsTrue) 121 defer peek.Reject() 122 c.Assert(peek.HookInfo(), gc.Equals, hook.Info{Kind: hooks.Install}) 123 case update, ok := <-source.UpdatesC: 124 c.Fatalf("got unexpected update: %#v %#v", update, ok) 125 case <-timeout: 126 c.Fatalf("timed out") 127 } 128 } 129 assertActive() 130 131 // Send an event on the Changes() chan. 132 select { 133 case source.ChangesC <- source.NewChange("sent"): 134 case <-timeout: 135 c.Fatalf("could not send change") 136 } 137 138 // Now that a change has been delivered, nothing should be sent on the out 139 // chan, or read from the changes chan, until the Update method has completed. 140 select { 141 case source.ChangesC <- source.NewChange("notSent"): 142 c.Fatalf("sent extra change while updating queue") 143 case peek, ok := <-peeker.Peeks(): 144 c.Fatalf("got unexpected peek while updating queue: %#v %#v", peek, ok) 145 case got, ok := <-source.UpdatesC: 146 c.Assert(ok, jc.IsTrue) 147 c.Assert(got, gc.Equals, "sent") 148 case <-timeout: 149 c.Fatalf("timed out") 150 } 151 152 // Check we're still being sent hooks and not updates. 153 assertActive() 154 } 155 156 func (s *PeekerSuite) TestUpdatesFullQueueSpam(c *gc.C) { 157 source := hooktesting.NewFullUnbufferedSource() 158 defer statetesting.AssertStop(c, source) 159 160 peeker := hook.NewPeeker(source) 161 defer statetesting.AssertStop(c, peeker) 162 163 // Spam all channels continuously for a bit. 164 timeout := time.After(coretesting.LongWait) 165 peekCount := 0 166 changeCount := 0 167 updateCount := 0 168 for i := 0; i < 100; i++ { 169 select { 170 case peek, ok := <-peeker.Peeks(): 171 c.Assert(ok, jc.IsTrue) 172 c.Assert(peek.HookInfo(), gc.DeepEquals, hook.Info{Kind: hooks.Install}) 173 peek.Consume() 174 peekCount++ 175 case source.ChangesC <- source.NewChange("!"): 176 changeCount++ 177 case update, ok := <-source.UpdatesC: 178 c.Assert(ok, jc.IsTrue) 179 c.Assert(update, gc.Equals, "!") 180 updateCount++ 181 case <-timeout: 182 c.Fatalf("not enough things happened in time") 183 } 184 } 185 186 // Once we've finished sending, exhaust the updates... 187 for i := updateCount; i < changeCount && updateCount < changeCount; i++ { 188 select { 189 case update, ok := <-source.UpdatesC: 190 c.Assert(ok, jc.IsTrue) 191 c.Assert(update, gc.DeepEquals, "!") 192 updateCount++ 193 case <-timeout: 194 c.Fatalf("expected %d updates, got %d", changeCount, updateCount) 195 } 196 } 197 198 // ...and check sane end state to validate the foregoing. 199 c.Check(peekCount, gc.Not(gc.Equals), 0) 200 c.Check(changeCount, gc.Not(gc.Equals), 0) 201 } 202 203 func (s *PeekerSuite) TestUpdatesEmptyQueue(c *gc.C) { 204 source := hooktesting.NewEmptySource() 205 defer statetesting.AssertStop(c, source) 206 207 peeker := hook.NewPeeker(source) 208 defer statetesting.AssertStop(c, peeker) 209 210 // Check no hooks are sent and no updates delivered. 211 assertIdle := func() { 212 select { 213 case peek, ok := <-peeker.Peeks(): 214 c.Fatalf("got unexpected peek: %#v %#v", peek, ok) 215 case update, ok := <-source.UpdatesC: 216 c.Fatalf("got unexpected update: %#v %#v", update, ok) 217 case <-time.After(coretesting.ShortWait): 218 } 219 } 220 assertIdle() 221 222 // Send an event on the Changes() chan. 223 timeout := time.After(coretesting.LongWait) 224 select { 225 case source.ChangesC <- source.NewChange("sent"): 226 case <-timeout: 227 c.Fatalf("timed out") 228 } 229 230 // Now that a change has been delivered, nothing should be sent on the out 231 // chan, or read from the changes chan, until the Update method has completed. 232 select { 233 case source.ChangesC <- source.NewChange("notSent"): 234 c.Fatalf("sent extra change while updating queue") 235 case peek, ok := <-peeker.Peeks(): 236 c.Fatalf("got unexpected peek while updating queue: %#v %#v", peek, ok) 237 case got, ok := <-source.UpdatesC: 238 c.Assert(ok, jc.IsTrue) 239 c.Assert(got, gc.Equals, "sent") 240 case <-timeout: 241 c.Fatalf("timed out") 242 } 243 244 // Now the change has been delivered, nothing should be happening. 245 assertIdle() 246 } 247 248 func (s *PeekerSuite) TestUpdatesEmptyQueueSpam(c *gc.C) { 249 source := hooktesting.NewEmptySource() 250 defer statetesting.AssertStop(c, source) 251 252 peeker := hook.NewPeeker(source) 253 defer statetesting.AssertStop(c, peeker) 254 255 // Spam all channels continuously for a bit. 256 timeout := time.After(coretesting.LongWait) 257 changeCount := 0 258 updateCount := 0 259 for i := 0; i < 100; i++ { 260 select { 261 case peek, ok := <-peeker.Peeks(): 262 c.Fatalf("got unexpected peek: %#v %#v", peek, ok) 263 case source.ChangesC <- source.NewChange("!"): 264 changeCount++ 265 case update, ok := <-source.UpdatesC: 266 c.Assert(ok, jc.IsTrue) 267 c.Assert(update, gc.Equals, "!") 268 updateCount++ 269 case <-timeout: 270 c.Fatalf("not enough things happened in time") 271 } 272 } 273 274 // Check sane end state. 275 c.Check(changeCount, gc.Equals, 50) 276 c.Check(updateCount, gc.Equals, 50) 277 } 278 279 func (s *PeekerSuite) TestPeeksBlockUntilRejected(c *gc.C) { 280 source := hooktesting.NewFullBufferedSource() 281 defer statetesting.AssertStop(c, source) 282 283 peeker := hook.NewPeeker(source) 284 defer statetesting.AssertStop(c, peeker) 285 286 // Collect a peek... 287 timeout := time.After(coretesting.LongWait) 288 select { 289 case <-timeout: 290 c.Fatalf("failed to receive peek") 291 case peek, ok := <-peeker.Peeks(): 292 c.Assert(ok, jc.IsTrue) 293 c.Assert(peek.HookInfo(), gc.Equals, hook.Info{Kind: hooks.Install}) 294 295 // ...and check that changes can't be delivered... 296 select { 297 case source.ChangesC <- source.NewChange(nil): 298 c.Fatalf("delivered change while supposedly peeking") 299 default: 300 } 301 302 // ...before the peek is rejected, at which point changes are unblocked. 303 peek.Reject() 304 select { 305 case source.ChangesC <- source.NewChange(nil): 306 case <-timeout: 307 c.Fatalf("failed to unblock changes") 308 } 309 } 310 } 311 312 func (s *PeekerSuite) TestPeeksBlockUntilConsumed(c *gc.C) { 313 source := hooktesting.NewFullBufferedSource() 314 defer statetesting.AssertStop(c, source) 315 316 peeker := hook.NewPeeker(source) 317 defer statetesting.AssertStop(c, peeker) 318 319 // Collect a peek... 320 timeout := time.After(coretesting.LongWait) 321 select { 322 case <-timeout: 323 c.Fatalf("failed to receive peek") 324 case peek, ok := <-peeker.Peeks(): 325 c.Assert(ok, jc.IsTrue) 326 c.Assert(peek.HookInfo(), gc.Equals, hook.Info{Kind: hooks.Install}) 327 328 // ...and check that changes can't be delivered... 329 select { 330 case source.ChangesC <- source.NewChange(nil): 331 c.Fatalf("delivered change while supposedly peeking") 332 default: 333 } 334 335 // ...before the peek is consumed, at which point changes are unblocked. 336 peek.Consume() 337 select { 338 case source.ChangesC <- source.NewChange(nil): 339 case <-timeout: 340 c.Fatalf("failed to unblock changes") 341 } 342 } 343 } 344 345 func (s *PeekerSuite) TestBlocksWhenUpdating(c *gc.C) { 346 source := hooktesting.NewFullUnbufferedSource() 347 defer statetesting.AssertStop(c, source) 348 349 peeker := hook.NewPeeker(source) 350 defer statetesting.AssertStop(c, peeker) 351 352 // Deliver a change. 353 timeout := time.After(coretesting.LongWait) 354 select { 355 case source.ChangesC <- source.NewChange("sent"): 356 case <-timeout: 357 c.Fatalf("failed to send change") 358 } 359 360 // Check peeks are not delivered... 361 select { 362 case peek, ok := <-peeker.Peeks(): 363 c.Fatalf("got unexpected peek: %#v, %#v", peek, ok) 364 default: 365 } 366 367 // ...before the update is handled... 368 select { 369 case update, ok := <-source.UpdatesC: 370 c.Assert(ok, jc.IsTrue) 371 c.Assert(update, gc.Equals, "sent") 372 case <-timeout: 373 c.Fatalf("failed to collect update") 374 } 375 376 // ...at which point peeks are expected again. 377 select { 378 case peek, ok := <-peeker.Peeks(): 379 c.Assert(ok, jc.IsTrue) 380 c.Assert(peek.HookInfo(), gc.Equals, hook.Info{Kind: hooks.Install}) 381 peek.Reject() 382 case <-timeout: 383 c.Fatalf("failed to send peek") 384 } 385 } 386 387 func assertStopPeeker(c *gc.C, peeker hook.Peeker, source *hooktesting.UpdateSource) { 388 // Stop the peeker... 389 err := peeker.Stop() 390 c.Assert(err, gc.IsNil) 391 392 // ...and check it closed the channel... 393 select { 394 case peek, ok := <-peeker.Peeks(): 395 c.Assert(peek, gc.IsNil) 396 c.Assert(ok, jc.IsFalse) 397 default: 398 c.Fatalf("peeks channel not closed") 399 } 400 401 // ...and stopped the source. 402 select { 403 case <-source.Tomb.Dead(): 404 c.Assert(source.Tomb.Err(), jc.ErrorIsNil) 405 default: 406 c.Fatalf("source not stopped") 407 } 408 }