Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / net / url_request / url_request_throttler_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/url_request/url_request_throttler_manager.h"
6
7 #include "base/memory/scoped_ptr.h"
8 #include "base/metrics/histogram_samples.h"
9 #include "base/pickle.h"
10 #include "base/stl_util.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/test/histogram_tester.h"
14 #include "base/time/time.h"
15 #include "net/base/load_flags.h"
16 #include "net/base/request_priority.h"
17 #include "net/base/test_completion_callback.h"
18 #include "net/url_request/url_request.h"
19 #include "net/url_request/url_request_context.h"
20 #include "net/url_request/url_request_test_util.h"
21 #include "net/url_request/url_request_throttler_header_interface.h"
22 #include "net/url_request/url_request_throttler_test_support.h"
23 #include "testing/gtest/include/gtest/gtest.h"
24
25 using base::TimeDelta;
26 using base::TimeTicks;
27
28 namespace net {
29
30 namespace {
31
32 const char kRequestThrottledHistogramName[] = "Throttling.RequestThrottled";
33
34 class MockURLRequestThrottlerEntry : public URLRequestThrottlerEntry {
35  public:
36   explicit MockURLRequestThrottlerEntry(
37       URLRequestThrottlerManager* manager)
38       : URLRequestThrottlerEntry(manager, std::string()),
39         mock_backoff_entry_(&backoff_policy_) {
40     InitPolicy();
41   }
42   MockURLRequestThrottlerEntry(
43       URLRequestThrottlerManager* manager,
44       const TimeTicks& exponential_backoff_release_time,
45       const TimeTicks& sliding_window_release_time,
46       const TimeTicks& fake_now)
47       : URLRequestThrottlerEntry(manager, std::string()),
48         fake_time_now_(fake_now),
49         mock_backoff_entry_(&backoff_policy_) {
50     InitPolicy();
51
52     mock_backoff_entry_.set_fake_now(fake_now);
53     set_exponential_backoff_release_time(exponential_backoff_release_time);
54     set_sliding_window_release_time(sliding_window_release_time);
55   }
56
57   void InitPolicy() {
58     // Some tests become flaky if we have jitter.
59     backoff_policy_.jitter_factor = 0.0;
60
61     // This lets us avoid having to make multiple failures initially (this
62     // logic is already tested in the BackoffEntry unit tests).
63     backoff_policy_.num_errors_to_ignore = 0;
64   }
65
66   const BackoffEntry* GetBackoffEntry() const override {
67     return &mock_backoff_entry_;
68   }
69
70   BackoffEntry* GetBackoffEntry() override { return &mock_backoff_entry_; }
71
72   static bool ExplicitUserRequest(int load_flags) {
73     return URLRequestThrottlerEntry::ExplicitUserRequest(load_flags);
74   }
75
76   void ResetToBlank(const TimeTicks& time_now) {
77     fake_time_now_ = time_now;
78     mock_backoff_entry_.set_fake_now(time_now);
79
80     GetBackoffEntry()->Reset();
81     GetBackoffEntry()->SetCustomReleaseTime(time_now);
82     set_sliding_window_release_time(time_now);
83   }
84
85   // Overridden for tests.
86   TimeTicks ImplGetTimeNow() const override { return fake_time_now_; }
87
88   void set_exponential_backoff_release_time(
89       const base::TimeTicks& release_time) {
90     GetBackoffEntry()->SetCustomReleaseTime(release_time);
91   }
92
93   base::TimeTicks sliding_window_release_time() const {
94     return URLRequestThrottlerEntry::sliding_window_release_time();
95   }
96
97   void set_sliding_window_release_time(
98       const base::TimeTicks& release_time) {
99     URLRequestThrottlerEntry::set_sliding_window_release_time(
100         release_time);
101   }
102
103   TimeTicks fake_time_now_;
104   MockBackoffEntry mock_backoff_entry_;
105
106  protected:
107   ~MockURLRequestThrottlerEntry() override {}
108 };
109
110 class MockURLRequestThrottlerManager : public URLRequestThrottlerManager {
111  public:
112   MockURLRequestThrottlerManager() : create_entry_index_(0) {}
113
114   // Method to process the URL using URLRequestThrottlerManager protected
115   // method.
116   std::string DoGetUrlIdFromUrl(const GURL& url) { return GetIdFromUrl(url); }
117
118   // Method to use the garbage collecting method of URLRequestThrottlerManager.
119   void DoGarbageCollectEntries() { GarbageCollectEntries(); }
120
121   // Returns the number of entries in the map.
122   int GetNumberOfEntries() const { return GetNumberOfEntriesForTests(); }
123
124   void CreateEntry(bool is_outdated) {
125     TimeTicks time = TimeTicks::Now();
126     if (is_outdated) {
127       time -= TimeDelta::FromMilliseconds(
128           MockURLRequestThrottlerEntry::kDefaultEntryLifetimeMs + 1000);
129     }
130     std::string fake_url_string("http://www.fakeurl.com/");
131     fake_url_string.append(base::IntToString(create_entry_index_++));
132     GURL fake_url(fake_url_string);
133     OverrideEntryForTests(
134         fake_url,
135         new MockURLRequestThrottlerEntry(this, time, TimeTicks::Now(),
136                                          TimeTicks::Now()));
137   }
138
139  private:
140   int create_entry_index_;
141 };
142
143 struct TimeAndBool {
144   TimeAndBool(const TimeTicks& time_value, bool expected, int line_num) {
145     time = time_value;
146     result = expected;
147     line = line_num;
148   }
149   TimeTicks time;
150   bool result;
151   int line;
152 };
153
154 struct GurlAndString {
155   GurlAndString(const GURL& url_value,
156                 const std::string& expected,
157                 int line_num) {
158     url = url_value;
159     result = expected;
160     line = line_num;
161   }
162   GURL url;
163   std::string result;
164   int line;
165 };
166
167 }  // namespace
168
169 class URLRequestThrottlerEntryTest : public testing::Test {
170  protected:
171   URLRequestThrottlerEntryTest()
172       : request_(context_.CreateRequest(GURL(), DEFAULT_PRIORITY, NULL, NULL)) {
173   }
174
175   void SetUp() override;
176
177   TimeTicks now_;
178   MockURLRequestThrottlerManager manager_;  // Dummy object, not used.
179   scoped_refptr<MockURLRequestThrottlerEntry> entry_;
180
181   TestURLRequestContext context_;
182   scoped_ptr<URLRequest> request_;
183 };
184
185 void URLRequestThrottlerEntryTest::SetUp() {
186   request_->SetLoadFlags(0);
187
188   now_ = TimeTicks::Now();
189   entry_ = new MockURLRequestThrottlerEntry(&manager_);
190   entry_->ResetToBlank(now_);
191 }
192
193 std::ostream& operator<<(std::ostream& out, const base::TimeTicks& time) {
194   return out << time.ToInternalValue();
195 }
196
197 TEST_F(URLRequestThrottlerEntryTest, CanThrottleRequest) {
198   TestNetworkDelegate d;
199   context_.set_network_delegate(&d);
200   entry_->set_exponential_backoff_release_time(
201       entry_->fake_time_now_ + TimeDelta::FromMilliseconds(1));
202
203   d.set_can_throttle_requests(false);
204   EXPECT_FALSE(entry_->ShouldRejectRequest(*request_,
205                                            context_.network_delegate()));
206   d.set_can_throttle_requests(true);
207   EXPECT_TRUE(entry_->ShouldRejectRequest(*request_,
208                                           context_.network_delegate()));
209 }
210
211 TEST_F(URLRequestThrottlerEntryTest, InterfaceDuringExponentialBackoff) {
212   base::HistogramTester histogram_tester;
213   entry_->set_exponential_backoff_release_time(
214       entry_->fake_time_now_ + TimeDelta::FromMilliseconds(1));
215   EXPECT_TRUE(entry_->ShouldRejectRequest(*request_,
216                                           context_.network_delegate()));
217
218   // Also end-to-end test the load flags exceptions.
219   request_->SetLoadFlags(LOAD_MAYBE_USER_GESTURE);
220   EXPECT_FALSE(entry_->ShouldRejectRequest(*request_,
221                                            context_.network_delegate()));
222
223   histogram_tester.ExpectBucketCount(kRequestThrottledHistogramName, 0, 1);
224   histogram_tester.ExpectBucketCount(kRequestThrottledHistogramName, 1, 1);
225 }
226
227 TEST_F(URLRequestThrottlerEntryTest, InterfaceNotDuringExponentialBackoff) {
228   base::HistogramTester histogram_tester;
229   entry_->set_exponential_backoff_release_time(entry_->fake_time_now_);
230   EXPECT_FALSE(entry_->ShouldRejectRequest(*request_,
231                                            context_.network_delegate()));
232   entry_->set_exponential_backoff_release_time(
233       entry_->fake_time_now_ - TimeDelta::FromMilliseconds(1));
234   EXPECT_FALSE(entry_->ShouldRejectRequest(*request_,
235                                            context_.network_delegate()));
236
237   histogram_tester.ExpectBucketCount(kRequestThrottledHistogramName, 0, 2);
238   histogram_tester.ExpectBucketCount(kRequestThrottledHistogramName, 1, 0);
239 }
240
241 TEST_F(URLRequestThrottlerEntryTest, InterfaceUpdateFailure) {
242   MockURLRequestThrottlerHeaderAdapter failure_response(503);
243   entry_->UpdateWithResponse(std::string(), &failure_response);
244   EXPECT_GT(entry_->GetExponentialBackoffReleaseTime(), entry_->fake_time_now_)
245       << "A failure should increase the release_time";
246 }
247
248 TEST_F(URLRequestThrottlerEntryTest, InterfaceUpdateSuccess) {
249   MockURLRequestThrottlerHeaderAdapter success_response(200);
250   entry_->UpdateWithResponse(std::string(), &success_response);
251   EXPECT_EQ(entry_->GetExponentialBackoffReleaseTime(), entry_->fake_time_now_)
252       << "A success should not add any delay";
253 }
254
255 TEST_F(URLRequestThrottlerEntryTest, InterfaceUpdateSuccessThenFailure) {
256   MockURLRequestThrottlerHeaderAdapter failure_response(503);
257   MockURLRequestThrottlerHeaderAdapter success_response(200);
258   entry_->UpdateWithResponse(std::string(), &success_response);
259   entry_->UpdateWithResponse(std::string(), &failure_response);
260   EXPECT_GT(entry_->GetExponentialBackoffReleaseTime(), entry_->fake_time_now_)
261       << "This scenario should add delay";
262   entry_->UpdateWithResponse(std::string(), &success_response);
263 }
264
265 TEST_F(URLRequestThrottlerEntryTest, IsEntryReallyOutdated) {
266   TimeDelta lifetime = TimeDelta::FromMilliseconds(
267       MockURLRequestThrottlerEntry::kDefaultEntryLifetimeMs);
268   const TimeDelta kFiveMs = TimeDelta::FromMilliseconds(5);
269
270   TimeAndBool test_values[] = {
271       TimeAndBool(now_, false, __LINE__),
272       TimeAndBool(now_ - kFiveMs, false, __LINE__),
273       TimeAndBool(now_ + kFiveMs, false, __LINE__),
274       TimeAndBool(now_ - (lifetime - kFiveMs), false, __LINE__),
275       TimeAndBool(now_ - lifetime, true, __LINE__),
276       TimeAndBool(now_ - (lifetime + kFiveMs), true, __LINE__)};
277
278   for (unsigned int i = 0; i < arraysize(test_values); ++i) {
279     entry_->set_exponential_backoff_release_time(test_values[i].time);
280     EXPECT_EQ(entry_->IsEntryOutdated(), test_values[i].result) <<
281         "Test case #" << i << " line " << test_values[i].line << " failed";
282   }
283 }
284
285 TEST_F(URLRequestThrottlerEntryTest, MaxAllowedBackoff) {
286   for (int i = 0; i < 30; ++i) {
287     MockURLRequestThrottlerHeaderAdapter response_adapter(503);
288     entry_->UpdateWithResponse(std::string(), &response_adapter);
289   }
290
291   TimeDelta delay = entry_->GetExponentialBackoffReleaseTime() - now_;
292   EXPECT_EQ(delay.InMilliseconds(),
293             MockURLRequestThrottlerEntry::kDefaultMaximumBackoffMs);
294 }
295
296 TEST_F(URLRequestThrottlerEntryTest, MalformedContent) {
297   MockURLRequestThrottlerHeaderAdapter response_adapter(503);
298   for (int i = 0; i < 5; ++i)
299     entry_->UpdateWithResponse(std::string(), &response_adapter);
300
301   TimeTicks release_after_failures = entry_->GetExponentialBackoffReleaseTime();
302
303   // Inform the entry that a response body was malformed, which is supposed to
304   // increase the back-off time.  Note that we also submit a successful
305   // UpdateWithResponse to pair with ReceivedContentWasMalformed() since that
306   // is what happens in practice (if a body is received, then a non-500
307   // response must also have been received).
308   entry_->ReceivedContentWasMalformed(200);
309   MockURLRequestThrottlerHeaderAdapter success_adapter(200);
310   entry_->UpdateWithResponse(std::string(), &success_adapter);
311   EXPECT_GT(entry_->GetExponentialBackoffReleaseTime(), release_after_failures);
312 }
313
314 TEST_F(URLRequestThrottlerEntryTest, SlidingWindow) {
315   int max_send = URLRequestThrottlerEntry::kDefaultMaxSendThreshold;
316   int sliding_window =
317       URLRequestThrottlerEntry::kDefaultSlidingWindowPeriodMs;
318
319   TimeTicks time_1 = entry_->fake_time_now_ +
320       TimeDelta::FromMilliseconds(sliding_window / 3);
321   TimeTicks time_2 = entry_->fake_time_now_ +
322       TimeDelta::FromMilliseconds(2 * sliding_window / 3);
323   TimeTicks time_3 = entry_->fake_time_now_ +
324       TimeDelta::FromMilliseconds(sliding_window);
325   TimeTicks time_4 = entry_->fake_time_now_ +
326       TimeDelta::FromMilliseconds(sliding_window + 2 * sliding_window / 3);
327
328   entry_->set_exponential_backoff_release_time(time_1);
329
330   for (int i = 0; i < max_send / 2; ++i) {
331     EXPECT_EQ(2 * sliding_window / 3,
332               entry_->ReserveSendingTimeForNextRequest(time_2));
333   }
334   EXPECT_EQ(time_2, entry_->sliding_window_release_time());
335
336   entry_->fake_time_now_ = time_3;
337
338   for (int i = 0; i < (max_send + 1) / 2; ++i)
339     EXPECT_EQ(0, entry_->ReserveSendingTimeForNextRequest(TimeTicks()));
340
341   EXPECT_EQ(time_4, entry_->sliding_window_release_time());
342 }
343
344 TEST_F(URLRequestThrottlerEntryTest, ExplicitUserRequest) {
345   ASSERT_FALSE(MockURLRequestThrottlerEntry::ExplicitUserRequest(0));
346   ASSERT_TRUE(MockURLRequestThrottlerEntry::ExplicitUserRequest(
347       LOAD_MAYBE_USER_GESTURE));
348   ASSERT_FALSE(MockURLRequestThrottlerEntry::ExplicitUserRequest(
349       ~LOAD_MAYBE_USER_GESTURE));
350 }
351
352 class URLRequestThrottlerManagerTest : public testing::Test {
353  protected:
354   URLRequestThrottlerManagerTest()
355       : request_(context_.CreateRequest(GURL(), DEFAULT_PRIORITY, NULL, NULL)) {
356   }
357
358   void SetUp() override { request_->SetLoadFlags(0); }
359
360   void ExpectEntryAllowsAllOnErrorIfOptedOut(
361       URLRequestThrottlerEntryInterface* entry,
362       bool opted_out,
363       const URLRequest& request) {
364     EXPECT_FALSE(entry->ShouldRejectRequest(request,
365                                             context_.network_delegate()));
366     MockURLRequestThrottlerHeaderAdapter failure_adapter(503);
367     for (int i = 0; i < 10; ++i) {
368       // Host doesn't really matter in this scenario so we skip it.
369       entry->UpdateWithResponse(std::string(), &failure_adapter);
370     }
371     EXPECT_NE(opted_out, entry->ShouldRejectRequest(
372                   request, context_.network_delegate()));
373
374     if (opted_out) {
375       // We're not mocking out GetTimeNow() in this scenario
376       // so add a 100 ms buffer to avoid flakiness (that should always
377       // give enough time to get from the TimeTicks::Now() call here
378       // to the TimeTicks::Now() call in the entry class).
379       EXPECT_GT(TimeTicks::Now() + TimeDelta::FromMilliseconds(100),
380                 entry->GetExponentialBackoffReleaseTime());
381     } else {
382       // As above, add 100 ms.
383       EXPECT_LT(TimeTicks::Now() + TimeDelta::FromMilliseconds(100),
384                 entry->GetExponentialBackoffReleaseTime());
385     }
386   }
387
388   // context_ must be declared before request_.
389   TestURLRequestContext context_;
390   scoped_ptr<URLRequest> request_;
391 };
392
393 TEST_F(URLRequestThrottlerManagerTest, IsUrlStandardised) {
394   MockURLRequestThrottlerManager manager;
395   GurlAndString test_values[] = {
396       GurlAndString(GURL("http://www.example.com"),
397                     std::string("http://www.example.com/"),
398                     __LINE__),
399       GurlAndString(GURL("http://www.Example.com"),
400                     std::string("http://www.example.com/"),
401                     __LINE__),
402       GurlAndString(GURL("http://www.ex4mple.com/Pr4c71c41"),
403                     std::string("http://www.ex4mple.com/pr4c71c41"),
404                     __LINE__),
405       GurlAndString(GURL("http://www.example.com/0/token/false"),
406                     std::string("http://www.example.com/0/token/false"),
407                     __LINE__),
408       GurlAndString(GURL("http://www.example.com/index.php?code=javascript"),
409                     std::string("http://www.example.com/index.php"),
410                     __LINE__),
411       GurlAndString(GURL("http://www.example.com/index.php?code=1#superEntry"),
412                     std::string("http://www.example.com/index.php"),
413                     __LINE__),
414       GurlAndString(GURL("http://www.example.com/index.php#superEntry"),
415                     std::string("http://www.example.com/index.php"),
416                     __LINE__),
417       GurlAndString(GURL("http://www.example.com:1234/"),
418                     std::string("http://www.example.com:1234/"),
419                     __LINE__)};
420
421   for (unsigned int i = 0; i < arraysize(test_values); ++i) {
422     std::string temp = manager.DoGetUrlIdFromUrl(test_values[i].url);
423     EXPECT_EQ(temp, test_values[i].result) <<
424         "Test case #" << i << " line " << test_values[i].line << " failed";
425   }
426 }
427
428 TEST_F(URLRequestThrottlerManagerTest, AreEntriesBeingCollected) {
429   MockURLRequestThrottlerManager manager;
430
431   manager.CreateEntry(true);  // true = Entry is outdated.
432   manager.CreateEntry(true);
433   manager.CreateEntry(true);
434   manager.DoGarbageCollectEntries();
435   EXPECT_EQ(0, manager.GetNumberOfEntries());
436
437   manager.CreateEntry(false);
438   manager.CreateEntry(false);
439   manager.CreateEntry(false);
440   manager.CreateEntry(true);
441   manager.DoGarbageCollectEntries();
442   EXPECT_EQ(3, manager.GetNumberOfEntries());
443 }
444
445 TEST_F(URLRequestThrottlerManagerTest, IsHostBeingRegistered) {
446   MockURLRequestThrottlerManager manager;
447
448   manager.RegisterRequestUrl(GURL("http://www.example.com/"));
449   manager.RegisterRequestUrl(GURL("http://www.google.com/"));
450   manager.RegisterRequestUrl(GURL("http://www.google.com/index/0"));
451   manager.RegisterRequestUrl(GURL("http://www.google.com/index/0?code=1"));
452   manager.RegisterRequestUrl(GURL("http://www.google.com/index/0#lolsaure"));
453
454   EXPECT_EQ(3, manager.GetNumberOfEntries());
455 }
456
457 TEST_F(URLRequestThrottlerManagerTest, OptOutHeader) {
458   MockURLRequestThrottlerManager manager;
459   scoped_refptr<URLRequestThrottlerEntryInterface> entry =
460       manager.RegisterRequestUrl(GURL("http://www.google.com/yodude"));
461
462   // Fake a response with the opt-out header.
463   MockURLRequestThrottlerHeaderAdapter response_adapter(
464       std::string(),
465       MockURLRequestThrottlerEntry::kExponentialThrottlingDisableValue,
466       200);
467   entry->UpdateWithResponse("www.google.com", &response_adapter);
468
469   // Ensure that the same entry on error always allows everything.
470   ExpectEntryAllowsAllOnErrorIfOptedOut(entry.get(), true, *request_);
471
472   // Ensure that a freshly created entry (for a different URL on an
473   // already opted-out host) also gets "always allow" behavior.
474   scoped_refptr<URLRequestThrottlerEntryInterface> other_entry =
475       manager.RegisterRequestUrl(GURL("http://www.google.com/bingobob"));
476   ExpectEntryAllowsAllOnErrorIfOptedOut(other_entry.get(), true, *request_);
477
478   // Fake a response with the opt-out header incorrectly specified.
479   scoped_refptr<URLRequestThrottlerEntryInterface> no_opt_out_entry =
480       manager.RegisterRequestUrl(GURL("http://www.nike.com/justdoit"));
481   MockURLRequestThrottlerHeaderAdapter wrong_adapter(
482       std::string(), "yesplease", 200);
483   no_opt_out_entry->UpdateWithResponse("www.nike.com", &wrong_adapter);
484   ExpectEntryAllowsAllOnErrorIfOptedOut(
485       no_opt_out_entry.get(), false, *request_);
486
487   // A localhost entry should always be opted out.
488   scoped_refptr<URLRequestThrottlerEntryInterface> localhost_entry =
489       manager.RegisterRequestUrl(GURL("http://localhost/hello"));
490   ExpectEntryAllowsAllOnErrorIfOptedOut(localhost_entry.get(), true, *request_);
491 }
492
493 TEST_F(URLRequestThrottlerManagerTest, ClearOnNetworkChange) {
494   for (int i = 0; i < 3; ++i) {
495     MockURLRequestThrottlerManager manager;
496     scoped_refptr<URLRequestThrottlerEntryInterface> entry_before =
497         manager.RegisterRequestUrl(GURL("http://www.example.com/"));
498     MockURLRequestThrottlerHeaderAdapter failure_adapter(503);
499     for (int j = 0; j < 10; ++j) {
500       // Host doesn't really matter in this scenario so we skip it.
501       entry_before->UpdateWithResponse(std::string(), &failure_adapter);
502     }
503     EXPECT_TRUE(entry_before->ShouldRejectRequest(*request_,
504                                                   context_.network_delegate()));
505
506     switch (i) {
507       case 0:
508         manager.OnIPAddressChanged();
509         break;
510       case 1:
511         manager.OnConnectionTypeChanged(
512             NetworkChangeNotifier::CONNECTION_UNKNOWN);
513         break;
514       case 2:
515         manager.OnConnectionTypeChanged(NetworkChangeNotifier::CONNECTION_NONE);
516         break;
517       default:
518         FAIL();
519     }
520
521     scoped_refptr<URLRequestThrottlerEntryInterface> entry_after =
522         manager.RegisterRequestUrl(GURL("http://www.example.com/"));
523     EXPECT_FALSE(entry_after->ShouldRejectRequest(
524                      *request_, context_.network_delegate()));
525   }
526 }
527
528 }  // namespace net