This source file includes following definitions.
- QuitLoopNow
- RunLoop
- PumpLoop
- PumpLoopFor
- TypesToRoutingInfo
- weak_ptr_factory_
- SetUp
- scheduler
- routing_info
- syncer
- delay
- connection
- zero
- timeout
- TearDown
- AnalyzePollRun
- DoQuitLoopNow
- StartSyncScheduler
- StopSyncScheduler
- RunAndGetBackoff
- UseMockDelayProvider
- context
- GetThrottledTypes
- GetRetryTimerDelay
- directory
- RecordSyncShareImpl
- ACTION_P
- ACTION_P2
- ACTION_P
- ACTION
- ACTION
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- SetUp
- TearDown
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- ACTION_P2
- TEST_F
#include "base/bind.h"
#include "base/callback.h"
#include "base/compiler_specific.h"
#include "base/memory/weak_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/test/test_timeouts.h"
#include "sync/engine/backoff_delay_provider.h"
#include "sync/engine/sync_scheduler_impl.h"
#include "sync/engine/syncer.h"
#include "sync/internal_api/public/base/cancelation_signal.h"
#include "sync/internal_api/public/base/model_type_test_util.h"
#include "sync/notifier/invalidation_util.h"
#include "sync/notifier/object_id_invalidation_map.h"
#include "sync/sessions/test_util.h"
#include "sync/test/callback_counter.h"
#include "sync/test/engine/fake_model_worker.h"
#include "sync/test/engine/mock_connection_manager.h"
#include "sync/test/engine/test_directory_setter_upper.h"
#include "sync/util/extensions_activity.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using base::TimeDelta;
using base::TimeTicks;
using testing::_;
using testing::AtLeast;
using testing::DoAll;
using testing::Invoke;
using testing::Mock;
using testing::Return;
using testing::WithArg;
using testing::WithArgs;
using testing::WithoutArgs;
namespace syncer {
using sessions::SyncSession;
using sessions::SyncSessionContext;
using sync_pb::GetUpdatesCallerInfo;
class MockSyncer : public Syncer {
public:
MockSyncer();
MOCK_METHOD3(NormalSyncShare, bool(ModelTypeSet,
const sessions::NudgeTracker&,
sessions::SyncSession*));
MOCK_METHOD3(ConfigureSyncShare,
bool(ModelTypeSet,
sync_pb::GetUpdatesCallerInfo::GetUpdatesSource,
SyncSession*));
MOCK_METHOD2(PollSyncShare, bool(ModelTypeSet, sessions::SyncSession*));
};
MockSyncer::MockSyncer()
: Syncer(NULL) {}
typedef std::vector<TimeTicks> SyncShareTimes;
void QuitLoopNow() {
base::MessageLoop::current()->QuitNow();
}
void RunLoop() {
base::MessageLoop::current()->Run();
}
void PumpLoop() {
base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(&QuitLoopNow));
RunLoop();
}
void PumpLoopFor(base::TimeDelta time) {
base::MessageLoop::current()->PostDelayedTask(
FROM_HERE, base::Bind(&QuitLoopNow), time);
RunLoop();
}
ModelSafeRoutingInfo TypesToRoutingInfo(ModelTypeSet types) {
ModelSafeRoutingInfo routes;
for (ModelTypeSet::Iterator iter = types.First(); iter.Good(); iter.Inc()) {
routes[iter.Get()] = GROUP_PASSIVE;
}
return routes;
}
static const size_t kMinNumSamples = 5;
class SyncSchedulerTest : public testing::Test {
public:
SyncSchedulerTest() : syncer_(NULL), delay_(NULL), weak_ptr_factory_(this) {}
class MockDelayProvider : public BackoffDelayProvider {
public:
MockDelayProvider() : BackoffDelayProvider(
TimeDelta::FromSeconds(kInitialBackoffRetrySeconds),
TimeDelta::FromSeconds(kInitialBackoffImmediateRetrySeconds)) {
}
MOCK_METHOD1(GetDelay, TimeDelta(const TimeDelta&));
};
virtual void SetUp() {
dir_maker_.SetUp();
syncer_ = new testing::StrictMock<MockSyncer>();
delay_ = NULL;
extensions_activity_ = new ExtensionsActivity();
routing_info_[BOOKMARKS] = GROUP_UI;
routing_info_[AUTOFILL] = GROUP_DB;
routing_info_[THEMES] = GROUP_UI;
routing_info_[NIGORI] = GROUP_PASSIVE;
workers_.clear();
workers_.push_back(make_scoped_refptr(new FakeModelWorker(GROUP_UI)));
workers_.push_back(make_scoped_refptr(new FakeModelWorker(GROUP_DB)));
workers_.push_back(make_scoped_refptr(new FakeModelWorker(GROUP_PASSIVE)));
connection_.reset(new MockConnectionManager(directory(),
&cancelation_signal_));
connection_->SetServerReachable();
model_type_registry_.reset(new ModelTypeRegistry(workers_, directory()));
context_.reset(new SyncSessionContext(
connection_.get(), directory(),
extensions_activity_.get(),
std::vector<SyncEngineEventListener*>(), NULL,
model_type_registry_.get(),
true,
false,
"fake_invalidator_client_id"));
context_->SetRoutingInfo(routing_info_);
context_->set_notifications_enabled(true);
context_->set_account_name("Test");
scheduler_.reset(
new SyncSchedulerImpl("TestSyncScheduler",
BackoffDelayProvider::FromDefaults(),
context(),
syncer_));
}
SyncSchedulerImpl* scheduler() { return scheduler_.get(); }
const ModelSafeRoutingInfo& routing_info() { return routing_info_; }
MockSyncer* syncer() { return syncer_; }
MockDelayProvider* delay() { return delay_; }
MockConnectionManager* connection() { return connection_.get(); }
TimeDelta zero() { return TimeDelta::FromSeconds(0); }
TimeDelta timeout() {
return TestTimeouts::action_timeout();
}
virtual void TearDown() {
PumpLoop();
scheduler_.reset();
PumpLoop();
dir_maker_.TearDown();
}
void AnalyzePollRun(const SyncShareTimes& times, size_t min_num_samples,
const TimeTicks& optimal_start, const TimeDelta& poll_interval) {
EXPECT_GE(times.size(), min_num_samples);
for (size_t i = 0; i < times.size(); i++) {
SCOPED_TRACE(testing::Message() << "SyncShare # (" << i << ")");
TimeTicks optimal_next_sync = optimal_start + poll_interval * i;
EXPECT_GE(times[i], optimal_next_sync);
}
}
void DoQuitLoopNow() {
QuitLoopNow();
}
void StartSyncScheduler(SyncScheduler::Mode mode) {
scheduler()->Start(mode);
}
void StopSyncScheduler() {
base::MessageLoop::current()->PostTask(
FROM_HERE,
base::Bind(&SyncSchedulerTest::DoQuitLoopNow,
weak_ptr_factory_.GetWeakPtr()));
RunLoop();
}
bool RunAndGetBackoff() {
ModelTypeSet nudge_types(BOOKMARKS);
StartSyncScheduler(SyncScheduler::NORMAL_MODE);
scheduler()->ScheduleLocalNudge(zero(), nudge_types, FROM_HERE);
RunLoop();
return scheduler()->IsBackingOff();
}
void UseMockDelayProvider() {
delay_ = new MockDelayProvider();
scheduler_->delay_provider_.reset(delay_);
}
SyncSessionContext* context() { return context_.get(); }
ModelTypeSet GetThrottledTypes() {
return scheduler_->nudge_tracker_.GetThrottledTypes();
}
base::TimeDelta GetRetryTimerDelay() {
EXPECT_TRUE(scheduler_->retry_timer_.IsRunning());
return scheduler_->retry_timer_.GetCurrentDelay();
}
private:
syncable::Directory* directory() {
return dir_maker_.directory();
}
base::MessageLoop loop_;
TestDirectorySetterUpper dir_maker_;
CancelationSignal cancelation_signal_;
scoped_ptr<MockConnectionManager> connection_;
scoped_ptr<ModelTypeRegistry> model_type_registry_;
scoped_ptr<SyncSessionContext> context_;
scoped_ptr<SyncSchedulerImpl> scheduler_;
MockSyncer* syncer_;
MockDelayProvider* delay_;
std::vector<scoped_refptr<ModelSafeWorker> > workers_;
scoped_refptr<ExtensionsActivity> extensions_activity_;
ModelSafeRoutingInfo routing_info_;
base::WeakPtrFactory<SyncSchedulerTest> weak_ptr_factory_;
};
void RecordSyncShareImpl(SyncShareTimes* times) {
times->push_back(TimeTicks::Now());
}
ACTION_P(RecordSyncShare, times) {
RecordSyncShareImpl(times);
if (base::MessageLoop::current()->is_running())
QuitLoopNow();
return true;
}
ACTION_P2(RecordSyncShareMultiple, times, quit_after) {
RecordSyncShareImpl(times);
EXPECT_LE(times->size(), quit_after);
if (times->size() >= quit_after &&
base::MessageLoop::current()->is_running()) {
QuitLoopNow();
}
return true;
}
ACTION_P(StopScheduler, scheduler) {
scheduler->Stop();
}
ACTION(AddFailureAndQuitLoopNow) {
ADD_FAILURE();
QuitLoopNow();
return true;
}
ACTION(QuitLoopNowAction) {
QuitLoopNow();
return true;
}
TEST_F(SyncSchedulerTest, Nudge) {
SyncShareTimes times;
ModelTypeSet model_types(BOOKMARKS);
EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
.WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
RecordSyncShare(×)))
.RetiresOnSaturation();
StartSyncScheduler(SyncScheduler::NORMAL_MODE);
scheduler()->ScheduleLocalNudge(zero(), model_types, FROM_HERE);
RunLoop();
Mock::VerifyAndClearExpectations(syncer());
SyncShareTimes times2;
model_types.Remove(BOOKMARKS);
model_types.Put(AUTOFILL);
EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
.WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
RecordSyncShare(×2)));
scheduler()->ScheduleLocalNudge(zero(), model_types, FROM_HERE);
RunLoop();
}
TEST_F(SyncSchedulerTest, Config) {
SyncShareTimes times;
const ModelTypeSet model_types(BOOKMARKS);
EXPECT_CALL(*syncer(), ConfigureSyncShare(_,_,_))
.WillOnce(DoAll(Invoke(sessions::test_util::SimulateConfigureSuccess),
RecordSyncShare(×)));
StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE);
CallbackCounter ready_counter;
CallbackCounter retry_counter;
ConfigurationParams params(
GetUpdatesCallerInfo::RECONFIGURATION,
model_types,
TypesToRoutingInfo(model_types),
base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
scheduler()->ScheduleConfiguration(params);
PumpLoop();
ASSERT_EQ(1, ready_counter.times_called());
ASSERT_EQ(0, retry_counter.times_called());
}
TEST_F(SyncSchedulerTest, ConfigWithBackingOff) {
UseMockDelayProvider();
EXPECT_CALL(*delay(), GetDelay(_))
.WillRepeatedly(Return(TimeDelta::FromMilliseconds(1)));
SyncShareTimes times;
const ModelTypeSet model_types(BOOKMARKS);
StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE);
EXPECT_CALL(*syncer(), ConfigureSyncShare(_,_,_))
.WillOnce(DoAll(Invoke(sessions::test_util::SimulateConfigureFailed),
RecordSyncShare(×)))
.WillOnce(DoAll(Invoke(sessions::test_util::SimulateConfigureFailed),
RecordSyncShare(×)));
CallbackCounter ready_counter;
CallbackCounter retry_counter;
ConfigurationParams params(
GetUpdatesCallerInfo::RECONFIGURATION,
model_types,
TypesToRoutingInfo(model_types),
base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
scheduler()->ScheduleConfiguration(params);
RunLoop();
ASSERT_EQ(0, ready_counter.times_called());
ASSERT_EQ(1, retry_counter.times_called());
RunLoop();
ASSERT_EQ(0, ready_counter.times_called());
ASSERT_EQ(1, retry_counter.times_called());
Mock::VerifyAndClearExpectations(syncer());
EXPECT_CALL(*syncer(), ConfigureSyncShare(_,_,_))
.WillOnce(DoAll(Invoke(sessions::test_util::SimulateConfigureSuccess),
RecordSyncShare(×)));
RunLoop();
ASSERT_EQ(1, ready_counter.times_called());
}
TEST_F(SyncSchedulerTest, ConfigWithStop) {
UseMockDelayProvider();
EXPECT_CALL(*delay(), GetDelay(_))
.WillRepeatedly(Return(TimeDelta::FromMilliseconds(1)));
SyncShareTimes times;
const ModelTypeSet model_types(BOOKMARKS);
StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE);
EXPECT_CALL(*syncer(), ConfigureSyncShare(_,_,_))
.WillOnce(DoAll(Invoke(sessions::test_util::SimulateConfigureFailed),
StopScheduler(scheduler()),
RecordSyncShare(×)));
CallbackCounter ready_counter;
CallbackCounter retry_counter;
ConfigurationParams params(
GetUpdatesCallerInfo::RECONFIGURATION,
model_types,
TypesToRoutingInfo(model_types),
base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
scheduler()->ScheduleConfiguration(params);
PumpLoop();
ASSERT_EQ(0, ready_counter.times_called());
ASSERT_EQ(0, retry_counter.times_called());
}
TEST_F(SyncSchedulerTest, NudgeWithConfigWithBackingOff) {
const ModelTypeSet model_types(BOOKMARKS);
UseMockDelayProvider();
EXPECT_CALL(*delay(), GetDelay(_))
.WillRepeatedly(Return(TimeDelta::FromMilliseconds(50)));
SyncShareTimes times;
StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE);
EXPECT_CALL(*syncer(), ConfigureSyncShare(_,_,_))
.WillOnce(DoAll(Invoke(sessions::test_util::SimulateConfigureFailed),
RecordSyncShare(×)));
CallbackCounter ready_counter;
CallbackCounter retry_counter;
ConfigurationParams params(
GetUpdatesCallerInfo::RECONFIGURATION,
model_types,
TypesToRoutingInfo(model_types),
base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
scheduler()->ScheduleConfiguration(params);
RunLoop();
ASSERT_EQ(0, ready_counter.times_called());
ASSERT_EQ(1, retry_counter.times_called());
Mock::VerifyAndClearExpectations(syncer());
EXPECT_CALL(*syncer(), ConfigureSyncShare(_,_,_))
.WillOnce(DoAll(Invoke(sessions::test_util::SimulateConfigureFailed),
RecordSyncShare(×)));
scheduler()->ScheduleLocalNudge(zero(), model_types, FROM_HERE);
RunLoop();
Mock::VerifyAndClearExpectations(syncer());
ASSERT_EQ(0, ready_counter.times_called());
EXPECT_CALL(*syncer(), ConfigureSyncShare(_,_,_))
.WillOnce(DoAll(Invoke(sessions::test_util::SimulateConfigureSuccess),
RecordSyncShare(×)));
RunLoop();
EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
.WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
RecordSyncShare(×)));
StartSyncScheduler(SyncScheduler::NORMAL_MODE);
PumpLoop();
}
TEST_F(SyncSchedulerTest, NudgeCoalescing) {
StartSyncScheduler(SyncScheduler::NORMAL_MODE);
SyncShareTimes times;
EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
.WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
RecordSyncShare(×)));
const ModelTypeSet types1(BOOKMARKS), types2(AUTOFILL), types3(THEMES);
TimeDelta delay = zero();
TimeTicks optimal_time = TimeTicks::Now() + delay;
scheduler()->ScheduleLocalNudge(delay, types1, FROM_HERE);
scheduler()->ScheduleLocalNudge(zero(), types2, FROM_HERE);
RunLoop();
ASSERT_EQ(1U, times.size());
EXPECT_GE(times[0], optimal_time);
Mock::VerifyAndClearExpectations(syncer());
SyncShareTimes times2;
EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
.WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
RecordSyncShare(×2)));
scheduler()->ScheduleLocalNudge(zero(), types3, FROM_HERE);
RunLoop();
}
TEST_F(SyncSchedulerTest, NudgeCoalescingWithDifferentTimings) {
StartSyncScheduler(SyncScheduler::NORMAL_MODE);
SyncShareTimes times;
EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
.WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
RecordSyncShare(×)));
ModelTypeSet types1(BOOKMARKS), types2(AUTOFILL), types3;
TimeDelta delay = TimeDelta::FromDays(1);
scheduler()->ScheduleLocalNudge(delay, types1, FROM_HERE);
scheduler()->ScheduleLocalNudge(zero(), types2, FROM_HERE);
TimeTicks min_time = TimeTicks::Now();
TimeTicks max_time = TimeTicks::Now() + delay;
RunLoop();
Mock::VerifyAndClearExpectations(syncer());
ASSERT_EQ(1U, times.size());
EXPECT_GE(times[0], min_time);
EXPECT_LE(times[0], max_time);
}
TEST_F(SyncSchedulerTest, NudgeWithStates) {
StartSyncScheduler(SyncScheduler::NORMAL_MODE);
SyncShareTimes times1;
ObjectIdInvalidationMap invalidations1 =
BuildInvalidationMap(BOOKMARKS, 10, "test");
EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
.WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
RecordSyncShare(×1)))
.RetiresOnSaturation();
scheduler()->ScheduleInvalidationNudge(zero(), invalidations1, FROM_HERE);
RunLoop();
Mock::VerifyAndClearExpectations(syncer());
SyncShareTimes times2;
ObjectIdInvalidationMap invalidations2 =
BuildInvalidationMap(AUTOFILL, 10, "test2");
EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
.WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
RecordSyncShare(×2)));
scheduler()->ScheduleInvalidationNudge(zero(), invalidations2, FROM_HERE);
RunLoop();
}
TEST_F(SyncSchedulerTest, Polling) {
SyncShareTimes times;
TimeDelta poll_interval(TimeDelta::FromMilliseconds(30));
EXPECT_CALL(*syncer(), PollSyncShare(_,_)).Times(AtLeast(kMinNumSamples))
.WillRepeatedly(
DoAll(Invoke(sessions::test_util::SimulatePollSuccess),
RecordSyncShareMultiple(×, kMinNumSamples)));
scheduler()->OnReceivedLongPollIntervalUpdate(poll_interval);
TimeTicks optimal_start = TimeTicks::Now() + poll_interval;
StartSyncScheduler(SyncScheduler::NORMAL_MODE);
RunLoop();
StopSyncScheduler();
AnalyzePollRun(times, kMinNumSamples, optimal_start, poll_interval);
}
TEST_F(SyncSchedulerTest, PollNotificationsDisabled) {
SyncShareTimes times;
TimeDelta poll_interval(TimeDelta::FromMilliseconds(30));
EXPECT_CALL(*syncer(), PollSyncShare(_,_)).Times(AtLeast(kMinNumSamples))
.WillRepeatedly(
DoAll(Invoke(sessions::test_util::SimulatePollSuccess),
RecordSyncShareMultiple(×, kMinNumSamples)));
scheduler()->OnReceivedShortPollIntervalUpdate(poll_interval);
scheduler()->SetNotificationsEnabled(false);
TimeTicks optimal_start = TimeTicks::Now() + poll_interval;
StartSyncScheduler(SyncScheduler::NORMAL_MODE);
RunLoop();
StopSyncScheduler();
AnalyzePollRun(times, kMinNumSamples, optimal_start, poll_interval);
}
TEST_F(SyncSchedulerTest, PollIntervalUpdate) {
SyncShareTimes times;
TimeDelta poll1(TimeDelta::FromMilliseconds(120));
TimeDelta poll2(TimeDelta::FromMilliseconds(30));
scheduler()->OnReceivedLongPollIntervalUpdate(poll1);
EXPECT_CALL(*syncer(), PollSyncShare(_,_)).Times(AtLeast(kMinNumSamples))
.WillOnce(DoAll(
WithArgs<0,1>(
sessions::test_util::SimulatePollIntervalUpdate(poll2)),
Return(true)))
.WillRepeatedly(
DoAll(Invoke(sessions::test_util::SimulatePollSuccess),
WithArg<1>(
RecordSyncShareMultiple(×, kMinNumSamples))));
TimeTicks optimal_start = TimeTicks::Now() + poll1 + poll2;
StartSyncScheduler(SyncScheduler::NORMAL_MODE);
RunLoop();
StopSyncScheduler();
AnalyzePollRun(times, kMinNumSamples, optimal_start, poll2);
}
TEST_F(SyncSchedulerTest, SessionsCommitDelay) {
SyncShareTimes times;
TimeDelta delay1(TimeDelta::FromMilliseconds(120));
TimeDelta delay2(TimeDelta::FromMilliseconds(30));
scheduler()->OnReceivedSessionsCommitDelay(delay1);
EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
.WillOnce(
DoAll(
WithArgs<0,1,2>(
sessions::test_util::SimulateSessionsCommitDelayUpdate(
delay2)),
Invoke(sessions::test_util::SimulateNormalSuccess),
QuitLoopNowAction()));
EXPECT_EQ(delay1, scheduler()->GetSessionsCommitDelay());
StartSyncScheduler(SyncScheduler::NORMAL_MODE);
EXPECT_EQ(delay1, scheduler()->GetSessionsCommitDelay());
const ModelTypeSet model_types(BOOKMARKS);
scheduler()->ScheduleLocalNudge(zero(), model_types, FROM_HERE);
RunLoop();
EXPECT_EQ(delay2, scheduler()->GetSessionsCommitDelay());
StopSyncScheduler();
}
TEST_F(SyncSchedulerTest, ThrottlingDoesThrottle) {
const ModelTypeSet types(BOOKMARKS);
TimeDelta poll(TimeDelta::FromMilliseconds(5));
TimeDelta throttle(TimeDelta::FromMinutes(10));
scheduler()->OnReceivedLongPollIntervalUpdate(poll);
EXPECT_CALL(*syncer(), ConfigureSyncShare(_,_,_))
.WillOnce(DoAll(
WithArg<2>(sessions::test_util::SimulateThrottled(throttle)),
Return(true)))
.WillRepeatedly(AddFailureAndQuitLoopNow());
StartSyncScheduler(SyncScheduler::NORMAL_MODE);
scheduler()->ScheduleLocalNudge(
TimeDelta::FromMicroseconds(1), types, FROM_HERE);
PumpLoop();
StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE);
CallbackCounter ready_counter;
CallbackCounter retry_counter;
ConfigurationParams params(
GetUpdatesCallerInfo::RECONFIGURATION,
types,
TypesToRoutingInfo(types),
base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
scheduler()->ScheduleConfiguration(params);
PumpLoop();
ASSERT_EQ(0, ready_counter.times_called());
ASSERT_EQ(1, retry_counter.times_called());
}
TEST_F(SyncSchedulerTest, ThrottlingExpiresFromPoll) {
SyncShareTimes times;
TimeDelta poll(TimeDelta::FromMilliseconds(15));
TimeDelta throttle1(TimeDelta::FromMilliseconds(150));
scheduler()->OnReceivedLongPollIntervalUpdate(poll);
::testing::InSequence seq;
EXPECT_CALL(*syncer(), PollSyncShare(_,_))
.WillOnce(DoAll(
WithArg<1>(sessions::test_util::SimulateThrottled(throttle1)),
Return(true)))
.RetiresOnSaturation();
EXPECT_CALL(*syncer(), PollSyncShare(_,_))
.WillRepeatedly(
DoAll(Invoke(sessions::test_util::SimulatePollSuccess),
RecordSyncShareMultiple(×, kMinNumSamples)));
TimeTicks optimal_start = TimeTicks::Now() + poll + throttle1;
StartSyncScheduler(SyncScheduler::NORMAL_MODE);
RunLoop();
StopSyncScheduler();
AnalyzePollRun(times, kMinNumSamples, optimal_start, poll);
}
TEST_F(SyncSchedulerTest, ThrottlingExpiresFromNudge) {
SyncShareTimes times;
TimeDelta poll(TimeDelta::FromDays(1));
TimeDelta throttle1(TimeDelta::FromMilliseconds(150));
scheduler()->OnReceivedLongPollIntervalUpdate(poll);
::testing::InSequence seq;
EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
.WillOnce(DoAll(
WithArg<2>(sessions::test_util::SimulateThrottled(throttle1)),
Return(true)))
.RetiresOnSaturation();
EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
.WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
QuitLoopNowAction()));
const ModelTypeSet types(BOOKMARKS);
StartSyncScheduler(SyncScheduler::NORMAL_MODE);
scheduler()->ScheduleLocalNudge(zero(), types, FROM_HERE);
PumpLoop();
PumpLoop();
EXPECT_TRUE(scheduler()->IsCurrentlyThrottled());
RunLoop();
EXPECT_FALSE(scheduler()->IsCurrentlyThrottled());
StopSyncScheduler();
}
TEST_F(SyncSchedulerTest, ThrottlingExpiresFromConfigure) {
SyncShareTimes times;
TimeDelta poll(TimeDelta::FromDays(1));
TimeDelta throttle1(TimeDelta::FromMilliseconds(150));
scheduler()->OnReceivedLongPollIntervalUpdate(poll);
::testing::InSequence seq;
EXPECT_CALL(*syncer(), ConfigureSyncShare(_,_,_))
.WillOnce(DoAll(
WithArg<2>(sessions::test_util::SimulateThrottled(throttle1)),
Return(true)))
.RetiresOnSaturation();
EXPECT_CALL(*syncer(), ConfigureSyncShare(_,_,_))
.WillOnce(DoAll(Invoke(sessions::test_util::SimulateConfigureSuccess),
QuitLoopNowAction()));
const ModelTypeSet types(BOOKMARKS);
StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE);
CallbackCounter ready_counter;
CallbackCounter retry_counter;
ConfigurationParams params(
GetUpdatesCallerInfo::RECONFIGURATION,
types,
TypesToRoutingInfo(types),
base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
scheduler()->ScheduleConfiguration(params);
PumpLoop();
EXPECT_EQ(0, ready_counter.times_called());
EXPECT_EQ(1, retry_counter.times_called());
EXPECT_TRUE(scheduler()->IsCurrentlyThrottled());
RunLoop();
EXPECT_FALSE(scheduler()->IsCurrentlyThrottled());
StopSyncScheduler();
}
TEST_F(SyncSchedulerTest, TypeThrottlingBlocksNudge) {
UseMockDelayProvider();
EXPECT_CALL(*delay(), GetDelay(_))
.WillRepeatedly(Return(zero()));
TimeDelta poll(TimeDelta::FromDays(1));
TimeDelta throttle1(TimeDelta::FromSeconds(60));
scheduler()->OnReceivedLongPollIntervalUpdate(poll);
const ModelTypeSet types(BOOKMARKS);
::testing::InSequence seq;
EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
.WillOnce(DoAll(
WithArg<2>(
sessions::test_util::SimulateTypesThrottled(types, throttle1)),
Return(true)))
.RetiresOnSaturation();
StartSyncScheduler(SyncScheduler::NORMAL_MODE);
scheduler()->ScheduleLocalNudge(zero(), types, FROM_HERE);
PumpLoop();
PumpLoop();
EXPECT_TRUE(GetThrottledTypes().HasAll(types));
scheduler()->ScheduleLocalNudge(zero(), types, FROM_HERE);
PumpLoop();
StopSyncScheduler();
}
TEST_F(SyncSchedulerTest, TypeThrottlingDoesBlockOtherSources) {
UseMockDelayProvider();
EXPECT_CALL(*delay(), GetDelay(_))
.WillRepeatedly(Return(zero()));
SyncShareTimes times;
TimeDelta poll(TimeDelta::FromDays(1));
TimeDelta throttle1(TimeDelta::FromSeconds(60));
scheduler()->OnReceivedLongPollIntervalUpdate(poll);
const ModelTypeSet throttled_types(BOOKMARKS);
const ModelTypeSet unthrottled_types(PREFERENCES);
::testing::InSequence seq;
EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
.WillOnce(DoAll(
WithArg<2>(
sessions::test_util::SimulateTypesThrottled(
throttled_types, throttle1)),
Return(true)))
.RetiresOnSaturation();
StartSyncScheduler(SyncScheduler::NORMAL_MODE);
scheduler()->ScheduleLocalNudge(zero(), throttled_types, FROM_HERE);
PumpLoop();
PumpLoop();
EXPECT_TRUE(GetThrottledTypes().HasAll(throttled_types));
ObjectIdInvalidationMap invalidations =
BuildInvalidationMap(BOOKMARKS, 10, "test");
scheduler()->ScheduleInvalidationNudge(zero(), invalidations, FROM_HERE);
PumpLoop();
scheduler()->ScheduleLocalRefreshRequest(zero(), throttled_types, FROM_HERE);
PumpLoop();
Mock::VerifyAndClearExpectations(syncer());
EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
.WillRepeatedly(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
RecordSyncShare(×)));
scheduler()->ScheduleLocalNudge(zero(), unthrottled_types, FROM_HERE);
RunLoop();
Mock::VerifyAndClearExpectations(syncer());
StopSyncScheduler();
}
TEST_F(SyncSchedulerTest, ConfigurationMode) {
TimeDelta poll(TimeDelta::FromMilliseconds(15));
SyncShareTimes times;
scheduler()->OnReceivedLongPollIntervalUpdate(poll);
StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE);
const ModelTypeSet nudge_types(AUTOFILL);
scheduler()->ScheduleLocalNudge(zero(), nudge_types, FROM_HERE);
scheduler()->ScheduleLocalNudge(zero(), nudge_types, FROM_HERE);
const ModelTypeSet config_types(BOOKMARKS);
EXPECT_CALL(*syncer(), ConfigureSyncShare(_,_,_))
.WillOnce(DoAll(Invoke(sessions::test_util::SimulateConfigureSuccess),
RecordSyncShare(×)))
.RetiresOnSaturation();
CallbackCounter ready_counter;
CallbackCounter retry_counter;
ConfigurationParams params(
GetUpdatesCallerInfo::RECONFIGURATION,
config_types,
TypesToRoutingInfo(config_types),
base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
scheduler()->ScheduleConfiguration(params);
RunLoop();
ASSERT_EQ(1, ready_counter.times_called());
ASSERT_EQ(0, retry_counter.times_called());
Mock::VerifyAndClearExpectations(syncer());
scheduler()->OnReceivedLongPollIntervalUpdate(TimeDelta::FromDays(1));
SyncShareTimes times2;
EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
.WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
RecordSyncShare(×2)));
context()->SetRoutingInfo(routing_info());
StartSyncScheduler(SyncScheduler::NORMAL_MODE);
RunLoop();
Mock::VerifyAndClearExpectations(syncer());
}
class BackoffTriggersSyncSchedulerTest : public SyncSchedulerTest {
virtual void SetUp() {
SyncSchedulerTest::SetUp();
UseMockDelayProvider();
EXPECT_CALL(*delay(), GetDelay(_))
.WillRepeatedly(Return(TimeDelta::FromMilliseconds(1)));
}
virtual void TearDown() {
StopSyncScheduler();
SyncSchedulerTest::TearDown();
}
};
TEST_F(BackoffTriggersSyncSchedulerTest, FailCommitOnce) {
EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
.WillOnce(DoAll(Invoke(sessions::test_util::SimulateCommitFailed),
QuitLoopNowAction()));
EXPECT_TRUE(RunAndGetBackoff());
}
TEST_F(BackoffTriggersSyncSchedulerTest, FailDownloadOnceThenSucceed) {
EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
.WillOnce(DoAll(
Invoke(sessions::test_util::SimulateDownloadUpdatesFailed),
Return(true)))
.WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
QuitLoopNowAction()));
EXPECT_FALSE(RunAndGetBackoff());
}
TEST_F(BackoffTriggersSyncSchedulerTest, FailCommitOnceThenSucceed) {
EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
.WillOnce(DoAll(
Invoke(sessions::test_util::SimulateCommitFailed),
Return(true)))
.WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
QuitLoopNowAction()));
EXPECT_FALSE(RunAndGetBackoff());
}
TEST_F(BackoffTriggersSyncSchedulerTest, FailDownloadTwice) {
EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
.WillOnce(DoAll(
Invoke(sessions::test_util::SimulateDownloadUpdatesFailed),
Return(true)))
.WillRepeatedly(DoAll(
Invoke(sessions::test_util::SimulateDownloadUpdatesFailed),
QuitLoopNowAction()));
EXPECT_TRUE(RunAndGetBackoff());
}
TEST_F(BackoffTriggersSyncSchedulerTest, FailGetEncryptionKey) {
EXPECT_CALL(*syncer(), ConfigureSyncShare(_,_,_))
.WillOnce(DoAll(
Invoke(sessions::test_util::SimulateGetEncryptionKeyFailed),
Return(true)))
.WillRepeatedly(DoAll(
Invoke(sessions::test_util::SimulateGetEncryptionKeyFailed),
QuitLoopNowAction()));
StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE);
ModelTypeSet types(BOOKMARKS);
CallbackCounter ready_counter;
CallbackCounter retry_counter;
ConfigurationParams params(
GetUpdatesCallerInfo::RECONFIGURATION,
types,
TypesToRoutingInfo(types),
base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
scheduler()->ScheduleConfiguration(params);
RunLoop();
EXPECT_TRUE(scheduler()->IsBackingOff());
}
TEST_F(SyncSchedulerTest, BackoffDropsJobs) {
SyncShareTimes times;
TimeDelta poll(TimeDelta::FromMilliseconds(5));
const ModelTypeSet types(BOOKMARKS);
scheduler()->OnReceivedLongPollIntervalUpdate(poll);
UseMockDelayProvider();
EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
.WillOnce(DoAll(Invoke(sessions::test_util::SimulateCommitFailed),
RecordSyncShareMultiple(×, 1U)));
EXPECT_CALL(*delay(), GetDelay(_)).
WillRepeatedly(Return(TimeDelta::FromDays(1)));
StartSyncScheduler(SyncScheduler::NORMAL_MODE);
scheduler()->ScheduleLocalNudge(zero(), types, FROM_HERE);
RunLoop();
Mock::VerifyAndClearExpectations(syncer());
PumpLoopFor(poll * 10);
scheduler()->ScheduleLocalNudge(
base::TimeDelta::FromMilliseconds(1),
types,
FROM_HERE);
Mock::VerifyAndClearExpectations(syncer());
Mock::VerifyAndClearExpectations(delay());
EXPECT_CALL(*delay(), GetDelay(_)).Times(0);
StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE);
CallbackCounter ready_counter;
CallbackCounter retry_counter;
ConfigurationParams params(
GetUpdatesCallerInfo::RECONFIGURATION,
types,
TypesToRoutingInfo(types),
base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
scheduler()->ScheduleConfiguration(params);
PumpLoop();
ASSERT_EQ(0, ready_counter.times_called());
ASSERT_EQ(1, retry_counter.times_called());
}
TEST_F(SyncSchedulerTest, BackoffElevation) {
SyncShareTimes times;
UseMockDelayProvider();
EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_)).Times(kMinNumSamples)
.WillRepeatedly(DoAll(Invoke(sessions::test_util::SimulateCommitFailed),
RecordSyncShareMultiple(×, kMinNumSamples)));
const TimeDelta first = TimeDelta::FromSeconds(kInitialBackoffRetrySeconds);
const TimeDelta second = TimeDelta::FromMilliseconds(2);
const TimeDelta third = TimeDelta::FromMilliseconds(3);
const TimeDelta fourth = TimeDelta::FromMilliseconds(4);
const TimeDelta fifth = TimeDelta::FromMilliseconds(5);
const TimeDelta sixth = TimeDelta::FromDays(1);
EXPECT_CALL(*delay(), GetDelay(first)).WillOnce(Return(second))
.RetiresOnSaturation();
EXPECT_CALL(*delay(), GetDelay(second)).WillOnce(Return(third))
.RetiresOnSaturation();
EXPECT_CALL(*delay(), GetDelay(third)).WillOnce(Return(fourth))
.RetiresOnSaturation();
EXPECT_CALL(*delay(), GetDelay(fourth)).WillOnce(Return(fifth))
.RetiresOnSaturation();
EXPECT_CALL(*delay(), GetDelay(fifth)).WillOnce(Return(sixth));
StartSyncScheduler(SyncScheduler::NORMAL_MODE);
scheduler()->ScheduleLocalNudge(zero(), ModelTypeSet(BOOKMARKS), FROM_HERE);
RunLoop();
ASSERT_EQ(kMinNumSamples, times.size());
EXPECT_GE(times[1] - times[0], second);
EXPECT_GE(times[2] - times[1], third);
EXPECT_GE(times[3] - times[2], fourth);
EXPECT_GE(times[4] - times[3], fifth);
}
TEST_F(SyncSchedulerTest, BackoffRelief) {
SyncShareTimes times;
const TimeDelta poll(TimeDelta::FromMilliseconds(10));
scheduler()->OnReceivedLongPollIntervalUpdate(poll);
UseMockDelayProvider();
const TimeDelta backoff = TimeDelta::FromMilliseconds(5);
EXPECT_CALL(*delay(), GetDelay(_)).WillOnce(Return(backoff));
TimeTicks optimal_start = TimeTicks::Now();
StartSyncScheduler(SyncScheduler::NORMAL_MODE);
EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
.WillOnce(DoAll(Invoke(sessions::test_util::SimulateCommitFailed),
RecordSyncShare(×)));
scheduler()->ScheduleLocalNudge(zero(), ModelTypeSet(BOOKMARKS), FROM_HERE);
RunLoop();
Mock::VerifyAndClearExpectations(syncer());
TimeTicks optimal_job_time = optimal_start;
ASSERT_EQ(1U, times.size());
EXPECT_GE(times[0], optimal_job_time);
EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
.WillOnce(DoAll(
Invoke(sessions::test_util::SimulateNormalSuccess),
RecordSyncShare(×)));
RunLoop();
Mock::VerifyAndClearExpectations(syncer());
optimal_job_time = optimal_job_time + backoff;
ASSERT_EQ(2U, times.size());
EXPECT_GE(times[1], optimal_job_time);
EXPECT_CALL(*syncer(), PollSyncShare(_,_))
.WillRepeatedly(DoAll(
Invoke(sessions::test_util::SimulatePollSuccess),
RecordSyncShareMultiple(×, kMinNumSamples)));
RunLoop();
Mock::VerifyAndClearExpectations(syncer());
ASSERT_EQ(kMinNumSamples, times.size());
for (size_t i = 2; i < times.size(); i++) {
optimal_job_time = optimal_job_time + poll;
SCOPED_TRACE(testing::Message() << "SyncShare # (" << i << ")");
EXPECT_GE(times[i], optimal_job_time);
}
StopSyncScheduler();
}
TEST_F(SyncSchedulerTest, TransientPollFailure) {
SyncShareTimes times;
const TimeDelta poll_interval(TimeDelta::FromMilliseconds(1));
scheduler()->OnReceivedLongPollIntervalUpdate(poll_interval);
UseMockDelayProvider();
EXPECT_CALL(*syncer(), PollSyncShare(_,_))
.WillOnce(DoAll(Invoke(sessions::test_util::SimulatePollFailed),
RecordSyncShare(×)))
.WillOnce(DoAll(Invoke(sessions::test_util::SimulatePollSuccess),
RecordSyncShare(×)));
StartSyncScheduler(SyncScheduler::NORMAL_MODE);
RunLoop();
EXPECT_FALSE(scheduler()->IsBackingOff());
RunLoop();
EXPECT_FALSE(scheduler()->IsBackingOff());
}
TEST_F(SyncSchedulerTest, StartWhenNotConnected) {
connection()->SetServerNotReachable();
connection()->UpdateConnectionStatus();
EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
.WillOnce(DoAll(Invoke(sessions::test_util::SimulateConnectionFailure),
Return(true)))
.WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
Return(true)));
StartSyncScheduler(SyncScheduler::NORMAL_MODE);
scheduler()->ScheduleLocalNudge(zero(), ModelTypeSet(BOOKMARKS), FROM_HERE);
base::MessageLoop::current()->RunUntilIdle();
scheduler()->OnConnectionStatusChange();
connection()->SetServerReachable();
connection()->UpdateConnectionStatus();
base::MessageLoop::current()->RunUntilIdle();
}
TEST_F(SyncSchedulerTest, ServerConnectionChangeDuringBackoff) {
UseMockDelayProvider();
EXPECT_CALL(*delay(), GetDelay(_))
.WillRepeatedly(Return(TimeDelta::FromMilliseconds(0)));
StartSyncScheduler(SyncScheduler::NORMAL_MODE);
connection()->SetServerNotReachable();
connection()->UpdateConnectionStatus();
EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
.WillOnce(DoAll(Invoke(sessions::test_util::SimulateConnectionFailure),
Return(true)))
.WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
Return(true)));
scheduler()->ScheduleLocalNudge(zero(), ModelTypeSet(BOOKMARKS), FROM_HERE);
PumpLoop();
PumpLoop();
ASSERT_TRUE(scheduler()->IsBackingOff());
scheduler()->OnConnectionStatusChange();
connection()->SetServerReachable();
connection()->UpdateConnectionStatus();
base::MessageLoop::current()->RunUntilIdle();
}
TEST_F(SyncSchedulerTest, ConnectionChangeCanaryPreemptedByNudge) {
UseMockDelayProvider();
EXPECT_CALL(*delay(), GetDelay(_))
.WillRepeatedly(Return(TimeDelta::FromMilliseconds(0)));
StartSyncScheduler(SyncScheduler::NORMAL_MODE);
connection()->SetServerNotReachable();
connection()->UpdateConnectionStatus();
EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
.WillOnce(DoAll(Invoke(sessions::test_util::SimulateConnectionFailure),
Return(true)))
.WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
Return(true)))
.WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
QuitLoopNowAction()));
scheduler()->ScheduleLocalNudge(zero(), ModelTypeSet(BOOKMARKS), FROM_HERE);
PumpLoop();
PumpLoop();
ASSERT_TRUE(scheduler()->IsBackingOff());
scheduler()->OnConnectionStatusChange();
PumpLoop();
connection()->SetServerReachable();
connection()->UpdateConnectionStatus();
scheduler()->ScheduleLocalNudge(zero(), ModelTypeSet(BOOKMARKS), FROM_HERE);
base::MessageLoop::current()->RunUntilIdle();
}
TEST_F(SyncSchedulerTest, DoubleCanaryInConfigure) {
EXPECT_CALL(*syncer(), ConfigureSyncShare(_,_,_))
.WillRepeatedly(DoAll(
Invoke(sessions::test_util::SimulateConfigureConnectionFailure),
Return(true)));
StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE);
connection()->SetServerNotReachable();
connection()->UpdateConnectionStatus();
ModelTypeSet model_types(BOOKMARKS);
CallbackCounter ready_counter;
CallbackCounter retry_counter;
ConfigurationParams params(
GetUpdatesCallerInfo::RECONFIGURATION,
model_types,
TypesToRoutingInfo(model_types),
base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
scheduler()->ScheduleConfiguration(params);
scheduler()->OnConnectionStatusChange();
scheduler()->OnConnectionStatusChange();
PumpLoop();
}
TEST_F(SyncSchedulerTest, PollFromCanaryAfterAuthError) {
SyncShareTimes times;
TimeDelta poll(TimeDelta::FromMilliseconds(15));
scheduler()->OnReceivedLongPollIntervalUpdate(poll);
::testing::InSequence seq;
EXPECT_CALL(*syncer(), PollSyncShare(_,_))
.WillRepeatedly(
DoAll(Invoke(sessions::test_util::SimulatePollSuccess),
RecordSyncShareMultiple(×, kMinNumSamples)));
connection()->SetServerStatus(HttpResponse::SYNC_AUTH_ERROR);
StartSyncScheduler(SyncScheduler::NORMAL_MODE);
RunLoop();
EXPECT_CALL(*syncer(), PollSyncShare(_,_))
.WillOnce(DoAll(Invoke(sessions::test_util::SimulatePollSuccess),
RecordSyncShare(×)));
scheduler()->OnCredentialsUpdated();
connection()->SetServerStatus(HttpResponse::SERVER_CONNECTION_OK);
RunLoop();
StopSyncScheduler();
}
TEST_F(SyncSchedulerTest, SuccessfulRetry) {
StartSyncScheduler(SyncScheduler::NORMAL_MODE);
SyncShareTimes times;
base::TimeDelta delay = base::TimeDelta::FromMilliseconds(1);
scheduler()->OnReceivedGuRetryDelay(delay);
EXPECT_EQ(delay, GetRetryTimerDelay());
EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
.WillOnce(
DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
RecordSyncShare(×)));
RunLoop();
StopSyncScheduler();
}
TEST_F(SyncSchedulerTest, FailedRetry) {
UseMockDelayProvider();
EXPECT_CALL(*delay(), GetDelay(_))
.WillRepeatedly(Return(TimeDelta::FromMilliseconds(1)));
StartSyncScheduler(SyncScheduler::NORMAL_MODE);
base::TimeDelta delay = base::TimeDelta::FromMilliseconds(1);
scheduler()->OnReceivedGuRetryDelay(delay);
EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
.WillOnce(
DoAll(Invoke(sessions::test_util::SimulateDownloadUpdatesFailed),
QuitLoopNowAction()));
RunLoop();
EXPECT_TRUE(scheduler()->IsBackingOff());
EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
.WillOnce(
DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
QuitLoopNowAction()));
RunLoop();
StopSyncScheduler();
}
ACTION_P2(VerifyRetryTimerDelay, scheduler_test, expected_delay) {
EXPECT_EQ(expected_delay, scheduler_test->GetRetryTimerDelay());
}
TEST_F(SyncSchedulerTest, ReceiveNewRetryDelay) {
StartSyncScheduler(SyncScheduler::NORMAL_MODE);
SyncShareTimes times;
base::TimeDelta delay1 = base::TimeDelta::FromMilliseconds(100);
base::TimeDelta delay2 = base::TimeDelta::FromMilliseconds(200);
scheduler()->ScheduleLocalRefreshRequest(zero(), ModelTypeSet(BOOKMARKS),
FROM_HERE);
scheduler()->OnReceivedGuRetryDelay(delay1);
EXPECT_EQ(delay1, GetRetryTimerDelay());
EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
.WillOnce(DoAll(
WithoutArgs(VerifyRetryTimerDelay(this, delay1)),
WithArg<2>(sessions::test_util::SimulateGuRetryDelayCommand(delay2)),
RecordSyncShare(×)));
RunLoop();
EXPECT_EQ(delay2, GetRetryTimerDelay());
EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
.WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
RecordSyncShare(×)));
RunLoop();
StopSyncScheduler();
}
}