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