Home | History | Annotate | Download | only in domain_reliability
      1 // Copyright 2014 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 "components/domain_reliability/scheduler.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/time/time.h"
      9 #include "components/domain_reliability/config.h"
     10 #include "components/domain_reliability/test_util.h"
     11 #include "components/domain_reliability/util.h"
     12 #include "testing/gtest/include/gtest/gtest.h"
     13 
     14 namespace domain_reliability {
     15 namespace {
     16 
     17 using base::TimeDelta;
     18 using base::TimeTicks;
     19 
     20 class DomainReliabilitySchedulerTest : public testing::Test {
     21  public:
     22   DomainReliabilitySchedulerTest()
     23       : num_collectors_(0),
     24         params_(MakeTestSchedulerParams()),
     25         callback_called_(false) {}
     26 
     27   void CreateScheduler(int num_collectors) {
     28     DCHECK_LT(0, num_collectors);
     29     DCHECK(!scheduler_);
     30 
     31     num_collectors_ = num_collectors;
     32     scheduler_.reset(new DomainReliabilityScheduler(
     33         &time_,
     34         num_collectors_,
     35         params_,
     36         base::Bind(&DomainReliabilitySchedulerTest::ScheduleUploadCallback,
     37                    base::Unretained(this))));
     38   }
     39 
     40   ::testing::AssertionResult CheckNoPendingUpload() {
     41     DCHECK(scheduler_);
     42 
     43     if (!callback_called_)
     44       return ::testing::AssertionSuccess();
     45 
     46     return ::testing::AssertionFailure()
     47            << "expected no upload, got upload between "
     48            << callback_min_.InSeconds() << " and "
     49            << callback_max_.InSeconds() << " seconds from now";
     50   }
     51 
     52   ::testing::AssertionResult CheckPendingUpload(TimeDelta expected_min,
     53                                                 TimeDelta expected_max) {
     54     DCHECK(scheduler_);
     55     DCHECK_LE(expected_min.InMicroseconds(), expected_max.InMicroseconds());
     56 
     57     if (callback_called_ && expected_min == callback_min_
     58                          && expected_max == callback_max_) {
     59       callback_called_ = false;
     60       return ::testing::AssertionSuccess();
     61     }
     62 
     63     if (callback_called_) {
     64       return ::testing::AssertionFailure()
     65              << "expected upload between " << expected_min.InSeconds()
     66              << " and " << expected_max.InSeconds() << " seconds from now, "
     67              << "got upload between " << callback_min_.InSeconds()
     68              << " and " << callback_max_.InSeconds() << " seconds from now";
     69     } else {
     70       return ::testing::AssertionFailure()
     71              << "expected upload between " << expected_min.InSeconds()
     72              << " and " << expected_max.InSeconds() << " seconds from now, "
     73              << "got no upload";
     74     }
     75   }
     76 
     77   ::testing::AssertionResult CheckStartingUpload(size_t expected_collector) {
     78     DCHECK(scheduler_);
     79     DCHECK_GT(num_collectors_, expected_collector);
     80 
     81     size_t collector = scheduler_->OnUploadStart();
     82     if (collector == expected_collector)
     83       return ::testing::AssertionSuccess();
     84 
     85     return ::testing::AssertionFailure()
     86            << "expected upload to collector " << expected_collector
     87            << ", got upload to collector " << collector;
     88   }
     89 
     90   TimeDelta min_delay() const { return params_.minimum_upload_delay; }
     91   TimeDelta max_delay() const { return params_.maximum_upload_delay; }
     92   TimeDelta retry_interval() const { return params_.upload_retry_interval; }
     93   TimeDelta zero_delta() const { return base::TimeDelta::FromMicroseconds(0); }
     94 
     95  protected:
     96   void ScheduleUploadCallback(TimeDelta min, TimeDelta max) {
     97     callback_called_ = true;
     98     callback_min_ = min;
     99     callback_max_ = max;
    100   }
    101 
    102   MockTime time_;
    103   size_t num_collectors_;
    104   DomainReliabilityScheduler::Params params_;
    105   scoped_ptr<DomainReliabilityScheduler> scheduler_;
    106 
    107   bool callback_called_;
    108   TimeDelta callback_min_;
    109   TimeDelta callback_max_;
    110 };
    111 
    112 TEST_F(DomainReliabilitySchedulerTest, Create) {
    113   CreateScheduler(1);
    114 }
    115 
    116 TEST_F(DomainReliabilitySchedulerTest, UploadNotPendingWithoutBeacon) {
    117   CreateScheduler(1);
    118 
    119   ASSERT_TRUE(CheckNoPendingUpload());
    120 }
    121 
    122 TEST_F(DomainReliabilitySchedulerTest, SuccessfulUploads) {
    123   CreateScheduler(1);
    124 
    125   scheduler_->OnBeaconAdded();
    126   ASSERT_TRUE(CheckPendingUpload(min_delay(), max_delay()));
    127   time_.Advance(min_delay());
    128   ASSERT_TRUE(CheckStartingUpload(0));
    129   scheduler_->OnUploadComplete(true);
    130 
    131   scheduler_->OnBeaconAdded();
    132   ASSERT_TRUE(CheckPendingUpload(min_delay(), max_delay()));
    133   time_.Advance(min_delay());
    134   ASSERT_TRUE(CheckStartingUpload(0));
    135   scheduler_->OnUploadComplete(true);
    136 }
    137 
    138 TEST_F(DomainReliabilitySchedulerTest, Failover) {
    139   CreateScheduler(2);
    140 
    141   scheduler_->OnBeaconAdded();
    142   ASSERT_TRUE(CheckPendingUpload(min_delay(), max_delay()));
    143   time_.Advance(min_delay());
    144   ASSERT_TRUE(CheckStartingUpload(0));
    145   scheduler_->OnUploadComplete(false);
    146 
    147   scheduler_->OnBeaconAdded();
    148   ASSERT_TRUE(CheckPendingUpload(zero_delta(), max_delay() - min_delay()));
    149   // Don't need to advance; should retry immediately.
    150   ASSERT_TRUE(CheckStartingUpload(1));
    151   scheduler_->OnUploadComplete(true);
    152 }
    153 
    154 TEST_F(DomainReliabilitySchedulerTest, FailedAllCollectors) {
    155   CreateScheduler(2);
    156 
    157   // T = 0
    158   scheduler_->OnBeaconAdded();
    159   ASSERT_TRUE(CheckPendingUpload(min_delay(), max_delay()));
    160   time_.Advance(min_delay());
    161 
    162   // T = min_delay
    163   ASSERT_TRUE(CheckStartingUpload(0));
    164   scheduler_->OnUploadComplete(false);
    165 
    166   ASSERT_TRUE(CheckPendingUpload(zero_delta(), max_delay() - min_delay()));
    167   // Don't need to advance; should retry immediately.
    168   ASSERT_TRUE(CheckStartingUpload(1));
    169   scheduler_->OnUploadComplete(false);
    170 
    171   ASSERT_TRUE(CheckPendingUpload(retry_interval(), max_delay() - min_delay()));
    172   time_.Advance(retry_interval());
    173 
    174   // T = min_delay + retry_interval
    175   ASSERT_TRUE(CheckStartingUpload(0));
    176   scheduler_->OnUploadComplete(false);
    177 
    178   ASSERT_TRUE(CheckPendingUpload(
    179       zero_delta(),
    180       max_delay() - min_delay() - retry_interval()));
    181   ASSERT_TRUE(CheckStartingUpload(1));
    182   scheduler_->OnUploadComplete(false);
    183 }
    184 
    185 // Make sure that the scheduler uses the first available collector at upload
    186 // time, even if it wasn't available at scheduling time.
    187 TEST_F(DomainReliabilitySchedulerTest, DetermineCollectorAtUpload) {
    188   CreateScheduler(2);
    189 
    190   // T = 0
    191   scheduler_->OnBeaconAdded();
    192   ASSERT_TRUE(CheckPendingUpload(min_delay(), max_delay()));
    193   time_.Advance(min_delay());
    194 
    195   // T = min_delay
    196   ASSERT_TRUE(CheckStartingUpload(0));
    197   scheduler_->OnUploadComplete(false);
    198 
    199   ASSERT_TRUE(CheckPendingUpload(zero_delta(), max_delay() - min_delay()));
    200   time_.Advance(retry_interval());
    201 
    202   // T = min_delay + retry_interval; collector 0 should be active again.
    203   ASSERT_TRUE(CheckStartingUpload(0));
    204   scheduler_->OnUploadComplete(true);
    205 }
    206 
    207 TEST_F(DomainReliabilitySchedulerTest, BeaconWhilePending) {
    208   CreateScheduler(1);
    209 
    210   scheduler_->OnBeaconAdded();
    211   ASSERT_TRUE(CheckPendingUpload(min_delay(), max_delay()));
    212 
    213   // Second beacon should not call callback again.
    214   scheduler_->OnBeaconAdded();
    215   ASSERT_TRUE(CheckNoPendingUpload());
    216   time_.Advance(min_delay());
    217 
    218   // No pending upload after beacon.
    219   ASSERT_TRUE(CheckStartingUpload(0));
    220   scheduler_->OnUploadComplete(true);
    221   ASSERT_TRUE(CheckNoPendingUpload());
    222 }
    223 
    224 TEST_F(DomainReliabilitySchedulerTest, BeaconWhileUploading) {
    225   CreateScheduler(1);
    226 
    227   scheduler_->OnBeaconAdded();
    228   ASSERT_TRUE(CheckPendingUpload(min_delay(), max_delay()));
    229   time_.Advance(min_delay());
    230 
    231   // If a beacon arrives during the upload, a new upload should be pending.
    232   ASSERT_TRUE(CheckStartingUpload(0));
    233   scheduler_->OnBeaconAdded();
    234   scheduler_->OnUploadComplete(true);
    235   ASSERT_TRUE(CheckPendingUpload(min_delay(), max_delay()));
    236 
    237   time_.Advance(min_delay());
    238   ASSERT_TRUE(CheckStartingUpload(0));
    239   scheduler_->OnUploadComplete(true);
    240   ASSERT_TRUE(CheckNoPendingUpload());
    241 }
    242 
    243 }  // namespace
    244 }  // namespace domain_reliability
    245