github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/worker/uniter/remotestate/watcher_test.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package remotestate_test 5 6 import ( 7 "time" 8 9 "github.com/juju/names" 10 jc "github.com/juju/testing/checkers" 11 gc "gopkg.in/check.v1" 12 "gopkg.in/juju/charm.v6-unstable" 13 14 "github.com/juju/juju/apiserver/params" 15 "github.com/juju/juju/testing" 16 "github.com/juju/juju/watcher" 17 "github.com/juju/juju/worker/uniter/remotestate" 18 ) 19 20 type WatcherSuite struct { 21 testing.BaseSuite 22 23 st *mockState 24 leadership *mockLeadershipTracker 25 watcher *remotestate.RemoteStateWatcher 26 clock *testing.Clock 27 } 28 29 // Duration is arbitrary, we'll trigger the ticker 30 // by advancing the clock past the duration. 31 var statusTickDuration = 10 * time.Second 32 33 var _ = gc.Suite(&WatcherSuite{}) 34 35 func (s *WatcherSuite) SetUpTest(c *gc.C) { 36 s.BaseSuite.SetUpTest(c) 37 s.st = &mockState{ 38 unit: mockUnit{ 39 tag: names.NewUnitTag("mysql/0"), 40 life: params.Alive, 41 service: mockService{ 42 tag: names.NewServiceTag("mysql"), 43 life: params.Alive, 44 curl: charm.MustParseURL("cs:trusty/mysql"), 45 charmModifiedVersion: 5, 46 serviceWatcher: newMockNotifyWatcher(), 47 leaderSettingsWatcher: newMockNotifyWatcher(), 48 relationsWatcher: newMockStringsWatcher(), 49 }, 50 unitWatcher: newMockNotifyWatcher(), 51 addressesWatcher: newMockNotifyWatcher(), 52 configSettingsWatcher: newMockNotifyWatcher(), 53 storageWatcher: newMockStringsWatcher(), 54 actionWatcher: newMockStringsWatcher(), 55 }, 56 relations: make(map[names.RelationTag]*mockRelation), 57 storageAttachment: make(map[params.StorageAttachmentId]params.StorageAttachment), 58 relationUnitsWatchers: make(map[names.RelationTag]*mockRelationUnitsWatcher), 59 storageAttachmentWatchers: make(map[names.StorageTag]*mockNotifyWatcher), 60 } 61 62 s.leadership = &mockLeadershipTracker{ 63 claimTicket: mockTicket{make(chan struct{}, 1), true}, 64 leaderTicket: mockTicket{make(chan struct{}, 1), true}, 65 minionTicket: mockTicket{make(chan struct{}, 1), true}, 66 } 67 68 s.clock = testing.NewClock(time.Now()) 69 statusTicker := func() <-chan time.Time { 70 return s.clock.After(statusTickDuration) 71 } 72 73 w, err := remotestate.NewWatcher(remotestate.WatcherConfig{ 74 State: s.st, 75 LeadershipTracker: s.leadership, 76 UnitTag: s.st.unit.tag, 77 UpdateStatusChannel: statusTicker, 78 }) 79 c.Assert(err, jc.ErrorIsNil) 80 s.watcher = w 81 } 82 83 func (s *WatcherSuite) TearDownTest(c *gc.C) { 84 if s.watcher != nil { 85 s.watcher.Kill() 86 err := s.watcher.Wait() 87 c.Assert(err, jc.ErrorIsNil) 88 } 89 } 90 91 func (s *WatcherSuite) TestInitialSnapshot(c *gc.C) { 92 snap := s.watcher.Snapshot() 93 c.Assert(snap, jc.DeepEquals, remotestate.Snapshot{ 94 Relations: map[int]remotestate.RelationSnapshot{}, 95 Storage: map[names.StorageTag]remotestate.StorageSnapshot{}, 96 }) 97 } 98 99 func (s *WatcherSuite) TestInitialSignal(c *gc.C) { 100 // There should not be a remote state change until 101 // we've seen all of the top-level notifications. 102 s.st.unit.unitWatcher.changes <- struct{}{} 103 assertNoNotifyEvent(c, s.watcher.RemoteStateChanged(), "remote state change") 104 105 s.st.unit.addressesWatcher.changes <- struct{}{} 106 s.st.unit.configSettingsWatcher.changes <- struct{}{} 107 s.st.unit.storageWatcher.changes <- []string{} 108 s.st.unit.actionWatcher.changes <- []string{} 109 s.st.unit.service.serviceWatcher.changes <- struct{}{} 110 s.st.unit.service.leaderSettingsWatcher.changes <- struct{}{} 111 s.st.unit.service.relationsWatcher.changes <- []string{} 112 s.leadership.claimTicket.ch <- struct{}{} 113 assertNotifyEvent(c, s.watcher.RemoteStateChanged(), "waiting for remote state change") 114 } 115 116 func signalAll(st *mockState, l *mockLeadershipTracker) { 117 st.unit.unitWatcher.changes <- struct{}{} 118 st.unit.addressesWatcher.changes <- struct{}{} 119 st.unit.configSettingsWatcher.changes <- struct{}{} 120 st.unit.storageWatcher.changes <- []string{} 121 st.unit.actionWatcher.changes <- []string{} 122 st.unit.service.serviceWatcher.changes <- struct{}{} 123 st.unit.service.leaderSettingsWatcher.changes <- struct{}{} 124 st.unit.service.relationsWatcher.changes <- []string{} 125 l.claimTicket.ch <- struct{}{} 126 } 127 128 func (s *WatcherSuite) TestSnapshot(c *gc.C) { 129 signalAll(s.st, s.leadership) 130 assertNotifyEvent(c, s.watcher.RemoteStateChanged(), "waiting for remote state change") 131 132 snap := s.watcher.Snapshot() 133 c.Assert(snap, jc.DeepEquals, remotestate.Snapshot{ 134 Life: s.st.unit.life, 135 Relations: map[int]remotestate.RelationSnapshot{}, 136 Storage: map[names.StorageTag]remotestate.StorageSnapshot{}, 137 CharmModifiedVersion: s.st.unit.service.charmModifiedVersion, 138 CharmURL: s.st.unit.service.curl, 139 ForceCharmUpgrade: s.st.unit.service.forceUpgrade, 140 ResolvedMode: s.st.unit.resolved, 141 ConfigVersion: 2, // config settings and addresses 142 LeaderSettingsVersion: 1, 143 Leader: true, 144 }) 145 } 146 147 func (s *WatcherSuite) TestRemoteStateChanged(c *gc.C) { 148 assertOneChange := func() { 149 assertNotifyEvent(c, s.watcher.RemoteStateChanged(), "waiting for remote state change") 150 assertNoNotifyEvent(c, s.watcher.RemoteStateChanged(), "remote state change") 151 } 152 153 signalAll(s.st, s.leadership) 154 assertOneChange() 155 initial := s.watcher.Snapshot() 156 157 s.st.unit.life = params.Dying 158 s.st.unit.unitWatcher.changes <- struct{}{} 159 assertOneChange() 160 c.Assert(s.watcher.Snapshot().Life, gc.Equals, params.Dying) 161 162 s.st.unit.addressesWatcher.changes <- struct{}{} 163 assertOneChange() 164 c.Assert(s.watcher.Snapshot().ConfigVersion, gc.Equals, initial.ConfigVersion+1) 165 166 s.st.unit.configSettingsWatcher.changes <- struct{}{} 167 assertOneChange() 168 c.Assert(s.watcher.Snapshot().ConfigVersion, gc.Equals, initial.ConfigVersion+2) 169 170 s.st.unit.storageWatcher.changes <- []string{} 171 assertOneChange() 172 173 s.st.unit.service.forceUpgrade = true 174 s.st.unit.service.serviceWatcher.changes <- struct{}{} 175 assertOneChange() 176 c.Assert(s.watcher.Snapshot().ForceCharmUpgrade, jc.IsTrue) 177 178 s.st.unit.service.leaderSettingsWatcher.changes <- struct{}{} 179 assertOneChange() 180 c.Assert(s.watcher.Snapshot().LeaderSettingsVersion, gc.Equals, initial.LeaderSettingsVersion+1) 181 182 s.st.unit.service.relationsWatcher.changes <- []string{} 183 assertOneChange() 184 185 s.clock.Advance(statusTickDuration + 1) 186 assertOneChange() 187 } 188 189 func (s *WatcherSuite) TestActionsReceived(c *gc.C) { 190 signalAll(s.st, s.leadership) 191 assertNotifyEvent(c, s.watcher.RemoteStateChanged(), "waiting for remote state change") 192 193 s.st.unit.actionWatcher.changes <- []string{"an-action"} 194 assertNotifyEvent(c, s.watcher.RemoteStateChanged(), "waiting for remote state change") 195 c.Assert(s.watcher.Snapshot().Actions, gc.DeepEquals, []string{"an-action"}) 196 } 197 198 func (s *WatcherSuite) TestClearResolvedMode(c *gc.C) { 199 s.st.unit.resolved = params.ResolvedRetryHooks 200 signalAll(s.st, s.leadership) 201 assertNotifyEvent(c, s.watcher.RemoteStateChanged(), "waiting for remote state change") 202 203 snap := s.watcher.Snapshot() 204 c.Assert(snap.ResolvedMode, gc.Equals, params.ResolvedRetryHooks) 205 206 s.watcher.ClearResolvedMode() 207 snap = s.watcher.Snapshot() 208 c.Assert(snap.ResolvedMode, gc.Equals, params.ResolvedNone) 209 } 210 211 func (s *WatcherSuite) TestLeadershipChanged(c *gc.C) { 212 s.leadership.claimTicket.result = false 213 signalAll(s.st, s.leadership) 214 assertNotifyEvent(c, s.watcher.RemoteStateChanged(), "waiting for remote state change") 215 c.Assert(s.watcher.Snapshot().Leader, jc.IsFalse) 216 217 s.leadership.leaderTicket.ch <- struct{}{} 218 assertNotifyEvent(c, s.watcher.RemoteStateChanged(), "waiting for remote state change") 219 c.Assert(s.watcher.Snapshot().Leader, jc.IsTrue) 220 221 s.leadership.minionTicket.ch <- struct{}{} 222 assertNotifyEvent(c, s.watcher.RemoteStateChanged(), "waiting for remote state change") 223 c.Assert(s.watcher.Snapshot().Leader, jc.IsFalse) 224 } 225 226 func (s *WatcherSuite) TestLeadershipMinionUnchanged(c *gc.C) { 227 s.leadership.claimTicket.result = false 228 signalAll(s.st, s.leadership) 229 assertNotifyEvent(c, s.watcher.RemoteStateChanged(), "waiting for remote state change") 230 231 // Initially minion, so triggering minion should have no effect. 232 s.leadership.minionTicket.ch <- struct{}{} 233 assertNoNotifyEvent(c, s.watcher.RemoteStateChanged(), "remote state change") 234 } 235 236 func (s *WatcherSuite) TestLeadershipLeaderUnchanged(c *gc.C) { 237 signalAll(s.st, s.leadership) 238 assertNotifyEvent(c, s.watcher.RemoteStateChanged(), "waiting for remote state change") 239 240 // Initially leader, so triggering leader should have no effect. 241 s.leadership.leaderTicket.ch <- struct{}{} 242 assertNoNotifyEvent(c, s.watcher.RemoteStateChanged(), "remote state change") 243 } 244 245 func (s *WatcherSuite) TestStorageChanged(c *gc.C) { 246 signalAll(s.st, s.leadership) 247 assertNotifyEvent(c, s.watcher.RemoteStateChanged(), "waiting for remote state change") 248 249 storageTag0 := names.NewStorageTag("blob/0") 250 storageAttachmentId0 := params.StorageAttachmentId{ 251 UnitTag: s.st.unit.tag.String(), 252 StorageTag: storageTag0.String(), 253 } 254 storageTag0Watcher := newMockNotifyWatcher() 255 s.st.storageAttachmentWatchers[storageTag0] = storageTag0Watcher 256 s.st.storageAttachment[storageAttachmentId0] = params.StorageAttachment{ 257 UnitTag: storageAttachmentId0.UnitTag, 258 StorageTag: storageAttachmentId0.StorageTag, 259 Life: params.Alive, 260 Kind: params.StorageKindUnknown, // unprovisioned 261 Location: "nowhere", 262 } 263 264 storageTag1 := names.NewStorageTag("blob/1") 265 storageAttachmentId1 := params.StorageAttachmentId{ 266 UnitTag: s.st.unit.tag.String(), 267 StorageTag: storageTag1.String(), 268 } 269 storageTag1Watcher := newMockNotifyWatcher() 270 s.st.storageAttachmentWatchers[storageTag1] = storageTag1Watcher 271 s.st.storageAttachment[storageAttachmentId1] = params.StorageAttachment{ 272 UnitTag: storageAttachmentId1.UnitTag, 273 StorageTag: storageAttachmentId1.StorageTag, 274 Life: params.Dying, 275 Kind: params.StorageKindBlock, 276 Location: "malta", 277 } 278 279 // We should not see any event until the storage attachment watchers 280 // return their initial events. 281 s.st.unit.storageWatcher.changes <- []string{"blob/0", "blob/1"} 282 assertNoNotifyEvent(c, s.watcher.RemoteStateChanged(), "remote state change") 283 storageTag0Watcher.changes <- struct{}{} 284 storageTag1Watcher.changes <- struct{}{} 285 assertNotifyEvent(c, s.watcher.RemoteStateChanged(), "waiting for remote state change") 286 287 c.Assert(s.watcher.Snapshot().Storage, jc.DeepEquals, map[names.StorageTag]remotestate.StorageSnapshot{ 288 storageTag0: remotestate.StorageSnapshot{ 289 Life: params.Alive, 290 }, 291 storageTag1: remotestate.StorageSnapshot{ 292 Life: params.Dying, 293 Kind: params.StorageKindBlock, 294 Attached: true, 295 Location: "malta", 296 }, 297 }) 298 299 s.st.storageAttachment[storageAttachmentId0] = params.StorageAttachment{ 300 UnitTag: storageAttachmentId0.UnitTag, 301 StorageTag: storageAttachmentId0.StorageTag, 302 Life: params.Dying, 303 Kind: params.StorageKindFilesystem, 304 Location: "somewhere", 305 } 306 delete(s.st.storageAttachment, storageAttachmentId1) 307 storageTag0Watcher.changes <- struct{}{} 308 assertNotifyEvent(c, s.watcher.RemoteStateChanged(), "waiting for remote state change") 309 s.st.unit.storageWatcher.changes <- []string{"blob/1"} 310 assertNotifyEvent(c, s.watcher.RemoteStateChanged(), "waiting for remote state change") 311 c.Assert(s.watcher.Snapshot().Storage, jc.DeepEquals, map[names.StorageTag]remotestate.StorageSnapshot{ 312 storageTag0: remotestate.StorageSnapshot{ 313 Life: params.Dying, 314 Attached: true, 315 Kind: params.StorageKindFilesystem, 316 Location: "somewhere", 317 }, 318 }) 319 } 320 321 func (s *WatcherSuite) TestStorageUnattachedChanged(c *gc.C) { 322 signalAll(s.st, s.leadership) 323 assertNotifyEvent(c, s.watcher.RemoteStateChanged(), "waiting for remote state change") 324 325 storageTag0 := names.NewStorageTag("blob/0") 326 storageAttachmentId0 := params.StorageAttachmentId{ 327 UnitTag: s.st.unit.tag.String(), 328 StorageTag: storageTag0.String(), 329 } 330 storageTag0Watcher := newMockNotifyWatcher() 331 s.st.storageAttachmentWatchers[storageTag0] = storageTag0Watcher 332 s.st.storageAttachment[storageAttachmentId0] = params.StorageAttachment{ 333 UnitTag: storageAttachmentId0.UnitTag, 334 StorageTag: storageAttachmentId0.StorageTag, 335 Life: params.Alive, 336 Kind: params.StorageKindUnknown, // unprovisioned 337 } 338 339 s.st.unit.storageWatcher.changes <- []string{"blob/0"} 340 storageTag0Watcher.changes <- struct{}{} 341 assertNotifyEvent(c, s.watcher.RemoteStateChanged(), "waiting for remote state change") 342 343 c.Assert(s.watcher.Snapshot().Storage, jc.DeepEquals, map[names.StorageTag]remotestate.StorageSnapshot{ 344 storageTag0: remotestate.StorageSnapshot{ 345 Life: params.Alive, 346 }, 347 }) 348 349 s.st.storageAttachment[storageAttachmentId0] = params.StorageAttachment{ 350 UnitTag: storageAttachmentId0.UnitTag, 351 StorageTag: storageAttachmentId0.StorageTag, 352 Life: params.Dying, 353 } 354 // The storage is still unattached; triggering the storage-specific 355 // watcher should not cause any event to be emitted. 356 storageTag0Watcher.changes <- struct{}{} 357 assertNoNotifyEvent(c, s.watcher.RemoteStateChanged(), "remote state change") 358 s.st.unit.storageWatcher.changes <- []string{"blob/0"} 359 assertNotifyEvent(c, s.watcher.RemoteStateChanged(), "waiting for remote state change") 360 c.Assert(s.watcher.Snapshot().Storage, jc.DeepEquals, map[names.StorageTag]remotestate.StorageSnapshot{ 361 storageTag0: remotestate.StorageSnapshot{ 362 Life: params.Dying, 363 }, 364 }) 365 } 366 367 func (s *WatcherSuite) TestStorageAttachmentRemoved(c *gc.C) { 368 signalAll(s.st, s.leadership) 369 assertNotifyEvent(c, s.watcher.RemoteStateChanged(), "waiting for remote state change") 370 371 storageTag0 := names.NewStorageTag("blob/0") 372 storageAttachmentId0 := params.StorageAttachmentId{ 373 UnitTag: s.st.unit.tag.String(), 374 StorageTag: storageTag0.String(), 375 } 376 storageTag0Watcher := newMockNotifyWatcher() 377 s.st.storageAttachmentWatchers[storageTag0] = storageTag0Watcher 378 s.st.storageAttachment[storageAttachmentId0] = params.StorageAttachment{ 379 UnitTag: storageAttachmentId0.UnitTag, 380 StorageTag: storageAttachmentId0.StorageTag, 381 Life: params.Dying, 382 Kind: params.StorageKindUnknown, // unprovisioned 383 } 384 385 s.st.unit.storageWatcher.changes <- []string{"blob/0"} 386 storageTag0Watcher.changes <- struct{}{} 387 assertNotifyEvent(c, s.watcher.RemoteStateChanged(), "waiting for remote state change") 388 389 c.Assert(s.watcher.Snapshot().Storage, jc.DeepEquals, map[names.StorageTag]remotestate.StorageSnapshot{ 390 storageTag0: remotestate.StorageSnapshot{ 391 Life: params.Dying, 392 }, 393 }) 394 395 // Removing the storage attachment and then triggering the storage- 396 // specific watcher should not cause an event to be emitted, but it 397 // will cause that watcher to stop running. Triggering the top-level 398 // storage watcher will remove it and update the snapshot. 399 delete(s.st.storageAttachment, storageAttachmentId0) 400 storageTag0Watcher.changes <- struct{}{} 401 assertNoNotifyEvent(c, s.watcher.RemoteStateChanged(), "remote state change") 402 c.Assert(storageTag0Watcher.Stopped(), jc.IsTrue) 403 s.st.unit.storageWatcher.changes <- []string{"blob/0"} 404 assertNotifyEvent(c, s.watcher.RemoteStateChanged(), "waiting for remote state change") 405 c.Assert(s.watcher.Snapshot().Storage, gc.HasLen, 0) 406 } 407 408 func (s *WatcherSuite) TestStorageChangedNotFoundInitially(c *gc.C) { 409 signalAll(s.st, s.leadership) 410 assertNotifyEvent(c, s.watcher.RemoteStateChanged(), "waiting for remote state change") 411 412 // blob/0 is initially in state, but is removed between the 413 // watcher signal and the uniter querying it. This should 414 // not cause the watcher to raise an error. 415 s.st.unit.storageWatcher.changes <- []string{"blob/0"} 416 assertNotifyEvent(c, s.watcher.RemoteStateChanged(), "waiting for remote state change") 417 c.Assert(s.watcher.Snapshot().Storage, gc.HasLen, 0) 418 } 419 420 func (s *WatcherSuite) TestRelationsChanged(c *gc.C) { 421 signalAll(s.st, s.leadership) 422 assertNotifyEvent(c, s.watcher.RemoteStateChanged(), "waiting for remote state change") 423 424 relationTag := names.NewRelationTag("mysql:peer") 425 s.st.relations[relationTag] = &mockRelation{ 426 id: 123, life: params.Alive, 427 } 428 s.st.relationUnitsWatchers[relationTag] = newMockRelationUnitsWatcher() 429 s.st.unit.service.relationsWatcher.changes <- []string{relationTag.Id()} 430 431 // There should not be any signal until the relation units watcher has 432 // returned its initial event also. 433 assertNoNotifyEvent(c, s.watcher.RemoteStateChanged(), "remote state change") 434 s.st.relationUnitsWatchers[relationTag].changes <- watcher.RelationUnitsChange{ 435 Changed: map[string]watcher.UnitSettings{"mysql/1": {1}, "mysql/2": {2}}, 436 } 437 assertNotifyEvent(c, s.watcher.RemoteStateChanged(), "waiting for remote state change") 438 c.Assert( 439 s.watcher.Snapshot().Relations, 440 jc.DeepEquals, 441 map[int]remotestate.RelationSnapshot{ 442 123: remotestate.RelationSnapshot{ 443 Life: params.Alive, 444 Members: map[string]int64{"mysql/1": 1, "mysql/2": 2}, 445 }, 446 }, 447 ) 448 449 // If a relation is known, then updating it does not require any input 450 // from the relation units watcher. 451 s.st.relations[relationTag].life = params.Dying 452 s.st.unit.service.relationsWatcher.changes <- []string{relationTag.Id()} 453 assertNotifyEvent(c, s.watcher.RemoteStateChanged(), "waiting for remote state change") 454 c.Assert(s.watcher.Snapshot().Relations[123].Life, gc.Equals, params.Dying) 455 456 // If a relation is not found, then it should be removed from the 457 // snapshot and its relation units watcher stopped. 458 delete(s.st.relations, relationTag) 459 s.st.unit.service.relationsWatcher.changes <- []string{relationTag.Id()} 460 assertNotifyEvent(c, s.watcher.RemoteStateChanged(), "waiting for remote state change") 461 c.Assert(s.watcher.Snapshot().Relations, gc.HasLen, 0) 462 c.Assert(s.st.relationUnitsWatchers[relationTag].Stopped(), jc.IsTrue) 463 } 464 465 func (s *WatcherSuite) TestRelationUnitsChanged(c *gc.C) { 466 signalAll(s.st, s.leadership) 467 assertNotifyEvent(c, s.watcher.RemoteStateChanged(), "waiting for remote state change") 468 469 relationTag := names.NewRelationTag("mysql:peer") 470 s.st.relations[relationTag] = &mockRelation{ 471 id: 123, life: params.Alive, 472 } 473 s.st.relationUnitsWatchers[relationTag] = newMockRelationUnitsWatcher() 474 475 s.st.unit.service.relationsWatcher.changes <- []string{relationTag.Id()} 476 s.st.relationUnitsWatchers[relationTag].changes <- watcher.RelationUnitsChange{ 477 Changed: map[string]watcher.UnitSettings{"mysql/1": {1}}, 478 } 479 assertNotifyEvent(c, s.watcher.RemoteStateChanged(), "waiting for remote state change") 480 481 s.st.relationUnitsWatchers[relationTag].changes <- watcher.RelationUnitsChange{ 482 Changed: map[string]watcher.UnitSettings{"mysql/1": {2}, "mysql/2": {1}}, 483 } 484 assertNotifyEvent(c, s.watcher.RemoteStateChanged(), "waiting for remote state change") 485 c.Assert( 486 s.watcher.Snapshot().Relations[123].Members, 487 jc.DeepEquals, 488 map[string]int64{"mysql/1": 2, "mysql/2": 1}, 489 ) 490 491 s.st.relationUnitsWatchers[relationTag].changes <- watcher.RelationUnitsChange{ 492 Departed: []string{"mysql/1", "mysql/42"}, 493 } 494 assertNotifyEvent(c, s.watcher.RemoteStateChanged(), "waiting for remote state change") 495 c.Assert( 496 s.watcher.Snapshot().Relations[123].Members, 497 jc.DeepEquals, 498 map[string]int64{"mysql/2": 1}, 499 ) 500 } 501 502 func (s *WatcherSuite) TestUpdateStatusTicker(c *gc.C) { 503 signalAll(s.st, s.leadership) 504 initial := s.watcher.Snapshot() 505 assertNotifyEvent(c, s.watcher.RemoteStateChanged(), "waiting for remote state change") 506 507 // Advance the clock past the trigger time. 508 s.clock.Advance(11 * time.Second) 509 assertNotifyEvent(c, s.watcher.RemoteStateChanged(), "waiting for remote state change") 510 c.Assert(s.watcher.Snapshot().UpdateStatusVersion, gc.Equals, initial.UpdateStatusVersion+1) 511 512 // Advance again but not past the trigger time. 513 s.clock.Advance(6 * time.Second) 514 assertNoNotifyEvent(c, s.watcher.RemoteStateChanged(), "unexpected remote state change") 515 c.Assert(s.watcher.Snapshot().UpdateStatusVersion, gc.Equals, initial.UpdateStatusVersion+1) 516 517 // And we hit the trigger time. 518 s.clock.Advance(5 * time.Second) 519 assertNotifyEvent(c, s.watcher.RemoteStateChanged(), "waiting for remote state change") 520 c.Assert(s.watcher.Snapshot().UpdateStatusVersion, gc.Equals, initial.UpdateStatusVersion+2) 521 }