OLD | NEW |
---|---|
(Empty) | |
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_thread2.h" | |
10 #include "chrome/browser/sync/sessions/test_util.h" | |
11 #include "chrome/test/sync/engine/test_directory_setter_upper.h" | |
12 #include "testing/gtest/include/gtest/gtest.h" | |
13 #include "testing/gmock/include/gmock/gmock.h" | |
14 | |
15 using base::TimeDelta; | |
16 using base::TimeTicks; | |
17 using testing::_; | |
18 using testing::AtLeast; | |
19 using testing::DoAll; | |
20 using testing::Eq; | |
21 using testing::Invoke; | |
22 using testing::Mock; | |
23 using testing::Return; | |
24 using testing::WithArg; | |
25 | |
26 namespace browser_sync { | |
27 using sessions::SyncSession; | |
28 using sessions::SyncSessionContext; | |
29 using sessions::SyncSessionSnapshot; | |
30 using syncable::ModelTypeBitSet; | |
31 using sync_pb::GetUpdatesCallerInfo; | |
32 | |
33 class MockSyncer : public Syncer { | |
34 public: | |
35 MOCK_METHOD1(SyncShare, void(sessions::SyncSession*)); | |
36 }; | |
37 | |
38 namespace s3 { | |
39 | |
40 // Used when tests want to record syncing activity to examine later. | |
41 struct 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. | |
47 static const size_t kMinNumSamples = 5; | |
48 | |
49 class SyncerThread2Test : public testing::Test { | |
50 public: | |
51 class MockDelayProvider : public SyncerThread::DelayProvider { | |
52 public: | |
53 MOCK_METHOD1(GetDelay, TimeDelta(const TimeDelta&)); | |
54 }; | |
55 | |
56 virtual void SetUp() { | |
57 syncdb_.SetUp(); | |
58 syncer_ = new MockSyncer(); | |
59 delay_ = NULL; | |
60 registrar_.reset(MockModelSafeWorkerRegistrar::PassiveBookmarks()); | |
61 context_ = new SyncSessionContext(NULL, syncdb_.manager(), | |
62 registrar_.get(), std::vector<SyncEngineEventListener*>()); | |
63 context_->set_notifications_enabled(true); | |
64 context_->set_account_name("Test"); | |
65 syncer_thread_.reset(new SyncerThread(context_, syncer_)); | |
66 // TODO(tim): Once the SCM is hooked up, remove this. | |
67 syncer_thread_->server_connection_ok_ = true; | |
68 } | |
69 | |
70 SyncerThread* syncer_thread() { return syncer_thread_.get(); } | |
71 MockSyncer* syncer() { return syncer_; } | |
72 MockDelayProvider* delay() { return delay_; } | |
73 TimeDelta zero() { return TimeDelta::FromSeconds(0); } | |
74 TimeDelta timeout() { | |
75 return TimeDelta::FromMilliseconds(TestTimeouts::action_timeout_ms()); | |
76 } | |
77 | |
78 virtual void TearDown() { | |
79 syncer_thread()->Stop(); | |
80 syncdb_.TearDown(); | |
81 } | |
82 | |
83 void AnalyzePollRun(const SyncShareRecords& records, size_t min_num_samples, | |
84 const TimeTicks& optimal_start, const TimeDelta& poll_interval) { | |
85 const std::vector<TimeTicks>& data(records.times); | |
86 EXPECT_GE(data.size(), min_num_samples); | |
87 for (size_t i = 0; i < data.size(); i++) { | |
88 SCOPED_TRACE(testing::Message() << "SyncShare # (" << i << ")"); | |
89 TimeTicks optimal_next_sync = optimal_start + poll_interval * i; | |
90 EXPECT_GE(data[i], optimal_next_sync); | |
91 EXPECT_LT(data[i], optimal_next_sync + poll_interval); | |
92 EXPECT_EQ(GetUpdatesCallerInfo::PERIODIC, | |
93 records.snapshots[i]->source.first); | |
94 } | |
95 } | |
96 | |
97 bool GetBackoffAndReset(base::WaitableEvent* done) { | |
98 syncable::ModelTypeBitSet nudge_types; | |
99 syncer_thread()->Start(SyncerThread::NORMAL_MODE); | |
100 syncer_thread()->ScheduleNudge(zero(), NUDGE_SOURCE_LOCAL, nudge_types); | |
101 done->TimedWait(timeout()); | |
102 TearDown(); | |
103 done->Reset(); | |
104 Mock::VerifyAndClearExpectations(syncer()); | |
105 bool backing_off = syncer_thread()->IsBackingOff(); | |
106 SetUp(); | |
107 UseMockDelayProvider(); | |
108 EXPECT_CALL(*delay(), GetDelay(_)) | |
109 .WillRepeatedly(Return(TimeDelta::FromMilliseconds(1))); | |
110 return backing_off; | |
111 } | |
112 | |
113 void UseMockDelayProvider() { | |
114 delay_ = new MockDelayProvider(); | |
115 syncer_thread_->delay_provider_.reset(delay_); | |
116 } | |
117 | |
118 void PostSignalTask(base::WaitableEvent* done) { | |
119 syncer_thread_->thread_.message_loop()->PostTask(FROM_HERE, | |
120 NewRunnableFunction(&SyncerThread2Test::SignalWaitableEvent, done)); | |
121 } | |
122 | |
123 void FlushLastTask(base::WaitableEvent* done) { | |
124 PostSignalTask(done); | |
125 done->TimedWait(timeout()); | |
126 done->Reset(); | |
127 } | |
128 | |
129 static void SignalWaitableEvent(base::WaitableEvent* event) { | |
130 event->Signal(); | |
131 } | |
132 | |
133 private: | |
134 scoped_ptr<SyncerThread> syncer_thread_; | |
135 SyncSessionContext* context_; | |
136 MockSyncer* syncer_; | |
137 MockDelayProvider* delay_; | |
138 scoped_ptr<MockModelSafeWorkerRegistrar> registrar_; | |
139 MockDirectorySetterUpper syncdb_; | |
140 }; | |
141 | |
142 // SyncerThread won't outlive the test! | |
143 DISABLE_RUNNABLE_METHOD_REFCOUNT(SyncerThread2Test); | |
144 | |
145 bool RecordSyncShareImpl(SyncSession* s, SyncShareRecords* record, | |
146 size_t signal_after) { | |
147 record->times.push_back(TimeTicks::Now()); | |
148 record->snapshots.push_back(make_linked_ptr(new SyncSessionSnapshot( | |
149 s->TakeSnapshot()))); | |
150 return record->times.size() >= signal_after; | |
151 } | |
152 | |
153 ACTION_P4(RecordSyncShareAndPostSignal, record, signal_after, test, event) { | |
154 if (RecordSyncShareImpl(arg0, record, signal_after) && event) | |
155 test->PostSignalTask(event); | |
156 } | |
157 | |
158 ACTION_P3(RecordSyncShare, record, signal_after, event) { | |
159 if (RecordSyncShareImpl(arg0, record, signal_after) && event) | |
160 event->Signal(); | |
161 } | |
162 | |
163 ACTION_P(SignalEvent, event) { | |
164 SyncerThread2Test::SignalWaitableEvent(event); | |
165 } | |
166 | |
167 // Test nudge scheduling. | |
168 TEST_F(SyncerThread2Test, Nudge) { | |
169 syncer_thread()->Start(SyncerThread::NORMAL_MODE); | |
170 base::WaitableEvent done(false, false); | |
171 SyncShareRecords records; | |
172 syncable::ModelTypeBitSet model_types; | |
173 model_types[syncable::BOOKMARKS] = true; | |
174 | |
175 EXPECT_CALL(*syncer(), SyncShare(_)) | |
176 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess), | |
177 WithArg<0>(RecordSyncShare(&records, 1U, &done)))); | |
178 syncer_thread()->ScheduleNudge(zero(), NUDGE_SOURCE_LOCAL, model_types); | |
179 done.TimedWait(timeout()); | |
180 | |
181 EXPECT_EQ(1, records.snapshots.size()); | |
182 EXPECT_EQ(model_types, records.snapshots[0]->source.second); | |
183 EXPECT_EQ(GetUpdatesCallerInfo::LOCAL, records.snapshots[0]->source.first); | |
184 } | |
185 | |
186 // Test that nudges are coalesced. | |
187 TEST_F(SyncerThread2Test, NudgeCoalescing) { | |
188 syncer_thread()->Start(SyncerThread::NORMAL_MODE); | |
189 base::WaitableEvent done(false, false); | |
190 SyncShareRecords r; | |
191 EXPECT_CALL(*syncer(), SyncShare(_)) | |
192 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess), | |
193 WithArg<0>(RecordSyncShare(&r, 1U, &done)))); | |
194 syncable::ModelTypeBitSet types1, types2, types3; | |
195 types1[syncable::BOOKMARKS] = true; | |
196 types2[syncable::AUTOFILL] = true; | |
197 types3[syncable::THEMES] = true; | |
198 TimeDelta delay = TimeDelta::FromMilliseconds(20); | |
199 TimeTicks optimal_time = TimeTicks::Now() + delay; | |
200 syncer_thread()->ScheduleNudge(delay, NUDGE_SOURCE_UNKNOWN, types1); | |
201 syncer_thread()->ScheduleNudge(zero(), NUDGE_SOURCE_LOCAL, types2); | |
202 syncer_thread()->ScheduleNudge(zero(), NUDGE_SOURCE_NOTIFICATION, types3); | |
203 done.TimedWait(timeout()); | |
204 | |
205 EXPECT_EQ(1, r.snapshots.size()); | |
206 EXPECT_GE(r.times[0], optimal_time); | |
207 EXPECT_EQ(types1 | types2 | types3, r.snapshots[0]->source.second); | |
208 EXPECT_EQ(GetUpdatesCallerInfo::NOTIFICATION, r.snapshots[0]->source.first); | |
209 | |
210 SyncShareRecords r2; | |
211 EXPECT_CALL(*syncer(), SyncShare(_)) | |
212 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess), | |
213 WithArg<0>(RecordSyncShare(&r2, 1U, &done)))); | |
214 syncer_thread()->ScheduleNudge(zero(), NUDGE_SOURCE_NOTIFICATION, types3); | |
215 done.TimedWait(timeout()); | |
216 EXPECT_EQ(1, r2.snapshots.size()); | |
217 EXPECT_EQ(types3, r2.snapshots[0]->source.second); | |
218 EXPECT_EQ(GetUpdatesCallerInfo::NOTIFICATION, r2.snapshots[0]->source.first); | |
219 } | |
220 | |
221 // Test that polling works as expected. | |
222 TEST_F(SyncerThread2Test, Polling) { | |
223 SyncShareRecords records; | |
224 base::WaitableEvent done(false, false); | |
225 TimeDelta poll_interval(TimeDelta::FromMilliseconds(30)); | |
226 syncer_thread()->OnReceivedLongPollIntervalUpdate(poll_interval); | |
227 EXPECT_CALL(*syncer(), SyncShare(_)).Times(AtLeast(kMinNumSamples)) | |
228 .WillRepeatedly(DoAll(Invoke(sessions::test_util::SimulateSuccess), | |
229 WithArg<0>(RecordSyncShare(&records, kMinNumSamples, &done)))); | |
230 | |
231 TimeTicks optimal_start = TimeTicks::Now() + poll_interval; | |
232 syncer_thread()->Start(SyncerThread::NORMAL_MODE); | |
233 done.TimedWait(timeout()); | |
234 syncer_thread()->Stop(); | |
235 | |
236 AnalyzePollRun(records, kMinNumSamples, optimal_start, poll_interval); | |
237 } | |
238 | |
239 // Test that the short poll interval is used. | |
240 TEST_F(SyncerThread2Test, PollNotificationsDisabled) { | |
241 SyncShareRecords records; | |
242 base::WaitableEvent done(false, false); | |
243 TimeDelta poll_interval(TimeDelta::FromMilliseconds(30)); | |
244 syncer_thread()->OnReceivedShortPollIntervalUpdate(poll_interval); | |
245 syncer_thread()->set_notifications_enabled(false); | |
246 EXPECT_CALL(*syncer(), SyncShare(_)).Times(AtLeast(kMinNumSamples)) | |
247 .WillRepeatedly(DoAll(Invoke(sessions::test_util::SimulateSuccess), | |
248 WithArg<0>(RecordSyncShare(&records, kMinNumSamples, &done)))); | |
249 | |
250 TimeTicks optimal_start = TimeTicks::Now() + poll_interval; | |
251 syncer_thread()->Start(SyncerThread::NORMAL_MODE); | |
252 done.TimedWait(timeout()); | |
253 syncer_thread()->Stop(); | |
254 | |
255 AnalyzePollRun(records, kMinNumSamples, optimal_start, poll_interval); | |
256 } | |
257 | |
258 // Test that polling intervals are updated when needed. | |
259 TEST_F(SyncerThread2Test, PollIntervalUpdate) { | |
260 SyncShareRecords records; | |
261 base::WaitableEvent done(false, false); | |
262 TimeDelta poll1(TimeDelta::FromMilliseconds(120)); | |
263 TimeDelta poll2(TimeDelta::FromMilliseconds(30)); | |
264 syncer_thread()->OnReceivedLongPollIntervalUpdate(poll1); | |
265 EXPECT_CALL(*syncer(), SyncShare(_)).Times(AtLeast(kMinNumSamples)) | |
266 .WillOnce(WithArg<0>( | |
267 sessions::test_util::SimulatePollIntervalUpdate(poll2))) | |
268 .WillRepeatedly(DoAll(Invoke(sessions::test_util::SimulateSuccess), | |
269 WithArg<0>(RecordSyncShare(&records, kMinNumSamples, &done)))); | |
270 | |
271 TimeTicks optimal_start = TimeTicks::Now() + poll1 + poll2; | |
272 syncer_thread()->Start(SyncerThread::NORMAL_MODE); | |
273 done.TimedWait(timeout()); | |
274 syncer_thread()->Stop(); | |
275 | |
276 AnalyzePollRun(records, kMinNumSamples, optimal_start, poll2); | |
277 } | |
278 | |
279 // Test that a sync session is run through to completion. | |
280 TEST_F(SyncerThread2Test, HasMoreToSync) { | |
281 syncer_thread()->Start(SyncerThread::NORMAL_MODE); | |
282 base::WaitableEvent done(false, false); | |
283 EXPECT_CALL(*syncer(), SyncShare(_)) | |
284 .WillOnce(Invoke(sessions::test_util::SimulateHasMoreToSync)) | |
285 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess), | |
286 SignalEvent(&done))); | |
287 syncer_thread()->ScheduleNudge(zero(), NUDGE_SOURCE_LOCAL, ModelTypeBitSet()); | |
288 done.TimedWait(timeout()); | |
289 // If more nudges are scheduled, they'll be waited on by TearDown, and would | |
290 // cause our expectation to break. | |
291 } | |
292 | |
293 // Test that no syncing occurs when throttled. | |
294 TEST_F(SyncerThread2Test, ThrottlingDoesThrottle) { | |
295 syncable::ModelTypeBitSet types; | |
296 types[syncable::BOOKMARKS] = true; | |
297 base::WaitableEvent done(false, false); | |
298 TimeDelta poll(TimeDelta::FromMilliseconds(5)); | |
299 TimeDelta throttle(TimeDelta::FromMinutes(10)); | |
300 syncer_thread()->OnReceivedLongPollIntervalUpdate(poll); | |
301 EXPECT_CALL(*syncer(), SyncShare(_)) | |
302 .WillOnce(WithArg<0>(sessions::test_util::SimulateThrottled(throttle))); | |
303 | |
304 syncer_thread()->Start(SyncerThread::NORMAL_MODE); | |
305 syncer_thread()->ScheduleNudge(zero(), NUDGE_SOURCE_LOCAL, types); | |
306 FlushLastTask(&done); | |
307 | |
308 syncer_thread()->Start(SyncerThread::CONFIGURATION_MODE); | |
309 syncer_thread()->ScheduleConfig(zero(), types); | |
310 FlushLastTask(&done); | |
311 } | |
312 | |
313 TEST_F(SyncerThread2Test, ThrottlingExpires) { | |
314 SyncShareRecords records; | |
315 base::WaitableEvent done(false, false); | |
316 TimeDelta poll(TimeDelta::FromMilliseconds(15)); | |
317 TimeDelta throttle1(TimeDelta::FromMilliseconds(150)); | |
318 TimeDelta throttle2(TimeDelta::FromMinutes(10)); | |
319 syncer_thread()->OnReceivedLongPollIntervalUpdate(poll); | |
320 | |
321 ::testing::InSequence seq; | |
322 EXPECT_CALL(*syncer(), SyncShare(_)) | |
323 .WillOnce(WithArg<0>(sessions::test_util::SimulateThrottled(throttle1))) | |
324 .RetiresOnSaturation(); | |
325 EXPECT_CALL(*syncer(), SyncShare(_)) | |
326 .WillRepeatedly(DoAll(Invoke(sessions::test_util::SimulateSuccess), | |
327 WithArg<0>(RecordSyncShare(&records, kMinNumSamples, &done)))); | |
328 | |
329 TimeTicks optimal_start = TimeTicks::Now() + poll + throttle1; | |
330 syncer_thread()->Start(SyncerThread::NORMAL_MODE); | |
331 done.TimedWait(timeout()); | |
332 syncer_thread()->Stop(); | |
333 | |
334 AnalyzePollRun(records, kMinNumSamples, optimal_start, poll); | |
335 } | |
336 | |
337 // Test nudges / polls don't run in config mode and config tasks do. | |
338 TEST_F(SyncerThread2Test, ConfigurationMode) { | |
339 TimeDelta poll(TimeDelta::FromMilliseconds(15)); | |
340 base::WaitableEvent done(false, false); | |
341 syncer_thread()->OnReceivedLongPollIntervalUpdate(poll); | |
342 EXPECT_CALL(*syncer(), SyncShare(_)).Times(0); | |
343 syncer_thread()->Start(SyncerThread::CONFIGURATION_MODE); | |
344 syncable::ModelTypeBitSet nudge_types; | |
345 nudge_types[syncable::AUTOFILL] = true; | |
346 syncer_thread()->ScheduleNudge(zero(), NUDGE_SOURCE_LOCAL, nudge_types); | |
347 syncer_thread()->ScheduleNudge(zero(), NUDGE_SOURCE_LOCAL, nudge_types); | |
348 | |
349 syncable::ModelTypeBitSet config_types; | |
350 config_types[syncable::BOOKMARKS] = true; | |
351 // TODO(tim): This will fail once CONFIGURATION tasks are implemented. Update | |
352 // the EXPECT when that happens. | |
353 syncer_thread()->ScheduleConfig(zero(), config_types); | |
354 FlushLastTask(&done); | |
355 } | |
356 | |
357 // Test that exponential backoff is properly triggered. | |
358 TEST_F(SyncerThread2Test, BackoffTriggers) { | |
359 base::WaitableEvent done(false, false); | |
360 UseMockDelayProvider(); | |
361 | |
362 EXPECT_CALL(*syncer(), SyncShare(_)) | |
363 .WillOnce(Invoke(sessions::test_util::SimulateDownloadUpdatesFailed)) | |
364 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess), | |
365 SignalEvent(&done))); | |
366 EXPECT_FALSE(GetBackoffAndReset(&done)); | |
akalin
2011/01/25 06:09:53
according to the gmock docs, results are undefined
tim (not reviewing)
2011/01/25 17:15:22
Not sure what you mean here, can you elaborate?
No
akalin
2011/01/25 19:20:14
Oh, I was referring to this line from the gmock do
| |
367 EXPECT_CALL(*syncer(), SyncShare(_)) | |
368 .WillOnce(Invoke(sessions::test_util::SimulateCommitFailed)) | |
369 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess), | |
370 SignalEvent(&done))); | |
371 EXPECT_FALSE(GetBackoffAndReset(&done)); | |
372 EXPECT_CALL(*syncer(), SyncShare(_)) | |
373 .WillOnce(Invoke(sessions::test_util::SimulateDownloadUpdatesFailed)) | |
374 .WillRepeatedly(DoAll(Invoke( | |
375 sessions::test_util::SimulateDownloadUpdatesFailed), | |
376 SignalEvent(&done))); | |
377 EXPECT_TRUE(GetBackoffAndReset(&done)); | |
378 EXPECT_CALL(*syncer(), SyncShare(_)) | |
379 .WillOnce(Invoke(sessions::test_util::SimulateCommitFailed)) | |
380 .WillRepeatedly(DoAll(Invoke(sessions::test_util::SimulateCommitFailed), | |
381 SignalEvent(&done))); | |
382 EXPECT_TRUE(GetBackoffAndReset(&done)); | |
383 EXPECT_CALL(*syncer(), SyncShare(_)) | |
384 .WillOnce(Invoke(sessions::test_util::SimulateDownloadUpdatesFailed)) | |
385 .WillOnce(Invoke(sessions::test_util::SimulateDownloadUpdatesFailed)) | |
386 .WillRepeatedly(DoAll(Invoke(sessions::test_util::SimulateSuccess), | |
387 SignalEvent(&done))); | |
388 EXPECT_FALSE(GetBackoffAndReset(&done)); | |
389 EXPECT_CALL(*syncer(), SyncShare(_)) | |
390 .WillOnce(Invoke(sessions::test_util::SimulateCommitFailed)) | |
391 .WillOnce(Invoke(sessions::test_util::SimulateCommitFailed)) | |
392 .WillRepeatedly(DoAll(Invoke(sessions::test_util::SimulateSuccess), | |
393 SignalEvent(&done))); | |
394 EXPECT_FALSE(GetBackoffAndReset(&done)); | |
395 } | |
396 | |
397 // Test that no polls or extraneous nudges occur when in backoff. | |
398 TEST_F(SyncerThread2Test, BackoffDropsJobs) { | |
399 SyncShareRecords r; | |
400 TimeDelta poll(TimeDelta::FromMilliseconds(5)); | |
401 base::WaitableEvent done(false, false); | |
402 syncable::ModelTypeBitSet types; | |
403 types[syncable::BOOKMARKS] = true; | |
404 syncer_thread()->OnReceivedLongPollIntervalUpdate(poll); | |
405 UseMockDelayProvider(); | |
406 | |
407 EXPECT_CALL(*syncer(), SyncShare(_)).Times(2) | |
408 .WillRepeatedly(DoAll(Invoke(sessions::test_util::SimulateCommitFailed), | |
409 RecordSyncShareAndPostSignal(&r, 2U, this, &done))); | |
410 EXPECT_CALL(*delay(), GetDelay(_)) | |
411 .WillRepeatedly(Return(TimeDelta::FromDays(1))); | |
412 | |
413 syncer_thread()->Start(SyncerThread::NORMAL_MODE); | |
414 ASSERT_TRUE(done.TimedWait(timeout())); | |
415 done.Reset(); | |
416 | |
417 Mock::VerifyAndClearExpectations(syncer()); | |
418 EXPECT_EQ(2U, r.snapshots.size()); | |
419 EXPECT_EQ(GetUpdatesCallerInfo::PERIODIC, r.snapshots[0]->source.first); | |
420 EXPECT_EQ(GetUpdatesCallerInfo::SYNC_CYCLE_CONTINUATION, | |
421 r.snapshots[1]->source.first); | |
422 | |
423 EXPECT_CALL(*syncer(), SyncShare(_)).Times(1) | |
424 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateCommitFailed), | |
425 RecordSyncShareAndPostSignal(&r, 1U, this, &done))); | |
426 | |
427 // We schedule a nudge with enough delay (10X poll interval) that at least | |
428 // one or two polls would have taken place. The nudge should succeed. | |
429 syncer_thread()->ScheduleNudge(poll * 10, NUDGE_SOURCE_LOCAL, types); | |
430 ASSERT_TRUE(done.TimedWait(timeout())); | |
431 done.Reset(); | |
432 | |
433 Mock::VerifyAndClearExpectations(syncer()); | |
434 Mock::VerifyAndClearExpectations(delay()); | |
435 EXPECT_EQ(3U, r.snapshots.size()); | |
436 EXPECT_EQ(GetUpdatesCallerInfo::LOCAL, r.snapshots[2]->source.first); | |
437 | |
438 EXPECT_CALL(*syncer(), SyncShare(_)).Times(0); | |
439 EXPECT_CALL(*delay(), GetDelay(_)).Times(0); | |
440 | |
441 syncer_thread()->Start(SyncerThread::CONFIGURATION_MODE); | |
442 syncer_thread()->ScheduleConfig(zero(), types); | |
443 FlushLastTask(&done); | |
444 | |
445 syncer_thread()->Start(SyncerThread::NORMAL_MODE); | |
446 syncer_thread()->ScheduleNudge(zero(), NUDGE_SOURCE_LOCAL, types); | |
447 syncer_thread()->ScheduleNudge(zero(), NUDGE_SOURCE_LOCAL, types); | |
448 FlushLastTask(&done); | |
449 } | |
450 | |
451 // Test that backoff is shaping traffic properly with consecutive errors. | |
452 TEST_F(SyncerThread2Test, BackoffElevation) { | |
453 SyncShareRecords r; | |
454 const TimeDelta poll(TimeDelta::FromMilliseconds(10)); | |
455 base::WaitableEvent done(false, false); | |
456 syncer_thread()->OnReceivedLongPollIntervalUpdate(poll); | |
457 UseMockDelayProvider(); | |
458 | |
459 const TimeDelta first = TimeDelta::FromSeconds(1); | |
460 const TimeDelta second = TimeDelta::FromMilliseconds(10); | |
461 const TimeDelta third = TimeDelta::FromMilliseconds(20); | |
462 const TimeDelta fourth = TimeDelta::FromMilliseconds(30); | |
463 const TimeDelta fifth = TimeDelta::FromDays(1); | |
464 | |
465 EXPECT_CALL(*syncer(), SyncShare(_)).Times(kMinNumSamples) | |
466 .WillRepeatedly(DoAll(Invoke(sessions::test_util::SimulateCommitFailed), | |
467 RecordSyncShareAndPostSignal(&r, kMinNumSamples, this, &done))); | |
468 | |
469 EXPECT_CALL(*delay(), GetDelay(Eq(first))).WillOnce(Return(second)) | |
470 .RetiresOnSaturation(); | |
471 EXPECT_CALL(*delay(), GetDelay(Eq(second))).WillOnce(Return(third)) | |
472 .RetiresOnSaturation(); | |
473 EXPECT_CALL(*delay(), GetDelay(Eq(third))).WillOnce(Return(fourth)) | |
474 .RetiresOnSaturation(); | |
475 EXPECT_CALL(*delay(), GetDelay(Eq(fourth))).WillOnce(Return(fifth)); | |
476 | |
477 syncer_thread()->Start(SyncerThread::NORMAL_MODE); | |
478 ASSERT_TRUE(done.TimedWait(timeout())); | |
479 | |
480 EXPECT_GE(r.times[2] - r.times[1], second); | |
481 EXPECT_GE(r.times[3] - r.times[2], third); | |
482 EXPECT_GE(r.times[4] - r.times[3], fourth); | |
483 } | |
484 | |
485 // Test that things go back to normal once a canary task makes forward progress | |
486 // following a succession of failures. | |
487 TEST_F(SyncerThread2Test, BackoffRelief) { | |
488 SyncShareRecords r; | |
489 const TimeDelta poll(TimeDelta::FromMilliseconds(10)); | |
490 base::WaitableEvent done(false, false); | |
491 syncer_thread()->OnReceivedLongPollIntervalUpdate(poll); | |
492 UseMockDelayProvider(); | |
493 | |
494 const TimeDelta backoff = TimeDelta::FromMilliseconds(100); | |
495 | |
496 EXPECT_CALL(*syncer(), SyncShare(_)) | |
497 .WillOnce(Invoke(sessions::test_util::SimulateCommitFailed)) | |
498 .WillOnce(Invoke(sessions::test_util::SimulateCommitFailed)) | |
499 .WillRepeatedly(DoAll(Invoke(sessions::test_util::SimulateSuccess), | |
500 RecordSyncShareAndPostSignal(&r, kMinNumSamples, this, &done))); | |
501 EXPECT_CALL(*delay(), GetDelay(_)).WillOnce(Return(backoff)); | |
502 | |
503 // Optimal start for the post-backoff poll party. | |
504 TimeTicks optimal_start = TimeTicks::Now() + poll + backoff; | |
505 syncer_thread()->Start(SyncerThread::NORMAL_MODE); | |
506 done.TimedWait(timeout()); | |
507 | |
508 // Check for healthy polling after backoff is relieved. | |
509 // Can't use AnalyzePollRun because first sync is a continuation. Bleh. | |
510 for (size_t i = 0; i < r.times.size(); i++) { | |
511 SCOPED_TRACE(testing::Message() << "SyncShare # (" << i << ")"); | |
512 TimeTicks optimal_next_sync = optimal_start + poll * i; | |
513 EXPECT_GE(r.times[i], optimal_next_sync); | |
514 EXPECT_LT(r.times[i], optimal_next_sync + poll); | |
515 EXPECT_EQ(i == 0 ? GetUpdatesCallerInfo::SYNC_CYCLE_CONTINUATION | |
516 : GetUpdatesCallerInfo::PERIODIC, | |
517 r.snapshots[i]->source.first); | |
518 } | |
519 } | |
520 | |
521 TEST_F(SyncerThread2Test, GetRecommendedDelay) { | |
522 EXPECT_LE(TimeDelta::FromSeconds(0), | |
523 SyncerThread::GetRecommendedDelay(TimeDelta::FromSeconds(0))); | |
524 EXPECT_LE(TimeDelta::FromSeconds(1), | |
525 SyncerThread::GetRecommendedDelay(TimeDelta::FromSeconds(1))); | |
526 EXPECT_LE(TimeDelta::FromSeconds(50), | |
527 SyncerThread::GetRecommendedDelay(TimeDelta::FromSeconds(50))); | |
528 EXPECT_LE(TimeDelta::FromSeconds(10), | |
529 SyncerThread::GetRecommendedDelay(TimeDelta::FromSeconds(10))); | |
530 EXPECT_EQ(TimeDelta::FromSeconds(kMaxBackoffSeconds), | |
531 SyncerThread::GetRecommendedDelay( | |
532 TimeDelta::FromSeconds(kMaxBackoffSeconds))); | |
533 EXPECT_EQ(TimeDelta::FromSeconds(kMaxBackoffSeconds), | |
534 SyncerThread::GetRecommendedDelay( | |
535 TimeDelta::FromSeconds(kMaxBackoffSeconds + 1))); | |
536 } | |
537 | |
538 // Test config tasks don't run during normal mode. | |
akalin
2011/01/25 06:09:53
Do you need a TODO here?
| |
539 TEST_F(SyncerThread2Test, DISABLED_NoConfigDuringNormal) { | |
540 } | |
541 | |
542 // Test that starting the syncer thread without a valid connection doesn't | |
543 // break things when a connection is detected. | |
544 TEST_F(SyncerThread2Test, DISABLED_StartWhenNotConnected) { | |
545 | |
546 } | |
547 | |
548 } // namespace s3 | |
549 } // namespace browser_sync | |
OLD | NEW |