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