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