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