Index: components/proximity_auth/cryptauth/sync_scheduler_impl_unittest.cc |
diff --git a/components/proximity_auth/cryptauth/sync_scheduler_impl_unittest.cc b/components/proximity_auth/cryptauth/sync_scheduler_impl_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..55bd7ea62d5ae3f9ae52f4db70362bd32a1eb904 |
--- /dev/null |
+++ b/components/proximity_auth/cryptauth/sync_scheduler_impl_unittest.cc |
@@ -0,0 +1,311 @@ |
+// Copyright 2015 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "components/proximity_auth/cryptauth/sync_scheduler_impl.h" |
+ |
+#include "base/timer/mock_timer.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+ |
+namespace proximity_auth { |
+ |
+namespace { |
+ |
+// Constants configuring the the scheduler. |
+const int kElapsedTimeDays = 40; |
+const int kRefreshPeriodDays = 30; |
+const int kRecoveryPeriodSeconds = 10; |
+const double kMaxJitterPercentage = 0.1; |
+const char kTestSchedulerName[] = "TestSyncSchedulerImpl"; |
+ |
+// Returns true if |jittered_time_delta| is within the range of a jittered |
+// |base_time_delta| with a maximum of |max_jitter_ratio|. |
+bool IsTimeDeltaWithinJitter(const base::TimeDelta& base_time_delta, |
+ const base::TimeDelta& jittered_time_delta, |
+ double max_jitter_ratio) { |
+ if (base_time_delta.is_zero()) |
+ return jittered_time_delta.is_zero(); |
+ |
+ base::TimeDelta difference = |
+ (jittered_time_delta - base_time_delta).magnitude(); |
+ double percentage_of_base = |
+ difference.InMillisecondsF() / base_time_delta.InMillisecondsF(); |
+ return percentage_of_base < max_jitter_ratio; |
+} |
+ |
+// Test harness for the SyncSchedulerImpl to create MockTimers. |
+class TestSyncSchedulerImpl : public SyncSchedulerImpl { |
+ public: |
+ TestSyncSchedulerImpl(Delegate* delegate, |
+ base::TimeDelta refresh_period, |
+ base::TimeDelta recovery_period, |
+ double max_jitter_ratio) |
+ : SyncSchedulerImpl(delegate, |
+ refresh_period, |
+ recovery_period, |
+ max_jitter_ratio, |
+ kTestSchedulerName) {} |
+ |
+ ~TestSyncSchedulerImpl() override {} |
+ |
+ base::MockTimer* timer() { return mock_timer_; } |
+ |
+ private: |
+ scoped_ptr<base::Timer> CreateTimer() override { |
+ bool retain_user_task = false; |
+ bool is_repeating = false; |
+ mock_timer_ = new base::MockTimer(retain_user_task, is_repeating); |
+ return make_scoped_ptr(mock_timer_); |
+ } |
+ |
+ // A timer instance for testing. Owned by the parent scheduler. |
+ base::MockTimer* mock_timer_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(TestSyncSchedulerImpl); |
+}; |
+ |
+} // namespace |
+ |
+class ProximityAuthSyncSchedulerImplTest : public testing::Test, |
+ public SyncSchedulerImpl::Delegate { |
+ protected: |
+ ProximityAuthSyncSchedulerImplTest() |
+ : refresh_period_(base::TimeDelta::FromDays(kRefreshPeriodDays)), |
+ base_recovery_period_( |
+ base::TimeDelta::FromSeconds(kRecoveryPeriodSeconds)), |
+ zero_elapsed_time_(base::TimeDelta::FromSeconds(0)), |
+ scheduler_(new TestSyncSchedulerImpl(this, |
+ refresh_period_, |
+ base_recovery_period_, |
+ 0)) {} |
+ |
+ ~ProximityAuthSyncSchedulerImplTest() override {} |
+ |
+ void OnSyncRequested( |
+ scoped_ptr<SyncScheduler::SyncRequest> sync_request) override { |
+ sync_request_ = sync_request.Pass(); |
+ } |
+ |
+ base::MockTimer* timer() { return scheduler_->timer(); } |
+ |
+ // The time deltas used to configure |scheduler_|. |
+ base::TimeDelta refresh_period_; |
+ base::TimeDelta base_recovery_period_; |
+ base::TimeDelta zero_elapsed_time_; |
+ |
+ // The scheduler instance under test. |
+ scoped_ptr<TestSyncSchedulerImpl> scheduler_; |
+ |
+ scoped_ptr<SyncScheduler::SyncRequest> sync_request_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(ProximityAuthSyncSchedulerImplTest); |
+}; |
+ |
+TEST_F(ProximityAuthSyncSchedulerImplTest, ForceSyncSuccess) { |
+ scheduler_->Start(zero_elapsed_time_, |
+ SyncScheduler::Strategy::PERIODIC_REFRESH); |
Ilya Sherman
2015/05/19 22:46:55
Optional nit: I'd add using stmts for SyncSchedule
Tim Song
2015/05/20 00:13:22
Done.
|
+ EXPECT_EQ(SyncScheduler::Strategy::PERIODIC_REFRESH, |
+ scheduler_->GetStrategy()); |
+ EXPECT_EQ(SyncScheduler::SyncState::WAITING_FOR_REFRESH, |
+ scheduler_->GetSyncState()); |
+ |
+ scheduler_->ForceSync(); |
+ EXPECT_EQ(SyncScheduler::SyncState::SYNC_IN_PROGRESS, |
+ scheduler_->GetSyncState()); |
+ EXPECT_TRUE(sync_request_); |
+ sync_request_->OnDidComplete(true); |
+ EXPECT_EQ(SyncScheduler::Strategy::PERIODIC_REFRESH, |
+ scheduler_->GetStrategy()); |
+ EXPECT_EQ(SyncScheduler::SyncState::WAITING_FOR_REFRESH, |
+ scheduler_->GetSyncState()); |
+} |
+ |
+TEST_F(ProximityAuthSyncSchedulerImplTest, ForceSyncFailure) { |
+ scheduler_->Start(zero_elapsed_time_, |
+ SyncScheduler::Strategy::PERIODIC_REFRESH); |
+ EXPECT_EQ(SyncScheduler::Strategy::PERIODIC_REFRESH, |
+ scheduler_->GetStrategy()); |
+ |
+ scheduler_->ForceSync(); |
+ EXPECT_TRUE(sync_request_); |
+ sync_request_->OnDidComplete(false); |
+ EXPECT_EQ(SyncScheduler::Strategy::AGGRESSIVE_RECOVERY, |
+ scheduler_->GetStrategy()); |
+} |
+ |
+TEST_F(ProximityAuthSyncSchedulerImplTest, PeriodicRefreshSuccess) { |
+ EXPECT_EQ(SyncScheduler::SyncState::NOT_STARTED, scheduler_->GetSyncState()); |
+ scheduler_->Start(zero_elapsed_time_, |
+ SyncScheduler::Strategy::PERIODIC_REFRESH); |
+ EXPECT_EQ(SyncScheduler::Strategy::PERIODIC_REFRESH, |
+ scheduler_->GetStrategy()); |
+ |
+ EXPECT_EQ(refresh_period_, timer()->GetCurrentDelay()); |
+ timer()->Fire(); |
+ EXPECT_EQ(SyncScheduler::SyncState::SYNC_IN_PROGRESS, |
+ scheduler_->GetSyncState()); |
+ ASSERT_TRUE(sync_request_.get()); |
+ |
+ sync_request_->OnDidComplete(true); |
+ EXPECT_EQ(SyncScheduler::SyncState::WAITING_FOR_REFRESH, |
+ scheduler_->GetSyncState()); |
+ EXPECT_EQ(SyncScheduler::Strategy::PERIODIC_REFRESH, |
+ scheduler_->GetStrategy()); |
+} |
+ |
+TEST_F(ProximityAuthSyncSchedulerImplTest, PeriodicRefreshFailure) { |
+ scheduler_->Start(zero_elapsed_time_, |
+ SyncScheduler::Strategy::PERIODIC_REFRESH); |
+ EXPECT_EQ(SyncScheduler::Strategy::PERIODIC_REFRESH, |
+ scheduler_->GetStrategy()); |
+ timer()->Fire(); |
+ sync_request_->OnDidComplete(false); |
+ EXPECT_EQ(SyncScheduler::Strategy::AGGRESSIVE_RECOVERY, |
+ scheduler_->GetStrategy()); |
+} |
+ |
+TEST_F(ProximityAuthSyncSchedulerImplTest, AggressiveRecoverySuccess) { |
+ scheduler_->Start(zero_elapsed_time_, |
+ SyncScheduler::Strategy::AGGRESSIVE_RECOVERY); |
+ EXPECT_EQ(SyncScheduler::Strategy::AGGRESSIVE_RECOVERY, |
+ scheduler_->GetStrategy()); |
+ |
+ EXPECT_EQ(base_recovery_period_, timer()->GetCurrentDelay()); |
+ timer()->Fire(); |
+ EXPECT_EQ(SyncScheduler::SyncState::SYNC_IN_PROGRESS, |
+ scheduler_->GetSyncState()); |
+ ASSERT_TRUE(sync_request_.get()); |
+ |
+ sync_request_->OnDidComplete(true); |
+ EXPECT_EQ(SyncScheduler::SyncState::WAITING_FOR_REFRESH, |
+ scheduler_->GetSyncState()); |
+ EXPECT_EQ(SyncScheduler::Strategy::PERIODIC_REFRESH, |
+ scheduler_->GetStrategy()); |
+} |
+ |
+TEST_F(ProximityAuthSyncSchedulerImplTest, AggressiveRecoveryFailure) { |
+ scheduler_->Start(zero_elapsed_time_, |
+ SyncScheduler::Strategy::AGGRESSIVE_RECOVERY); |
+ |
+ timer()->Fire(); |
+ sync_request_->OnDidComplete(false); |
+ EXPECT_EQ(SyncScheduler::Strategy::AGGRESSIVE_RECOVERY, |
+ scheduler_->GetStrategy()); |
+} |
+ |
+TEST_F(ProximityAuthSyncSchedulerImplTest, AggressiveRecoveryBackOff) { |
+ scheduler_->Start(zero_elapsed_time_, |
+ SyncScheduler::Strategy::AGGRESSIVE_RECOVERY); |
+ base::TimeDelta last_recovery_period = base::TimeDelta::FromSeconds(0); |
+ |
+ for (int i = 0; i < 20; ++i) { |
+ timer()->Fire(); |
+ EXPECT_EQ(SyncScheduler::SyncState::SYNC_IN_PROGRESS, |
+ scheduler_->GetSyncState()); |
+ sync_request_->OnDidComplete(false); |
+ EXPECT_EQ(SyncScheduler::Strategy::AGGRESSIVE_RECOVERY, |
+ scheduler_->GetStrategy()); |
+ EXPECT_EQ(SyncScheduler::SyncState::WAITING_FOR_REFRESH, |
+ scheduler_->GetSyncState()); |
+ |
+ base::TimeDelta recovery_period = scheduler_->GetTimeToNextSync(); |
+ EXPECT_LE(last_recovery_period, recovery_period); |
+ last_recovery_period = recovery_period; |
+ } |
+ |
+ // Backoffs should rapidly converge to the normal refresh period. |
+ EXPECT_EQ(refresh_period_, last_recovery_period); |
+} |
+ |
+TEST_F(ProximityAuthSyncSchedulerImplTest, RefreshFailureRecoverySuccess) { |
+ scheduler_->Start(zero_elapsed_time_, |
+ SyncScheduler::Strategy::PERIODIC_REFRESH); |
+ EXPECT_EQ(SyncScheduler::Strategy::PERIODIC_REFRESH, |
+ scheduler_->GetStrategy()); |
+ |
+ timer()->Fire(); |
+ sync_request_->OnDidComplete(false); |
+ EXPECT_EQ(SyncScheduler::Strategy::AGGRESSIVE_RECOVERY, |
+ scheduler_->GetStrategy()); |
+ |
+ timer()->Fire(); |
+ sync_request_->OnDidComplete(true); |
+ EXPECT_EQ(SyncScheduler::Strategy::PERIODIC_REFRESH, |
+ scheduler_->GetStrategy()); |
+} |
+ |
+TEST_F(ProximityAuthSyncSchedulerImplTest, SyncImmediatelyForPeriodicRefresh) { |
+ scheduler_->Start(base::TimeDelta::FromDays(kElapsedTimeDays), |
+ SyncScheduler::Strategy::PERIODIC_REFRESH); |
+ EXPECT_TRUE(scheduler_->GetTimeToNextSync().is_zero()); |
+ EXPECT_TRUE(timer()->GetCurrentDelay().is_zero()); |
+ timer()->Fire(); |
+ EXPECT_TRUE(sync_request_); |
+ |
+ EXPECT_EQ(SyncScheduler::Strategy::PERIODIC_REFRESH, |
+ scheduler_->GetStrategy()); |
+} |
+ |
+TEST_F(ProximityAuthSyncSchedulerImplTest, |
+ SyncImmediatelyForAggressiveRecovery) { |
+ scheduler_->Start(base::TimeDelta::FromDays(kElapsedTimeDays), |
+ SyncScheduler::Strategy::AGGRESSIVE_RECOVERY); |
+ EXPECT_TRUE(scheduler_->GetTimeToNextSync().is_zero()); |
+ EXPECT_TRUE(timer()->GetCurrentDelay().is_zero()); |
+ timer()->Fire(); |
+ EXPECT_TRUE(sync_request_); |
+ |
+ EXPECT_EQ(SyncScheduler::Strategy::AGGRESSIVE_RECOVERY, |
+ scheduler_->GetStrategy()); |
+} |
+ |
+TEST_F(ProximityAuthSyncSchedulerImplTest, InitialSyncShorterByElapsedTime) { |
+ base::TimeDelta elapsed_time = base::TimeDelta::FromDays(2); |
+ scheduler_->Start(elapsed_time, SyncScheduler::Strategy::PERIODIC_REFRESH); |
+ EXPECT_EQ(refresh_period_ - elapsed_time, scheduler_->GetTimeToNextSync()); |
+ timer()->Fire(); |
+ EXPECT_TRUE(sync_request_); |
+} |
+ |
+TEST_F(ProximityAuthSyncSchedulerImplTest, PeriodicRefreshJitter) { |
+ scheduler_.reset(new TestSyncSchedulerImpl( |
+ this, refresh_period_, base_recovery_period_, kMaxJitterPercentage)); |
+ |
+ scheduler_->Start(zero_elapsed_time_, |
+ SyncScheduler::Strategy::PERIODIC_REFRESH); |
+ |
+ base::TimeDelta cumulative_jitter = base::TimeDelta::FromSeconds(0); |
+ for (int i = 0; i < 10; ++i) { |
+ base::TimeDelta next_sync_delta = scheduler_->GetTimeToNextSync(); |
+ cumulative_jitter += (next_sync_delta - refresh_period_).magnitude(); |
+ EXPECT_TRUE(IsTimeDeltaWithinJitter(refresh_period_, next_sync_delta, |
+ kMaxJitterPercentage)); |
+ timer()->Fire(); |
+ sync_request_->OnDidComplete(true); |
+ } |
+ |
+ // The probablility that all periods are randomly equal to |refresh_period_| |
+ // is so low that we would expect the heat death of the universe before this |
+ // test flakes. |
+ EXPECT_FALSE(cumulative_jitter.is_zero()); |
+} |
+ |
+TEST_F(ProximityAuthSyncSchedulerImplTest, JitteredTimeDeltaIsNonNegative) { |
+ base::TimeDelta zero_delta = base::TimeDelta::FromSeconds(0); |
+ double max_jitter_ratio = 1; |
+ scheduler_.reset(new TestSyncSchedulerImpl(this, zero_delta, zero_delta, |
+ max_jitter_ratio)); |
+ scheduler_->Start(zero_elapsed_time_, |
+ SyncScheduler::Strategy::PERIODIC_REFRESH); |
+ |
+ for (int i = 0; i < 10; ++i) { |
+ base::TimeDelta next_sync_delta = scheduler_->GetTimeToNextSync(); |
+ EXPECT_GE(zero_delta, next_sync_delta); |
+ EXPECT_TRUE( |
+ IsTimeDeltaWithinJitter(zero_delta, next_sync_delta, max_jitter_ratio)); |
+ timer()->Fire(); |
+ sync_request_->OnDidComplete(true); |
+ } |
+} |
+ |
+} // namespace proximity_auth |