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.
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/spdyproxy/proxy_advisor.h"
18 #include "chrome/browser/net/url_info.h"
19 #include "chrome/common/net/predictor_common.h"
20 #include "content/public/test/test_browser_thread.h"
21 #include "net/base/address_list.h"
22 #include "net/base/winsock_init.h"
23 #include "net/dns/mock_host_resolver.h"
24 #include "testing/gmock/include/gmock/gmock.h"
25 #include "testing/gtest/include/gtest/gtest.h"
28 using base::TimeDelta
;
29 using content::BrowserThread
;
31 namespace chrome_browser_net
{
33 class WaitForResolutionHelper
;
35 typedef base::RepeatingTimer
<WaitForResolutionHelper
> HelperTimer
;
37 class WaitForResolutionHelper
{
39 WaitForResolutionHelper(Predictor
* predictor
, const UrlList
& hosts
,
40 HelperTimer
* timer
, int checks_until_quit
)
41 : predictor_(predictor
),
44 checks_until_quit_(checks_until_quit
) {
47 void CheckIfResolutionsDone() {
48 if (--checks_until_quit_
> 0) {
49 for (UrlList::const_iterator i
= hosts_
.begin(); i
!= hosts_
.end(); ++i
)
50 if (predictor_
->GetResolutionDuration(*i
) ==
51 UrlInfo::NullDuration())
52 return; // We don't have resolution for that host.
55 // When all hostnames have been resolved, or we've hit the limit,
58 base::MessageLoop::current()->Quit();
64 Predictor
* predictor_
;
67 int checks_until_quit_
;
70 class PredictorTest
: public testing::Test
{
73 : ui_thread_(BrowserThread::UI
, &loop_
),
74 io_thread_(BrowserThread::IO
, &loop_
),
75 host_resolver_(new net::MockCachingHostResolver()) {
79 virtual void SetUp() {
81 net::EnsureWinsockInit();
83 Predictor::set_max_parallel_resolves(
84 Predictor::kMaxSpeculativeParallelResolves
);
85 Predictor::set_max_queueing_delay(
86 Predictor::kMaxSpeculativeResolveQueueDelayMs
);
87 // Since we are using a caching HostResolver, the following latencies will
88 // only be incurred by the first request, after which the result will be
89 // cached internally by |host_resolver_|.
90 net::RuleBasedHostResolverProc
* rules
= host_resolver_
->rules();
91 rules
->AddRuleWithLatency("www.google.com", "127.0.0.1", 50);
92 rules
->AddRuleWithLatency("gmail.google.com.com", "127.0.0.1", 70);
93 rules
->AddRuleWithLatency("mail.google.com", "127.0.0.1", 44);
94 rules
->AddRuleWithLatency("gmail.com", "127.0.0.1", 63);
97 void WaitForResolution(Predictor
* predictor
, const UrlList
& hosts
) {
98 HelperTimer
* timer
= new HelperTimer();
99 // By default allow the loop to run for a minute -- 600 iterations.
100 timer
->Start(FROM_HERE
, TimeDelta::FromMilliseconds(100),
101 new WaitForResolutionHelper(predictor
, hosts
, timer
, 600),
102 &WaitForResolutionHelper::CheckIfResolutionsDone
);
103 base::MessageLoop::current()->Run();
106 void WaitForResolutionWithLimit(
107 Predictor
* predictor
, const UrlList
& hosts
, int limit
) {
108 HelperTimer
* timer
= new HelperTimer();
109 timer
->Start(FROM_HERE
, TimeDelta::FromMilliseconds(100),
110 new WaitForResolutionHelper(predictor
, hosts
, timer
, limit
),
111 &WaitForResolutionHelper::CheckIfResolutionsDone
);
112 base::MessageLoop::current()->Run();
116 // IMPORTANT: do not move this below |host_resolver_|; the host resolver
117 // must not outlive the message loop, otherwise bad things can happen
118 // (like posting to a deleted message loop).
119 base::MessageLoopForUI loop_
;
120 content::TestBrowserThread ui_thread_
;
121 content::TestBrowserThread io_thread_
;
124 scoped_ptr
<net::MockCachingHostResolver
> host_resolver_
;
127 //------------------------------------------------------------------------------
129 TEST_F(PredictorTest
, StartupShutdownTest
) {
130 Predictor
testing_master(true);
131 testing_master
.Shutdown();
135 TEST_F(PredictorTest
, ShutdownWhenResolutionIsPendingTest
) {
136 scoped_ptr
<net::HostResolver
> host_resolver(new net::HangingHostResolver());
138 Predictor
testing_master(true);
139 testing_master
.SetHostResolver(host_resolver
.get());
141 GURL
localhost("http://localhost:80");
143 names
.push_back(localhost
);
145 testing_master
.ResolveList(names
, UrlInfo::PAGE_SCAN_MOTIVATED
);
147 base::MessageLoop::current()->PostDelayedTask(
149 base::MessageLoop::QuitClosure(),
150 base::TimeDelta::FromMilliseconds(500));
151 base::MessageLoop::current()->Run();
153 EXPECT_FALSE(testing_master
.WasFound(localhost
));
155 testing_master
.Shutdown();
157 // Clean up after ourselves.
158 base::MessageLoop::current()->RunUntilIdle();
161 TEST_F(PredictorTest
, SingleLookupTest
) {
162 Predictor
testing_master(true);
163 testing_master
.SetHostResolver(host_resolver_
.get());
165 GURL
goog("http://www.google.com:80");
168 names
.push_back(goog
);
170 // Try to flood the predictor with many concurrent requests.
171 for (int i
= 0; i
< 10; i
++)
172 testing_master
.ResolveList(names
, UrlInfo::PAGE_SCAN_MOTIVATED
);
174 WaitForResolution(&testing_master
, names
);
176 EXPECT_TRUE(testing_master
.WasFound(goog
));
178 base::MessageLoop::current()->RunUntilIdle();
180 EXPECT_GT(testing_master
.peak_pending_lookups(), names
.size() / 2);
181 EXPECT_LE(testing_master
.peak_pending_lookups(), names
.size());
182 EXPECT_LE(testing_master
.peak_pending_lookups(),
183 testing_master
.max_concurrent_dns_lookups());
185 testing_master
.Shutdown();
188 TEST_F(PredictorTest
, ConcurrentLookupTest
) {
189 host_resolver_
->rules()->AddSimulatedFailure("*.notfound");
191 Predictor
testing_master(true);
192 testing_master
.SetHostResolver(host_resolver_
.get());
194 GURL
goog("http://www.google.com:80"),
195 goog2("http://gmail.google.com.com:80"),
196 goog3("http://mail.google.com:80"),
197 goog4("http://gmail.com:80");
198 GURL
bad1("http://bad1.notfound:80"),
199 bad2("http://bad2.notfound:80");
202 names
.push_back(goog
);
203 names
.push_back(goog3
);
204 names
.push_back(bad1
);
205 names
.push_back(goog2
);
206 names
.push_back(bad2
);
207 names
.push_back(goog4
);
208 names
.push_back(goog
);
210 // Try to flood the predictor with many concurrent requests.
211 for (int i
= 0; i
< 10; i
++)
212 testing_master
.ResolveList(names
, UrlInfo::PAGE_SCAN_MOTIVATED
);
214 WaitForResolution(&testing_master
, names
);
216 EXPECT_TRUE(testing_master
.WasFound(goog
));
217 EXPECT_TRUE(testing_master
.WasFound(goog3
));
218 EXPECT_TRUE(testing_master
.WasFound(goog2
));
219 EXPECT_TRUE(testing_master
.WasFound(goog4
));
220 EXPECT_FALSE(testing_master
.WasFound(bad1
));
221 EXPECT_FALSE(testing_master
.WasFound(bad2
));
223 base::MessageLoop::current()->RunUntilIdle();
225 EXPECT_FALSE(testing_master
.WasFound(bad1
));
226 EXPECT_FALSE(testing_master
.WasFound(bad2
));
228 EXPECT_LE(testing_master
.peak_pending_lookups(), names
.size());
229 EXPECT_LE(testing_master
.peak_pending_lookups(),
230 testing_master
.max_concurrent_dns_lookups());
232 testing_master
.Shutdown();
235 TEST_F(PredictorTest
, MassiveConcurrentLookupTest
) {
236 host_resolver_
->rules()->AddSimulatedFailure("*.notfound");
238 Predictor
testing_master(true);
239 testing_master
.SetHostResolver(host_resolver_
.get());
242 for (int i
= 0; i
< 100; i
++)
243 names
.push_back(GURL(
244 "http://host" + base::IntToString(i
) + ".notfound:80"));
246 // Try to flood the predictor with many concurrent requests.
247 for (int i
= 0; i
< 10; i
++)
248 testing_master
.ResolveList(names
, UrlInfo::PAGE_SCAN_MOTIVATED
);
250 WaitForResolution(&testing_master
, names
);
252 base::MessageLoop::current()->RunUntilIdle();
254 EXPECT_LE(testing_master
.peak_pending_lookups(), names
.size());
255 EXPECT_LE(testing_master
.peak_pending_lookups(),
256 testing_master
.max_concurrent_dns_lookups());
258 testing_master
.Shutdown();
261 //------------------------------------------------------------------------------
262 // Functions to help synthesize and test serializations of subresource referrer
265 // Return a motivation_list if we can find one for the given motivating_host (or
266 // NULL if a match is not found).
267 static const base::ListValue
* FindSerializationMotivation(
268 const GURL
& motivation
,
269 const base::ListValue
* referral_list
) {
270 CHECK_LT(0u, referral_list
->GetSize()); // Room for version.
271 int format_version
= -1;
272 CHECK(referral_list
->GetInteger(0, &format_version
));
273 CHECK_EQ(Predictor::kPredictorReferrerVersion
, format_version
);
274 const base::ListValue
* motivation_list(NULL
);
275 for (size_t i
= 1; i
< referral_list
->GetSize(); ++i
) {
276 referral_list
->GetList(i
, &motivation_list
);
277 std::string existing_spec
;
278 EXPECT_TRUE(motivation_list
->GetString(0, &existing_spec
));
279 if (motivation
== GURL(existing_spec
))
280 return motivation_list
;
285 static base::ListValue
* FindSerializationMotivation(
286 const GURL
& motivation
,
287 base::ListValue
* referral_list
) {
288 return const_cast<base::ListValue
*>(FindSerializationMotivation(
289 motivation
, static_cast<const base::ListValue
*>(referral_list
)));
292 // Create a new empty serialization list.
293 static base::ListValue
* NewEmptySerializationList() {
294 base::ListValue
* list
= new base::ListValue
;
296 new base::FundamentalValue(Predictor::kPredictorReferrerVersion
));
300 // Add a motivating_url and a subresource_url to a serialized list, using
301 // this given latency. This is a helper function for quickly building these
303 static void AddToSerializedList(const GURL
& motivation
,
304 const GURL
& subresource
,
306 base::ListValue
* referral_list
) {
307 // Find the motivation if it is already used.
308 base::ListValue
* motivation_list
= FindSerializationMotivation(motivation
,
310 if (!motivation_list
) {
311 // This is the first mention of this motivation, so build a list.
312 motivation_list
= new base::ListValue
;
313 motivation_list
->Append(new base::StringValue(motivation
.spec()));
314 // Provide empty subresource list.
315 motivation_list
->Append(new base::ListValue());
317 // ...and make it part of the serialized referral_list.
318 referral_list
->Append(motivation_list
);
321 base::ListValue
* subresource_list(NULL
);
322 // 0 == url; 1 == subresource_list.
323 EXPECT_TRUE(motivation_list
->GetList(1, &subresource_list
));
325 // We won't bother to check for the subresource being there already. Worst
326 // case, during deserialization, the latency value we supply plus the
327 // existing value(s) will be added to the referrer.
329 subresource_list
->Append(new base::StringValue(subresource
.spec()));
330 subresource_list
->Append(new base::FundamentalValue(use_rate
));
333 // For a given motivation, and subresource, find what latency is currently
334 // listed. This assume a well formed serialization, which has at most one such
335 // entry for any pair of names. If no such pair is found, then return false.
336 // Data is written into use_rate arguments.
337 static bool GetDataFromSerialization(const GURL
& motivation
,
338 const GURL
& subresource
,
339 const base::ListValue
& referral_list
,
341 const base::ListValue
* motivation_list
=
342 FindSerializationMotivation(motivation
, &referral_list
);
343 if (!motivation_list
)
345 const base::ListValue
* subresource_list
;
346 EXPECT_TRUE(motivation_list
->GetList(1, &subresource_list
));
347 for (size_t i
= 0; i
< subresource_list
->GetSize();) {
348 std::string url_spec
;
349 EXPECT_TRUE(subresource_list
->GetString(i
++, &url_spec
));
350 EXPECT_TRUE(subresource_list
->GetDouble(i
++, use_rate
));
351 if (subresource
== GURL(url_spec
)) {
358 //------------------------------------------------------------------------------
360 // Make sure nil referral lists really have no entries, and no latency listed.
361 TEST_F(PredictorTest
, ReferrerSerializationNilTest
) {
362 Predictor
predictor(true);
363 predictor
.SetHostResolver(host_resolver_
.get());
365 scoped_ptr
<base::ListValue
> referral_list(NewEmptySerializationList());
366 predictor
.SerializeReferrers(referral_list
.get());
367 EXPECT_EQ(1U, referral_list
->GetSize());
368 EXPECT_FALSE(GetDataFromSerialization(
369 GURL("http://a.com:79"), GURL("http://b.com:78"),
370 *referral_list
.get(), NULL
));
372 predictor
.Shutdown();
375 // Make sure that when a serialization list includes a value, that it can be
376 // deserialized into the database, and can be extracted back out via
377 // serialization without being changed.
378 TEST_F(PredictorTest
, ReferrerSerializationSingleReferrerTest
) {
379 Predictor
predictor(true);
380 predictor
.SetHostResolver(host_resolver_
.get());
381 const GURL
motivation_url("http://www.google.com:91");
382 const GURL
subresource_url("http://icons.google.com:90");
383 const double kUseRate
= 23.4;
384 scoped_ptr
<base::ListValue
> referral_list(NewEmptySerializationList());
386 AddToSerializedList(motivation_url
, subresource_url
,
387 kUseRate
, referral_list
.get());
389 predictor
.DeserializeReferrers(*referral_list
.get());
391 base::ListValue recovered_referral_list
;
392 predictor
.SerializeReferrers(&recovered_referral_list
);
393 EXPECT_EQ(2U, recovered_referral_list
.GetSize());
395 EXPECT_TRUE(GetDataFromSerialization(
396 motivation_url
, subresource_url
, recovered_referral_list
, &rate
));
397 EXPECT_EQ(rate
, kUseRate
);
399 predictor
.Shutdown();
402 // Check that GetHtmlReferrerLists() doesn't crash when given duplicated
403 // domains for referring URL, and that it sorts the results in the
405 TEST_F(PredictorTest
, GetHtmlReferrerLists
) {
406 Predictor
predictor(true);
407 predictor
.SetHostResolver(host_resolver_
.get());
408 const double kUseRate
= 23.4;
409 scoped_ptr
<base::ListValue
> referral_list(NewEmptySerializationList());
412 GURL("http://d.google.com/x1"),
413 GURL("http://foo.com/"),
414 kUseRate
, referral_list
.get());
416 // Duplicated hostname (d.google.com). This should not cause any crashes
417 // (i.e. crbug.com/116345)
419 GURL("http://d.google.com/x2"),
420 GURL("http://foo.com/"),
421 kUseRate
, referral_list
.get());
424 GURL("http://a.yahoo.com/y"),
425 GURL("http://foo1.com/"),
426 kUseRate
, referral_list
.get());
429 GURL("http://b.google.com/x3"),
430 GURL("http://foo2.com/"),
431 kUseRate
, referral_list
.get());
434 GURL("http://d.yahoo.com/x5"),
435 GURL("http://i.like.turtles/"),
436 kUseRate
, referral_list
.get());
439 GURL("http://c.yahoo.com/x4"),
440 GURL("http://foo3.com/"),
441 kUseRate
, referral_list
.get());
443 predictor
.DeserializeReferrers(*referral_list
.get());
446 predictor
.GetHtmlReferrerLists(&html
);
448 // The lexicographic sorting of hostnames would be:
455 // However we expect to sort them by domain in the output:
463 html
.find("<td rowspan=1>http://b.google.com/x3"),
464 html
.find("<td rowspan=1>http://d.google.com/x1"),
465 html
.find("<td rowspan=1>http://d.google.com/x2"),
466 html
.find("<td rowspan=1>http://a.yahoo.com/y"),
467 html
.find("<td rowspan=1>http://c.yahoo.com/x4"),
468 html
.find("<td rowspan=1>http://d.yahoo.com/x5"),
471 // Make sure things appeared in the expected order.
472 for (size_t i
= 1; i
< arraysize(pos
); ++i
) {
473 EXPECT_LT(pos
[i
- 1], pos
[i
]) << "Mismatch for pos[" << i
<< "]";
476 predictor
.Shutdown();
479 // Verify that two floats are within 1% of each other in value.
480 #define EXPECT_SIMILAR(a, b) do { \
481 double espilon_ratio = 1.01; \
483 espilon_ratio = 1 / espilon_ratio; \
484 EXPECT_LT(a, espilon_ratio * (b)); \
485 EXPECT_GT((a) * espilon_ratio, b); \
489 // Make sure the Trim() functionality works as expected.
490 TEST_F(PredictorTest
, ReferrerSerializationTrimTest
) {
491 Predictor
predictor(true);
492 predictor
.SetHostResolver(host_resolver_
.get());
493 GURL
motivation_url("http://www.google.com:110");
495 GURL
icon_subresource_url("http://icons.google.com:111");
496 const double kRateIcon
= 16.0 * Predictor::kDiscardableExpectedValue
;
497 GURL
img_subresource_url("http://img.google.com:118");
498 const double kRateImg
= 8.0 * Predictor::kDiscardableExpectedValue
;
500 scoped_ptr
<base::ListValue
> referral_list(NewEmptySerializationList());
502 motivation_url
, icon_subresource_url
, kRateIcon
, referral_list
.get());
504 motivation_url
, img_subresource_url
, kRateImg
, referral_list
.get());
506 predictor
.DeserializeReferrers(*referral_list
.get());
508 base::ListValue recovered_referral_list
;
509 predictor
.SerializeReferrers(&recovered_referral_list
);
510 EXPECT_EQ(2U, recovered_referral_list
.GetSize());
512 EXPECT_TRUE(GetDataFromSerialization(
513 motivation_url
, icon_subresource_url
, recovered_referral_list
,
515 EXPECT_SIMILAR(rate
, kRateIcon
);
517 EXPECT_TRUE(GetDataFromSerialization(
518 motivation_url
, img_subresource_url
, recovered_referral_list
, &rate
));
519 EXPECT_SIMILAR(rate
, kRateImg
);
521 // Each time we Trim 24 times, the user_rate figures should reduce by a factor
522 // of two, until they are small, and then a trim will delete the whole entry.
523 for (int i
= 0; i
< 24; ++i
)
524 predictor
.TrimReferrersNow();
525 predictor
.SerializeReferrers(&recovered_referral_list
);
526 EXPECT_EQ(2U, recovered_referral_list
.GetSize());
527 EXPECT_TRUE(GetDataFromSerialization(
528 motivation_url
, icon_subresource_url
, recovered_referral_list
, &rate
));
529 EXPECT_SIMILAR(rate
, kRateIcon
/ 2);
531 EXPECT_TRUE(GetDataFromSerialization(
532 motivation_url
, img_subresource_url
, recovered_referral_list
, &rate
));
533 EXPECT_SIMILAR(rate
, kRateImg
/ 2);
535 for (int i
= 0; i
< 24; ++i
)
536 predictor
.TrimReferrersNow();
537 predictor
.SerializeReferrers(&recovered_referral_list
);
538 EXPECT_EQ(2U, recovered_referral_list
.GetSize());
539 EXPECT_TRUE(GetDataFromSerialization(
540 motivation_url
, icon_subresource_url
, recovered_referral_list
, &rate
));
541 EXPECT_SIMILAR(rate
, kRateIcon
/ 4);
542 EXPECT_TRUE(GetDataFromSerialization(
543 motivation_url
, img_subresource_url
, recovered_referral_list
, &rate
));
544 EXPECT_SIMILAR(rate
, kRateImg
/ 4);
546 for (int i
= 0; i
< 24; ++i
)
547 predictor
.TrimReferrersNow();
548 predictor
.SerializeReferrers(&recovered_referral_list
);
549 EXPECT_EQ(2U, recovered_referral_list
.GetSize());
550 EXPECT_TRUE(GetDataFromSerialization(
551 motivation_url
, icon_subresource_url
, recovered_referral_list
, &rate
));
552 EXPECT_SIMILAR(rate
, kRateIcon
/ 8);
554 // Img is below threshold, and so it gets deleted.
555 EXPECT_FALSE(GetDataFromSerialization(
556 motivation_url
, img_subresource_url
, recovered_referral_list
, &rate
));
558 for (int i
= 0; i
< 24; ++i
)
559 predictor
.TrimReferrersNow();
560 predictor
.SerializeReferrers(&recovered_referral_list
);
561 // Icon is also trimmed away, so entire set gets discarded.
562 EXPECT_EQ(1U, recovered_referral_list
.GetSize());
563 EXPECT_FALSE(GetDataFromSerialization(
564 motivation_url
, icon_subresource_url
, recovered_referral_list
, &rate
));
565 EXPECT_FALSE(GetDataFromSerialization(
566 motivation_url
, img_subresource_url
, recovered_referral_list
, &rate
));
568 predictor
.Shutdown();
572 TEST_F(PredictorTest
, PriorityQueuePushPopTest
) {
573 Predictor::HostNameQueue queue
;
575 GURL
first("http://first:80"), second("http://second:90");
577 // First check high priority queue FIFO functionality.
578 EXPECT_TRUE(queue
.IsEmpty());
579 queue
.Push(first
, UrlInfo::LEARNED_REFERAL_MOTIVATED
);
580 EXPECT_FALSE(queue
.IsEmpty());
581 queue
.Push(second
, UrlInfo::MOUSE_OVER_MOTIVATED
);
582 EXPECT_FALSE(queue
.IsEmpty());
583 EXPECT_EQ(queue
.Pop(), first
);
584 EXPECT_FALSE(queue
.IsEmpty());
585 EXPECT_EQ(queue
.Pop(), second
);
586 EXPECT_TRUE(queue
.IsEmpty());
588 // Then check low priority queue FIFO functionality.
589 queue
.Push(first
, UrlInfo::PAGE_SCAN_MOTIVATED
);
590 EXPECT_FALSE(queue
.IsEmpty());
591 queue
.Push(second
, UrlInfo::OMNIBOX_MOTIVATED
);
592 EXPECT_FALSE(queue
.IsEmpty());
593 EXPECT_EQ(queue
.Pop(), first
);
594 EXPECT_FALSE(queue
.IsEmpty());
595 EXPECT_EQ(queue
.Pop(), second
);
596 EXPECT_TRUE(queue
.IsEmpty());
599 TEST_F(PredictorTest
, PriorityQueueReorderTest
) {
600 Predictor::HostNameQueue queue
;
602 // Push all the low priority items.
603 GURL
low1("http://low1:80"),
604 low2("http://low2:80"),
605 low3("http://low3:443"),
606 low4("http://low4:80"),
607 low5("http://low5:80"),
608 hi1("http://hi1:80"),
609 hi2("http://hi2:80"),
610 hi3("http://hi3:80");
612 EXPECT_TRUE(queue
.IsEmpty());
613 queue
.Push(low1
, UrlInfo::PAGE_SCAN_MOTIVATED
);
614 queue
.Push(low2
, UrlInfo::UNIT_TEST_MOTIVATED
);
615 queue
.Push(low3
, UrlInfo::LINKED_MAX_MOTIVATED
);
616 queue
.Push(low4
, UrlInfo::OMNIBOX_MOTIVATED
);
617 queue
.Push(low5
, UrlInfo::STARTUP_LIST_MOTIVATED
);
618 queue
.Push(low4
, UrlInfo::OMNIBOX_MOTIVATED
);
620 // Push all the high prority items
621 queue
.Push(hi1
, UrlInfo::LEARNED_REFERAL_MOTIVATED
);
622 queue
.Push(hi2
, UrlInfo::STATIC_REFERAL_MOTIVATED
);
623 queue
.Push(hi3
, UrlInfo::MOUSE_OVER_MOTIVATED
);
625 // Check that high priority stuff comes out first, and in FIFO order.
626 EXPECT_EQ(queue
.Pop(), hi1
);
627 EXPECT_EQ(queue
.Pop(), hi2
);
628 EXPECT_EQ(queue
.Pop(), hi3
);
630 // ...and then low priority strings.
631 EXPECT_EQ(queue
.Pop(), low1
);
632 EXPECT_EQ(queue
.Pop(), low2
);
633 EXPECT_EQ(queue
.Pop(), low3
);
634 EXPECT_EQ(queue
.Pop(), low4
);
635 EXPECT_EQ(queue
.Pop(), low5
);
636 EXPECT_EQ(queue
.Pop(), low4
);
638 EXPECT_TRUE(queue
.IsEmpty());
641 TEST_F(PredictorTest
, CanonicalizeUrl
) {
642 // Base case, only handles HTTP and HTTPS.
643 EXPECT_EQ(GURL(), Predictor::CanonicalizeUrl(GURL("ftp://anything")));
645 // Remove path testing.
646 GURL
long_url("http://host:999/path?query=value");
647 EXPECT_EQ(Predictor::CanonicalizeUrl(long_url
), long_url
.GetWithEmptyPath());
649 // Default port cannoncalization.
650 GURL
implied_port("http://test");
651 GURL
explicit_port("http://test:80");
652 EXPECT_EQ(Predictor::CanonicalizeUrl(implied_port
),
653 Predictor::CanonicalizeUrl(explicit_port
));
655 // Port is still maintained.
656 GURL
port_80("http://test:80");
657 GURL
port_90("http://test:90");
658 EXPECT_NE(Predictor::CanonicalizeUrl(port_80
),
659 Predictor::CanonicalizeUrl(port_90
));
661 // Host is still maintained.
662 GURL
host_1("http://test_1");
663 GURL
host_2("http://test_2");
664 EXPECT_NE(Predictor::CanonicalizeUrl(host_1
),
665 Predictor::CanonicalizeUrl(host_2
));
667 // Scheme is maintained (mismatch identified).
668 GURL
http("http://test");
669 GURL
https("https://test");
670 EXPECT_NE(Predictor::CanonicalizeUrl(http
),
671 Predictor::CanonicalizeUrl(https
));
674 GURL
long_https("https://host:999/path?query=value");
675 EXPECT_EQ(Predictor::CanonicalizeUrl(long_https
),
676 long_https
.GetWithEmptyPath());
679 TEST_F(PredictorTest
, DiscardPredictorResults
) {
680 Predictor
predictor(true);
681 predictor
.SetHostResolver(host_resolver_
.get());
682 base::ListValue referral_list
;
683 predictor
.SerializeReferrers(&referral_list
);
684 EXPECT_EQ(1U, referral_list
.GetSize());
686 GURL
host_1("http://test_1");
687 GURL
host_2("http://test_2");
688 predictor
.LearnFromNavigation(host_1
, host_2
);
690 predictor
.SerializeReferrers(&referral_list
);
691 EXPECT_EQ(2U, referral_list
.GetSize());
693 predictor
.DiscardAllResults();
694 predictor
.SerializeReferrers(&referral_list
);
695 EXPECT_EQ(1U, referral_list
.GetSize());
697 predictor
.Shutdown();
700 #if defined(OS_ANDROID) || defined(OS_IOS)
701 // Tests for the predictor with a proxy advisor
703 class TestProxyAdvisor
: public ProxyAdvisor
{
706 : ProxyAdvisor(NULL
, NULL
),
709 would_proxy_count_(0) {
712 virtual ~TestProxyAdvisor() {}
714 virtual void Advise(const GURL
& url
,
715 UrlInfo::ResolutionMotivation motivation
,
716 bool is_preconnect
) OVERRIDE
{
720 virtual bool WouldProxyURL(const GURL
& url
) OVERRIDE
{
721 ++would_proxy_count_
;
727 int would_proxy_count_
;
730 TEST_F(PredictorTest
, SingleLookupTestWithDisabledAdvisor
) {
731 Predictor
testing_master(true);
732 TestProxyAdvisor
* advisor
= new TestProxyAdvisor();
733 testing_master
.SetHostResolver(host_resolver_
.get());
734 testing_master
.proxy_advisor_
.reset(advisor
);
736 GURL
goog("http://www.google.com:80");
738 advisor
->would_proxy_
= false;
741 names
.push_back(goog
);
742 testing_master
.ResolveList(names
, UrlInfo::PAGE_SCAN_MOTIVATED
);
744 WaitForResolution(&testing_master
, names
);
745 EXPECT_TRUE(testing_master
.WasFound(goog
));
746 EXPECT_EQ(advisor
->would_proxy_count_
, 1);
747 EXPECT_EQ(advisor
->advise_count_
, 1);
749 base::MessageLoop::current()->RunUntilIdle();
751 testing_master
.Shutdown();
754 TEST_F(PredictorTest
, SingleLookupTestWithEnabledAdvisor
) {
755 Predictor
testing_master(true);
756 testing_master
.SetHostResolver(host_resolver_
.get());
757 TestProxyAdvisor
* advisor
= new TestProxyAdvisor();
758 testing_master
.proxy_advisor_
.reset(advisor
);
760 GURL
goog("http://www.google.com:80");
762 advisor
->would_proxy_
= true;
765 names
.push_back(goog
);
767 testing_master
.ResolveList(names
, UrlInfo::PAGE_SCAN_MOTIVATED
);
769 // Attempt to resolve a few times.
770 WaitForResolutionWithLimit(&testing_master
, names
, 10);
772 // Because the advisor indicated that the url would be proxied,
773 // no resolution should have occurred.
774 EXPECT_FALSE(testing_master
.WasFound(goog
));
775 EXPECT_EQ(advisor
->would_proxy_count_
, 1);
776 EXPECT_EQ(advisor
->advise_count_
, 1);
778 base::MessageLoop::current()->RunUntilIdle();
780 testing_master
.Shutdown();
783 TEST_F(PredictorTest
, TestSimplePreconnectAdvisor
) {
784 Predictor
testing_master(true);
785 testing_master
.SetHostResolver(host_resolver_
.get());
786 TestProxyAdvisor
* advisor
= new TestProxyAdvisor();
787 testing_master
.proxy_advisor_
.reset(advisor
);
789 GURL
goog("http://www.google.com:80");
791 testing_master
.PreconnectUrl(goog
, goog
, UrlInfo::OMNIBOX_MOTIVATED
, 2);
793 EXPECT_EQ(advisor
->would_proxy_count_
, 0);
794 EXPECT_EQ(advisor
->advise_count_
, 1);
796 testing_master
.Shutdown();
799 #endif // defined(OS_ANDROID) || defined(OS_IOS)
801 } // namespace chrome_browser_net