PlzNavigate: Improvements to RFHM commit logic.
[chromium-blink-merge.git] / net / base / backoff_entry_unittest.cc
blob89ec2c4d2f160c4551fc6fa7a8672528017925a1
1 // Copyright (c) 2012 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.
5 #include "net/base/backoff_entry.h"
6 #include "testing/gtest/include/gtest/gtest.h"
8 namespace {
10 using base::TimeDelta;
11 using base::TimeTicks;
12 using net::BackoffEntry;
14 BackoffEntry::Policy base_policy = { 0, 1000, 2.0, 0.0, 20000, 2000, false };
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());
26 ~TestBackoffEntry() override {}
28 TimeTicks ImplGetTimeNow() const override { return now_; }
30 void set_now(const TimeTicks& now) {
31 now_ = now;
34 private:
35 TimeTicks now_;
37 DISALLOW_COPY_AND_ASSIGN(TestBackoffEntry);
40 TEST(BackoffEntryTest, BaseTest) {
41 TestBackoffEntry entry(&base_policy);
42 EXPECT_FALSE(entry.ShouldRejectRequest());
43 EXPECT_EQ(TimeDelta(), entry.GetTimeUntilRelease());
45 entry.InformOfRequest(false);
46 EXPECT_TRUE(entry.ShouldRejectRequest());
47 EXPECT_EQ(TimeDelta::FromMilliseconds(1000), entry.GetTimeUntilRelease());
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());
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());
64 // Test the "being used" case.
65 entry.InformOfRequest(false);
66 EXPECT_FALSE(entry.CanDiscard());
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());
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());
86 TEST(BackoffEntryTest, CanDiscardAlwaysDelay) {
87 BackoffEntry::Policy always_delay_policy = base_policy;
88 always_delay_policy.always_use_initial_delay = true;
89 always_delay_policy.entry_lifetime_ms = 0;
91 TestBackoffEntry entry(&always_delay_policy);
93 // Because lifetime is non-zero, we shouldn't be able to discard yet.
94 entry.set_now(entry.GetReleaseTime() + TimeDelta::FromMilliseconds(2000));
95 EXPECT_TRUE(entry.CanDiscard());
97 // Even with no failures, we wait until the delay before we allow discard.
98 entry.InformOfRequest(true);
99 EXPECT_FALSE(entry.CanDiscard());
101 // Wait until the delay expires, and we can discard the entry again.
102 entry.set_now(entry.GetReleaseTime() + TimeDelta::FromMilliseconds(1000));
103 EXPECT_TRUE(entry.CanDiscard());
106 TEST(BackoffEntryTest, CanDiscardNotStored) {
107 BackoffEntry::Policy no_store_policy = base_policy;
108 no_store_policy.entry_lifetime_ms = 0;
109 TestBackoffEntry not_stored(&no_store_policy);
110 EXPECT_TRUE(not_stored.CanDiscard());
113 TEST(BackoffEntryTest, ShouldIgnoreFirstTwo) {
114 BackoffEntry::Policy lenient_policy = base_policy;
115 lenient_policy.num_errors_to_ignore = 2;
117 BackoffEntry entry(&lenient_policy);
119 entry.InformOfRequest(false);
120 EXPECT_FALSE(entry.ShouldRejectRequest());
122 entry.InformOfRequest(false);
123 EXPECT_FALSE(entry.ShouldRejectRequest());
125 entry.InformOfRequest(false);
126 EXPECT_TRUE(entry.ShouldRejectRequest());
129 TEST(BackoffEntryTest, ReleaseTimeCalculation) {
130 TestBackoffEntry entry(&base_policy);
132 // With zero errors, should return "now".
133 TimeTicks result = entry.GetReleaseTime();
134 EXPECT_EQ(entry.ImplGetTimeNow(), result);
136 // 1 error.
137 entry.InformOfRequest(false);
138 result = entry.GetReleaseTime();
139 EXPECT_EQ(entry.ImplGetTimeNow() + TimeDelta::FromMilliseconds(1000), result);
140 EXPECT_EQ(TimeDelta::FromMilliseconds(1000), entry.GetTimeUntilRelease());
142 // 2 errors.
143 entry.InformOfRequest(false);
144 result = entry.GetReleaseTime();
145 EXPECT_EQ(entry.ImplGetTimeNow() + TimeDelta::FromMilliseconds(2000), result);
146 EXPECT_EQ(TimeDelta::FromMilliseconds(2000), entry.GetTimeUntilRelease());
148 // 3 errors.
149 entry.InformOfRequest(false);
150 result = entry.GetReleaseTime();
151 EXPECT_EQ(entry.ImplGetTimeNow() + TimeDelta::FromMilliseconds(4000), result);
152 EXPECT_EQ(TimeDelta::FromMilliseconds(4000), entry.GetTimeUntilRelease());
154 // 6 errors (to check it doesn't pass maximum).
155 entry.InformOfRequest(false);
156 entry.InformOfRequest(false);
157 entry.InformOfRequest(false);
158 result = entry.GetReleaseTime();
159 EXPECT_EQ(
160 entry.ImplGetTimeNow() + TimeDelta::FromMilliseconds(20000), result);
163 TEST(BackoffEntryTest, ReleaseTimeCalculationAlwaysDelay) {
164 BackoffEntry::Policy always_delay_policy = base_policy;
165 always_delay_policy.always_use_initial_delay = true;
166 always_delay_policy.num_errors_to_ignore = 2;
168 TestBackoffEntry entry(&always_delay_policy);
170 // With previous requests, should return "now".
171 TimeTicks result = entry.GetReleaseTime();
172 EXPECT_EQ(TimeDelta(), entry.GetTimeUntilRelease());
174 // 1 error.
175 entry.InformOfRequest(false);
176 EXPECT_EQ(TimeDelta::FromMilliseconds(1000), entry.GetTimeUntilRelease());
178 // 2 errors.
179 entry.InformOfRequest(false);
180 EXPECT_EQ(TimeDelta::FromMilliseconds(1000), entry.GetTimeUntilRelease());
182 // 3 errors, exponential backoff starts.
183 entry.InformOfRequest(false);
184 EXPECT_EQ(TimeDelta::FromMilliseconds(2000), entry.GetTimeUntilRelease());
186 // 4 errors.
187 entry.InformOfRequest(false);
188 EXPECT_EQ(TimeDelta::FromMilliseconds(4000), entry.GetTimeUntilRelease());
190 // 8 errors (to check it doesn't pass maximum).
191 entry.InformOfRequest(false);
192 entry.InformOfRequest(false);
193 entry.InformOfRequest(false);
194 entry.InformOfRequest(false);
195 result = entry.GetReleaseTime();
196 EXPECT_EQ(TimeDelta::FromMilliseconds(20000), entry.GetTimeUntilRelease());
199 TEST(BackoffEntryTest, ReleaseTimeCalculationWithJitter) {
200 for (int i = 0; i < 10; ++i) {
201 BackoffEntry::Policy jittery_policy = base_policy;
202 jittery_policy.jitter_factor = 0.2;
204 TestBackoffEntry entry(&jittery_policy);
206 entry.InformOfRequest(false);
207 entry.InformOfRequest(false);
208 entry.InformOfRequest(false);
209 TimeTicks result = entry.GetReleaseTime();
210 EXPECT_LE(
211 entry.ImplGetTimeNow() + TimeDelta::FromMilliseconds(3200), result);
212 EXPECT_GE(
213 entry.ImplGetTimeNow() + TimeDelta::FromMilliseconds(4000), result);
217 TEST(BackoffEntryTest, FailureThenSuccess) {
218 TestBackoffEntry entry(&base_policy);
220 // Failure count 1, establishes horizon.
221 entry.InformOfRequest(false);
222 TimeTicks release_time = entry.GetReleaseTime();
223 EXPECT_EQ(TimeTicks() + TimeDelta::FromMilliseconds(1000), release_time);
225 // Success, failure count 0, should not advance past
226 // the horizon that was already set.
227 entry.set_now(release_time - TimeDelta::FromMilliseconds(200));
228 entry.InformOfRequest(true);
229 EXPECT_EQ(release_time, entry.GetReleaseTime());
231 // Failure, failure count 1.
232 entry.InformOfRequest(false);
233 EXPECT_EQ(release_time + TimeDelta::FromMilliseconds(800),
234 entry.GetReleaseTime());
237 TEST(BackoffEntryTest, FailureThenSuccessAlwaysDelay) {
238 BackoffEntry::Policy always_delay_policy = base_policy;
239 always_delay_policy.always_use_initial_delay = true;
240 always_delay_policy.num_errors_to_ignore = 1;
242 TestBackoffEntry entry(&always_delay_policy);
244 // Failure count 1.
245 entry.InformOfRequest(false);
246 EXPECT_EQ(TimeDelta::FromMilliseconds(1000), entry.GetTimeUntilRelease());
248 // Failure count 2.
249 entry.InformOfRequest(false);
250 EXPECT_EQ(TimeDelta::FromMilliseconds(2000), entry.GetTimeUntilRelease());
251 entry.set_now(entry.GetReleaseTime() + TimeDelta::FromMilliseconds(2000));
253 // Success. We should go back to the original delay.
254 entry.InformOfRequest(true);
255 EXPECT_EQ(TimeDelta::FromMilliseconds(1000), entry.GetTimeUntilRelease());
257 // Failure count reaches 2 again. We should increase the delay once more.
258 entry.InformOfRequest(false);
259 EXPECT_EQ(TimeDelta::FromMilliseconds(2000), entry.GetTimeUntilRelease());
260 entry.set_now(entry.GetReleaseTime() + TimeDelta::FromMilliseconds(2000));
263 TEST(BackoffEntryTest, RetainCustomHorizon) {
264 TestBackoffEntry custom(&base_policy);
265 TimeTicks custom_horizon = TimeTicks() + TimeDelta::FromDays(3);
266 custom.SetCustomReleaseTime(custom_horizon);
267 custom.InformOfRequest(false);
268 custom.InformOfRequest(true);
269 custom.set_now(TimeTicks() + TimeDelta::FromDays(2));
270 custom.InformOfRequest(false);
271 custom.InformOfRequest(true);
272 EXPECT_EQ(custom_horizon, custom.GetReleaseTime());
274 // Now check that once we are at or past the custom horizon,
275 // we get normal behavior.
276 custom.set_now(TimeTicks() + TimeDelta::FromDays(3));
277 custom.InformOfRequest(false);
278 EXPECT_EQ(
279 TimeTicks() + TimeDelta::FromDays(3) + TimeDelta::FromMilliseconds(1000),
280 custom.GetReleaseTime());
283 TEST(BackoffEntryTest, RetainCustomHorizonWhenInitialErrorsIgnored) {
284 // Regression test for a bug discovered during code review.
285 BackoffEntry::Policy lenient_policy = base_policy;
286 lenient_policy.num_errors_to_ignore = 1;
287 TestBackoffEntry custom(&lenient_policy);
288 TimeTicks custom_horizon = TimeTicks() + TimeDelta::FromDays(3);
289 custom.SetCustomReleaseTime(custom_horizon);
290 custom.InformOfRequest(false); // This must not reset the horizon.
291 EXPECT_EQ(custom_horizon, custom.GetReleaseTime());
294 TEST(BackoffEntryTest, OverflowProtection) {
295 BackoffEntry::Policy large_multiply_policy = base_policy;
296 large_multiply_policy.multiply_factor = 256;
297 TestBackoffEntry custom(&large_multiply_policy);
299 // Trigger enough failures such that more than 11 bits of exponent are used
300 // to represent the exponential backoff intermediate values. Given a multiply
301 // factor of 256 (2^8), 129 iterations is enough: 2^(8*(129-1)) = 2^1024.
302 for (int i = 0; i < 129; ++i) {
303 custom.set_now(custom.ImplGetTimeNow() + custom.GetTimeUntilRelease());
304 custom.InformOfRequest(false);
305 ASSERT_TRUE(custom.ShouldRejectRequest());
308 // Max delay should still be respected.
309 EXPECT_EQ(20000, custom.GetTimeUntilRelease().InMilliseconds());
312 } // namespace