• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
TestBackoffEntry(const Policy * const policy)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 
~TestBackoffEntry()26   virtual ~TestBackoffEntry() {}
27 
GetTimeNow() const28   virtual TimeTicks GetTimeNow() const {
29     return now_;
30   }
31 
set_now(const TimeTicks & now)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 
TEST(BackoffEntryTest,BaseTest)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 
TEST(BackoffEntryTest,CanDiscardNeverExpires)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 
TEST(BackoffEntryTest,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());
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 
TEST(BackoffEntryTest,CanDiscardNotStored)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 
TEST(BackoffEntryTest,ShouldIgnoreFirstTwo)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 
TEST(BackoffEntryTest,ReleaseTimeCalculation)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 
TEST(BackoffEntryTest,ReleaseTimeCalculationWithJitter)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 
TEST(BackoffEntryTest,FailureThenSuccess)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 
TEST(BackoffEntryTest,RetainCustomHorizon)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 
TEST(BackoffEntryTest,RetainCustomHorizonWhenInitialErrorsIgnored)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