launchpad.net/~rogpeppe/juju-core/500-errgo-fix@v0.0.0-20140213181702-000000002356/state/watcher/watcher_test.go (about) 1 // Copyright 2012, 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package watcher_test 5 6 import ( 7 stdtesting "testing" 8 "time" 9 10 "labix.org/v2/mgo" 11 "labix.org/v2/mgo/txn" 12 gc "launchpad.net/gocheck" 13 "launchpad.net/tomb" 14 15 "launchpad.net/juju-core/state/watcher" 16 "launchpad.net/juju-core/testing" 17 "launchpad.net/juju-core/testing/testbase" 18 ) 19 20 // Test tuning parameters. 21 const ( 22 // worstCase is used for timeouts when timing out 23 // will fail the test. Raising this value should 24 // not affect the overall running time of the tests 25 // unless they fail. 26 worstCase = testing.LongWait 27 28 // justLongEnough is used for timeouts that 29 // are expected to happen for a test to complete 30 // successfully. Reducing this value will make 31 // the tests run faster at the expense of making them 32 // fail more often on heavily loaded or slow hardware. 33 justLongEnough = testing.ShortWait 34 35 // fastPeriod specifies the period of the watcher for 36 // tests where the timing is not critical. 37 fastPeriod = 10 * time.Millisecond 38 39 // slowPeriod specifies the period of the watcher 40 // for tests where the timing is important. 41 slowPeriod = 1 * time.Second 42 ) 43 44 func TestPackage(t *stdtesting.T) { 45 testing.MgoTestPackage(t) 46 } 47 48 type watcherSuite struct { 49 testing.MgoSuite 50 testbase.LoggingSuite 51 52 log *mgo.Collection 53 stash *mgo.Collection 54 runner *txn.Runner 55 w *watcher.Watcher 56 ch chan watcher.Change 57 oldPeriod time.Duration 58 } 59 60 // FastPeriodSuite implements tests that should 61 // work regardless of the watcher refresh period. 62 type FastPeriodSuite struct { 63 watcherSuite 64 } 65 66 func (s *FastPeriodSuite) SetUpSuite(c *gc.C) { 67 s.watcherSuite.SetUpSuite(c) 68 watcher.Period = fastPeriod 69 } 70 71 var _ = gc.Suite(&FastPeriodSuite{}) 72 73 func (s *watcherSuite) SetUpSuite(c *gc.C) { 74 s.LoggingSuite.SetUpSuite(c) 75 s.MgoSuite.SetUpSuite(c) 76 s.oldPeriod = watcher.Period 77 } 78 79 func (s *watcherSuite) TearDownSuite(c *gc.C) { 80 s.MgoSuite.TearDownSuite(c) 81 s.LoggingSuite.TearDownSuite(c) 82 watcher.Period = s.oldPeriod 83 } 84 85 func (s *watcherSuite) SetUpTest(c *gc.C) { 86 s.LoggingSuite.SetUpTest(c) 87 s.MgoSuite.SetUpTest(c) 88 89 db := s.MgoSuite.Session.DB("juju") 90 s.log = db.C("txnlog") 91 s.log.Create(&mgo.CollectionInfo{ 92 Capped: true, 93 MaxBytes: 1000000, 94 }) 95 s.stash = db.C("txn.stash") 96 s.runner = txn.NewRunner(db.C("txn")) 97 s.runner.ChangeLog(s.log) 98 s.w = watcher.New(s.log) 99 s.ch = make(chan watcher.Change) 100 } 101 102 func (s *watcherSuite) TearDownTest(c *gc.C) { 103 c.Assert(s.w.Stop(), gc.IsNil) 104 105 s.MgoSuite.TearDownTest(c) 106 s.LoggingSuite.TearDownTest(c) 107 } 108 109 type M map[string]interface{} 110 111 func assertChange(c *gc.C, watch <-chan watcher.Change, want watcher.Change) { 112 select { 113 case got := <-watch: 114 if got != want { 115 c.Fatalf("watch reported %v, want %v", got, want) 116 } 117 case <-time.After(worstCase): 118 c.Fatalf("watch reported nothing, want %v", want) 119 } 120 } 121 122 func assertNoChange(c *gc.C, watch <-chan watcher.Change) { 123 select { 124 case got := <-watch: 125 c.Fatalf("watch reported %v, want nothing", got) 126 case <-time.After(justLongEnough): 127 } 128 } 129 130 func assertOrder(c *gc.C, revnos ...int64) { 131 last := int64(-2) 132 for _, revno := range revnos { 133 if revno <= last { 134 c.Fatalf("got bad revno sequence: %v", revnos) 135 } 136 last = revno 137 } 138 } 139 140 func (s *watcherSuite) revno(c string, id interface{}) (revno int64) { 141 var doc struct { 142 Revno int64 "txn-revno" 143 } 144 err := s.log.Database.C(c).FindId(id).One(&doc) 145 if err != nil { 146 panic(err) 147 } 148 return doc.Revno 149 } 150 151 func (s *watcherSuite) insert(c *gc.C, coll string, id interface{}) (revno int64) { 152 ops := []txn.Op{{C: coll, Id: id, Insert: M{"n": 1}}} 153 err := s.runner.Run(ops, "", nil) 154 if err != nil { 155 panic(err) 156 } 157 revno = s.revno(coll, id) 158 c.Logf("insert(%#v, %#v) => revno %d", coll, id, revno) 159 return revno 160 } 161 162 func (s *watcherSuite) insertAll(c *gc.C, coll string, ids ...interface{}) (revnos []int64) { 163 var ops []txn.Op 164 for _, id := range ids { 165 ops = append(ops, txn.Op{C: coll, Id: id, Insert: M{"n": 1}}) 166 } 167 err := s.runner.Run(ops, "", nil) 168 if err != nil { 169 panic(err) 170 } 171 for _, id := range ids { 172 revnos = append(revnos, s.revno(coll, id)) 173 } 174 c.Logf("insertAll(%#v, %v) => revnos %v", coll, ids, revnos) 175 return revnos 176 } 177 178 func (s *watcherSuite) update(c *gc.C, coll string, id interface{}) (revno int64) { 179 ops := []txn.Op{{C: coll, Id: id, Update: M{"$inc": M{"n": 1}}}} 180 err := s.runner.Run(ops, "", nil) 181 if err != nil { 182 panic(err) 183 } 184 revno = s.revno(coll, id) 185 c.Logf("update(%#v, %#v) => revno %d", coll, id, revno) 186 return revno 187 } 188 189 func (s *watcherSuite) remove(c *gc.C, coll string, id interface{}) (revno int64) { 190 ops := []txn.Op{{C: coll, Id: id, Remove: true}} 191 err := s.runner.Run(ops, "", nil) 192 if err != nil { 193 panic(err) 194 } 195 c.Logf("remove(%#v, %#v) => revno -1", coll, id) 196 return -1 197 } 198 199 func (s *FastPeriodSuite) TestErrAndDead(c *gc.C) { 200 c.Assert(s.w.Err(), gc.Equals, tomb.ErrStillAlive) 201 select { 202 case <-s.w.Dead(): 203 c.Fatalf("Dead channel fired unexpectedly") 204 default: 205 } 206 c.Assert(s.w.Stop(), gc.IsNil) 207 c.Assert(s.w.Err(), gc.IsNil) 208 select { 209 case <-s.w.Dead(): 210 default: 211 c.Fatalf("Dead channel should have fired") 212 } 213 } 214 215 func (s *FastPeriodSuite) TestWatchBeforeKnown(c *gc.C) { 216 s.w.Watch("test", "a", -1, s.ch) 217 assertNoChange(c, s.ch) 218 219 revno := s.insert(c, "test", "a") 220 221 s.w.StartSync() 222 assertChange(c, s.ch, watcher.Change{"test", "a", revno}) 223 assertNoChange(c, s.ch) 224 225 assertOrder(c, -1, revno) 226 } 227 228 func (s *FastPeriodSuite) TestWatchAfterKnown(c *gc.C) { 229 revno := s.insert(c, "test", "a") 230 231 s.w.StartSync() 232 233 s.w.Watch("test", "a", -1, s.ch) 234 assertChange(c, s.ch, watcher.Change{"test", "a", revno}) 235 assertNoChange(c, s.ch) 236 237 assertOrder(c, -1, revno) 238 } 239 240 func (s *FastPeriodSuite) TestWatchIgnoreUnwatched(c *gc.C) { 241 s.w.Watch("test", "a", -1, s.ch) 242 assertNoChange(c, s.ch) 243 244 s.insert(c, "test", "b") 245 246 s.w.StartSync() 247 assertNoChange(c, s.ch) 248 } 249 250 func (s *FastPeriodSuite) TestWatchOrder(c *gc.C) { 251 s.w.StartSync() 252 for _, id := range []string{"a", "b", "c", "d"} { 253 s.w.Watch("test", id, -1, s.ch) 254 } 255 revno1 := s.insert(c, "test", "a") 256 revno2 := s.insert(c, "test", "b") 257 revno3 := s.insert(c, "test", "c") 258 259 s.w.StartSync() 260 assertChange(c, s.ch, watcher.Change{"test", "a", revno1}) 261 assertChange(c, s.ch, watcher.Change{"test", "b", revno2}) 262 assertChange(c, s.ch, watcher.Change{"test", "c", revno3}) 263 assertNoChange(c, s.ch) 264 } 265 266 func (s *FastPeriodSuite) TestTransactionWithMultiple(c *gc.C) { 267 s.w.StartSync() 268 for _, id := range []string{"a", "b", "c"} { 269 s.w.Watch("test", id, -1, s.ch) 270 } 271 revnos := s.insertAll(c, "test", "a", "b", "c") 272 s.w.StartSync() 273 assertChange(c, s.ch, watcher.Change{"test", "a", revnos[0]}) 274 assertChange(c, s.ch, watcher.Change{"test", "b", revnos[1]}) 275 assertChange(c, s.ch, watcher.Change{"test", "c", revnos[2]}) 276 assertNoChange(c, s.ch) 277 } 278 279 func (s *FastPeriodSuite) TestWatchMultipleChannels(c *gc.C) { 280 ch1 := make(chan watcher.Change) 281 ch2 := make(chan watcher.Change) 282 ch3 := make(chan watcher.Change) 283 s.w.Watch("test1", 1, -1, ch1) 284 s.w.Watch("test2", 2, -1, ch2) 285 s.w.Watch("test3", 3, -1, ch3) 286 revno1 := s.insert(c, "test1", 1) 287 revno2 := s.insert(c, "test2", 2) 288 revno3 := s.insert(c, "test3", 3) 289 s.w.StartSync() 290 s.w.Unwatch("test2", 2, ch2) 291 assertChange(c, ch1, watcher.Change{"test1", 1, revno1}) 292 _ = revno2 293 assertChange(c, ch3, watcher.Change{"test3", 3, revno3}) 294 assertNoChange(c, ch1) 295 assertNoChange(c, ch2) 296 assertNoChange(c, ch3) 297 } 298 299 func (s *FastPeriodSuite) TestIgnoreAncientHistory(c *gc.C) { 300 s.insert(c, "test", "a") 301 302 w := watcher.New(s.log) 303 defer w.Stop() 304 w.StartSync() 305 306 w.Watch("test", "a", -1, s.ch) 307 assertNoChange(c, s.ch) 308 } 309 310 func (s *FastPeriodSuite) TestUpdate(c *gc.C) { 311 s.w.Watch("test", "a", -1, s.ch) 312 assertNoChange(c, s.ch) 313 314 revno1 := s.insert(c, "test", "a") 315 s.w.StartSync() 316 assertChange(c, s.ch, watcher.Change{"test", "a", revno1}) 317 assertNoChange(c, s.ch) 318 319 revno2 := s.update(c, "test", "a") 320 s.w.StartSync() 321 assertChange(c, s.ch, watcher.Change{"test", "a", revno2}) 322 323 assertOrder(c, -1, revno1, revno2) 324 } 325 326 func (s *FastPeriodSuite) TestRemove(c *gc.C) { 327 s.w.Watch("test", "a", -1, s.ch) 328 assertNoChange(c, s.ch) 329 330 revno1 := s.insert(c, "test", "a") 331 s.w.StartSync() 332 assertChange(c, s.ch, watcher.Change{"test", "a", revno1}) 333 assertNoChange(c, s.ch) 334 335 revno2 := s.remove(c, "test", "a") 336 s.w.StartSync() 337 assertChange(c, s.ch, watcher.Change{"test", "a", -1}) 338 assertNoChange(c, s.ch) 339 340 revno3 := s.insert(c, "test", "a") 341 s.w.StartSync() 342 assertChange(c, s.ch, watcher.Change{"test", "a", revno3}) 343 assertNoChange(c, s.ch) 344 345 assertOrder(c, revno2, revno1) 346 assertOrder(c, revno2, revno3) 347 } 348 349 func (s *FastPeriodSuite) TestWatchKnownRemove(c *gc.C) { 350 revno1 := s.insert(c, "test", "a") 351 revno2 := s.remove(c, "test", "a") 352 s.w.StartSync() 353 354 s.w.Watch("test", "a", revno1, s.ch) 355 assertChange(c, s.ch, watcher.Change{"test", "a", revno2}) 356 357 assertOrder(c, revno2, revno1) 358 } 359 360 func (s *FastPeriodSuite) TestScale(c *gc.C) { 361 const N = 500 362 const T = 10 363 364 c.Logf("Creating %d documents, %d per transaction...", N, T) 365 ops := make([]txn.Op, T) 366 for i := 0; i < (N / T); i++ { 367 ops = ops[:0] 368 for j := 0; j < T && i*T+j < N; j++ { 369 ops = append(ops, txn.Op{C: "test", Id: i*T + j, Insert: M{"n": 1}}) 370 } 371 err := s.runner.Run(ops, "", nil) 372 c.Assert(err, gc.IsNil) 373 } 374 375 c.Logf("Watching all documents...") 376 for i := 0; i < N; i++ { 377 s.w.Watch("test", i, -1, s.ch) 378 } 379 380 c.Logf("Forcing a refresh...") 381 s.w.StartSync() 382 383 count, err := s.Session.DB("juju").C("test").Count() 384 c.Assert(err, gc.IsNil) 385 c.Logf("Got %d documents in the collection...", count) 386 c.Assert(count, gc.Equals, N) 387 388 c.Logf("Reading all changes...") 389 seen := make(map[interface{}]bool) 390 for i := 0; i < N; i++ { 391 select { 392 case change := <-s.ch: 393 seen[change.Id] = true 394 case <-time.After(worstCase): 395 c.Fatalf("not enough changes: got %d, want %d", len(seen), N) 396 } 397 } 398 c.Assert(len(seen), gc.Equals, N) 399 } 400 401 func (s *FastPeriodSuite) TestWatchUnwatchOnQueue(c *gc.C) { 402 const N = 10 403 for i := 0; i < N; i++ { 404 s.insert(c, "test", i) 405 } 406 s.w.StartSync() 407 for i := 0; i < N; i++ { 408 s.w.Watch("test", i, -1, s.ch) 409 } 410 for i := 1; i < N; i += 2 { 411 s.w.Unwatch("test", i, s.ch) 412 } 413 s.w.StartSync() 414 seen := make(map[interface{}]bool) 415 for i := 0; i < N/2; i++ { 416 select { 417 case change := <-s.ch: 418 seen[change.Id] = true 419 case <-time.After(worstCase): 420 c.Fatalf("not enough changes: got %d, want %d", len(seen), N/2) 421 } 422 } 423 c.Assert(len(seen), gc.Equals, N/2) 424 assertNoChange(c, s.ch) 425 } 426 427 func (s *FastPeriodSuite) TestStartSync(c *gc.C) { 428 s.w.Watch("test", "a", -1, s.ch) 429 430 revno := s.insert(c, "test", "a") 431 432 done := make(chan bool) 433 go func() { 434 s.w.StartSync() 435 s.w.StartSync() 436 s.w.StartSync() 437 done <- true 438 }() 439 440 select { 441 case <-done: 442 case <-time.After(worstCase): 443 c.Fatalf("StartSync failed to return") 444 } 445 446 assertChange(c, s.ch, watcher.Change{"test", "a", revno}) 447 } 448 449 func (s *FastPeriodSuite) TestWatchCollection(c *gc.C) { 450 chA1 := make(chan watcher.Change) 451 chB1 := make(chan watcher.Change) 452 chA := make(chan watcher.Change) 453 chB := make(chan watcher.Change) 454 455 s.w.Watch("testA", 1, -1, chA1) 456 s.w.Watch("testB", 1, -1, chB1) 457 s.w.WatchCollection("testA", chA) 458 s.w.WatchCollection("testB", chB) 459 460 revno1 := s.insert(c, "testA", 1) 461 revno2 := s.insert(c, "testA", 2) 462 revno3 := s.insert(c, "testB", 1) 463 revno4 := s.insert(c, "testB", 2) 464 465 s.w.StartSync() 466 467 seen := map[chan<- watcher.Change][]watcher.Change{} 468 timeout := time.After(testing.LongWait) 469 n := 0 470 Loop1: 471 for n < 6 { 472 select { 473 case chg := <-chA1: 474 seen[chA1] = append(seen[chA1], chg) 475 case chg := <-chB1: 476 seen[chB1] = append(seen[chB1], chg) 477 case chg := <-chA: 478 seen[chA] = append(seen[chA], chg) 479 case chg := <-chB: 480 seen[chB] = append(seen[chB], chg) 481 case <-timeout: 482 break Loop1 483 } 484 n++ 485 } 486 487 c.Check(seen[chA1], gc.DeepEquals, []watcher.Change{{"testA", 1, revno1}}) 488 c.Check(seen[chB1], gc.DeepEquals, []watcher.Change{{"testB", 1, revno3}}) 489 c.Check(seen[chA], gc.DeepEquals, []watcher.Change{{"testA", 1, revno1}, {"testA", 2, revno2}}) 490 c.Check(seen[chB], gc.DeepEquals, []watcher.Change{{"testB", 1, revno3}, {"testB", 2, revno4}}) 491 if c.Failed() { 492 return 493 } 494 495 s.w.UnwatchCollection("testB", chB) 496 s.w.Unwatch("testB", 1, chB1) 497 498 revno1 = s.update(c, "testA", 1) 499 revno3 = s.update(c, "testB", 1) 500 501 s.w.StartSync() 502 503 timeout = time.After(testing.LongWait) 504 seen = map[chan<- watcher.Change][]watcher.Change{} 505 n = 0 506 Loop2: 507 for n < 2 { 508 select { 509 case chg := <-chA1: 510 seen[chA1] = append(seen[chA1], chg) 511 case chg := <-chB1: 512 seen[chB1] = append(seen[chB1], chg) 513 case chg := <-chA: 514 seen[chA] = append(seen[chA], chg) 515 case chg := <-chB: 516 seen[chB] = append(seen[chB], chg) 517 case <-timeout: 518 break Loop2 519 } 520 n++ 521 } 522 c.Check(seen[chA1], gc.DeepEquals, []watcher.Change{{"testA", 1, revno1}}) 523 c.Check(seen[chB1], gc.IsNil) 524 c.Check(seen[chA], gc.DeepEquals, []watcher.Change{{"testA", 1, revno1}}) 525 c.Check(seen[chB], gc.IsNil) 526 527 // Check that no extra events arrive. 528 seen = map[chan<- watcher.Change][]watcher.Change{} 529 timeout = time.After(testing.ShortWait) 530 Loop3: 531 for { 532 select { 533 case chg := <-chA1: 534 seen[chA1] = append(seen[chA1], chg) 535 case chg := <-chB1: 536 seen[chB1] = append(seen[chB1], chg) 537 case chg := <-chA: 538 seen[chA] = append(seen[chA], chg) 539 case chg := <-chB: 540 seen[chB] = append(seen[chB], chg) 541 case <-timeout: 542 break Loop3 543 } 544 } 545 c.Check(seen[chA1], gc.IsNil) 546 c.Check(seen[chB1], gc.IsNil) 547 c.Check(seen[chA], gc.IsNil) 548 c.Check(seen[chB], gc.IsNil) 549 } 550 551 func (s *FastPeriodSuite) TestUnwatchCollectionWithFilter(c *gc.C) { 552 filter := func(key interface{}) bool { 553 id := key.(int) 554 return id != 2 555 } 556 chA := make(chan watcher.Change) 557 s.w.WatchCollectionWithFilter("testA", chA, filter) 558 revnoA := s.insert(c, "testA", 1) 559 assertChange(c, chA, watcher.Change{"testA", 1, revnoA}) 560 s.insert(c, "testA", 2) 561 assertNoChange(c, chA) 562 s.insert(c, "testA", 3) 563 s.w.StartSync() 564 assertChange(c, chA, watcher.Change{"testA", 3, revnoA}) 565 } 566 567 func (s *FastPeriodSuite) TestUnwatchCollectionWithOutstandingRequest(c *gc.C) { 568 chA := make(chan watcher.Change) 569 s.w.WatchCollection("testA", chA) 570 chB := make(chan watcher.Change) 571 s.w.Watch("testB", 1, -1, chB) 572 revnoA := s.insert(c, "testA", 1) 573 s.insert(c, "testA", 2) 574 // By inserting this *after* the testA document, we ensure that 575 // the watcher will try to send on chB after sending on chA. 576 // The original bug that this test guards against meant that the 577 // UnwatchCollection did not correctly cancel the outstanding 578 // request, so the loop would never get around to sending on 579 // chB. 580 revnoB := s.insert(c, "testB", 1) 581 s.w.StartSync() 582 // When we receive the first change on chA, we know that 583 // the watcher is trying to send changes on all the 584 // watcher channels (2 changes on chA and 1 change on chB). 585 assertChange(c, chA, watcher.Change{"testA", 1, revnoA}) 586 s.w.UnwatchCollection("testA", chA) 587 assertChange(c, chB, watcher.Change{"testB", 1, revnoB}) 588 } 589 590 func (s *FastPeriodSuite) TestNonMutatingTxn(c *gc.C) { 591 chA1 := make(chan watcher.Change) 592 chA := make(chan watcher.Change) 593 594 revno1 := s.insert(c, "test", "a") 595 596 s.w.StartSync() 597 598 s.w.Watch("test", 1, revno1, chA1) 599 s.w.WatchCollection("test", chA) 600 601 revno2 := s.insert(c, "test", "a") 602 603 c.Assert(revno1, gc.Equals, revno2) 604 605 s.w.StartSync() 606 607 assertNoChange(c, chA1) 608 assertNoChange(c, chA) 609 } 610 611 // SlowPeriodSuite implements tests 612 // that are flaky when the watcher refresh period 613 // is small. 614 type SlowPeriodSuite struct { 615 watcherSuite 616 } 617 618 func (s *SlowPeriodSuite) SetUpSuite(c *gc.C) { 619 s.watcherSuite.SetUpSuite(c) 620 watcher.Period = slowPeriod 621 } 622 623 var _ = gc.Suite(&SlowPeriodSuite{}) 624 625 func (s *SlowPeriodSuite) TestWatchBeforeRemoveKnown(c *gc.C) { 626 revno1 := s.insert(c, "test", "a") 627 s.w.StartSync() 628 revno2 := s.remove(c, "test", "a") 629 630 s.w.Watch("test", "a", -1, s.ch) 631 assertChange(c, s.ch, watcher.Change{"test", "a", revno1}) 632 s.w.StartSync() 633 assertChange(c, s.ch, watcher.Change{"test", "a", revno2}) 634 635 assertOrder(c, revno2, revno1) 636 } 637 638 func (s *SlowPeriodSuite) TestDoubleUpdate(c *gc.C) { 639 assertNoChange(c, s.ch) 640 641 revno1 := s.insert(c, "test", "a") 642 s.w.StartSync() 643 644 revno2 := s.update(c, "test", "a") 645 revno3 := s.update(c, "test", "a") 646 647 s.w.Watch("test", "a", revno2, s.ch) 648 assertNoChange(c, s.ch) 649 650 s.w.StartSync() 651 assertChange(c, s.ch, watcher.Change{"test", "a", revno3}) 652 assertNoChange(c, s.ch) 653 654 assertOrder(c, -1, revno1, revno2, revno3) 655 } 656 657 func (s *SlowPeriodSuite) TestWatchPeriod(c *gc.C) { 658 revno1 := s.insert(c, "test", "a") 659 s.w.StartSync() 660 t0 := time.Now() 661 s.w.Watch("test", "a", revno1, s.ch) 662 revno2 := s.update(c, "test", "a") 663 664 leeway := watcher.Period / 4 665 select { 666 case got := <-s.ch: 667 gotPeriod := time.Since(t0) 668 c.Assert(got, gc.Equals, watcher.Change{"test", "a", revno2}) 669 if gotPeriod < watcher.Period-leeway { 670 c.Fatalf("watcher not waiting long enough; got %v want %v", gotPeriod, watcher.Period) 671 } 672 case <-time.After(watcher.Period + leeway): 673 gotPeriod := time.Since(t0) 674 c.Fatalf("watcher waited too long; got %v want %v", gotPeriod, watcher.Period) 675 } 676 677 assertOrder(c, -1, revno1, revno2) 678 } 679 680 func (s *SlowPeriodSuite) TestStartSyncStartsImmediately(c *gc.C) { 681 // Ensure we're at the start of a sync cycle. 682 s.w.StartSync() 683 time.Sleep(justLongEnough) 684 685 // Watching after StartSync should see the current state of affairs. 686 revno := s.insert(c, "test", "a") 687 s.w.StartSync() 688 s.w.Watch("test", "a", -1, s.ch) 689 select { 690 case got := <-s.ch: 691 c.Assert(got.Revno, gc.Equals, revno) 692 case <-time.After(watcher.Period / 2): 693 c.Fatalf("watch after StartSync is still using old info") 694 } 695 696 s.remove(c, "test", "a") 697 s.w.StartSync() 698 ch := make(chan watcher.Change) 699 s.w.Watch("test", "a", -1, ch) 700 select { 701 case got := <-ch: 702 c.Fatalf("got event %#v when starting watcher after doc was removed", got) 703 case <-time.After(justLongEnough): 704 } 705 }