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