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"
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
{
18 explicit TestBackoffEntry(const Policy
* const policy
)
19 : BackoffEntry(policy
),
21 // Work around initialization in constructor not picking up
23 SetCustomReleaseTime(TimeTicks());
26 virtual ~TestBackoffEntry() {}
28 virtual TimeTicks
ImplGetTimeNow() const OVERRIDE
{
32 void set_now(const TimeTicks
& now
) {
39 DISALLOW_COPY_AND_ASSIGN(TestBackoffEntry
);
42 TEST(BackoffEntryTest
, BaseTest
) {
43 TestBackoffEntry
entry(&base_policy
);
44 EXPECT_FALSE(entry
.ShouldRejectRequest());
45 EXPECT_EQ(TimeDelta(), entry
.GetTimeUntilRelease());
47 entry
.InformOfRequest(false);
48 EXPECT_TRUE(entry
.ShouldRejectRequest());
49 EXPECT_EQ(TimeDelta::FromMilliseconds(1000), entry
.GetTimeUntilRelease());
52 TEST(BackoffEntryTest
, CanDiscardNeverExpires
) {
53 BackoffEntry::Policy never_expires_policy
= base_policy
;
54 never_expires_policy
.entry_lifetime_ms
= -1;
55 TestBackoffEntry
never_expires(&never_expires_policy
);
56 EXPECT_FALSE(never_expires
.CanDiscard());
57 never_expires
.set_now(TimeTicks() + TimeDelta::FromDays(100));
58 EXPECT_FALSE(never_expires
.CanDiscard());
61 TEST(BackoffEntryTest
, CanDiscard
) {
62 TestBackoffEntry
entry(&base_policy
);
63 // Because lifetime is non-zero, we shouldn't be able to discard yet.
64 EXPECT_FALSE(entry
.CanDiscard());
66 // Test the "being used" case.
67 entry
.InformOfRequest(false);
68 EXPECT_FALSE(entry
.CanDiscard());
70 // Test the case where there are errors but we can time out.
72 entry
.GetReleaseTime() + TimeDelta::FromMilliseconds(1));
73 EXPECT_FALSE(entry
.CanDiscard());
74 entry
.set_now(entry
.GetReleaseTime() + TimeDelta::FromMilliseconds(
75 base_policy
.maximum_backoff_ms
+ 1));
76 EXPECT_TRUE(entry
.CanDiscard());
78 // Test the final case (no errors, dependent only on specified lifetime).
79 entry
.set_now(entry
.GetReleaseTime() + TimeDelta::FromMilliseconds(
80 base_policy
.entry_lifetime_ms
- 1));
81 entry
.InformOfRequest(true);
82 EXPECT_FALSE(entry
.CanDiscard());
83 entry
.set_now(entry
.GetReleaseTime() + TimeDelta::FromMilliseconds(
84 base_policy
.entry_lifetime_ms
));
85 EXPECT_TRUE(entry
.CanDiscard());
88 TEST(BackoffEntryTest
, CanDiscardAlwaysDelay
) {
89 BackoffEntry::Policy always_delay_policy
= base_policy
;
90 always_delay_policy
.always_use_initial_delay
= true;
91 always_delay_policy
.entry_lifetime_ms
= 0;
93 TestBackoffEntry
entry(&always_delay_policy
);
95 // Because lifetime is non-zero, we shouldn't be able to discard yet.
96 entry
.set_now(entry
.GetReleaseTime() + TimeDelta::FromMilliseconds(2000));
97 EXPECT_TRUE(entry
.CanDiscard());
99 // Even with no failures, we wait until the delay before we allow discard.
100 entry
.InformOfRequest(true);
101 EXPECT_FALSE(entry
.CanDiscard());
103 // Wait until the delay expires, and we can discard the entry again.
104 entry
.set_now(entry
.GetReleaseTime() + TimeDelta::FromMilliseconds(1000));
105 EXPECT_TRUE(entry
.CanDiscard());
108 TEST(BackoffEntryTest
, CanDiscardNotStored
) {
109 BackoffEntry::Policy no_store_policy
= base_policy
;
110 no_store_policy
.entry_lifetime_ms
= 0;
111 TestBackoffEntry
not_stored(&no_store_policy
);
112 EXPECT_TRUE(not_stored
.CanDiscard());
115 TEST(BackoffEntryTest
, ShouldIgnoreFirstTwo
) {
116 BackoffEntry::Policy lenient_policy
= base_policy
;
117 lenient_policy
.num_errors_to_ignore
= 2;
119 BackoffEntry
entry(&lenient_policy
);
121 entry
.InformOfRequest(false);
122 EXPECT_FALSE(entry
.ShouldRejectRequest());
124 entry
.InformOfRequest(false);
125 EXPECT_FALSE(entry
.ShouldRejectRequest());
127 entry
.InformOfRequest(false);
128 EXPECT_TRUE(entry
.ShouldRejectRequest());
131 TEST(BackoffEntryTest
, ReleaseTimeCalculation
) {
132 TestBackoffEntry
entry(&base_policy
);
134 // With zero errors, should return "now".
135 TimeTicks result
= entry
.GetReleaseTime();
136 EXPECT_EQ(entry
.ImplGetTimeNow(), result
);
139 entry
.InformOfRequest(false);
140 result
= entry
.GetReleaseTime();
141 EXPECT_EQ(entry
.ImplGetTimeNow() + TimeDelta::FromMilliseconds(1000), result
);
142 EXPECT_EQ(TimeDelta::FromMilliseconds(1000), entry
.GetTimeUntilRelease());
145 entry
.InformOfRequest(false);
146 result
= entry
.GetReleaseTime();
147 EXPECT_EQ(entry
.ImplGetTimeNow() + TimeDelta::FromMilliseconds(2000), result
);
148 EXPECT_EQ(TimeDelta::FromMilliseconds(2000), entry
.GetTimeUntilRelease());
151 entry
.InformOfRequest(false);
152 result
= entry
.GetReleaseTime();
153 EXPECT_EQ(entry
.ImplGetTimeNow() + TimeDelta::FromMilliseconds(4000), result
);
154 EXPECT_EQ(TimeDelta::FromMilliseconds(4000), entry
.GetTimeUntilRelease());
156 // 6 errors (to check it doesn't pass maximum).
157 entry
.InformOfRequest(false);
158 entry
.InformOfRequest(false);
159 entry
.InformOfRequest(false);
160 result
= entry
.GetReleaseTime();
162 entry
.ImplGetTimeNow() + TimeDelta::FromMilliseconds(20000), result
);
165 TEST(BackoffEntryTest
, ReleaseTimeCalculationAlwaysDelay
) {
166 BackoffEntry::Policy always_delay_policy
= base_policy
;
167 always_delay_policy
.always_use_initial_delay
= true;
168 always_delay_policy
.num_errors_to_ignore
= 2;
170 TestBackoffEntry
entry(&always_delay_policy
);
172 // With previous requests, should return "now".
173 TimeTicks result
= entry
.GetReleaseTime();
174 EXPECT_EQ(TimeDelta(), entry
.GetTimeUntilRelease());
177 entry
.InformOfRequest(false);
178 EXPECT_EQ(TimeDelta::FromMilliseconds(1000), entry
.GetTimeUntilRelease());
181 entry
.InformOfRequest(false);
182 EXPECT_EQ(TimeDelta::FromMilliseconds(1000), entry
.GetTimeUntilRelease());
184 // 3 errors, exponential backoff starts.
185 entry
.InformOfRequest(false);
186 EXPECT_EQ(TimeDelta::FromMilliseconds(2000), entry
.GetTimeUntilRelease());
189 entry
.InformOfRequest(false);
190 EXPECT_EQ(TimeDelta::FromMilliseconds(4000), entry
.GetTimeUntilRelease());
192 // 8 errors (to check it doesn't pass maximum).
193 entry
.InformOfRequest(false);
194 entry
.InformOfRequest(false);
195 entry
.InformOfRequest(false);
196 entry
.InformOfRequest(false);
197 result
= entry
.GetReleaseTime();
198 EXPECT_EQ(TimeDelta::FromMilliseconds(20000), entry
.GetTimeUntilRelease());
201 TEST(BackoffEntryTest
, ReleaseTimeCalculationWithJitter
) {
202 for (int i
= 0; i
< 10; ++i
) {
203 BackoffEntry::Policy jittery_policy
= base_policy
;
204 jittery_policy
.jitter_factor
= 0.2;
206 TestBackoffEntry
entry(&jittery_policy
);
208 entry
.InformOfRequest(false);
209 entry
.InformOfRequest(false);
210 entry
.InformOfRequest(false);
211 TimeTicks result
= entry
.GetReleaseTime();
213 entry
.ImplGetTimeNow() + TimeDelta::FromMilliseconds(3200), result
);
215 entry
.ImplGetTimeNow() + TimeDelta::FromMilliseconds(4000), result
);
219 TEST(BackoffEntryTest
, FailureThenSuccess
) {
220 TestBackoffEntry
entry(&base_policy
);
222 // Failure count 1, establishes horizon.
223 entry
.InformOfRequest(false);
224 TimeTicks release_time
= entry
.GetReleaseTime();
225 EXPECT_EQ(TimeTicks() + TimeDelta::FromMilliseconds(1000), release_time
);
227 // Success, failure count 0, should not advance past
228 // the horizon that was already set.
229 entry
.set_now(release_time
- TimeDelta::FromMilliseconds(200));
230 entry
.InformOfRequest(true);
231 EXPECT_EQ(release_time
, entry
.GetReleaseTime());
233 // Failure, failure count 1.
234 entry
.InformOfRequest(false);
235 EXPECT_EQ(release_time
+ TimeDelta::FromMilliseconds(800),
236 entry
.GetReleaseTime());
239 TEST(BackoffEntryTest
, FailureThenSuccessAlwaysDelay
) {
240 BackoffEntry::Policy always_delay_policy
= base_policy
;
241 always_delay_policy
.always_use_initial_delay
= true;
242 always_delay_policy
.num_errors_to_ignore
= 1;
244 TestBackoffEntry
entry(&always_delay_policy
);
247 entry
.InformOfRequest(false);
248 EXPECT_EQ(TimeDelta::FromMilliseconds(1000), entry
.GetTimeUntilRelease());
251 entry
.InformOfRequest(false);
252 EXPECT_EQ(TimeDelta::FromMilliseconds(2000), entry
.GetTimeUntilRelease());
253 entry
.set_now(entry
.GetReleaseTime() + TimeDelta::FromMilliseconds(2000));
255 // Success. We should go back to the original delay.
256 entry
.InformOfRequest(true);
257 EXPECT_EQ(TimeDelta::FromMilliseconds(1000), entry
.GetTimeUntilRelease());
259 // Failure count reaches 2 again. We should increase the delay once more.
260 entry
.InformOfRequest(false);
261 EXPECT_EQ(TimeDelta::FromMilliseconds(2000), entry
.GetTimeUntilRelease());
262 entry
.set_now(entry
.GetReleaseTime() + TimeDelta::FromMilliseconds(2000));
265 TEST(BackoffEntryTest
, RetainCustomHorizon
) {
266 TestBackoffEntry
custom(&base_policy
);
267 TimeTicks custom_horizon
= TimeTicks() + TimeDelta::FromDays(3);
268 custom
.SetCustomReleaseTime(custom_horizon
);
269 custom
.InformOfRequest(false);
270 custom
.InformOfRequest(true);
271 custom
.set_now(TimeTicks() + TimeDelta::FromDays(2));
272 custom
.InformOfRequest(false);
273 custom
.InformOfRequest(true);
274 EXPECT_EQ(custom_horizon
, custom
.GetReleaseTime());
276 // Now check that once we are at or past the custom horizon,
277 // we get normal behavior.
278 custom
.set_now(TimeTicks() + TimeDelta::FromDays(3));
279 custom
.InformOfRequest(false);
281 TimeTicks() + TimeDelta::FromDays(3) + TimeDelta::FromMilliseconds(1000),
282 custom
.GetReleaseTime());
285 TEST(BackoffEntryTest
, RetainCustomHorizonWhenInitialErrorsIgnored
) {
286 // Regression test for a bug discovered during code review.
287 BackoffEntry::Policy lenient_policy
= base_policy
;
288 lenient_policy
.num_errors_to_ignore
= 1;
289 TestBackoffEntry
custom(&lenient_policy
);
290 TimeTicks custom_horizon
= TimeTicks() + TimeDelta::FromDays(3);
291 custom
.SetCustomReleaseTime(custom_horizon
);
292 custom
.InformOfRequest(false); // This must not reset the horizon.
293 EXPECT_EQ(custom_horizon
, custom
.GetReleaseTime());
296 TEST(BackoffEntryTest
, OverflowProtection
) {
297 BackoffEntry::Policy large_multiply_policy
= base_policy
;
298 large_multiply_policy
.multiply_factor
= 256;
299 TestBackoffEntry
custom(&large_multiply_policy
);
301 // Trigger enough failures such that more than 11 bits of exponent are used
302 // to represent the exponential backoff intermediate values. Given a multiply
303 // factor of 256 (2^8), 129 iterations is enough: 2^(8*(129-1)) = 2^1024.
304 for (int i
= 0; i
< 129; ++i
) {
305 custom
.set_now(custom
.ImplGetTimeNow() + custom
.GetTimeUntilRelease());
306 custom
.InformOfRequest(false);
307 ASSERT_TRUE(custom
.ShouldRejectRequest());
310 // Max delay should still be respected.
311 EXPECT_EQ(20000, custom
.GetTimeUntilRelease().InMilliseconds());