1 // Copyright (c) 2011 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 "net/base/backoff_entry.h" 6 #include "testing/gtest/include/gtest/gtest.h" 7 8 namespace { 9 10 using base::TimeDelta; 11 using base::TimeTicks; 12 using net::BackoffEntry; 13 14 BackoffEntry::Policy base_policy = { 0, 1000, 2.0, 0.0, 20000, 2000 }; 15 16 class TestBackoffEntry : public BackoffEntry { 17 public: 18 explicit TestBackoffEntry(const Policy* const policy) 19 : BackoffEntry(policy), 20 now_(TimeTicks()) { 21 // Work around initialization in constructor not picking up 22 // fake time. 23 SetCustomReleaseTime(TimeTicks()); 24 } 25 26 virtual ~TestBackoffEntry() {} 27 28 virtual TimeTicks GetTimeNow() const { 29 return now_; 30 } 31 32 void set_now(const TimeTicks& now) { 33 now_ = now; 34 } 35 36 private: 37 TimeTicks now_; 38 39 DISALLOW_COPY_AND_ASSIGN(TestBackoffEntry); 40 }; 41 42 TEST(BackoffEntryTest, BaseTest) { 43 TestBackoffEntry entry(&base_policy); 44 EXPECT_FALSE(entry.ShouldRejectRequest()); 45 46 entry.InformOfRequest(false); 47 EXPECT_TRUE(entry.ShouldRejectRequest()); 48 } 49 50 TEST(BackoffEntryTest, CanDiscardNeverExpires) { 51 BackoffEntry::Policy never_expires_policy = base_policy; 52 never_expires_policy.entry_lifetime_ms = -1; 53 TestBackoffEntry never_expires(&never_expires_policy); 54 EXPECT_FALSE(never_expires.CanDiscard()); 55 never_expires.set_now(TimeTicks() + TimeDelta::FromDays(100)); 56 EXPECT_FALSE(never_expires.CanDiscard()); 57 } 58 59 TEST(BackoffEntryTest, CanDiscard) { 60 TestBackoffEntry entry(&base_policy); 61 // Because lifetime is non-zero, we shouldn't be able to discard yet. 62 EXPECT_FALSE(entry.CanDiscard()); 63 64 // Test the "being used" case. 65 entry.InformOfRequest(false); 66 EXPECT_FALSE(entry.CanDiscard()); 67 68 // Test the case where there are errors but we can time out. 69 entry.set_now( 70 entry.GetReleaseTime() + TimeDelta::FromMilliseconds(1)); 71 EXPECT_FALSE(entry.CanDiscard()); 72 entry.set_now(entry.GetReleaseTime() + TimeDelta::FromMilliseconds( 73 base_policy.maximum_backoff_ms + 1)); 74 EXPECT_TRUE(entry.CanDiscard()); 75 76 // Test the final case (no errors, dependent only on specified lifetime). 77 entry.set_now(entry.GetReleaseTime() + TimeDelta::FromMilliseconds( 78 base_policy.entry_lifetime_ms - 1)); 79 entry.InformOfRequest(true); 80 EXPECT_FALSE(entry.CanDiscard()); 81 entry.set_now(entry.GetReleaseTime() + TimeDelta::FromMilliseconds( 82 base_policy.entry_lifetime_ms)); 83 EXPECT_TRUE(entry.CanDiscard()); 84 } 85 86 TEST(BackoffEntryTest, CanDiscardNotStored) { 87 BackoffEntry::Policy no_store_policy = base_policy; 88 no_store_policy.entry_lifetime_ms = 0; 89 TestBackoffEntry not_stored(&no_store_policy); 90 EXPECT_TRUE(not_stored.CanDiscard()); 91 } 92 93 TEST(BackoffEntryTest, ShouldIgnoreFirstTwo) { 94 BackoffEntry::Policy lenient_policy = base_policy; 95 lenient_policy.num_errors_to_ignore = 2; 96 97 BackoffEntry entry(&lenient_policy); 98 entry.InformOfRequest(false); 99 EXPECT_FALSE(entry.ShouldRejectRequest()); 100 entry.InformOfRequest(false); 101 EXPECT_FALSE(entry.ShouldRejectRequest()); 102 entry.InformOfRequest(false); 103 EXPECT_TRUE(entry.ShouldRejectRequest()); 104 } 105 106 TEST(BackoffEntryTest, ReleaseTimeCalculation) { 107 TestBackoffEntry entry(&base_policy); 108 109 // With zero errors, should return "now". 110 TimeTicks result = entry.GetReleaseTime(); 111 EXPECT_EQ(entry.GetTimeNow(), result); 112 113 // 1 error. 114 entry.InformOfRequest(false); 115 result = entry.GetReleaseTime(); 116 EXPECT_EQ(entry.GetTimeNow() + TimeDelta::FromMilliseconds(1000), result); 117 118 // 2 errors. 119 entry.InformOfRequest(false); 120 result = entry.GetReleaseTime(); 121 EXPECT_EQ(entry.GetTimeNow() + TimeDelta::FromMilliseconds(2000), result); 122 123 // 3 errors. 124 entry.InformOfRequest(false); 125 result = entry.GetReleaseTime(); 126 EXPECT_EQ(entry.GetTimeNow() + TimeDelta::FromMilliseconds(4000), result); 127 128 // 6 errors (to check it doesn't pass maximum). 129 entry.InformOfRequest(false); 130 entry.InformOfRequest(false); 131 entry.InformOfRequest(false); 132 result = entry.GetReleaseTime(); 133 EXPECT_EQ(entry.GetTimeNow() + TimeDelta::FromMilliseconds(20000), result); 134 } 135 136 TEST(BackoffEntryTest, ReleaseTimeCalculationWithJitter) { 137 for (int i = 0; i < 10; ++i) { 138 BackoffEntry::Policy jittery_policy = base_policy; 139 jittery_policy.jitter_factor = 0.2; 140 141 TestBackoffEntry entry(&jittery_policy); 142 143 entry.InformOfRequest(false); 144 entry.InformOfRequest(false); 145 entry.InformOfRequest(false); 146 TimeTicks result = entry.GetReleaseTime(); 147 EXPECT_LE(entry.GetTimeNow() + TimeDelta::FromMilliseconds(3200), result); 148 EXPECT_GE(entry.GetTimeNow() + TimeDelta::FromMilliseconds(4000), result); 149 } 150 } 151 152 TEST(BackoffEntryTest, FailureThenSuccess) { 153 TestBackoffEntry entry(&base_policy); 154 155 // Failure count 1, establishes horizon. 156 entry.InformOfRequest(false); 157 TimeTicks release_time = entry.GetReleaseTime(); 158 EXPECT_EQ(TimeTicks() + TimeDelta::FromMilliseconds(1000), release_time); 159 160 // Success, failure count 0, should not advance past 161 // the horizon that was already set. 162 entry.set_now(release_time - TimeDelta::FromMilliseconds(200)); 163 entry.InformOfRequest(true); 164 EXPECT_EQ(release_time, entry.GetReleaseTime()); 165 166 // Failure, failure count 1. 167 entry.InformOfRequest(false); 168 EXPECT_EQ(release_time + TimeDelta::FromMilliseconds(800), 169 entry.GetReleaseTime()); 170 } 171 172 TEST(BackoffEntryTest, RetainCustomHorizon) { 173 TestBackoffEntry custom(&base_policy); 174 TimeTicks custom_horizon = TimeTicks() + TimeDelta::FromDays(3); 175 custom.SetCustomReleaseTime(custom_horizon); 176 custom.InformOfRequest(false); 177 custom.InformOfRequest(true); 178 custom.set_now(TimeTicks() + TimeDelta::FromDays(2)); 179 custom.InformOfRequest(false); 180 custom.InformOfRequest(true); 181 EXPECT_EQ(custom_horizon, custom.GetReleaseTime()); 182 183 // Now check that once we are at or past the custom horizon, 184 // we get normal behavior. 185 custom.set_now(TimeTicks() + TimeDelta::FromDays(3)); 186 custom.InformOfRequest(false); 187 EXPECT_EQ( 188 TimeTicks() + TimeDelta::FromDays(3) + TimeDelta::FromMilliseconds(1000), 189 custom.GetReleaseTime()); 190 } 191 192 TEST(BackoffEntryTest, RetainCustomHorizonWhenInitialErrorsIgnored) { 193 // Regression test for a bug discovered during code review. 194 BackoffEntry::Policy lenient_policy = base_policy; 195 lenient_policy.num_errors_to_ignore = 1; 196 TestBackoffEntry custom(&lenient_policy); 197 TimeTicks custom_horizon = TimeTicks() + TimeDelta::FromDays(3); 198 custom.SetCustomReleaseTime(custom_horizon); 199 custom.InformOfRequest(false); // This must not reset the horizon. 200 EXPECT_EQ(custom_horizon, custom.GetReleaseTime()); 201 } 202 203 } // namespace 204