Home | History | Annotate | Download | only in net
      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 <time.h>
      6 
      7 #include <algorithm>
      8 #include <sstream>
      9 #include <string>
     10 
     11 #include "base/memory/scoped_ptr.h"
     12 #include "base/message_loop.h"
     13 #include "base/string_number_conversions.h"
     14 #include "base/timer.h"
     15 #include "base/values.h"
     16 #include "chrome/browser/net/predictor_api.h"
     17 #include "chrome/browser/net/url_info.h"
     18 #include "chrome/common/net/predictor_common.h"
     19 #include "content/browser/browser_thread.h"
     20 #include "net/base/address_list.h"
     21 #include "net/base/mock_host_resolver.h"
     22 #include "net/base/winsock_init.h"
     23 #include "testing/gtest/include/gtest/gtest.h"
     24 
     25 using base::Time;
     26 using base::TimeDelta;
     27 
     28 namespace chrome_browser_net {
     29 
     30 class WaitForResolutionHelper;
     31 
     32 typedef base::RepeatingTimer<WaitForResolutionHelper> HelperTimer;
     33 
     34 class WaitForResolutionHelper {
     35  public:
     36   WaitForResolutionHelper(Predictor* predictor, const UrlList& hosts,
     37                           HelperTimer* timer)
     38       : predictor_(predictor),
     39         hosts_(hosts),
     40         timer_(timer) {
     41   }
     42 
     43   void Run() {
     44     for (UrlList::const_iterator i = hosts_.begin(); i != hosts_.end(); ++i)
     45       if (predictor_->GetResolutionDuration(*i) ==
     46           UrlInfo::kNullDuration)
     47         return;  // We don't have resolution for that host.
     48 
     49     // When all hostnames have been resolved, exit the loop.
     50     timer_->Stop();
     51     MessageLoop::current()->Quit();
     52     delete timer_;
     53     delete this;
     54   }
     55 
     56  private:
     57   Predictor* predictor_;
     58   const UrlList hosts_;
     59   HelperTimer* timer_;
     60 };
     61 
     62 class PredictorTest : public testing::Test {
     63  public:
     64   PredictorTest()
     65       : io_thread_(BrowserThread::IO, &loop_),
     66         host_resolver_(new net::MockCachingHostResolver()),
     67         default_max_queueing_delay_(TimeDelta::FromMilliseconds(
     68             PredictorInit::kMaxSpeculativeResolveQueueDelayMs)) {
     69   }
     70 
     71  protected:
     72   virtual void SetUp() {
     73 #if defined(OS_WIN)
     74     net::EnsureWinsockInit();
     75 #endif
     76     // Since we are using a caching HostResolver, the following latencies will
     77     // only be incurred by the first request, after which the result will be
     78     // cached internally by |host_resolver_|.
     79     net::RuleBasedHostResolverProc* rules = host_resolver_->rules();
     80     rules->AddRuleWithLatency("www.google.com", "127.0.0.1", 50);
     81     rules->AddRuleWithLatency("gmail.google.com.com", "127.0.0.1", 70);
     82     rules->AddRuleWithLatency("mail.google.com", "127.0.0.1", 44);
     83     rules->AddRuleWithLatency("gmail.com", "127.0.0.1", 63);
     84   }
     85 
     86   void WaitForResolution(Predictor* predictor, const UrlList& hosts) {
     87     HelperTimer* timer = new HelperTimer();
     88     timer->Start(TimeDelta::FromMilliseconds(100),
     89                  new WaitForResolutionHelper(predictor, hosts, timer),
     90                  &WaitForResolutionHelper::Run);
     91     MessageLoop::current()->Run();
     92   }
     93 
     94  private:
     95   // IMPORTANT: do not move this below |host_resolver_|; the host resolver
     96   // must not outlive the message loop, otherwise bad things can happen
     97   // (like posting to a deleted message loop).
     98   MessageLoop loop_;
     99   BrowserThread io_thread_;
    100 
    101  protected:
    102   scoped_ptr<net::MockCachingHostResolver> host_resolver_;
    103 
    104   // Shorthand to access TimeDelta of PredictorInit::kMaxQueueingDelayMs.
    105   // (It would be a static constant... except style rules preclude that :-/ ).
    106   const TimeDelta default_max_queueing_delay_;
    107 };
    108 
    109 //------------------------------------------------------------------------------
    110 
    111 TEST_F(PredictorTest, StartupShutdownTest) {
    112   scoped_refptr<Predictor> testing_master(
    113       new Predictor(host_resolver_.get(),
    114                     default_max_queueing_delay_,
    115                     PredictorInit::kMaxSpeculativeParallelResolves,
    116                     false));
    117   testing_master->Shutdown();
    118 }
    119 
    120 
    121 TEST_F(PredictorTest, ShutdownWhenResolutionIsPendingTest) {
    122   scoped_refptr<net::WaitingHostResolverProc> resolver_proc(
    123       new net::WaitingHostResolverProc(NULL));
    124   host_resolver_->Reset(resolver_proc);
    125 
    126   scoped_refptr<Predictor> testing_master(
    127       new Predictor(host_resolver_.get(),
    128                     default_max_queueing_delay_,
    129                     PredictorInit::kMaxSpeculativeParallelResolves,
    130                     false));
    131 
    132   GURL localhost("http://localhost:80");
    133   UrlList names;
    134   names.push_back(localhost);
    135 
    136   testing_master->ResolveList(names, UrlInfo::PAGE_SCAN_MOTIVATED);
    137 
    138   MessageLoop::current()->PostDelayedTask(FROM_HERE,
    139                                           new MessageLoop::QuitTask(), 500);
    140   MessageLoop::current()->Run();
    141 
    142   EXPECT_FALSE(testing_master->WasFound(localhost));
    143 
    144   testing_master->Shutdown();
    145 
    146   // Clean up after ourselves.
    147   resolver_proc->Signal();
    148   MessageLoop::current()->RunAllPending();
    149 }
    150 
    151 TEST_F(PredictorTest, SingleLookupTest) {
    152   scoped_refptr<Predictor> testing_master(
    153       new Predictor(host_resolver_.get(),
    154                     default_max_queueing_delay_,
    155                     PredictorInit::kMaxSpeculativeParallelResolves,
    156                     false));
    157 
    158   GURL goog("http://www.google.com:80");
    159 
    160   UrlList names;
    161   names.push_back(goog);
    162 
    163   // Try to flood the predictor with many concurrent requests.
    164   for (int i = 0; i < 10; i++)
    165     testing_master->ResolveList(names, UrlInfo::PAGE_SCAN_MOTIVATED);
    166 
    167   WaitForResolution(testing_master, names);
    168 
    169   EXPECT_TRUE(testing_master->WasFound(goog));
    170 
    171   MessageLoop::current()->RunAllPending();
    172 
    173   EXPECT_GT(testing_master->peak_pending_lookups(), names.size() / 2);
    174   EXPECT_LE(testing_master->peak_pending_lookups(), names.size());
    175   EXPECT_LE(testing_master->peak_pending_lookups(),
    176             testing_master->max_concurrent_dns_lookups());
    177 
    178   testing_master->Shutdown();
    179 }
    180 
    181 TEST_F(PredictorTest, ConcurrentLookupTest) {
    182   host_resolver_->rules()->AddSimulatedFailure("*.notfound");
    183 
    184   scoped_refptr<Predictor> testing_master(
    185       new Predictor(host_resolver_.get(),
    186                     default_max_queueing_delay_,
    187                     PredictorInit::kMaxSpeculativeParallelResolves,
    188                     false));
    189 
    190   GURL goog("http://www.google.com:80"),
    191       goog2("http://gmail.google.com.com:80"),
    192       goog3("http://mail.google.com:80"),
    193       goog4("http://gmail.com:80");
    194   GURL bad1("http://bad1.notfound:80"),
    195       bad2("http://bad2.notfound:80");
    196 
    197   UrlList names;
    198   names.push_back(goog);
    199   names.push_back(goog3);
    200   names.push_back(bad1);
    201   names.push_back(goog2);
    202   names.push_back(bad2);
    203   names.push_back(goog4);
    204   names.push_back(goog);
    205 
    206   // Try to flood the predictor with many concurrent requests.
    207   for (int i = 0; i < 10; i++)
    208     testing_master->ResolveList(names, UrlInfo::PAGE_SCAN_MOTIVATED);
    209 
    210   WaitForResolution(testing_master, names);
    211 
    212   EXPECT_TRUE(testing_master->WasFound(goog));
    213   EXPECT_TRUE(testing_master->WasFound(goog3));
    214   EXPECT_TRUE(testing_master->WasFound(goog2));
    215   EXPECT_TRUE(testing_master->WasFound(goog4));
    216   EXPECT_FALSE(testing_master->WasFound(bad1));
    217   EXPECT_FALSE(testing_master->WasFound(bad2));
    218 
    219   MessageLoop::current()->RunAllPending();
    220 
    221   EXPECT_FALSE(testing_master->WasFound(bad1));
    222   EXPECT_FALSE(testing_master->WasFound(bad2));
    223 
    224   EXPECT_LE(testing_master->peak_pending_lookups(), names.size());
    225   EXPECT_LE(testing_master->peak_pending_lookups(),
    226             testing_master->max_concurrent_dns_lookups());
    227 
    228   testing_master->Shutdown();
    229 }
    230 
    231 TEST_F(PredictorTest, MassiveConcurrentLookupTest) {
    232   host_resolver_->rules()->AddSimulatedFailure("*.notfound");
    233 
    234   scoped_refptr<Predictor> testing_master(
    235       new Predictor(host_resolver_.get(),
    236                     default_max_queueing_delay_,
    237                     PredictorInit::kMaxSpeculativeParallelResolves,
    238                     false));
    239 
    240   UrlList names;
    241   for (int i = 0; i < 100; i++)
    242     names.push_back(GURL(
    243         "http://host" + base::IntToString(i) + ".notfound:80"));
    244 
    245   // Try to flood the predictor with many concurrent requests.
    246   for (int i = 0; i < 10; i++)
    247     testing_master->ResolveList(names, UrlInfo::PAGE_SCAN_MOTIVATED);
    248 
    249   WaitForResolution(testing_master, names);
    250 
    251   MessageLoop::current()->RunAllPending();
    252 
    253   EXPECT_LE(testing_master->peak_pending_lookups(), names.size());
    254   EXPECT_LE(testing_master->peak_pending_lookups(),
    255             testing_master->max_concurrent_dns_lookups());
    256 
    257   testing_master->Shutdown();
    258 }
    259 
    260 //------------------------------------------------------------------------------
    261 // Functions to help synthesize and test serializations of subresource referrer
    262 // lists.
    263 
    264 // Return a motivation_list if we can find one for the given motivating_host (or
    265 // NULL if a match is not found).
    266 static ListValue* FindSerializationMotivation(
    267     const GURL& motivation, const ListValue& referral_list) {
    268   CHECK_LT(0u, referral_list.GetSize());  // Room for version.
    269   int format_version = -1;
    270   CHECK(referral_list.GetInteger(0, &format_version));
    271   CHECK_EQ(Predictor::PREDICTOR_REFERRER_VERSION, format_version);
    272   ListValue* motivation_list(NULL);
    273   for (size_t i = 1; i < referral_list.GetSize(); ++i) {
    274     referral_list.GetList(i, &motivation_list);
    275     std::string existing_spec;
    276     EXPECT_TRUE(motivation_list->GetString(0, &existing_spec));
    277     if (motivation == GURL(existing_spec))
    278       return motivation_list;
    279   }
    280   return NULL;
    281 }
    282 
    283 // Create a new empty serialization list.
    284 static ListValue* NewEmptySerializationList() {
    285   ListValue* list = new ListValue;
    286   list->Append(new FundamentalValue(Predictor::PREDICTOR_REFERRER_VERSION));
    287   return list;
    288 }
    289 
    290 // Add a motivating_url and a subresource_url to a serialized list, using
    291 // this given latency. This is a helper function for quickly building these
    292 // lists.
    293 static void AddToSerializedList(const GURL& motivation,
    294                                 const GURL& subresource,
    295                                 double use_rate,
    296                                 ListValue* referral_list ) {
    297   // Find the motivation if it is already used.
    298   ListValue* motivation_list = FindSerializationMotivation(motivation,
    299                                                            *referral_list);
    300   if (!motivation_list) {
    301     // This is the first mention of this motivation, so build a list.
    302     motivation_list = new ListValue;
    303     motivation_list->Append(new StringValue(motivation.spec()));
    304     // Provide empty subresource list.
    305     motivation_list->Append(new ListValue());
    306 
    307     // ...and make it part of the serialized referral_list.
    308     referral_list->Append(motivation_list);
    309   }
    310 
    311   ListValue* subresource_list(NULL);
    312   // 0 == url; 1 == subresource_list.
    313   EXPECT_TRUE(motivation_list->GetList(1, &subresource_list));
    314 
    315   // We won't bother to check for the subresource being there already.  Worst
    316   // case, during deserialization, the latency value we supply plus the
    317   // existing value(s) will be added to the referrer.
    318 
    319   subresource_list->Append(new StringValue(subresource.spec()));
    320   subresource_list->Append(new FundamentalValue(use_rate));
    321 }
    322 
    323 static const int kLatencyNotFound = -1;
    324 
    325 // For a given motivation, and subresource, find what latency is currently
    326 // listed.  This assume a well formed serialization, which has at most one such
    327 // entry for any pair of names.  If no such pair is found, then return false.
    328 // Data is written into use_rate arguments.
    329 static bool GetDataFromSerialization(const GURL& motivation,
    330                                      const GURL& subresource,
    331                                      const ListValue& referral_list,
    332                                      double* use_rate) {
    333   ListValue* motivation_list = FindSerializationMotivation(motivation,
    334                                                            referral_list);
    335   if (!motivation_list)
    336     return false;
    337   ListValue* subresource_list;
    338   EXPECT_TRUE(motivation_list->GetList(1, &subresource_list));
    339   for (size_t i = 0; i < subresource_list->GetSize();) {
    340     std::string url_spec;
    341     EXPECT_TRUE(subresource_list->GetString(i++, &url_spec));
    342     EXPECT_TRUE(subresource_list->GetDouble(i++, use_rate));
    343     if (subresource == GURL(url_spec)) {
    344       return true;
    345     }
    346   }
    347   return false;
    348 }
    349 
    350 //------------------------------------------------------------------------------
    351 
    352 // Make sure nil referral lists really have no entries, and no latency listed.
    353 TEST_F(PredictorTest, ReferrerSerializationNilTest) {
    354   scoped_refptr<Predictor> predictor(
    355       new Predictor(host_resolver_.get(),
    356                     default_max_queueing_delay_,
    357                     PredictorInit::kMaxSpeculativeParallelResolves,
    358                     false));
    359   scoped_ptr<ListValue> referral_list(NewEmptySerializationList());
    360   predictor->SerializeReferrers(referral_list.get());
    361   EXPECT_EQ(1U, referral_list->GetSize());
    362   EXPECT_FALSE(GetDataFromSerialization(
    363     GURL("http://a.com:79"), GURL("http://b.com:78"),
    364       *referral_list.get(), NULL));
    365 
    366   predictor->Shutdown();
    367 }
    368 
    369 // Make sure that when a serialization list includes a value, that it can be
    370 // deserialized into the database, and can be extracted back out via
    371 // serialization without being changed.
    372 TEST_F(PredictorTest, ReferrerSerializationSingleReferrerTest) {
    373   scoped_refptr<Predictor> predictor(
    374       new Predictor(host_resolver_.get(),
    375                     default_max_queueing_delay_,
    376                     PredictorInit::kMaxSpeculativeParallelResolves,
    377                     false));
    378   const GURL motivation_url("http://www.google.com:91");
    379   const GURL subresource_url("http://icons.google.com:90");
    380   const double kUseRate = 23.4;
    381   scoped_ptr<ListValue> referral_list(NewEmptySerializationList());
    382 
    383   AddToSerializedList(motivation_url, subresource_url,
    384       kUseRate, referral_list.get());
    385 
    386   predictor->DeserializeReferrers(*referral_list.get());
    387 
    388   ListValue recovered_referral_list;
    389   predictor->SerializeReferrers(&recovered_referral_list);
    390   EXPECT_EQ(2U, recovered_referral_list.GetSize());
    391   double rate;
    392   EXPECT_TRUE(GetDataFromSerialization(
    393       motivation_url, subresource_url, recovered_referral_list, &rate));
    394   EXPECT_EQ(rate, kUseRate);
    395 
    396   predictor->Shutdown();
    397 }
    398 
    399 // Verify that two floats are within 1% of each other in value.
    400 #define EXPECT_SIMILAR(a, b) do { \
    401     double espilon_ratio = 1.01;  \
    402     if ((a) < 0.)  \
    403       espilon_ratio = 1 / espilon_ratio;  \
    404     EXPECT_LT(a, espilon_ratio * (b));   \
    405     EXPECT_GT((a) * espilon_ratio, b);   \
    406     } while (0)
    407 
    408 
    409 // Make sure the Trim() functionality works as expected.
    410 TEST_F(PredictorTest, ReferrerSerializationTrimTest) {
    411   scoped_refptr<Predictor> predictor(
    412       new Predictor(host_resolver_.get(),
    413                     default_max_queueing_delay_,
    414                     PredictorInit::kMaxSpeculativeParallelResolves,
    415                     false));
    416   GURL motivation_url("http://www.google.com:110");
    417 
    418   GURL icon_subresource_url("http://icons.google.com:111");
    419   const double kRateIcon = 16.0 * Predictor::kDiscardableExpectedValue;
    420   GURL img_subresource_url("http://img.google.com:118");
    421   const double kRateImg = 8.0 * Predictor::kDiscardableExpectedValue;
    422 
    423   scoped_ptr<ListValue> referral_list(NewEmptySerializationList());
    424   AddToSerializedList(
    425       motivation_url, icon_subresource_url, kRateIcon, referral_list.get());
    426   AddToSerializedList(
    427       motivation_url, img_subresource_url, kRateImg, referral_list.get());
    428 
    429   predictor->DeserializeReferrers(*referral_list.get());
    430 
    431   ListValue recovered_referral_list;
    432   predictor->SerializeReferrers(&recovered_referral_list);
    433   EXPECT_EQ(2U, recovered_referral_list.GetSize());
    434   double rate;
    435   EXPECT_TRUE(GetDataFromSerialization(
    436       motivation_url, icon_subresource_url, recovered_referral_list,
    437       &rate));
    438   EXPECT_SIMILAR(rate, kRateIcon);
    439 
    440   EXPECT_TRUE(GetDataFromSerialization(
    441       motivation_url, img_subresource_url, recovered_referral_list, &rate));
    442   EXPECT_SIMILAR(rate, kRateImg);
    443 
    444   // Each time we Trim 24 times, the user_rate figures should reduce by a factor
    445   // of two,  until they are small, and then a trim will delete the whole entry.
    446   for (int i = 0; i < 24; ++i)
    447     predictor->TrimReferrersNow();
    448   predictor->SerializeReferrers(&recovered_referral_list);
    449   EXPECT_EQ(2U, recovered_referral_list.GetSize());
    450   EXPECT_TRUE(GetDataFromSerialization(
    451       motivation_url, icon_subresource_url, recovered_referral_list, &rate));
    452   EXPECT_SIMILAR(rate, kRateIcon / 2);
    453 
    454   EXPECT_TRUE(GetDataFromSerialization(
    455       motivation_url, img_subresource_url, recovered_referral_list, &rate));
    456   EXPECT_SIMILAR(rate, kRateImg / 2);
    457 
    458   for (int i = 0; i < 24; ++i)
    459     predictor->TrimReferrersNow();
    460   predictor->SerializeReferrers(&recovered_referral_list);
    461   EXPECT_EQ(2U, recovered_referral_list.GetSize());
    462   EXPECT_TRUE(GetDataFromSerialization(
    463       motivation_url, icon_subresource_url, recovered_referral_list, &rate));
    464   EXPECT_SIMILAR(rate, kRateIcon / 4);
    465   EXPECT_TRUE(GetDataFromSerialization(
    466       motivation_url, img_subresource_url, recovered_referral_list, &rate));
    467   EXPECT_SIMILAR(rate, kRateImg / 4);
    468 
    469   for (int i = 0; i < 24; ++i)
    470     predictor->TrimReferrersNow();
    471   predictor->SerializeReferrers(&recovered_referral_list);
    472   EXPECT_EQ(2U, recovered_referral_list.GetSize());
    473   EXPECT_TRUE(GetDataFromSerialization(
    474       motivation_url, icon_subresource_url, recovered_referral_list, &rate));
    475   EXPECT_SIMILAR(rate, kRateIcon / 8);
    476 
    477   // Img is below threshold, and so it gets deleted.
    478   EXPECT_FALSE(GetDataFromSerialization(
    479       motivation_url, img_subresource_url, recovered_referral_list, &rate));
    480 
    481   for (int i = 0; i < 24; ++i)
    482     predictor->TrimReferrersNow();
    483   predictor->SerializeReferrers(&recovered_referral_list);
    484   // Icon is also trimmed away, so entire set gets discarded.
    485   EXPECT_EQ(1U, recovered_referral_list.GetSize());
    486   EXPECT_FALSE(GetDataFromSerialization(
    487       motivation_url, icon_subresource_url, recovered_referral_list, &rate));
    488   EXPECT_FALSE(GetDataFromSerialization(
    489       motivation_url, img_subresource_url, recovered_referral_list, &rate));
    490 
    491   predictor->Shutdown();
    492 }
    493 
    494 
    495 TEST_F(PredictorTest, PriorityQueuePushPopTest) {
    496   Predictor::HostNameQueue queue;
    497 
    498   GURL first("http://first:80"), second("http://second:90");
    499 
    500   // First check high priority queue FIFO functionality.
    501   EXPECT_TRUE(queue.IsEmpty());
    502   queue.Push(first, UrlInfo::LEARNED_REFERAL_MOTIVATED);
    503   EXPECT_FALSE(queue.IsEmpty());
    504   queue.Push(second, UrlInfo::MOUSE_OVER_MOTIVATED);
    505   EXPECT_FALSE(queue.IsEmpty());
    506   EXPECT_EQ(queue.Pop(), first);
    507   EXPECT_FALSE(queue.IsEmpty());
    508   EXPECT_EQ(queue.Pop(), second);
    509   EXPECT_TRUE(queue.IsEmpty());
    510 
    511   // Then check low priority queue FIFO functionality.
    512   queue.Push(first, UrlInfo::PAGE_SCAN_MOTIVATED);
    513   EXPECT_FALSE(queue.IsEmpty());
    514   queue.Push(second, UrlInfo::OMNIBOX_MOTIVATED);
    515   EXPECT_FALSE(queue.IsEmpty());
    516   EXPECT_EQ(queue.Pop(), first);
    517   EXPECT_FALSE(queue.IsEmpty());
    518   EXPECT_EQ(queue.Pop(), second);
    519   EXPECT_TRUE(queue.IsEmpty());
    520 }
    521 
    522 TEST_F(PredictorTest, PriorityQueueReorderTest) {
    523   Predictor::HostNameQueue queue;
    524 
    525   // Push all the low priority items.
    526   GURL low1("http://low1:80"),
    527       low2("http://low2:80"),
    528       low3("http://low3:443"),
    529       low4("http://low4:80"),
    530       low5("http://low5:80"),
    531       hi1("http://hi1:80"),
    532       hi2("http://hi2:80"),
    533       hi3("http://hi3:80");
    534 
    535   EXPECT_TRUE(queue.IsEmpty());
    536   queue.Push(low1, UrlInfo::PAGE_SCAN_MOTIVATED);
    537   queue.Push(low2, UrlInfo::UNIT_TEST_MOTIVATED);
    538   queue.Push(low3, UrlInfo::LINKED_MAX_MOTIVATED);
    539   queue.Push(low4, UrlInfo::OMNIBOX_MOTIVATED);
    540   queue.Push(low5, UrlInfo::STARTUP_LIST_MOTIVATED);
    541   queue.Push(low4, UrlInfo::OMNIBOX_MOTIVATED);
    542 
    543   // Push all the high prority items
    544   queue.Push(hi1, UrlInfo::LEARNED_REFERAL_MOTIVATED);
    545   queue.Push(hi2, UrlInfo::STATIC_REFERAL_MOTIVATED);
    546   queue.Push(hi3, UrlInfo::MOUSE_OVER_MOTIVATED);
    547 
    548   // Check that high priority stuff comes out first, and in FIFO order.
    549   EXPECT_EQ(queue.Pop(), hi1);
    550   EXPECT_EQ(queue.Pop(), hi2);
    551   EXPECT_EQ(queue.Pop(), hi3);
    552 
    553   // ...and then low priority strings.
    554   EXPECT_EQ(queue.Pop(), low1);
    555   EXPECT_EQ(queue.Pop(), low2);
    556   EXPECT_EQ(queue.Pop(), low3);
    557   EXPECT_EQ(queue.Pop(), low4);
    558   EXPECT_EQ(queue.Pop(), low5);
    559   EXPECT_EQ(queue.Pop(), low4);
    560 
    561   EXPECT_TRUE(queue.IsEmpty());
    562 }
    563 
    564 TEST_F(PredictorTest, CanonicalizeUrl) {
    565   // Base case, only handles HTTP and HTTPS.
    566   EXPECT_EQ(GURL(), Predictor::CanonicalizeUrl(GURL("ftp://anything")));
    567 
    568   // Remove path testing.
    569   GURL long_url("http://host:999/path?query=value");
    570   EXPECT_EQ(Predictor::CanonicalizeUrl(long_url), long_url.GetWithEmptyPath());
    571 
    572   // Default port cannoncalization.
    573   GURL implied_port("http://test");
    574   GURL explicit_port("http://test:80");
    575   EXPECT_EQ(Predictor::CanonicalizeUrl(implied_port),
    576             Predictor::CanonicalizeUrl(explicit_port));
    577 
    578   // Port is still maintained.
    579   GURL port_80("http://test:80");
    580   GURL port_90("http://test:90");
    581   EXPECT_NE(Predictor::CanonicalizeUrl(port_80),
    582             Predictor::CanonicalizeUrl(port_90));
    583 
    584   // Host is still maintained.
    585   GURL host_1("http://test_1");
    586   GURL host_2("http://test_2");
    587   EXPECT_NE(Predictor::CanonicalizeUrl(host_1),
    588             Predictor::CanonicalizeUrl(host_2));
    589 
    590   // Scheme is maintained (mismatch identified).
    591   GURL http("http://test");
    592   GURL https("https://test");
    593   EXPECT_NE(Predictor::CanonicalizeUrl(http),
    594             Predictor::CanonicalizeUrl(https));
    595 
    596   // Https works fine.
    597   GURL long_https("https://host:999/path?query=value");
    598   EXPECT_EQ(Predictor::CanonicalizeUrl(long_https),
    599             long_https.GetWithEmptyPath());
    600 }
    601 
    602 TEST_F(PredictorTest, DiscardPredictorResults) {
    603   scoped_refptr<Predictor> predictor(
    604       new Predictor(host_resolver_.get(),
    605                     default_max_queueing_delay_,
    606                     PredictorInit::kMaxSpeculativeParallelResolves,
    607                     false));
    608   ListValue referral_list;
    609   predictor->SerializeReferrers(&referral_list);
    610   EXPECT_EQ(1U, referral_list.GetSize());
    611 
    612   GURL host_1("http://test_1");
    613   GURL host_2("http://test_2");
    614   predictor->LearnFromNavigation(host_1, host_2);
    615 
    616   predictor->SerializeReferrers(&referral_list);
    617   EXPECT_EQ(2U, referral_list.GetSize());
    618 
    619   predictor->DiscardAllResults();
    620   predictor->SerializeReferrers(&referral_list);
    621   EXPECT_EQ(1U, referral_list.GetSize());
    622 
    623   predictor->Shutdown();
    624 }
    625 
    626 }  // namespace chrome_browser_net
    627