| 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..82c7a9d497ac7648bb50ce902b808a8419fb0f4b
|
| --- /dev/null
|
| +++ b/components/proximity_auth/cryptauth/sync_scheduler_impl_unittest.cc
|
| @@ -0,0 +1,279 @@
|
| +// 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_percentage|.
|
| +bool IsTimeDeltaWithinJitter(const base::TimeDelta& base_time_delta,
|
| + const base::TimeDelta& jittered_time_delta,
|
| + double max_jitter_percentage) {
|
| + 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_percentage;
|
| +}
|
| +
|
| +// 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_percentage)
|
| + : SyncSchedulerImpl(delegate,
|
| + refresh_period,
|
| + recovery_period,
|
| + max_jitter_percentage,
|
| + 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_, false);
|
| + EXPECT_EQ(SyncScheduler::State::PERIODIC_REFRESH, scheduler_->GetState());
|
| +
|
| + scheduler_->ForceSync();
|
| + EXPECT_TRUE(sync_request_);
|
| + sync_request_->Complete(true);
|
| + EXPECT_EQ(SyncScheduler::State::PERIODIC_REFRESH, scheduler_->GetState());
|
| +}
|
| +
|
| +TEST_F(ProximityAuthSyncSchedulerImplTest, ForceSyncFailure) {
|
| + scheduler_->Start(zero_elapsed_time_, false);
|
| + EXPECT_EQ(SyncScheduler::State::PERIODIC_REFRESH, scheduler_->GetState());
|
| +
|
| + scheduler_->ForceSync();
|
| + EXPECT_TRUE(sync_request_);
|
| + sync_request_->Complete(false);
|
| + EXPECT_EQ(SyncScheduler::State::AGGRESSIVE_RECOVERY, scheduler_->GetState());
|
| +}
|
| +
|
| +TEST_F(ProximityAuthSyncSchedulerImplTest, PeriodicRefreshSuccess) {
|
| + EXPECT_EQ(SyncScheduler::State::NOT_STARTED, scheduler_->GetState());
|
| + scheduler_->Start(zero_elapsed_time_, false);
|
| + EXPECT_EQ(SyncScheduler::State::PERIODIC_REFRESH, scheduler_->GetState());
|
| +
|
| + EXPECT_EQ(refresh_period_, timer()->GetCurrentDelay());
|
| + timer()->Fire();
|
| + EXPECT_EQ(SyncScheduler::State::SYNCING_FOR_PERIODIC_REFRESH,
|
| + scheduler_->GetState());
|
| + ASSERT_TRUE(sync_request_.get());
|
| + EXPECT_FALSE(sync_request_->is_aggressive_recovery());
|
| +
|
| + sync_request_->Complete(true);
|
| + EXPECT_EQ(SyncScheduler::State::PERIODIC_REFRESH, scheduler_->GetState());
|
| +}
|
| +
|
| +TEST_F(ProximityAuthSyncSchedulerImplTest, PeriodicRefreshFailure) {
|
| + scheduler_->Start(zero_elapsed_time_, false);
|
| + EXPECT_EQ(SyncScheduler::State::PERIODIC_REFRESH, scheduler_->GetState());
|
| + timer()->Fire();
|
| + sync_request_->Complete(false);
|
| + EXPECT_EQ(SyncScheduler::State::AGGRESSIVE_RECOVERY, scheduler_->GetState());
|
| +}
|
| +
|
| +TEST_F(ProximityAuthSyncSchedulerImplTest, AggressiveRecoverySuccess) {
|
| + scheduler_->Start(zero_elapsed_time_, true);
|
| + EXPECT_EQ(SyncScheduler::State::AGGRESSIVE_RECOVERY, scheduler_->GetState());
|
| +
|
| + EXPECT_EQ(base_recovery_period_, timer()->GetCurrentDelay());
|
| + timer()->Fire();
|
| + EXPECT_EQ(SyncScheduler::State::SYNCING_FOR_AGGRESSIVE_RECOVERY,
|
| + scheduler_->GetState());
|
| + ASSERT_TRUE(sync_request_.get());
|
| + EXPECT_TRUE(sync_request_->is_aggressive_recovery());
|
| +
|
| + sync_request_->Complete(true);
|
| + EXPECT_EQ(SyncScheduler::State::PERIODIC_REFRESH, scheduler_->GetState());
|
| +}
|
| +
|
| +TEST_F(ProximityAuthSyncSchedulerImplTest, AggressiveRecoveryFailure) {
|
| + scheduler_->Start(zero_elapsed_time_, true);
|
| +
|
| + timer()->Fire();
|
| + EXPECT_EQ(SyncScheduler::State::SYNCING_FOR_AGGRESSIVE_RECOVERY,
|
| + scheduler_->GetState());
|
| + sync_request_->Complete(false);
|
| + EXPECT_EQ(SyncScheduler::State::AGGRESSIVE_RECOVERY, scheduler_->GetState());
|
| +}
|
| +
|
| +TEST_F(ProximityAuthSyncSchedulerImplTest, AggressiveRecoveryBackOff) {
|
| + scheduler_->Start(zero_elapsed_time_, true);
|
| + base::TimeDelta last_recovery_period = base::TimeDelta::FromSeconds(0);
|
| +
|
| + for (int i = 0; i < 20; ++i) {
|
| + timer()->Fire();
|
| + EXPECT_EQ(SyncScheduler::State::SYNCING_FOR_AGGRESSIVE_RECOVERY,
|
| + scheduler_->GetState());
|
| + sync_request_->Complete(false);
|
| + EXPECT_EQ(SyncScheduler::State::AGGRESSIVE_RECOVERY,
|
| + scheduler_->GetState());
|
| +
|
| + 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_, false);
|
| + EXPECT_EQ(SyncScheduler::State::PERIODIC_REFRESH, scheduler_->GetState());
|
| +
|
| + timer()->Fire();
|
| + sync_request_->Complete(false);
|
| + EXPECT_EQ(SyncScheduler::State::AGGRESSIVE_RECOVERY, scheduler_->GetState());
|
| +
|
| + timer()->Fire();
|
| + EXPECT_EQ(SyncScheduler::State::SYNCING_FOR_AGGRESSIVE_RECOVERY,
|
| + scheduler_->GetState());
|
| + sync_request_->Complete(true);
|
| + EXPECT_EQ(SyncScheduler::State::PERIODIC_REFRESH, scheduler_->GetState());
|
| +}
|
| +
|
| +TEST_F(ProximityAuthSyncSchedulerImplTest, SyncImmediatelyForPeriodicRefresh) {
|
| + scheduler_->Start(base::TimeDelta::FromDays(kElapsedTimeDays), false);
|
| + EXPECT_EQ(SyncScheduler::State::PERIODIC_REFRESH, scheduler_->GetState());
|
| +
|
| + EXPECT_TRUE(scheduler_->GetTimeToNextSync().is_zero());
|
| + EXPECT_TRUE(timer()->GetCurrentDelay().is_zero());
|
| + timer()->Fire();
|
| + EXPECT_TRUE(sync_request_);
|
| +}
|
| +
|
| +TEST_F(ProximityAuthSyncSchedulerImplTest,
|
| + SyncImmediatelyForAggressiveRecovery) {
|
| + scheduler_->Start(base::TimeDelta::FromDays(kElapsedTimeDays), true);
|
| + EXPECT_EQ(SyncScheduler::State::AGGRESSIVE_RECOVERY, scheduler_->GetState());
|
| +
|
| + EXPECT_TRUE(scheduler_->GetTimeToNextSync().is_zero());
|
| + EXPECT_TRUE(timer()->GetCurrentDelay().is_zero());
|
| + timer()->Fire();
|
| + EXPECT_TRUE(sync_request_);
|
| +}
|
| +
|
| +TEST_F(ProximityAuthSyncSchedulerImplTest, InitialSyncShorterByElapsedTime) {
|
| + base::TimeDelta elapsed_time = base::TimeDelta::FromDays(2);
|
| + scheduler_->Start(elapsed_time, false);
|
| + EXPECT_EQ(SyncScheduler::State::PERIODIC_REFRESH, scheduler_->GetState());
|
| +
|
| + 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_, false);
|
| +
|
| + 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_->Complete(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_percentage = 1;
|
| + scheduler_.reset(new TestSyncSchedulerImpl(this, zero_delta, zero_delta,
|
| + max_jitter_percentage));
|
| + scheduler_->Start(zero_elapsed_time_, false);
|
| +
|
| + 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_percentage));
|
| + timer()->Fire();
|
| + sync_request_->Complete(true);
|
| + }
|
| +}
|
| +
|
| +} // namespace proximity_auth
|
|
|