• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
WaitForResolutionHelper(Predictor * predictor,const UrlList & hosts,HelperTimer * timer)36   WaitForResolutionHelper(Predictor* predictor, const UrlList& hosts,
37                           HelperTimer* timer)
38       : predictor_(predictor),
39         hosts_(hosts),
40         timer_(timer) {
41   }
42 
Run()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:
PredictorTest()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:
SetUp()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 
WaitForResolution(Predictor * predictor,const UrlList & hosts)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 
TEST_F(PredictorTest,StartupShutdownTest)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 
TEST_F(PredictorTest,ShutdownWhenResolutionIsPendingTest)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 
TEST_F(PredictorTest,SingleLookupTest)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 
TEST_F(PredictorTest,ConcurrentLookupTest)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 
TEST_F(PredictorTest,MassiveConcurrentLookupTest)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).
FindSerializationMotivation(const GURL & motivation,const ListValue & referral_list)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.
NewEmptySerializationList()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.
AddToSerializedList(const GURL & motivation,const GURL & subresource,double use_rate,ListValue * referral_list)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.
GetDataFromSerialization(const GURL & motivation,const GURL & subresource,const ListValue & referral_list,double * use_rate)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.
TEST_F(PredictorTest,ReferrerSerializationNilTest)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.
TEST_F(PredictorTest,ReferrerSerializationSingleReferrerTest)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.
TEST_F(PredictorTest,ReferrerSerializationTrimTest)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 
TEST_F(PredictorTest,PriorityQueuePushPopTest)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 
TEST_F(PredictorTest,PriorityQueueReorderTest)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 
TEST_F(PredictorTest,CanonicalizeUrl)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 
TEST_F(PredictorTest,DiscardPredictorResults)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