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