Upstream version 11.40.277.0
[platform/framework/web/crosswalk.git] / src / net / base / backoff_entry_unittest.cc
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.
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, false };
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   ~TestBackoffEntry() override {}
27
28   TimeTicks ImplGetTimeNow() const override { return now_; }
29
30   void set_now(const TimeTicks& now) {
31     now_ = now;
32   }
33
34  private:
35   TimeTicks now_;
36
37   DISALLOW_COPY_AND_ASSIGN(TestBackoffEntry);
38 };
39
40 TEST(BackoffEntryTest, BaseTest) {
41   TestBackoffEntry entry(&base_policy);
42   EXPECT_FALSE(entry.ShouldRejectRequest());
43   EXPECT_EQ(TimeDelta(), entry.GetTimeUntilRelease());
44
45   entry.InformOfRequest(false);
46   EXPECT_TRUE(entry.ShouldRejectRequest());
47   EXPECT_EQ(TimeDelta::FromMilliseconds(1000), entry.GetTimeUntilRelease());
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, 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;
90
91   TestBackoffEntry entry(&always_delay_policy);
92
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());
96
97   // Even with no failures, we wait until the delay before we allow discard.
98   entry.InformOfRequest(true);
99   EXPECT_FALSE(entry.CanDiscard());
100
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());
104 }
105
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());
111 }
112
113 TEST(BackoffEntryTest, ShouldIgnoreFirstTwo) {
114   BackoffEntry::Policy lenient_policy = base_policy;
115   lenient_policy.num_errors_to_ignore = 2;
116
117   BackoffEntry entry(&lenient_policy);
118
119   entry.InformOfRequest(false);
120   EXPECT_FALSE(entry.ShouldRejectRequest());
121
122   entry.InformOfRequest(false);
123   EXPECT_FALSE(entry.ShouldRejectRequest());
124
125   entry.InformOfRequest(false);
126   EXPECT_TRUE(entry.ShouldRejectRequest());
127 }
128
129 TEST(BackoffEntryTest, ReleaseTimeCalculation) {
130   TestBackoffEntry entry(&base_policy);
131
132   // With zero errors, should return "now".
133   TimeTicks result = entry.GetReleaseTime();
134   EXPECT_EQ(entry.ImplGetTimeNow(), result);
135
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());
141
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());
147
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());
153
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);
161 }
162
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;
167
168   TestBackoffEntry entry(&always_delay_policy);
169
170   // With previous requests, should return "now".
171   TimeTicks result = entry.GetReleaseTime();
172   EXPECT_EQ(TimeDelta(), entry.GetTimeUntilRelease());
173
174   // 1 error.
175   entry.InformOfRequest(false);
176   EXPECT_EQ(TimeDelta::FromMilliseconds(1000), entry.GetTimeUntilRelease());
177
178   // 2 errors.
179   entry.InformOfRequest(false);
180   EXPECT_EQ(TimeDelta::FromMilliseconds(1000), entry.GetTimeUntilRelease());
181
182   // 3 errors, exponential backoff starts.
183   entry.InformOfRequest(false);
184   EXPECT_EQ(TimeDelta::FromMilliseconds(2000), entry.GetTimeUntilRelease());
185
186   // 4 errors.
187   entry.InformOfRequest(false);
188   EXPECT_EQ(TimeDelta::FromMilliseconds(4000), entry.GetTimeUntilRelease());
189
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());
197 }
198
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;
203
204     TestBackoffEntry entry(&jittery_policy);
205
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);
214   }
215 }
216
217 TEST(BackoffEntryTest, FailureThenSuccess) {
218   TestBackoffEntry entry(&base_policy);
219
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);
224
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());
230
231   // Failure, failure count 1.
232   entry.InformOfRequest(false);
233   EXPECT_EQ(release_time + TimeDelta::FromMilliseconds(800),
234             entry.GetReleaseTime());
235 }
236
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;
241
242   TestBackoffEntry entry(&always_delay_policy);
243
244   // Failure count 1.
245   entry.InformOfRequest(false);
246   EXPECT_EQ(TimeDelta::FromMilliseconds(1000), entry.GetTimeUntilRelease());
247
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));
252
253   // Success.  We should go back to the original delay.
254   entry.InformOfRequest(true);
255   EXPECT_EQ(TimeDelta::FromMilliseconds(1000), entry.GetTimeUntilRelease());
256
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));
261 }
262
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());
273
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());
281 }
282
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());
292 }
293
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);
298
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());
306   }
307
308   // Max delay should still be respected.
309   EXPECT_EQ(20000, custom.GetTimeUntilRelease().InMilliseconds());
310 }
311
312 }  // namespace