launchpad.net/~rogpeppe/juju-core/500-errgo-fix@v0.0.0-20140213181702-000000002356/state/presence/presence_test.go (about) 1 // Copyright 2012, 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package presence_test 5 6 import ( 7 "strconv" 8 stdtesting "testing" 9 "time" 10 11 "labix.org/v2/mgo" 12 gc "launchpad.net/gocheck" 13 "launchpad.net/tomb" 14 15 "launchpad.net/juju-core/state/presence" 16 "launchpad.net/juju-core/testing" 17 "launchpad.net/juju-core/testing/testbase" 18 ) 19 20 func TestPackage(t *stdtesting.T) { 21 testing.MgoTestPackage(t) 22 } 23 24 type PresenceSuite struct { 25 testing.MgoSuite 26 testbase.LoggingSuite 27 presence *mgo.Collection 28 pings *mgo.Collection 29 } 30 31 var _ = gc.Suite(&PresenceSuite{}) 32 33 func (s *PresenceSuite) SetUpSuite(c *gc.C) { 34 s.LoggingSuite.SetUpSuite(c) 35 s.MgoSuite.SetUpSuite(c) 36 } 37 38 func (s *PresenceSuite) TearDownSuite(c *gc.C) { 39 s.MgoSuite.TearDownSuite(c) 40 s.LoggingSuite.TearDownSuite(c) 41 } 42 43 func (s *PresenceSuite) SetUpTest(c *gc.C) { 44 s.LoggingSuite.SetUpTest(c) 45 s.MgoSuite.SetUpTest(c) 46 47 db := s.MgoSuite.Session.DB("presence") 48 s.presence = db.C("presence") 49 s.pings = db.C("presence.pings") 50 51 presence.FakeTimeSlot(0) 52 } 53 54 func (s *PresenceSuite) TearDownTest(c *gc.C) { 55 s.MgoSuite.TearDownTest(c) 56 s.LoggingSuite.TearDownTest(c) 57 58 presence.RealTimeSlot() 59 presence.RealPeriod() 60 } 61 62 func assertChange(c *gc.C, watch <-chan presence.Change, want presence.Change) { 63 select { 64 case got := <-watch: 65 if got != want { 66 c.Fatalf("watch reported %v, want %v", got, want) 67 } 68 case <-time.After(testing.LongWait): 69 c.Fatalf("watch reported nothing, want %v", want) 70 } 71 } 72 73 func assertNoChange(c *gc.C, watch <-chan presence.Change) { 74 select { 75 case got := <-watch: 76 c.Fatalf("watch reported %v, want nothing", got) 77 case <-time.After(testing.ShortWait): 78 } 79 } 80 81 func assertAlive(c *gc.C, w *presence.Watcher, key string, alive bool) { 82 alive, err := w.Alive("a") 83 c.Assert(err, gc.IsNil) 84 c.Assert(alive, gc.Equals, alive) 85 } 86 87 func (s *PresenceSuite) TestErrAndDead(c *gc.C) { 88 w := presence.NewWatcher(s.presence) 89 defer w.Stop() 90 91 c.Assert(w.Err(), gc.Equals, tomb.ErrStillAlive) 92 select { 93 case <-w.Dead(): 94 c.Fatalf("Dead channel fired unexpectedly") 95 default: 96 } 97 c.Assert(w.Stop(), gc.IsNil) 98 c.Assert(w.Err(), gc.IsNil) 99 select { 100 case <-w.Dead(): 101 default: 102 c.Fatalf("Dead channel should have fired") 103 } 104 } 105 106 func (s *PresenceSuite) TestAliveError(c *gc.C) { 107 w := presence.NewWatcher(s.presence) 108 c.Assert(w.Stop(), gc.IsNil) 109 110 alive, err := w.Alive("a") 111 c.Assert(err, gc.ErrorMatches, ".*: watcher is dying") 112 c.Assert(alive, gc.Equals, false) 113 } 114 115 func (s *PresenceSuite) TestWorkflow(c *gc.C) { 116 w := presence.NewWatcher(s.presence) 117 pa := presence.NewPinger(s.presence, "a") 118 pb := presence.NewPinger(s.presence, "b") 119 defer w.Stop() 120 defer pa.Stop() 121 defer pb.Stop() 122 123 assertAlive(c, w, "a", false) 124 assertAlive(c, w, "b", false) 125 126 // Buffer one entry to avoid blocking the watcher here. 127 cha := make(chan presence.Change, 1) 128 chb := make(chan presence.Change, 1) 129 w.Watch("a", cha) 130 w.Watch("b", chb) 131 132 // Initial events with current status. 133 assertChange(c, cha, presence.Change{"a", false}) 134 assertChange(c, chb, presence.Change{"b", false}) 135 136 w.StartSync() 137 assertNoChange(c, cha) 138 assertNoChange(c, chb) 139 140 c.Assert(pa.Start(), gc.IsNil) 141 142 w.StartSync() 143 assertChange(c, cha, presence.Change{"a", true}) 144 assertNoChange(c, cha) 145 assertNoChange(c, chb) 146 147 assertAlive(c, w, "a", true) 148 assertAlive(c, w, "b", false) 149 150 // Changes while the channel is out are not observed. 151 w.Unwatch("a", cha) 152 assertNoChange(c, cha) 153 pa.Kill() 154 w.Sync() 155 pa = presence.NewPinger(s.presence, "a") 156 pa.Start() 157 w.StartSync() 158 assertNoChange(c, cha) 159 160 // We can still query it manually, though. 161 assertAlive(c, w, "a", true) 162 assertAlive(c, w, "b", false) 163 164 // Initial positive event. No refresh needed. 165 w.Watch("a", cha) 166 assertChange(c, cha, presence.Change{"a", true}) 167 168 c.Assert(pb.Start(), gc.IsNil) 169 170 w.StartSync() 171 assertChange(c, chb, presence.Change{"b", true}) 172 assertNoChange(c, cha) 173 assertNoChange(c, chb) 174 175 c.Assert(pa.Stop(), gc.IsNil) 176 177 w.StartSync() 178 assertNoChange(c, cha) 179 assertNoChange(c, chb) 180 181 // pb is running, pa isn't. 182 c.Assert(pa.Kill(), gc.IsNil) 183 c.Assert(pb.Kill(), gc.IsNil) 184 185 w.StartSync() 186 assertChange(c, cha, presence.Change{"a", false}) 187 assertChange(c, chb, presence.Change{"b", false}) 188 189 c.Assert(w.Stop(), gc.IsNil) 190 } 191 192 func (s *PresenceSuite) TestScale(c *gc.C) { 193 const N = 1000 194 var ps []*presence.Pinger 195 defer func() { 196 for _, p := range ps { 197 p.Stop() 198 } 199 }() 200 201 c.Logf("Starting %d pingers...", N) 202 for i := 0; i < N; i++ { 203 p := presence.NewPinger(s.presence, strconv.Itoa(i)) 204 c.Assert(p.Start(), gc.IsNil) 205 ps = append(ps, p) 206 } 207 208 c.Logf("Killing odd ones...") 209 for i := 1; i < N; i += 2 { 210 c.Assert(ps[i].Kill(), gc.IsNil) 211 } 212 213 c.Logf("Checking who's still alive...") 214 w := presence.NewWatcher(s.presence) 215 defer w.Stop() 216 w.Sync() 217 ch := make(chan presence.Change) 218 for i := 0; i < N; i++ { 219 k := strconv.Itoa(i) 220 w.Watch(k, ch) 221 if i%2 == 0 { 222 assertChange(c, ch, presence.Change{k, true}) 223 } else { 224 assertChange(c, ch, presence.Change{k, false}) 225 } 226 } 227 } 228 229 func (s *PresenceSuite) TestExpiry(c *gc.C) { 230 w := presence.NewWatcher(s.presence) 231 p := presence.NewPinger(s.presence, "a") 232 defer w.Stop() 233 defer p.Stop() 234 235 ch := make(chan presence.Change) 236 w.Watch("a", ch) 237 assertChange(c, ch, presence.Change{"a", false}) 238 239 c.Assert(p.Start(), gc.IsNil) 240 w.StartSync() 241 assertChange(c, ch, presence.Change{"a", true}) 242 243 // Still alive in previous slot. 244 presence.FakeTimeSlot(1) 245 w.StartSync() 246 assertNoChange(c, ch) 247 248 // Two last slots are empty. 249 presence.FakeTimeSlot(2) 250 w.StartSync() 251 assertChange(c, ch, presence.Change{"a", false}) 252 253 // Already dead so killing isn't noticed. 254 p.Kill() 255 w.StartSync() 256 assertNoChange(c, ch) 257 } 258 259 func (s *PresenceSuite) TestWatchPeriod(c *gc.C) { 260 presence.FakePeriod(1) 261 presence.RealTimeSlot() 262 263 w := presence.NewWatcher(s.presence) 264 p := presence.NewPinger(s.presence, "a") 265 defer w.Stop() 266 defer p.Stop() 267 268 ch := make(chan presence.Change) 269 w.Watch("a", ch) 270 assertChange(c, ch, presence.Change{"a", false}) 271 272 // A single ping. 273 c.Assert(p.Start(), gc.IsNil) 274 c.Assert(p.Stop(), gc.IsNil) 275 276 // Wait for next periodic refresh. 277 time.Sleep(1 * time.Second) 278 assertChange(c, ch, presence.Change{"a", true}) 279 } 280 281 func (s *PresenceSuite) TestWatchUnwatchOnQueue(c *gc.C) { 282 w := presence.NewWatcher(s.presence) 283 ch := make(chan presence.Change) 284 for i := 0; i < 100; i++ { 285 key := strconv.Itoa(i) 286 c.Logf("Adding %q", key) 287 w.Watch(key, ch) 288 } 289 for i := 1; i < 100; i += 2 { 290 key := strconv.Itoa(i) 291 c.Logf("Removing %q", key) 292 w.Unwatch(key, ch) 293 } 294 alive := make(map[string]bool) 295 for i := 0; i < 50; i++ { 296 change := <-ch 297 c.Logf("Got change for %q: %v", change.Key, change.Alive) 298 alive[change.Key] = change.Alive 299 } 300 for i := 0; i < 100; i += 2 { 301 key := strconv.Itoa(i) 302 c.Logf("Checking %q...", key) 303 c.Assert(alive[key], gc.Equals, false) 304 } 305 } 306 307 func (s *PresenceSuite) TestRestartWithoutGaps(c *gc.C) { 308 p := presence.NewPinger(s.presence, "a") 309 c.Assert(p.Start(), gc.IsNil) 310 defer p.Stop() 311 312 done := make(chan bool) 313 go func() { 314 stop := false 315 for !stop { 316 if !c.Check(p.Stop(), gc.IsNil) { 317 break 318 } 319 if !c.Check(p.Start(), gc.IsNil) { 320 break 321 } 322 select { 323 case stop = <-done: 324 default: 325 } 326 } 327 }() 328 go func() { 329 stop := false 330 for !stop { 331 w := presence.NewWatcher(s.presence) 332 w.Sync() 333 alive, err := w.Alive("a") 334 c.Check(w.Stop(), gc.IsNil) 335 if !c.Check(err, gc.IsNil) || !c.Check(alive, gc.Equals, true) { 336 break 337 } 338 select { 339 case stop = <-done: 340 default: 341 } 342 } 343 }() 344 // TODO(jam): This forceful delay of 500ms sounds like a bad test, 345 // since we always sleep for the full timeout 346 time.Sleep(500 * time.Millisecond) 347 done <- true 348 done <- true 349 } 350 351 func (s *PresenceSuite) TestPingerPeriodAndResilience(c *gc.C) { 352 // This test verifies both the periodic pinging, 353 // and also a great property of the design: deaths 354 // also expire, which means erroneous scenarios are 355 // automatically recovered from. 356 357 const period = 1 358 presence.FakePeriod(period) 359 presence.RealTimeSlot() 360 361 w := presence.NewWatcher(s.presence) 362 p1 := presence.NewPinger(s.presence, "a") 363 p2 := presence.NewPinger(s.presence, "a") 364 defer w.Stop() 365 defer p1.Stop() 366 defer p2.Stop() 367 368 // Start p1 and let it go on. 369 c.Assert(p1.Start(), gc.IsNil) 370 371 w.Sync() 372 assertAlive(c, w, "a", true) 373 374 // Start and kill p2, which will temporarily 375 // invalidate p1 and set the key as dead. 376 c.Assert(p2.Start(), gc.IsNil) 377 c.Assert(p2.Kill(), gc.IsNil) 378 379 w.Sync() 380 assertAlive(c, w, "a", false) 381 382 // Wait for two periods, and check again. Since 383 // p1 is still alive, p2's death will expire and 384 // the key will come back. 385 time.Sleep(period * 2 * time.Second) 386 387 w.Sync() 388 assertAlive(c, w, "a", true) 389 } 390 391 func (s *PresenceSuite) TestStartSync(c *gc.C) { 392 w := presence.NewWatcher(s.presence) 393 p := presence.NewPinger(s.presence, "a") 394 defer w.Stop() 395 defer p.Stop() 396 397 ch := make(chan presence.Change) 398 w.Watch("a", ch) 399 assertChange(c, ch, presence.Change{"a", false}) 400 401 c.Assert(p.Start(), gc.IsNil) 402 403 done := make(chan bool) 404 go func() { 405 w.StartSync() 406 w.StartSync() 407 w.StartSync() 408 done <- true 409 }() 410 411 select { 412 case <-done: 413 case <-time.After(testing.LongWait): 414 c.Fatalf("StartSync failed to return") 415 } 416 417 assertChange(c, ch, presence.Change{"a", true}) 418 } 419 420 func (s *PresenceSuite) TestSync(c *gc.C) { 421 w := presence.NewWatcher(s.presence) 422 p := presence.NewPinger(s.presence, "a") 423 defer w.Stop() 424 defer p.Stop() 425 426 ch := make(chan presence.Change) 427 w.Watch("a", ch) 428 assertChange(c, ch, presence.Change{"a", false}) 429 430 // Nothing to do here. 431 w.Sync() 432 433 c.Assert(p.Start(), gc.IsNil) 434 435 done := make(chan bool) 436 go func() { 437 w.Sync() 438 done <- true 439 }() 440 441 select { 442 case <-done: 443 c.Fatalf("Sync returned too early") 444 // Note(jam): This used to wait 200ms to ensure that 445 // Sync was actually blocked waiting for a presence 446 // change. Is ShortWait long enough for this assurance? 447 case <-time.After(testing.ShortWait): 448 } 449 450 assertChange(c, ch, presence.Change{"a", true}) 451 452 select { 453 case <-done: 454 case <-time.After(testing.LongWait): 455 c.Fatalf("Sync failed to returned") 456 } 457 } 458 459 func (s *PresenceSuite) TestFindAllBeings(c *gc.C) { 460 w := presence.NewWatcher(s.presence) 461 p := presence.NewPinger(s.presence, "a") 462 defer w.Stop() 463 defer p.Stop() 464 465 ch := make(chan presence.Change) 466 w.Watch("a", ch) 467 assertChange(c, ch, presence.Change{"a", false}) 468 c.Assert(p.Start(), gc.IsNil) 469 done := make(chan bool) 470 go func() { 471 w.Sync() 472 done <- true 473 }() 474 assertChange(c, ch, presence.Change{"a", true}) 475 results, err := presence.FindAllBeings(w) 476 c.Assert(err, gc.IsNil) 477 c.Assert(results, gc.HasLen, 1) 478 select { 479 case <-done: 480 case <-time.After(testing.LongWait): 481 c.Fatalf("Sync failed to returned") 482 } 483 }