Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(648)

Side by Side Diff: net/url_request/request_throttler_unittest.cc

Issue 4194001: Implement exponential back-off mechanism and enforce it at the URLRequestHttpJob level. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 10 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
1 // Copyright (c) 2010 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 "base/pickle.h"
6 #include "base/scoped_ptr.h"
7 #include "base/string_number_conversions.h"
8 #include "base/time.h"
9 #include "net/base/test_completion_callback.h"
10 #include "net/url_request/request_throttler_header_interface.h"
11 #include "net/url_request/request_throttler_manager.h"
12 #include "net/url_request/url_request_context.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14
15 using base::TimeDelta;
16 using base::TimeTicks;
17
18 namespace {
19 class MockRequestThrottlerManager;
20
21 class MockRequestThrottlerEntry : public RequestThrottlerEntry {
22 public :
23 MockRequestThrottlerEntry() {}
24 MockRequestThrottlerEntry(const TimeTicks& exponential_backoff_release_time,
25 const TimeTicks& sliding_window_release_time,
26 const TimeTicks& fake_now)
27 : fake_time_now_(fake_now) {
28 set_exponential_backoff_release_time(exponential_backoff_release_time);
29 set_sliding_window_release_time(sliding_window_release_time);
30 }
31 virtual ~MockRequestThrottlerEntry() {}
32
33 void ResetToBlank(const TimeTicks& time_now) {
34 fake_time_now_ = time_now;
35 set_exponential_backoff_release_time(time_now);
36 set_failure_count(0);
37 set_sliding_window_release_time(time_now);
38 }
39
40 // Overridden for tests.
41 virtual TimeTicks GetTimeNow() const { return fake_time_now_; }
42
43 void set_exponential_backoff_release_time(
44 const base::TimeTicks& release_time) {
45 RequestThrottlerEntry::set_exponential_backoff_release_time(release_time);
46 }
47
48 base::TimeTicks sliding_window_release_time() const {
49 return RequestThrottlerEntry::sliding_window_release_time();
50 }
51
52 void set_sliding_window_release_time(
53 const base::TimeTicks& release_time) {
54 RequestThrottlerEntry::set_sliding_window_release_time(release_time);
55 }
56
57 TimeTicks fake_time_now_;
58 };
59
60 class MockRequestThrottlerHeaderAdapter
61 : public RequestThrottlerHeaderInterface {
62 public:
63 MockRequestThrottlerHeaderAdapter()
64 : fake_retry_value_("0.0"),
65 fake_response_code_(0) {
66 }
67
68 MockRequestThrottlerHeaderAdapter(const std::string& retry_value,
69 int response_code)
70 : fake_retry_value_(retry_value),
71 fake_response_code_(response_code) {
72 }
73
74 virtual ~MockRequestThrottlerHeaderAdapter() {}
75
76 virtual std::string GetNormalizedValue(const std::string& key) const {
77 if (key == MockRequestThrottlerEntry::kRetryHeaderName)
78 return fake_retry_value_;
79 return "";
80 }
81
82 virtual int GetResponseCode() const { return fake_response_code_; }
83
84 std::string fake_retry_value_;
85 int fake_response_code_;
86 };
87
88 class MockRequestThrottlerManager : public RequestThrottlerManager {
89 public:
90 MockRequestThrottlerManager() : create_entry_index_(0) {}
91
92 // Method to process the url using RequestThrottlerManager protected method.
93 std::string DoGetUrlIdFromUrl(const GURL& url) { return GetIdFromUrl(url); }
94
95 // Method to use the garbage collecting method of RequestThrottlerManager.
96 void DoGarbageCollectEntries() { GarbageCollectEntries(); }
97
98 // Returns the number of entries in the map.
99 int GetNumberOfEntries() const { return GetNumberOfEntriesForTests(); }
100
101 void CreateEntry(bool is_outdated) {
102 TimeTicks time = TimeTicks::Now();
103 if (is_outdated) {
104 time -= TimeDelta::FromMilliseconds(
105 MockRequestThrottlerEntry::kDefaultEntryLifetimeMs + 1000);
106 }
107 std::string fake_url_string("http://www.fakeurl.com/");
108 fake_url_string.append(base::IntToString(create_entry_index_++));
109 GURL fake_url(fake_url_string);
110 OverrideEntryForTests(fake_url,
111 new MockRequestThrottlerEntry(time, TimeTicks::Now(),
112 TimeTicks::Now()));
113 }
114
115 private:
116 int create_entry_index_;
117 };
118
119 struct TimeAndBool {
120 TimeAndBool(const TimeTicks& time_value, bool expected, int line_num) {
121 time = time_value;
122 result = expected;
123 line = line_num;
124 }
125 TimeTicks time;
126 bool result;
127 int line;
128 };
129
130 struct GurlAndString {
131 GurlAndString(const GURL& url_value,
132 const std::string& expected,
133 int line_num) {
134 url = url_value;
135 result = expected;
136 line = line_num;
137 }
138 GURL url;
139 std::string result;
140 int line;
141 };
142
143 } // namespace
144
145 class RequestThrottlerEntryTest : public testing::Test {
146 protected:
147 virtual void SetUp();
148 TimeTicks now_;
149 scoped_refptr<MockRequestThrottlerEntry> entry_;
150 };
151
152 void RequestThrottlerEntryTest::SetUp() {
153 now_ = TimeTicks::Now();
154 entry_ = new MockRequestThrottlerEntry();
155 entry_->ResetToBlank(now_);
156 }
157
158 std::ostream& operator<<(std::ostream& out, const base::TimeTicks& time) {
159 return out << time.ToInternalValue();
160 }
161
162 TEST_F(RequestThrottlerEntryTest, InterfaceDuringExponentialBackoff) {
163 entry_->set_exponential_backoff_release_time(
164 entry_->fake_time_now_ + TimeDelta::FromMilliseconds(1));
165 EXPECT_TRUE(entry_->IsDuringExponentialBackoff());
166 }
167
168 TEST_F(RequestThrottlerEntryTest, InterfaceNotDuringExponentialBackoff) {
169 entry_->set_exponential_backoff_release_time(entry_->fake_time_now_);
170 EXPECT_FALSE(entry_->IsDuringExponentialBackoff());
171 entry_->set_exponential_backoff_release_time(
172 entry_->fake_time_now_ - TimeDelta::FromMilliseconds(1));
173 EXPECT_FALSE(entry_->IsDuringExponentialBackoff());
174 }
175
176 TEST_F(RequestThrottlerEntryTest, InterfaceUpdateRetryAfter) {
177 // If the response we received has a retry-after field,
178 // the request should be delayed.
179 MockRequestThrottlerHeaderAdapter header_w_delay_header("5.5", 200);
180 entry_->UpdateWithResponse(&header_w_delay_header);
181 EXPECT_GT(entry_->GetExponentialBackoffReleaseTime(), entry_->fake_time_now_)
182 << "When the server put a positive value in retry-after we should "
183 "increase release_time";
184
185 entry_->ResetToBlank(now_);
186 header_w_delay_header.fake_retry_value_ = "-5.5";
187 EXPECT_EQ(entry_->GetExponentialBackoffReleaseTime(), entry_->fake_time_now_)
188 << "When given a negative value, it should not change the release_time";
189 }
190
191 TEST_F(RequestThrottlerEntryTest, InterfaceUpdateFailure) {
192 MockRequestThrottlerHeaderAdapter failure_response("0", 505);
193 entry_->UpdateWithResponse(&failure_response);
194 EXPECT_GT(entry_->GetExponentialBackoffReleaseTime(), entry_->fake_time_now_)
195 << "A failure should increase the release_time";
196 }
197
198 TEST_F(RequestThrottlerEntryTest, InterfaceUpdateSuccess) {
199 MockRequestThrottlerHeaderAdapter success_response("0", 200);
200 entry_->UpdateWithResponse(&success_response);
201 EXPECT_EQ(entry_->GetExponentialBackoffReleaseTime(), entry_->fake_time_now_)
202 << "A success should not add any delay";
203 }
204
205 TEST_F(RequestThrottlerEntryTest, InterfaceUpdateSuccessThenFailure) {
206 MockRequestThrottlerHeaderAdapter failure_response("0", 500);
207 MockRequestThrottlerHeaderAdapter success_response("0", 200);
208 entry_->UpdateWithResponse(&success_response);
209 entry_->UpdateWithResponse(&failure_response);
210 EXPECT_GT(entry_->GetExponentialBackoffReleaseTime(), entry_->fake_time_now_)
211 << "This scenario should add delay";
212 }
213
214 TEST_F(RequestThrottlerEntryTest, IsEntryReallyOutdated) {
215 TimeDelta lifetime = TimeDelta::FromMilliseconds(
216 MockRequestThrottlerEntry::kDefaultEntryLifetimeMs);
217 const TimeDelta kFiveMs = TimeDelta::FromMilliseconds(5);
218
219 TimeAndBool test_values[] = {
220 TimeAndBool(now_, false, __LINE__),
221 TimeAndBool(now_ - kFiveMs, false, __LINE__),
222 TimeAndBool(now_ + kFiveMs, false, __LINE__),
223 TimeAndBool(now_ - lifetime, false, __LINE__),
224 TimeAndBool(now_ - (lifetime + kFiveMs), true, __LINE__)};
225
226 for (unsigned int i = 0; i < arraysize(test_values); ++i) {
227 entry_->set_exponential_backoff_release_time(test_values[i].time);
228 EXPECT_EQ(entry_->IsEntryOutdated(), test_values[i].result) <<
229 "Test case #" << i << " line " << test_values[i].line << " failed";
230 }
231 }
232
233 TEST_F(RequestThrottlerEntryTest, MaxAllowedBackoff) {
234 for (int i = 0; i < 30; ++i) {
235 MockRequestThrottlerHeaderAdapter response_adapter("0.0", 505);
236 entry_->UpdateWithResponse(&response_adapter);
237 }
238
239 TimeDelta delay = entry_->GetExponentialBackoffReleaseTime() - now_;
240 EXPECT_EQ(delay.InMilliseconds(),
241 MockRequestThrottlerEntry::kDefaultMaximumBackoffMs);
242 }
243
244 TEST_F(RequestThrottlerEntryTest, MalformedContent) {
245 MockRequestThrottlerHeaderAdapter response_adapter("0.0", 505);
246 for (int i = 0; i < 5; ++i)
247 entry_->UpdateWithResponse(&response_adapter);
248
249 TimeTicks release_after_failures = entry_->GetExponentialBackoffReleaseTime();
250
251 // Inform the entry that a response body was malformed, which is supposed to
252 // increase the back-off time.
253 entry_->ReceivedContentWasMalformed();
254 EXPECT_GT(entry_->GetExponentialBackoffReleaseTime(), release_after_failures);
255 }
256
257 TEST_F(RequestThrottlerEntryTest, SlidingWindow) {
258 int max_send = RequestThrottlerEntry::kDefaultMaxSendThreshold;
259 int sliding_window = RequestThrottlerEntry::kDefaultSlidingWindowPeriodMs;
260
261 TimeTicks time_1 = entry_->fake_time_now_ +
262 TimeDelta::FromMilliseconds(sliding_window / 3);
263 TimeTicks time_2 = entry_->fake_time_now_ +
264 TimeDelta::FromMilliseconds(2 * sliding_window / 3);
265 TimeTicks time_3 = entry_->fake_time_now_ +
266 TimeDelta::FromMilliseconds(sliding_window);
267 TimeTicks time_4 = entry_->fake_time_now_ +
268 TimeDelta::FromMilliseconds(sliding_window + 2 * sliding_window / 3);
269
270 entry_->set_exponential_backoff_release_time(time_1);
271
272 for (int i = 0; i < max_send / 2; ++i) {
273 EXPECT_EQ(2 * sliding_window / 3,
274 entry_->ReserveSendingTimeForNextRequest(time_2));
275 }
276 EXPECT_EQ(time_2, entry_->sliding_window_release_time());
277
278 entry_->fake_time_now_ = time_3;
279
280 for (int i = 0; i < (max_send + 1) / 2; ++i)
281 EXPECT_EQ(0, entry_->ReserveSendingTimeForNextRequest(TimeTicks()));
282
283 EXPECT_EQ(time_4, entry_->sliding_window_release_time());
284 }
285
286 TEST(RequestThrottlerManager, IsUrlStandardised) {
287 MockRequestThrottlerManager manager;
288 GurlAndString test_values[] = {
289 GurlAndString(GURL("http://www.example.com"),
290 std::string("http://www.example.com/"), __LINE__),
291 GurlAndString(GURL("http://www.Example.com"),
292 std::string("http://www.example.com/"), __LINE__),
293 GurlAndString(GURL("http://www.ex4mple.com/Pr4c71c41"),
294 std::string("http://www.ex4mple.com/pr4c71c41"), __LINE__),
295 GurlAndString(GURL("http://www.example.com/0/token/false"),
296 std::string("http://www.example.com/0/token/false"),
297 __LINE__),
298 GurlAndString(GURL("http://www.example.com/index.php?code=javascript"),
299 std::string("http://www.example.com/index.php"), __LINE__),
300 GurlAndString(GURL("http://www.example.com/index.php?code=1#superEntry"),
301 std::string("http://www.example.com/index.php"),
302 __LINE__)};
303
304 for (unsigned int i = 0; i < arraysize(test_values); ++i) {
305 std::string temp = manager.DoGetUrlIdFromUrl(test_values[i].url);
306 EXPECT_EQ(temp, test_values[i].result) <<
307 "Test case #" << i << " line " << test_values[i].line << " failed";
308 }
309 }
310
311 TEST(RequestThrottlerManager, AreEntriesBeingCollected) {
312 MockRequestThrottlerManager manager;
313
314 manager.CreateEntry(true); // true = Entry is outdated.
315 manager.CreateEntry(true);
316 manager.CreateEntry(true);
317 manager.DoGarbageCollectEntries();
318 EXPECT_EQ(0, manager.GetNumberOfEntries());
319
320 manager.CreateEntry(false);
321 manager.CreateEntry(false);
322 manager.CreateEntry(false);
323 manager.CreateEntry(true);
324 manager.DoGarbageCollectEntries();
325 EXPECT_EQ(3, manager.GetNumberOfEntries());
326 }
327
328 TEST(RequestThrottlerManager, IsHostBeingRegistered) {
329 MockRequestThrottlerManager manager;
330
331 manager.RegisterRequestUrl(GURL("http://www.example.com/"));
332 manager.RegisterRequestUrl(GURL("http://www.google.com/"));
333 manager.RegisterRequestUrl(GURL("http://www.google.com/index/0"));
334 manager.RegisterRequestUrl(GURL("http://www.google.com/index/0?code=1"));
335 manager.RegisterRequestUrl(GURL("http://www.google.com/index/0#lolsaure"));
336
337 EXPECT_EQ(3, manager.GetNumberOfEntries());
338 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698