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