1// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "base/synchronization/waitable_event.h" 6#include "base/test/test_timeouts.h" 7#include "chrome/browser/sync/engine/mock_model_safe_workers.h" 8#include "chrome/browser/sync/engine/syncer.h" 9#include "chrome/browser/sync/engine/syncer_thread.h" 10#include "chrome/browser/sync/sessions/test_util.h" 11#include "chrome/test/sync/engine/mock_connection_manager.h" 12#include "chrome/test/sync/engine/test_directory_setter_upper.h" 13#include "testing/gtest/include/gtest/gtest.h" 14#include "testing/gmock/include/gmock/gmock.h" 15 16using base::TimeDelta; 17using base::TimeTicks; 18using testing::_; 19using testing::AtLeast; 20using testing::DoAll; 21using testing::Eq; 22using testing::Invoke; 23using testing::Mock; 24using testing::Return; 25using testing::WithArg; 26 27namespace browser_sync { 28using sessions::SyncSession; 29using sessions::SyncSessionContext; 30using sessions::SyncSessionSnapshot; 31using syncable::ModelTypeBitSet; 32using sync_pb::GetUpdatesCallerInfo; 33 34class MockSyncer : public Syncer { 35 public: 36 MOCK_METHOD3(SyncShare, void(sessions::SyncSession*, SyncerStep, 37 SyncerStep)); 38}; 39 40// Used when tests want to record syncing activity to examine later. 41struct SyncShareRecords { 42 std::vector<TimeTicks> times; 43 std::vector<linked_ptr<SyncSessionSnapshot> > snapshots; 44}; 45 46// Convenient to use in tests wishing to analyze SyncShare calls over time. 47static const size_t kMinNumSamples = 5; 48class SyncerThread2Test : public testing::Test { 49 public: 50 class MockDelayProvider : public SyncerThread::DelayProvider { 51 public: 52 MOCK_METHOD1(GetDelay, TimeDelta(const TimeDelta&)); 53 }; 54 55 virtual void SetUp() { 56 syncdb_.SetUp(); 57 syncer_ = new MockSyncer(); 58 delay_ = NULL; 59 registrar_.reset(MockModelSafeWorkerRegistrar::PassiveBookmarks()); 60 connection_.reset(new MockConnectionManager(syncdb_.manager(), "Test")); 61 connection_->SetServerReachable(); 62 context_ = new SyncSessionContext(connection_.get(), syncdb_.manager(), 63 registrar_.get(), std::vector<SyncEngineEventListener*>()); 64 context_->set_notifications_enabled(true); 65 context_->set_account_name("Test"); 66 syncer_thread_.reset(new SyncerThread(context_, syncer_)); 67 } 68 69 virtual void SetUpWithTypes(syncable::ModelTypeBitSet types) { 70 syncdb_.SetUp(); 71 syncer_ = new MockSyncer(); 72 delay_ = NULL; 73 registrar_.reset(MockModelSafeWorkerRegistrar::PassiveForTypes(types)); 74 connection_.reset(new MockConnectionManager(syncdb_.manager(), "Test")); 75 connection_->SetServerReachable(); 76 context_ = new SyncSessionContext(connection_.get(), syncdb_.manager(), 77 registrar_.get(), std::vector<SyncEngineEventListener*>()); 78 context_->set_notifications_enabled(true); 79 context_->set_account_name("Test"); 80 syncer_thread_.reset(new SyncerThread(context_, syncer_)); 81 } 82 83 SyncerThread* syncer_thread() { return syncer_thread_.get(); } 84 MockSyncer* syncer() { return syncer_; } 85 MockDelayProvider* delay() { return delay_; } 86 MockConnectionManager* connection() { return connection_.get(); } 87 TimeDelta zero() { return TimeDelta::FromSeconds(0); } 88 TimeDelta timeout() { 89 return TimeDelta::FromMilliseconds(TestTimeouts::action_timeout_ms()); 90 } 91 92 virtual void TearDown() { 93 syncer_thread()->Stop(); 94 syncdb_.TearDown(); 95 } 96 97 void AnalyzePollRun(const SyncShareRecords& records, size_t min_num_samples, 98 const TimeTicks& optimal_start, const TimeDelta& poll_interval) { 99 const std::vector<TimeTicks>& data(records.times); 100 EXPECT_GE(data.size(), min_num_samples); 101 for (size_t i = 0; i < data.size(); i++) { 102 SCOPED_TRACE(testing::Message() << "SyncShare # (" << i << ")"); 103 TimeTicks optimal_next_sync = optimal_start + poll_interval * i; 104 EXPECT_GE(data[i], optimal_next_sync); 105 EXPECT_EQ(GetUpdatesCallerInfo::PERIODIC, 106 records.snapshots[i]->source.updates_source); 107 } 108 } 109 110 bool GetBackoffAndResetTest(base::WaitableEvent* done) { 111 syncable::ModelTypeBitSet nudge_types; 112 syncer_thread()->Start(SyncerThread::NORMAL_MODE, NULL); 113 syncer_thread()->ScheduleNudge(zero(), NUDGE_SOURCE_LOCAL, nudge_types, 114 FROM_HERE); 115 done->TimedWait(timeout()); 116 TearDown(); 117 done->Reset(); 118 Mock::VerifyAndClearExpectations(syncer()); 119 bool backing_off = syncer_thread()->IsBackingOff(); 120 SetUp(); 121 UseMockDelayProvider(); 122 EXPECT_CALL(*delay(), GetDelay(_)) 123 .WillRepeatedly(Return(TimeDelta::FromMilliseconds(1))); 124 return backing_off; 125 } 126 127 void UseMockDelayProvider() { 128 delay_ = new MockDelayProvider(); 129 syncer_thread_->delay_provider_.reset(delay_); 130 } 131 132 void PostSignalTask(base::WaitableEvent* done) { 133 syncer_thread_->thread_.message_loop()->PostTask(FROM_HERE, 134 NewRunnableFunction(&SyncerThread2Test::SignalWaitableEvent, done)); 135 } 136 137 void FlushLastTask(base::WaitableEvent* done) { 138 PostSignalTask(done); 139 done->TimedWait(timeout()); 140 done->Reset(); 141 } 142 143 static void SignalWaitableEvent(base::WaitableEvent* event) { 144 event->Signal(); 145 } 146 147 static void QuitMessageLoop() { 148 MessageLoop::current()->Quit(); 149 } 150 151 // Compare a ModelTypeBitSet to a ModelTypePayloadMap, ignoring 152 // payload values. 153 bool CompareModelTypeBitSetToModelTypePayloadMap( 154 const syncable::ModelTypeBitSet& lhs, 155 const syncable::ModelTypePayloadMap& rhs) { 156 size_t count = 0; 157 for (syncable::ModelTypePayloadMap::const_iterator i = rhs.begin(); 158 i != rhs.end(); ++i, ++count) { 159 if (!lhs.test(i->first)) 160 return false; 161 } 162 if (lhs.count() != count) 163 return false; 164 return true; 165 } 166 167 SyncSessionContext* context() { return context_; } 168 169 private: 170 scoped_ptr<SyncerThread> syncer_thread_; 171 scoped_ptr<MockConnectionManager> connection_; 172 SyncSessionContext* context_; 173 MockSyncer* syncer_; 174 MockDelayProvider* delay_; 175 scoped_ptr<MockModelSafeWorkerRegistrar> registrar_; 176 MockDirectorySetterUpper syncdb_; 177}; 178 179bool RecordSyncShareImpl(SyncSession* s, SyncShareRecords* record, 180 size_t signal_after) { 181 record->times.push_back(TimeTicks::Now()); 182 record->snapshots.push_back(make_linked_ptr(new SyncSessionSnapshot( 183 s->TakeSnapshot()))); 184 return record->times.size() >= signal_after; 185} 186 187ACTION_P4(RecordSyncShareAndPostSignal, record, signal_after, test, event) { 188 if (RecordSyncShareImpl(arg0, record, signal_after) && event) 189 test->PostSignalTask(event); 190} 191 192ACTION_P3(RecordSyncShare, record, signal_after, event) { 193 if (RecordSyncShareImpl(arg0, record, signal_after) && event) 194 event->Signal(); 195} 196 197ACTION_P(SignalEvent, event) { 198 SyncerThread2Test::SignalWaitableEvent(event); 199} 200 201// Test nudge scheduling. 202TEST_F(SyncerThread2Test, Nudge) { 203 syncer_thread()->Start(SyncerThread::NORMAL_MODE, NULL); 204 base::WaitableEvent done(false, false); 205 SyncShareRecords records; 206 syncable::ModelTypeBitSet model_types; 207 model_types[syncable::BOOKMARKS] = true; 208 209 EXPECT_CALL(*syncer(), SyncShare(_,_,_)) 210 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess), 211 WithArg<0>(RecordSyncShare(&records, 1U, &done)))) 212 .RetiresOnSaturation(); 213 syncer_thread()->ScheduleNudge(zero(), NUDGE_SOURCE_LOCAL, model_types, 214 FROM_HERE); 215 done.TimedWait(timeout()); 216 217 EXPECT_EQ(1U, records.snapshots.size()); 218 EXPECT_TRUE(CompareModelTypeBitSetToModelTypePayloadMap(model_types, 219 records.snapshots[0]->source.types)); 220 EXPECT_EQ(GetUpdatesCallerInfo::LOCAL, 221 records.snapshots[0]->source.updates_source); 222 223 // Make sure a second, later, nudge is unaffected by first (no coalescing). 224 SyncShareRecords records2; 225 model_types[syncable::BOOKMARKS] = false; 226 model_types[syncable::AUTOFILL] = true; 227 EXPECT_CALL(*syncer(), SyncShare(_,_,_)) 228 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess), 229 WithArg<0>(RecordSyncShare(&records2, 1U, &done)))); 230 syncer_thread()->ScheduleNudge(zero(), NUDGE_SOURCE_LOCAL, model_types, 231 FROM_HERE); 232 done.TimedWait(timeout()); 233 234 EXPECT_EQ(1U, records2.snapshots.size()); 235 EXPECT_TRUE(CompareModelTypeBitSetToModelTypePayloadMap(model_types, 236 records2.snapshots[0]->source.types)); 237 EXPECT_EQ(GetUpdatesCallerInfo::LOCAL, 238 records2.snapshots[0]->source.updates_source); 239} 240 241// Make sure a regular config command is scheduled fine in the absence of any 242// errors. 243TEST_F(SyncerThread2Test, Config) { 244 base::WaitableEvent done(false, false); 245 SyncShareRecords records; 246 syncable::ModelTypeBitSet model_types; 247 model_types[syncable::BOOKMARKS] = true; 248 249 EXPECT_CALL(*syncer(), SyncShare(_,_,_)) 250 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess), 251 WithArg<0>(RecordSyncShare(&records, 1U, &done)))); 252 253 syncer_thread()->Start(SyncerThread::CONFIGURATION_MODE, NULL); 254 255 syncer_thread()->ScheduleConfig(model_types); 256 done.TimedWait(timeout()); 257 258 EXPECT_EQ(1U, records.snapshots.size()); 259 EXPECT_TRUE(CompareModelTypeBitSetToModelTypePayloadMap(model_types, 260 records.snapshots[0]->source.types)); 261 EXPECT_EQ(GetUpdatesCallerInfo::FIRST_UPDATE, 262 records.snapshots[0]->source.updates_source); 263} 264 265// Simulate a failure and make sure the config request is retried. 266TEST_F(SyncerThread2Test, ConfigWithBackingOff) { 267 base::WaitableEvent done(false, false); 268 base::WaitableEvent* dummy = NULL; 269 UseMockDelayProvider(); 270 EXPECT_CALL(*delay(), GetDelay(_)) 271 .WillRepeatedly(Return(TimeDelta::FromMilliseconds(1))); 272 SyncShareRecords records; 273 syncable::ModelTypeBitSet model_types; 274 model_types[syncable::BOOKMARKS] = true; 275 276 EXPECT_CALL(*syncer(), SyncShare(_,_,_)) 277 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateCommitFailed), 278 WithArg<0>(RecordSyncShare(&records, 1U, dummy)))) 279 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess), 280 WithArg<0>(RecordSyncShare(&records, 1U, &done)))); 281 282 syncer_thread()->Start(SyncerThread::CONFIGURATION_MODE, NULL); 283 284 syncer_thread()->ScheduleConfig(model_types); 285 done.TimedWait(timeout()); 286 287 EXPECT_EQ(2U, records.snapshots.size()); 288 EXPECT_TRUE(CompareModelTypeBitSetToModelTypePayloadMap(model_types, 289 records.snapshots[1]->source.types)); 290 EXPECT_EQ(GetUpdatesCallerInfo::SYNC_CYCLE_CONTINUATION, 291 records.snapshots[1]->source.updates_source); 292} 293 294// Issue 2 config commands. Second one right after the first has failed 295// and make sure LATEST is executed. 296TEST_F(SyncerThread2Test, MultipleConfigWithBackingOff) { 297 syncable::ModelTypeBitSet model_types1, model_types2; 298 model_types1[syncable::BOOKMARKS] = true; 299 model_types2[syncable::AUTOFILL] = true; 300 SetUpWithTypes(model_types1 | model_types2); 301 base::WaitableEvent done(false, false); 302 base::WaitableEvent done1(false, false); 303 base::WaitableEvent* dummy = NULL; 304 UseMockDelayProvider(); 305 EXPECT_CALL(*delay(), GetDelay(_)) 306 .WillRepeatedly(Return(TimeDelta::FromMilliseconds(30))); 307 SyncShareRecords records; 308 309 EXPECT_CALL(*syncer(), SyncShare(_,_,_)) 310 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateCommitFailed), 311 WithArg<0>(RecordSyncShare(&records, 1U, dummy)))) 312 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateCommitFailed), 313 WithArg<0>(RecordSyncShare(&records, 1U, &done1)))) 314 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess), 315 WithArg<0>(RecordSyncShare(&records, 1U, &done)))); 316 317 syncer_thread()->Start(SyncerThread::CONFIGURATION_MODE, NULL); 318 319 syncer_thread()->ScheduleConfig(model_types1); 320 321 // done1 indicates the first config failed. 322 done1.TimedWait(timeout()); 323 syncer_thread()->ScheduleConfig(model_types2); 324 done.TimedWait(timeout()); 325 326 EXPECT_EQ(3U, records.snapshots.size()); 327 EXPECT_TRUE(CompareModelTypeBitSetToModelTypePayloadMap(model_types2, 328 records.snapshots[2]->source.types)); 329 EXPECT_EQ(GetUpdatesCallerInfo::FIRST_UPDATE, 330 records.snapshots[2]->source.updates_source); 331} 332 333// Issue a nudge when the config has failed. Make sure both the config and 334// nudge are executed. 335TEST_F(SyncerThread2Test, NudgeWithConfigWithBackingOff) { 336 syncable::ModelTypeBitSet model_types; 337 model_types[syncable::BOOKMARKS] = true; 338 base::WaitableEvent done(false, false); 339 base::WaitableEvent done1(false, false); 340 base::WaitableEvent done2(false, false); 341 base::WaitableEvent* dummy = NULL; 342 UseMockDelayProvider(); 343 EXPECT_CALL(*delay(), GetDelay(_)) 344 .WillRepeatedly(Return(TimeDelta::FromMilliseconds(50))); 345 SyncShareRecords records; 346 347 EXPECT_CALL(*syncer(), SyncShare(_,_,_)) 348 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateCommitFailed), 349 WithArg<0>(RecordSyncShare(&records, 1U, dummy)))) 350 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateCommitFailed), 351 WithArg<0>(RecordSyncShare(&records, 1U, &done1)))) 352 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess), 353 WithArg<0>(RecordSyncShare(&records, 1U, &done2)))) 354 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess), 355 WithArg<0>(RecordSyncShare(&records, 1U, &done)))); 356 357 syncer_thread()->Start(SyncerThread::CONFIGURATION_MODE, NULL); 358 359 syncer_thread()->ScheduleConfig(model_types); 360 done1.TimedWait(timeout()); 361 syncer_thread()->ScheduleNudge(zero(), NUDGE_SOURCE_LOCAL, model_types, 362 FROM_HERE); 363 364 // done2 indicates config suceeded. Now change the mode so nudge can execute. 365 done2.TimedWait(timeout()); 366 syncer_thread()->Start(SyncerThread::NORMAL_MODE, NULL); 367 done.TimedWait(timeout()); 368 EXPECT_EQ(4U, records.snapshots.size()); 369 370 EXPECT_TRUE(CompareModelTypeBitSetToModelTypePayloadMap(model_types, 371 records.snapshots[2]->source.types)); 372 EXPECT_EQ(GetUpdatesCallerInfo::SYNC_CYCLE_CONTINUATION, 373 records.snapshots[2]->source.updates_source); 374 375 EXPECT_TRUE(CompareModelTypeBitSetToModelTypePayloadMap(model_types, 376 records.snapshots[3]->source.types)); 377 EXPECT_EQ(GetUpdatesCallerInfo::LOCAL, 378 records.snapshots[3]->source.updates_source); 379 380} 381 382 383// Test that nudges are coalesced. 384TEST_F(SyncerThread2Test, NudgeCoalescing) { 385 syncer_thread()->Start(SyncerThread::NORMAL_MODE, NULL); 386 base::WaitableEvent done(false, false); 387 SyncShareRecords r; 388 EXPECT_CALL(*syncer(), SyncShare(_,_,_)) 389 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess), 390 WithArg<0>(RecordSyncShare(&r, 1U, &done)))); 391 syncable::ModelTypeBitSet types1, types2, types3; 392 types1[syncable::BOOKMARKS] = true; 393 types2[syncable::AUTOFILL] = true; 394 types3[syncable::THEMES] = true; 395 TimeDelta delay = TimeDelta::FromMilliseconds( 396 TestTimeouts::tiny_timeout_ms()); 397 TimeTicks optimal_time = TimeTicks::Now() + delay; 398 syncer_thread()->ScheduleNudge(delay, NUDGE_SOURCE_UNKNOWN, types1, 399 FROM_HERE); 400 syncer_thread()->ScheduleNudge(zero(), NUDGE_SOURCE_LOCAL, types2, 401 FROM_HERE); 402 done.TimedWait(timeout()); 403 404 EXPECT_EQ(1U, r.snapshots.size()); 405 EXPECT_GE(r.times[0], optimal_time); 406 EXPECT_TRUE(CompareModelTypeBitSetToModelTypePayloadMap( 407 types1 | types2, r.snapshots[0]->source.types)); 408 EXPECT_EQ(GetUpdatesCallerInfo::LOCAL, 409 r.snapshots[0]->source.updates_source); 410 411 SyncShareRecords r2; 412 EXPECT_CALL(*syncer(), SyncShare(_,_,_)) 413 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess), 414 WithArg<0>(RecordSyncShare(&r2, 1U, &done)))); 415 syncer_thread()->ScheduleNudge(zero(), NUDGE_SOURCE_NOTIFICATION, types3, 416 FROM_HERE); 417 done.TimedWait(timeout()); 418 EXPECT_EQ(1U, r2.snapshots.size()); 419 EXPECT_TRUE(CompareModelTypeBitSetToModelTypePayloadMap(types3, 420 r2.snapshots[0]->source.types)); 421 EXPECT_EQ(GetUpdatesCallerInfo::NOTIFICATION, 422 r2.snapshots[0]->source.updates_source); 423} 424 425// Test nudge scheduling. 426TEST_F(SyncerThread2Test, NudgeWithPayloads) { 427 syncer_thread()->Start(SyncerThread::NORMAL_MODE, NULL); 428 base::WaitableEvent done(false, false); 429 SyncShareRecords records; 430 syncable::ModelTypePayloadMap model_types_with_payloads; 431 model_types_with_payloads[syncable::BOOKMARKS] = "test"; 432 433 EXPECT_CALL(*syncer(), SyncShare(_,_,_)) 434 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess), 435 WithArg<0>(RecordSyncShare(&records, 1U, &done)))) 436 .RetiresOnSaturation(); 437 syncer_thread()->ScheduleNudgeWithPayloads(zero(), NUDGE_SOURCE_LOCAL, 438 model_types_with_payloads, FROM_HERE); 439 done.TimedWait(timeout()); 440 441 EXPECT_EQ(1U, records.snapshots.size()); 442 EXPECT_EQ(model_types_with_payloads, records.snapshots[0]->source.types); 443 EXPECT_EQ(GetUpdatesCallerInfo::LOCAL, 444 records.snapshots[0]->source.updates_source); 445 446 // Make sure a second, later, nudge is unaffected by first (no coalescing). 447 SyncShareRecords records2; 448 model_types_with_payloads.erase(syncable::BOOKMARKS); 449 model_types_with_payloads[syncable::AUTOFILL] = "test2"; 450 EXPECT_CALL(*syncer(), SyncShare(_,_,_)) 451 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess), 452 WithArg<0>(RecordSyncShare(&records2, 1U, &done)))); 453 syncer_thread()->ScheduleNudgeWithPayloads(zero(), NUDGE_SOURCE_LOCAL, 454 model_types_with_payloads, FROM_HERE); 455 done.TimedWait(timeout()); 456 457 EXPECT_EQ(1U, records2.snapshots.size()); 458 EXPECT_EQ(model_types_with_payloads, records2.snapshots[0]->source.types); 459 EXPECT_EQ(GetUpdatesCallerInfo::LOCAL, 460 records2.snapshots[0]->source.updates_source); 461} 462 463// Test that nudges are coalesced. 464TEST_F(SyncerThread2Test, NudgeWithPayloadsCoalescing) { 465 syncer_thread()->Start(SyncerThread::NORMAL_MODE, NULL); 466 base::WaitableEvent done(false, false); 467 SyncShareRecords r; 468 EXPECT_CALL(*syncer(), SyncShare(_,_,_)) 469 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess), 470 WithArg<0>(RecordSyncShare(&r, 1U, &done)))); 471 syncable::ModelTypePayloadMap types1, types2, types3; 472 types1[syncable::BOOKMARKS] = "test1"; 473 types2[syncable::AUTOFILL] = "test2"; 474 types3[syncable::THEMES] = "test3"; 475 TimeDelta delay = TimeDelta::FromMilliseconds( 476 TestTimeouts::tiny_timeout_ms()); 477 TimeTicks optimal_time = TimeTicks::Now() + delay; 478 syncer_thread()->ScheduleNudgeWithPayloads(delay, NUDGE_SOURCE_UNKNOWN, 479 types1, FROM_HERE); 480 syncer_thread()->ScheduleNudgeWithPayloads(zero(), NUDGE_SOURCE_LOCAL, 481 types2, FROM_HERE); 482 done.TimedWait(timeout()); 483 484 EXPECT_EQ(1U, r.snapshots.size()); 485 EXPECT_GE(r.times[0], optimal_time); 486 syncable::ModelTypePayloadMap coalesced_types; 487 syncable::CoalescePayloads(&coalesced_types, types1); 488 syncable::CoalescePayloads(&coalesced_types, types2); 489 EXPECT_EQ(coalesced_types, r.snapshots[0]->source.types); 490 EXPECT_EQ(GetUpdatesCallerInfo::LOCAL, 491 r.snapshots[0]->source.updates_source); 492 493 SyncShareRecords r2; 494 EXPECT_CALL(*syncer(), SyncShare(_,_,_)) 495 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess), 496 WithArg<0>(RecordSyncShare(&r2, 1U, &done)))); 497 syncer_thread()->ScheduleNudgeWithPayloads(zero(), NUDGE_SOURCE_NOTIFICATION, 498 types3, FROM_HERE); 499 done.TimedWait(timeout()); 500 EXPECT_EQ(1U, r2.snapshots.size()); 501 EXPECT_EQ(types3, r2.snapshots[0]->source.types); 502 EXPECT_EQ(GetUpdatesCallerInfo::NOTIFICATION, 503 r2.snapshots[0]->source.updates_source); 504} 505 506// Test that polling works as expected. 507TEST_F(SyncerThread2Test, Polling) { 508 SyncShareRecords records; 509 base::WaitableEvent done(false, false); 510 TimeDelta poll_interval(TimeDelta::FromMilliseconds(30)); 511 syncer_thread()->OnReceivedLongPollIntervalUpdate(poll_interval); 512 EXPECT_CALL(*syncer(), SyncShare(_,_,_)).Times(AtLeast(kMinNumSamples)) 513 .WillRepeatedly(DoAll(Invoke(sessions::test_util::SimulateSuccess), 514 WithArg<0>(RecordSyncShare(&records, kMinNumSamples, &done)))); 515 516 TimeTicks optimal_start = TimeTicks::Now() + poll_interval; 517 syncer_thread()->Start(SyncerThread::NORMAL_MODE, NULL); 518 done.TimedWait(timeout()); 519 syncer_thread()->Stop(); 520 521 AnalyzePollRun(records, kMinNumSamples, optimal_start, poll_interval); 522} 523 524// Test that the short poll interval is used. 525TEST_F(SyncerThread2Test, PollNotificationsDisabled) { 526 SyncShareRecords records; 527 base::WaitableEvent done(false, false); 528 TimeDelta poll_interval(TimeDelta::FromMilliseconds(30)); 529 syncer_thread()->OnReceivedShortPollIntervalUpdate(poll_interval); 530 syncer_thread()->set_notifications_enabled(false); 531 EXPECT_CALL(*syncer(), SyncShare(_,_,_)).Times(AtLeast(kMinNumSamples)) 532 .WillRepeatedly(DoAll(Invoke(sessions::test_util::SimulateSuccess), 533 WithArg<0>(RecordSyncShare(&records, kMinNumSamples, &done)))); 534 535 TimeTicks optimal_start = TimeTicks::Now() + poll_interval; 536 syncer_thread()->Start(SyncerThread::NORMAL_MODE, NULL); 537 done.TimedWait(timeout()); 538 syncer_thread()->Stop(); 539 540 AnalyzePollRun(records, kMinNumSamples, optimal_start, poll_interval); 541} 542 543// Test that polling intervals are updated when needed. 544TEST_F(SyncerThread2Test, PollIntervalUpdate) { 545 SyncShareRecords records; 546 base::WaitableEvent done(false, false); 547 TimeDelta poll1(TimeDelta::FromMilliseconds(120)); 548 TimeDelta poll2(TimeDelta::FromMilliseconds(30)); 549 syncer_thread()->OnReceivedLongPollIntervalUpdate(poll1); 550 EXPECT_CALL(*syncer(), SyncShare(_,_,_)).Times(AtLeast(kMinNumSamples)) 551 .WillOnce(WithArg<0>( 552 sessions::test_util::SimulatePollIntervalUpdate(poll2))) 553 .WillRepeatedly(DoAll(Invoke(sessions::test_util::SimulateSuccess), 554 WithArg<0>(RecordSyncShare(&records, kMinNumSamples, &done)))); 555 556 TimeTicks optimal_start = TimeTicks::Now() + poll1 + poll2; 557 syncer_thread()->Start(SyncerThread::NORMAL_MODE, NULL); 558 done.TimedWait(timeout()); 559 syncer_thread()->Stop(); 560 561 AnalyzePollRun(records, kMinNumSamples, optimal_start, poll2); 562} 563 564// Test that a sync session is run through to completion. 565TEST_F(SyncerThread2Test, HasMoreToSync) { 566 syncer_thread()->Start(SyncerThread::NORMAL_MODE, NULL); 567 base::WaitableEvent done(false, false); 568 EXPECT_CALL(*syncer(), SyncShare(_,_,_)) 569 .WillOnce(Invoke(sessions::test_util::SimulateHasMoreToSync)) 570 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess), 571 SignalEvent(&done))); 572 syncer_thread()->ScheduleNudge(zero(), NUDGE_SOURCE_LOCAL, ModelTypeBitSet(), 573 FROM_HERE); 574 done.TimedWait(timeout()); 575 // If more nudges are scheduled, they'll be waited on by TearDown, and would 576 // cause our expectation to break. 577} 578 579// Test that no syncing occurs when throttled. 580TEST_F(SyncerThread2Test, ThrottlingDoesThrottle) { 581 syncable::ModelTypeBitSet types; 582 types[syncable::BOOKMARKS] = true; 583 base::WaitableEvent done(false, false); 584 TimeDelta poll(TimeDelta::FromMilliseconds(5)); 585 TimeDelta throttle(TimeDelta::FromMinutes(10)); 586 syncer_thread()->OnReceivedLongPollIntervalUpdate(poll); 587 EXPECT_CALL(*syncer(), SyncShare(_,_,_)) 588 .WillOnce(WithArg<0>(sessions::test_util::SimulateThrottled(throttle))); 589 590 syncer_thread()->Start(SyncerThread::NORMAL_MODE, NULL); 591 syncer_thread()->ScheduleNudge(zero(), NUDGE_SOURCE_LOCAL, types, 592 FROM_HERE); 593 FlushLastTask(&done); 594 595 syncer_thread()->Start(SyncerThread::CONFIGURATION_MODE, NULL); 596 syncer_thread()->ScheduleConfig(types); 597 FlushLastTask(&done); 598} 599 600TEST_F(SyncerThread2Test, ThrottlingExpires) { 601 SyncShareRecords records; 602 base::WaitableEvent done(false, false); 603 TimeDelta poll(TimeDelta::FromMilliseconds(15)); 604 TimeDelta throttle1(TimeDelta::FromMilliseconds(150)); 605 TimeDelta throttle2(TimeDelta::FromMinutes(10)); 606 syncer_thread()->OnReceivedLongPollIntervalUpdate(poll); 607 608 ::testing::InSequence seq; 609 EXPECT_CALL(*syncer(), SyncShare(_,_,_)) 610 .WillOnce(WithArg<0>(sessions::test_util::SimulateThrottled(throttle1))) 611 .RetiresOnSaturation(); 612 EXPECT_CALL(*syncer(), SyncShare(_,_,_)) 613 .WillRepeatedly(DoAll(Invoke(sessions::test_util::SimulateSuccess), 614 WithArg<0>(RecordSyncShare(&records, kMinNumSamples, &done)))); 615 616 TimeTicks optimal_start = TimeTicks::Now() + poll + throttle1; 617 syncer_thread()->Start(SyncerThread::NORMAL_MODE, NULL); 618 done.TimedWait(timeout()); 619 syncer_thread()->Stop(); 620 621 AnalyzePollRun(records, kMinNumSamples, optimal_start, poll); 622} 623 624// Test nudges / polls don't run in config mode and config tasks do. 625TEST_F(SyncerThread2Test, ConfigurationMode) { 626 TimeDelta poll(TimeDelta::FromMilliseconds(15)); 627 SyncShareRecords records; 628 base::WaitableEvent done(false, false); 629 base::WaitableEvent* dummy = NULL; 630 syncer_thread()->OnReceivedLongPollIntervalUpdate(poll); 631 EXPECT_CALL(*syncer(), SyncShare(_,_,_)) 632 .WillOnce((Invoke(sessions::test_util::SimulateSuccess), 633 WithArg<0>(RecordSyncShare(&records, 1U, dummy)))); 634 syncer_thread()->Start(SyncerThread::CONFIGURATION_MODE, NULL); 635 syncable::ModelTypeBitSet nudge_types; 636 nudge_types[syncable::AUTOFILL] = true; 637 syncer_thread()->ScheduleNudge(zero(), NUDGE_SOURCE_LOCAL, nudge_types, 638 FROM_HERE); 639 syncer_thread()->ScheduleNudge(zero(), NUDGE_SOURCE_LOCAL, nudge_types, 640 FROM_HERE); 641 642 syncable::ModelTypeBitSet config_types; 643 config_types[syncable::BOOKMARKS] = true; 644 // TODO(tim): This will fail once CONFIGURATION tasks are implemented. Update 645 // the EXPECT when that happens. 646 syncer_thread()->ScheduleConfig(config_types); 647 FlushLastTask(&done); 648 syncer_thread()->Stop(); 649 650 EXPECT_EQ(1U, records.snapshots.size()); 651 EXPECT_TRUE(CompareModelTypeBitSetToModelTypePayloadMap(config_types, 652 records.snapshots[0]->source.types)); 653} 654 655// Test that exponential backoff is properly triggered. 656TEST_F(SyncerThread2Test, BackoffTriggers) { 657 base::WaitableEvent done(false, false); 658 UseMockDelayProvider(); 659 660 EXPECT_CALL(*syncer(), SyncShare(_,_,_)) 661 .WillOnce(Invoke(sessions::test_util::SimulateDownloadUpdatesFailed)) 662 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess), 663 SignalEvent(&done))); 664 EXPECT_FALSE(GetBackoffAndResetTest(&done)); 665 // Note GetBackoffAndResetTest clears mocks and re-instantiates the syncer. 666 EXPECT_CALL(*syncer(), SyncShare(_,_,_)) 667 .WillOnce(Invoke(sessions::test_util::SimulateCommitFailed)) 668 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess), 669 SignalEvent(&done))); 670 EXPECT_FALSE(GetBackoffAndResetTest(&done)); 671 EXPECT_CALL(*syncer(), SyncShare(_,_,_)) 672 .WillOnce(Invoke(sessions::test_util::SimulateDownloadUpdatesFailed)) 673 .WillRepeatedly(DoAll(Invoke( 674 sessions::test_util::SimulateDownloadUpdatesFailed), 675 SignalEvent(&done))); 676 EXPECT_TRUE(GetBackoffAndResetTest(&done)); 677 EXPECT_CALL(*syncer(), SyncShare(_,_,_)) 678 .WillOnce(Invoke(sessions::test_util::SimulateCommitFailed)) 679 .WillRepeatedly(DoAll(Invoke(sessions::test_util::SimulateCommitFailed), 680 SignalEvent(&done))); 681 EXPECT_TRUE(GetBackoffAndResetTest(&done)); 682 EXPECT_CALL(*syncer(), SyncShare(_,_,_)) 683 .WillOnce(Invoke(sessions::test_util::SimulateDownloadUpdatesFailed)) 684 .WillOnce(Invoke(sessions::test_util::SimulateDownloadUpdatesFailed)) 685 .WillRepeatedly(DoAll(Invoke(sessions::test_util::SimulateSuccess), 686 SignalEvent(&done))); 687 EXPECT_FALSE(GetBackoffAndResetTest(&done)); 688 EXPECT_CALL(*syncer(), SyncShare(_,_,_)) 689 .WillOnce(Invoke(sessions::test_util::SimulateCommitFailed)) 690 .WillOnce(Invoke(sessions::test_util::SimulateCommitFailed)) 691 .WillRepeatedly(DoAll(Invoke(sessions::test_util::SimulateSuccess), 692 SignalEvent(&done))); 693 EXPECT_FALSE(GetBackoffAndResetTest(&done)); 694} 695 696// Test that no polls or extraneous nudges occur when in backoff. 697TEST_F(SyncerThread2Test, BackoffDropsJobs) { 698 SyncShareRecords r; 699 TimeDelta poll(TimeDelta::FromMilliseconds(5)); 700 base::WaitableEvent done(false, false); 701 syncable::ModelTypeBitSet types; 702 types[syncable::BOOKMARKS] = true; 703 syncer_thread()->OnReceivedLongPollIntervalUpdate(poll); 704 UseMockDelayProvider(); 705 706 EXPECT_CALL(*syncer(), SyncShare(_,_,_)).Times(2) 707 .WillRepeatedly(DoAll(Invoke(sessions::test_util::SimulateCommitFailed), 708 RecordSyncShareAndPostSignal(&r, 2U, this, &done))); 709 EXPECT_CALL(*delay(), GetDelay(_)) 710 .WillRepeatedly(Return(TimeDelta::FromDays(1))); 711 712 syncer_thread()->Start(SyncerThread::NORMAL_MODE, NULL); 713 ASSERT_TRUE(done.TimedWait(timeout())); 714 done.Reset(); 715 716 Mock::VerifyAndClearExpectations(syncer()); 717 EXPECT_EQ(2U, r.snapshots.size()); 718 EXPECT_EQ(GetUpdatesCallerInfo::PERIODIC, 719 r.snapshots[0]->source.updates_source); 720 EXPECT_EQ(GetUpdatesCallerInfo::SYNC_CYCLE_CONTINUATION, 721 r.snapshots[1]->source.updates_source); 722 723 EXPECT_CALL(*syncer(), SyncShare(_,_,_)).Times(1) 724 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateCommitFailed), 725 RecordSyncShareAndPostSignal(&r, 1U, this, &done))); 726 727 // We schedule a nudge with enough delay (10X poll interval) that at least 728 // one or two polls would have taken place. The nudge should succeed. 729 syncer_thread()->ScheduleNudge(poll * 10, NUDGE_SOURCE_LOCAL, types, 730 FROM_HERE); 731 ASSERT_TRUE(done.TimedWait(timeout())); 732 done.Reset(); 733 734 Mock::VerifyAndClearExpectations(syncer()); 735 Mock::VerifyAndClearExpectations(delay()); 736 EXPECT_EQ(3U, r.snapshots.size()); 737 EXPECT_EQ(GetUpdatesCallerInfo::LOCAL, 738 r.snapshots[2]->source.updates_source); 739 740 EXPECT_CALL(*syncer(), SyncShare(_,_,_)).Times(0); 741 EXPECT_CALL(*delay(), GetDelay(_)).Times(0); 742 743 syncer_thread()->Start(SyncerThread::CONFIGURATION_MODE, NULL); 744 syncer_thread()->ScheduleConfig(types); 745 FlushLastTask(&done); 746 747 syncer_thread()->Start(SyncerThread::NORMAL_MODE, NULL); 748 syncer_thread()->ScheduleNudge(zero(), NUDGE_SOURCE_LOCAL, types, 749 FROM_HERE); 750 syncer_thread()->ScheduleNudge(zero(), NUDGE_SOURCE_LOCAL, types, 751 FROM_HERE); 752 FlushLastTask(&done); 753} 754 755// Test that backoff is shaping traffic properly with consecutive errors. 756TEST_F(SyncerThread2Test, BackoffElevation) { 757 SyncShareRecords r; 758 const TimeDelta poll(TimeDelta::FromMilliseconds(10)); 759 base::WaitableEvent done(false, false); 760 syncer_thread()->OnReceivedLongPollIntervalUpdate(poll); 761 UseMockDelayProvider(); 762 763 const TimeDelta first = TimeDelta::FromSeconds(1); 764 const TimeDelta second = TimeDelta::FromMilliseconds(10); 765 const TimeDelta third = TimeDelta::FromMilliseconds(20); 766 const TimeDelta fourth = TimeDelta::FromMilliseconds(30); 767 const TimeDelta fifth = TimeDelta::FromDays(1); 768 769 EXPECT_CALL(*syncer(), SyncShare(_,_,_)).Times(kMinNumSamples) 770 .WillRepeatedly(DoAll(Invoke(sessions::test_util::SimulateCommitFailed), 771 RecordSyncShareAndPostSignal(&r, kMinNumSamples, this, &done))); 772 773 EXPECT_CALL(*delay(), GetDelay(Eq(first))).WillOnce(Return(second)) 774 .RetiresOnSaturation(); 775 EXPECT_CALL(*delay(), GetDelay(Eq(second))).WillOnce(Return(third)) 776 .RetiresOnSaturation(); 777 EXPECT_CALL(*delay(), GetDelay(Eq(third))).WillOnce(Return(fourth)) 778 .RetiresOnSaturation(); 779 EXPECT_CALL(*delay(), GetDelay(Eq(fourth))).WillOnce(Return(fifth)); 780 781 syncer_thread()->Start(SyncerThread::NORMAL_MODE, NULL); 782 ASSERT_TRUE(done.TimedWait(timeout())); 783 784 EXPECT_GE(r.times[2] - r.times[1], second); 785 EXPECT_GE(r.times[3] - r.times[2], third); 786 EXPECT_GE(r.times[4] - r.times[3], fourth); 787} 788 789// Test that things go back to normal once a canary task makes forward progress 790// following a succession of failures. 791TEST_F(SyncerThread2Test, BackoffRelief) { 792 SyncShareRecords r; 793 const TimeDelta poll(TimeDelta::FromMilliseconds(10)); 794 base::WaitableEvent done(false, false); 795 syncer_thread()->OnReceivedLongPollIntervalUpdate(poll); 796 UseMockDelayProvider(); 797 798 const TimeDelta backoff = TimeDelta::FromMilliseconds(100); 799 800 EXPECT_CALL(*syncer(), SyncShare(_,_,_)) 801 .WillOnce(Invoke(sessions::test_util::SimulateCommitFailed)) 802 .WillOnce(Invoke(sessions::test_util::SimulateCommitFailed)) 803 .WillRepeatedly(DoAll(Invoke(sessions::test_util::SimulateSuccess), 804 RecordSyncShareAndPostSignal(&r, kMinNumSamples, this, &done))); 805 EXPECT_CALL(*delay(), GetDelay(_)).WillOnce(Return(backoff)); 806 807 // Optimal start for the post-backoff poll party. 808 TimeTicks optimal_start = TimeTicks::Now() + poll + backoff; 809 syncer_thread()->Start(SyncerThread::NORMAL_MODE, NULL); 810 done.TimedWait(timeout()); 811 syncer_thread()->Stop(); 812 813 // Check for healthy polling after backoff is relieved. 814 // Can't use AnalyzePollRun because first sync is a continuation. Bleh. 815 for (size_t i = 0; i < r.times.size(); i++) { 816 SCOPED_TRACE(testing::Message() << "SyncShare # (" << i << ")"); 817 TimeTicks optimal_next_sync = optimal_start + poll * i; 818 EXPECT_GE(r.times[i], optimal_next_sync); 819 EXPECT_EQ(i == 0 ? GetUpdatesCallerInfo::SYNC_CYCLE_CONTINUATION 820 : GetUpdatesCallerInfo::PERIODIC, 821 r.snapshots[i]->source.updates_source); 822 } 823} 824 825TEST_F(SyncerThread2Test, GetRecommendedDelay) { 826 EXPECT_LE(TimeDelta::FromSeconds(0), 827 SyncerThread::GetRecommendedDelay(TimeDelta::FromSeconds(0))); 828 EXPECT_LE(TimeDelta::FromSeconds(1), 829 SyncerThread::GetRecommendedDelay(TimeDelta::FromSeconds(1))); 830 EXPECT_LE(TimeDelta::FromSeconds(50), 831 SyncerThread::GetRecommendedDelay(TimeDelta::FromSeconds(50))); 832 EXPECT_LE(TimeDelta::FromSeconds(10), 833 SyncerThread::GetRecommendedDelay(TimeDelta::FromSeconds(10))); 834 EXPECT_EQ(TimeDelta::FromSeconds(kMaxBackoffSeconds), 835 SyncerThread::GetRecommendedDelay( 836 TimeDelta::FromSeconds(kMaxBackoffSeconds))); 837 EXPECT_EQ(TimeDelta::FromSeconds(kMaxBackoffSeconds), 838 SyncerThread::GetRecommendedDelay( 839 TimeDelta::FromSeconds(kMaxBackoffSeconds + 1))); 840} 841 842// Test that appropriate syncer steps are requested for each job type. 843TEST_F(SyncerThread2Test, SyncerSteps) { 844 // Nudges. 845 base::WaitableEvent done(false, false); 846 EXPECT_CALL(*syncer(), SyncShare(_, SYNCER_BEGIN, SYNCER_END)) 847 .Times(1); 848 syncer_thread()->Start(SyncerThread::NORMAL_MODE, NULL); 849 syncer_thread()->ScheduleNudge(zero(), NUDGE_SOURCE_LOCAL, ModelTypeBitSet(), 850 FROM_HERE); 851 FlushLastTask(&done); 852 syncer_thread()->Stop(); 853 Mock::VerifyAndClearExpectations(syncer()); 854 855 // ClearUserData. 856 EXPECT_CALL(*syncer(), SyncShare(_, CLEAR_PRIVATE_DATA, SYNCER_END)) 857 .Times(1); 858 syncer_thread()->Start(SyncerThread::NORMAL_MODE, NULL); 859 syncer_thread()->ScheduleClearUserData(); 860 FlushLastTask(&done); 861 syncer_thread()->Stop(); 862 Mock::VerifyAndClearExpectations(syncer()); 863 // Configuration. 864 EXPECT_CALL(*syncer(), SyncShare(_, DOWNLOAD_UPDATES, APPLY_UPDATES)); 865 syncer_thread()->Start(SyncerThread::CONFIGURATION_MODE, NULL); 866 syncer_thread()->ScheduleConfig(ModelTypeBitSet()); 867 FlushLastTask(&done); 868 syncer_thread()->Stop(); 869 Mock::VerifyAndClearExpectations(syncer()); 870 871 // Poll. 872 EXPECT_CALL(*syncer(), SyncShare(_, SYNCER_BEGIN, SYNCER_END)) 873 .Times(AtLeast(1)) 874 .WillRepeatedly(SignalEvent(&done)); 875 const TimeDelta poll(TimeDelta::FromMilliseconds(10)); 876 syncer_thread()->OnReceivedLongPollIntervalUpdate(poll); 877 syncer_thread()->Start(SyncerThread::NORMAL_MODE, NULL); 878 done.TimedWait(timeout()); 879 syncer_thread()->Stop(); 880 Mock::VerifyAndClearExpectations(syncer()); 881 done.Reset(); 882} 883 884// Test config tasks don't run during normal mode. 885// TODO(tim): Implement this test and then the functionality! 886TEST_F(SyncerThread2Test, DISABLED_NoConfigDuringNormal) { 887} 888 889// Test that starting the syncer thread without a valid connection doesn't 890// break things when a connection is detected. 891TEST_F(SyncerThread2Test, StartWhenNotConnected) { 892 base::WaitableEvent done(false, false); 893 MessageLoop cur; 894 connection()->SetServerNotReachable(); 895 EXPECT_CALL(*syncer(), SyncShare(_,_,_)).WillOnce(SignalEvent(&done)); 896 syncer_thread()->Start(SyncerThread::NORMAL_MODE, NULL); 897 syncer_thread()->ScheduleNudge(zero(), NUDGE_SOURCE_LOCAL, ModelTypeBitSet(), 898 FROM_HERE); 899 FlushLastTask(&done); 900 901 connection()->SetServerReachable(); 902 cur.PostTask(FROM_HERE, NewRunnableFunction( 903 &SyncerThread2Test::QuitMessageLoop)); 904 cur.Run(); 905 906 // By now, the server connection event should have been posted to the 907 // SyncerThread. 908 FlushLastTask(&done); 909 done.TimedWait(timeout()); 910} 911 912TEST_F(SyncerThread2Test, SetsPreviousRoutingInfo) { 913 base::WaitableEvent done(false, false); 914 ModelSafeRoutingInfo info; 915 EXPECT_TRUE(info == context()->previous_session_routing_info()); 916 ModelSafeRoutingInfo expected; 917 context()->registrar()->GetModelSafeRoutingInfo(&expected); 918 ASSERT_FALSE(expected.empty()); 919 EXPECT_CALL(*syncer(), SyncShare(_,_,_)).Times(1); 920 921 syncer_thread()->Start(SyncerThread::NORMAL_MODE, NULL); 922 syncer_thread()->ScheduleNudge(zero(), NUDGE_SOURCE_LOCAL, ModelTypeBitSet(), 923 FROM_HERE); 924 FlushLastTask(&done); 925 syncer_thread()->Stop(); 926 927 EXPECT_TRUE(expected == context()->previous_session_routing_info()); 928} 929 930} // namespace browser_sync 931 932// SyncerThread won't outlive the test! 933DISABLE_RUNNABLE_METHOD_REFCOUNT(browser_sync::SyncerThread2Test); 934