- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / net / predictor_unittest.cc
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 // For a given motivation, and subresource, find what latency is currently
316 // listed.  This assume a well formed serialization, which has at most one such
317 // entry for any pair of names.  If no such pair is found, then return false.
318 // Data is written into use_rate arguments.
319 static bool GetDataFromSerialization(const GURL& motivation,
320                                      const GURL& subresource,
321                                      const ListValue& referral_list,
322                                      double* use_rate) {
323   const ListValue* motivation_list =
324       FindSerializationMotivation(motivation, &referral_list);
325   if (!motivation_list)
326     return false;
327   const ListValue* subresource_list;
328   EXPECT_TRUE(motivation_list->GetList(1, &subresource_list));
329   for (size_t i = 0; i < subresource_list->GetSize();) {
330     std::string url_spec;
331     EXPECT_TRUE(subresource_list->GetString(i++, &url_spec));
332     EXPECT_TRUE(subresource_list->GetDouble(i++, use_rate));
333     if (subresource == GURL(url_spec)) {
334       return true;
335     }
336   }
337   return false;
338 }
339
340 //------------------------------------------------------------------------------
341
342 // Make sure nil referral lists really have no entries, and no latency listed.
343 TEST_F(PredictorTest, ReferrerSerializationNilTest) {
344   Predictor predictor(true);
345   predictor.SetHostResolver(host_resolver_.get());
346
347   scoped_ptr<ListValue> referral_list(NewEmptySerializationList());
348   predictor.SerializeReferrers(referral_list.get());
349   EXPECT_EQ(1U, referral_list->GetSize());
350   EXPECT_FALSE(GetDataFromSerialization(
351     GURL("http://a.com:79"), GURL("http://b.com:78"),
352       *referral_list.get(), NULL));
353
354   predictor.Shutdown();
355 }
356
357 // Make sure that when a serialization list includes a value, that it can be
358 // deserialized into the database, and can be extracted back out via
359 // serialization without being changed.
360 TEST_F(PredictorTest, ReferrerSerializationSingleReferrerTest) {
361   Predictor predictor(true);
362   predictor.SetHostResolver(host_resolver_.get());
363   const GURL motivation_url("http://www.google.com:91");
364   const GURL subresource_url("http://icons.google.com:90");
365   const double kUseRate = 23.4;
366   scoped_ptr<ListValue> referral_list(NewEmptySerializationList());
367
368   AddToSerializedList(motivation_url, subresource_url,
369       kUseRate, referral_list.get());
370
371   predictor.DeserializeReferrers(*referral_list.get());
372
373   ListValue recovered_referral_list;
374   predictor.SerializeReferrers(&recovered_referral_list);
375   EXPECT_EQ(2U, recovered_referral_list.GetSize());
376   double rate;
377   EXPECT_TRUE(GetDataFromSerialization(
378       motivation_url, subresource_url, recovered_referral_list, &rate));
379   EXPECT_EQ(rate, kUseRate);
380
381   predictor.Shutdown();
382 }
383
384 // Check that GetHtmlReferrerLists() doesn't crash when given duplicated
385 // domains for referring URL, and that it sorts the results in the
386 // correct order.
387 TEST_F(PredictorTest, GetHtmlReferrerLists) {
388   Predictor predictor(true);
389   predictor.SetHostResolver(host_resolver_.get());
390   const double kUseRate = 23.4;
391   scoped_ptr<ListValue> referral_list(NewEmptySerializationList());
392
393   AddToSerializedList(
394       GURL("http://d.google.com/x1"),
395       GURL("http://foo.com/"),
396       kUseRate, referral_list.get());
397
398   // Duplicated hostname (d.google.com). This should not cause any crashes
399   // (i.e. crbug.com/116345)
400   AddToSerializedList(
401       GURL("http://d.google.com/x2"),
402       GURL("http://foo.com/"),
403       kUseRate, referral_list.get());
404
405   AddToSerializedList(
406       GURL("http://a.yahoo.com/y"),
407       GURL("http://foo1.com/"),
408       kUseRate, referral_list.get());
409
410   AddToSerializedList(
411       GURL("http://b.google.com/x3"),
412       GURL("http://foo2.com/"),
413       kUseRate, referral_list.get());
414
415   AddToSerializedList(
416       GURL("http://d.yahoo.com/x5"),
417       GURL("http://i.like.turtles/"),
418       kUseRate, referral_list.get());
419
420   AddToSerializedList(
421       GURL("http://c.yahoo.com/x4"),
422       GURL("http://foo3.com/"),
423       kUseRate, referral_list.get());
424
425   predictor.DeserializeReferrers(*referral_list.get());
426
427   std::string html;
428   predictor.GetHtmlReferrerLists(&html);
429
430   // The lexicographic sorting of hostnames would be:
431   //   a.yahoo.com
432   //   b.google.com
433   //   c.yahoo.com
434   //   d.google.com
435   //   d.yahoo.com
436   //
437   // However we expect to sort them by domain in the output:
438   //   b.google.com
439   //   d.google.com
440   //   a.yahoo.com
441   //   c.yahoo.com
442   //   d.yahoo.com
443
444   size_t pos[] = {
445       html.find("<td rowspan=1>http://b.google.com/x3"),
446       html.find("<td rowspan=1>http://d.google.com/x1"),
447       html.find("<td rowspan=1>http://d.google.com/x2"),
448       html.find("<td rowspan=1>http://a.yahoo.com/y"),
449       html.find("<td rowspan=1>http://c.yahoo.com/x4"),
450       html.find("<td rowspan=1>http://d.yahoo.com/x5"),
451   };
452
453   // Make sure things appeared in the expected order.
454   for (size_t i = 1; i < arraysize(pos); ++i) {
455     EXPECT_LT(pos[i - 1], pos[i]) << "Mismatch for pos[" << i << "]";
456   }
457
458   predictor.Shutdown();
459 }
460
461 // Verify that two floats are within 1% of each other in value.
462 #define EXPECT_SIMILAR(a, b) do { \
463     double espilon_ratio = 1.01;  \
464     if ((a) < 0.)  \
465       espilon_ratio = 1 / espilon_ratio;  \
466     EXPECT_LT(a, espilon_ratio * (b));   \
467     EXPECT_GT((a) * espilon_ratio, b);   \
468     } while (0)
469
470
471 // Make sure the Trim() functionality works as expected.
472 TEST_F(PredictorTest, ReferrerSerializationTrimTest) {
473   Predictor predictor(true);
474   predictor.SetHostResolver(host_resolver_.get());
475   GURL motivation_url("http://www.google.com:110");
476
477   GURL icon_subresource_url("http://icons.google.com:111");
478   const double kRateIcon = 16.0 * Predictor::kDiscardableExpectedValue;
479   GURL img_subresource_url("http://img.google.com:118");
480   const double kRateImg = 8.0 * Predictor::kDiscardableExpectedValue;
481
482   scoped_ptr<ListValue> referral_list(NewEmptySerializationList());
483   AddToSerializedList(
484       motivation_url, icon_subresource_url, kRateIcon, referral_list.get());
485   AddToSerializedList(
486       motivation_url, img_subresource_url, kRateImg, referral_list.get());
487
488   predictor.DeserializeReferrers(*referral_list.get());
489
490   ListValue recovered_referral_list;
491   predictor.SerializeReferrers(&recovered_referral_list);
492   EXPECT_EQ(2U, recovered_referral_list.GetSize());
493   double rate;
494   EXPECT_TRUE(GetDataFromSerialization(
495       motivation_url, icon_subresource_url, recovered_referral_list,
496       &rate));
497   EXPECT_SIMILAR(rate, kRateIcon);
498
499   EXPECT_TRUE(GetDataFromSerialization(
500       motivation_url, img_subresource_url, recovered_referral_list, &rate));
501   EXPECT_SIMILAR(rate, kRateImg);
502
503   // Each time we Trim 24 times, the user_rate figures should reduce by a factor
504   // of two,  until they are small, and then a trim will delete the whole entry.
505   for (int i = 0; i < 24; ++i)
506     predictor.TrimReferrersNow();
507   predictor.SerializeReferrers(&recovered_referral_list);
508   EXPECT_EQ(2U, recovered_referral_list.GetSize());
509   EXPECT_TRUE(GetDataFromSerialization(
510       motivation_url, icon_subresource_url, recovered_referral_list, &rate));
511   EXPECT_SIMILAR(rate, kRateIcon / 2);
512
513   EXPECT_TRUE(GetDataFromSerialization(
514       motivation_url, img_subresource_url, recovered_referral_list, &rate));
515   EXPECT_SIMILAR(rate, kRateImg / 2);
516
517   for (int i = 0; i < 24; ++i)
518     predictor.TrimReferrersNow();
519   predictor.SerializeReferrers(&recovered_referral_list);
520   EXPECT_EQ(2U, recovered_referral_list.GetSize());
521   EXPECT_TRUE(GetDataFromSerialization(
522       motivation_url, icon_subresource_url, recovered_referral_list, &rate));
523   EXPECT_SIMILAR(rate, kRateIcon / 4);
524   EXPECT_TRUE(GetDataFromSerialization(
525       motivation_url, img_subresource_url, recovered_referral_list, &rate));
526   EXPECT_SIMILAR(rate, kRateImg / 4);
527
528   for (int i = 0; i < 24; ++i)
529     predictor.TrimReferrersNow();
530   predictor.SerializeReferrers(&recovered_referral_list);
531   EXPECT_EQ(2U, recovered_referral_list.GetSize());
532   EXPECT_TRUE(GetDataFromSerialization(
533       motivation_url, icon_subresource_url, recovered_referral_list, &rate));
534   EXPECT_SIMILAR(rate, kRateIcon / 8);
535
536   // Img is below threshold, and so it gets deleted.
537   EXPECT_FALSE(GetDataFromSerialization(
538       motivation_url, img_subresource_url, recovered_referral_list, &rate));
539
540   for (int i = 0; i < 24; ++i)
541     predictor.TrimReferrersNow();
542   predictor.SerializeReferrers(&recovered_referral_list);
543   // Icon is also trimmed away, so entire set gets discarded.
544   EXPECT_EQ(1U, recovered_referral_list.GetSize());
545   EXPECT_FALSE(GetDataFromSerialization(
546       motivation_url, icon_subresource_url, recovered_referral_list, &rate));
547   EXPECT_FALSE(GetDataFromSerialization(
548       motivation_url, img_subresource_url, recovered_referral_list, &rate));
549
550   predictor.Shutdown();
551 }
552
553
554 TEST_F(PredictorTest, PriorityQueuePushPopTest) {
555   Predictor::HostNameQueue queue;
556
557   GURL first("http://first:80"), second("http://second:90");
558
559   // First check high priority queue FIFO functionality.
560   EXPECT_TRUE(queue.IsEmpty());
561   queue.Push(first, UrlInfo::LEARNED_REFERAL_MOTIVATED);
562   EXPECT_FALSE(queue.IsEmpty());
563   queue.Push(second, UrlInfo::MOUSE_OVER_MOTIVATED);
564   EXPECT_FALSE(queue.IsEmpty());
565   EXPECT_EQ(queue.Pop(), first);
566   EXPECT_FALSE(queue.IsEmpty());
567   EXPECT_EQ(queue.Pop(), second);
568   EXPECT_TRUE(queue.IsEmpty());
569
570   // Then check low priority queue FIFO functionality.
571   queue.Push(first, UrlInfo::PAGE_SCAN_MOTIVATED);
572   EXPECT_FALSE(queue.IsEmpty());
573   queue.Push(second, UrlInfo::OMNIBOX_MOTIVATED);
574   EXPECT_FALSE(queue.IsEmpty());
575   EXPECT_EQ(queue.Pop(), first);
576   EXPECT_FALSE(queue.IsEmpty());
577   EXPECT_EQ(queue.Pop(), second);
578   EXPECT_TRUE(queue.IsEmpty());
579 }
580
581 TEST_F(PredictorTest, PriorityQueueReorderTest) {
582   Predictor::HostNameQueue queue;
583
584   // Push all the low priority items.
585   GURL low1("http://low1:80"),
586       low2("http://low2:80"),
587       low3("http://low3:443"),
588       low4("http://low4:80"),
589       low5("http://low5:80"),
590       hi1("http://hi1:80"),
591       hi2("http://hi2:80"),
592       hi3("http://hi3:80");
593
594   EXPECT_TRUE(queue.IsEmpty());
595   queue.Push(low1, UrlInfo::PAGE_SCAN_MOTIVATED);
596   queue.Push(low2, UrlInfo::UNIT_TEST_MOTIVATED);
597   queue.Push(low3, UrlInfo::LINKED_MAX_MOTIVATED);
598   queue.Push(low4, UrlInfo::OMNIBOX_MOTIVATED);
599   queue.Push(low5, UrlInfo::STARTUP_LIST_MOTIVATED);
600   queue.Push(low4, UrlInfo::OMNIBOX_MOTIVATED);
601
602   // Push all the high prority items
603   queue.Push(hi1, UrlInfo::LEARNED_REFERAL_MOTIVATED);
604   queue.Push(hi2, UrlInfo::STATIC_REFERAL_MOTIVATED);
605   queue.Push(hi3, UrlInfo::MOUSE_OVER_MOTIVATED);
606
607   // Check that high priority stuff comes out first, and in FIFO order.
608   EXPECT_EQ(queue.Pop(), hi1);
609   EXPECT_EQ(queue.Pop(), hi2);
610   EXPECT_EQ(queue.Pop(), hi3);
611
612   // ...and then low priority strings.
613   EXPECT_EQ(queue.Pop(), low1);
614   EXPECT_EQ(queue.Pop(), low2);
615   EXPECT_EQ(queue.Pop(), low3);
616   EXPECT_EQ(queue.Pop(), low4);
617   EXPECT_EQ(queue.Pop(), low5);
618   EXPECT_EQ(queue.Pop(), low4);
619
620   EXPECT_TRUE(queue.IsEmpty());
621 }
622
623 TEST_F(PredictorTest, CanonicalizeUrl) {
624   // Base case, only handles HTTP and HTTPS.
625   EXPECT_EQ(GURL(), Predictor::CanonicalizeUrl(GURL("ftp://anything")));
626
627   // Remove path testing.
628   GURL long_url("http://host:999/path?query=value");
629   EXPECT_EQ(Predictor::CanonicalizeUrl(long_url), long_url.GetWithEmptyPath());
630
631   // Default port cannoncalization.
632   GURL implied_port("http://test");
633   GURL explicit_port("http://test:80");
634   EXPECT_EQ(Predictor::CanonicalizeUrl(implied_port),
635             Predictor::CanonicalizeUrl(explicit_port));
636
637   // Port is still maintained.
638   GURL port_80("http://test:80");
639   GURL port_90("http://test:90");
640   EXPECT_NE(Predictor::CanonicalizeUrl(port_80),
641             Predictor::CanonicalizeUrl(port_90));
642
643   // Host is still maintained.
644   GURL host_1("http://test_1");
645   GURL host_2("http://test_2");
646   EXPECT_NE(Predictor::CanonicalizeUrl(host_1),
647             Predictor::CanonicalizeUrl(host_2));
648
649   // Scheme is maintained (mismatch identified).
650   GURL http("http://test");
651   GURL https("https://test");
652   EXPECT_NE(Predictor::CanonicalizeUrl(http),
653             Predictor::CanonicalizeUrl(https));
654
655   // Https works fine.
656   GURL long_https("https://host:999/path?query=value");
657   EXPECT_EQ(Predictor::CanonicalizeUrl(long_https),
658             long_https.GetWithEmptyPath());
659 }
660
661 TEST_F(PredictorTest, DiscardPredictorResults) {
662   Predictor predictor(true);
663   predictor.SetHostResolver(host_resolver_.get());
664   ListValue referral_list;
665   predictor.SerializeReferrers(&referral_list);
666   EXPECT_EQ(1U, referral_list.GetSize());
667
668   GURL host_1("http://test_1");
669   GURL host_2("http://test_2");
670   predictor.LearnFromNavigation(host_1, host_2);
671
672   predictor.SerializeReferrers(&referral_list);
673   EXPECT_EQ(2U, referral_list.GetSize());
674
675   predictor.DiscardAllResults();
676   predictor.SerializeReferrers(&referral_list);
677   EXPECT_EQ(1U, referral_list.GetSize());
678
679   predictor.Shutdown();
680 }
681
682 }  // namespace chrome_browser_net