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/location.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/message_loop/message_loop.h"
14 #include "base/single_thread_task_runner.h"
15 #include "base/strings/string_number_conversions.h"
16 #include "base/thread_task_runner_handle.h"
17 #include "base/timer/timer.h"
18 #include "base/values.h"
19 #include "chrome/browser/net/predictor.h"
20 #include "chrome/browser/net/url_info.h"
21 #include "components/network_hints/common/network_hints_common.h"
22 #include "content/public/test/test_browser_thread.h"
23 #include "net/base/address_list.h"
24 #include "net/base/load_flags.h"
25 #include "net/base/net_errors.h"
26 #include "net/base/winsock_init.h"
27 #include "net/dns/mock_host_resolver.h"
28 #include "net/http/transport_security_state.h"
29 #include "net/proxy/proxy_config_service_fixed.h"
30 #include "net/proxy/proxy_service.h"
31 #include "testing/gmock/include/gmock/gmock.h"
32 #include "testing/gtest/include/gtest/gtest.h"
35 using base::TimeDelta
;
36 using content::BrowserThread
;
38 namespace chrome_browser_net
{
40 class WaitForResolutionHelper
;
42 typedef base::RepeatingTimer
<WaitForResolutionHelper
> HelperTimer
;
44 class WaitForResolutionHelper
{
46 WaitForResolutionHelper(Predictor
* predictor
, const UrlList
& hosts
,
47 HelperTimer
* timer
, int checks_until_quit
)
48 : predictor_(predictor
),
51 checks_until_quit_(checks_until_quit
) {
54 void CheckIfResolutionsDone() {
55 if (--checks_until_quit_
> 0) {
56 for (UrlList::const_iterator i
= hosts_
.begin(); i
!= hosts_
.end(); ++i
)
57 if (predictor_
->GetResolutionDuration(*i
) ==
58 UrlInfo::NullDuration())
59 return; // We don't have resolution for that host.
62 // When all hostnames have been resolved, or we've hit the limit,
65 base::MessageLoop::current()->Quit();
71 Predictor
* predictor_
;
74 int checks_until_quit_
;
77 class PredictorTest
: public testing::Test
{
80 : ui_thread_(BrowserThread::UI
, &loop_
),
81 io_thread_(BrowserThread::IO
, &loop_
),
82 host_resolver_(new net::MockCachingHostResolver()) {
86 void SetUp() override
{
88 net::EnsureWinsockInit();
90 Predictor::set_max_parallel_resolves(
91 Predictor::kMaxSpeculativeParallelResolves
);
92 Predictor::set_max_queueing_delay(
93 Predictor::kMaxSpeculativeResolveQueueDelayMs
);
94 // Since we are using a caching HostResolver, the following latencies will
95 // only be incurred by the first request, after which the result will be
96 // cached internally by |host_resolver_|.
97 net::RuleBasedHostResolverProc
* rules
= host_resolver_
->rules();
98 rules
->AddRuleWithLatency("www.google.com", "127.0.0.1", 50);
99 rules
->AddRuleWithLatency("gmail.google.com.com", "127.0.0.1", 70);
100 rules
->AddRuleWithLatency("mail.google.com", "127.0.0.1", 44);
101 rules
->AddRuleWithLatency("gmail.com", "127.0.0.1", 63);
104 void WaitForResolution(Predictor
* predictor
, const UrlList
& hosts
) {
105 HelperTimer
* timer
= new HelperTimer();
106 // By default allow the loop to run for a minute -- 600 iterations.
107 timer
->Start(FROM_HERE
, TimeDelta::FromMilliseconds(100),
108 new WaitForResolutionHelper(predictor
, hosts
, timer
, 600),
109 &WaitForResolutionHelper::CheckIfResolutionsDone
);
110 base::MessageLoop::current()->Run();
113 void WaitForResolutionWithLimit(
114 Predictor
* predictor
, const UrlList
& hosts
, int limit
) {
115 HelperTimer
* timer
= new HelperTimer();
116 timer
->Start(FROM_HERE
, TimeDelta::FromMilliseconds(100),
117 new WaitForResolutionHelper(predictor
, hosts
, timer
, limit
),
118 &WaitForResolutionHelper::CheckIfResolutionsDone
);
119 base::MessageLoop::current()->Run();
123 // IMPORTANT: do not move this below |host_resolver_|; the host resolver
124 // must not outlive the message loop, otherwise bad things can happen
125 // (like posting to a deleted message loop).
126 base::MessageLoopForUI loop_
;
127 content::TestBrowserThread ui_thread_
;
128 content::TestBrowserThread io_thread_
;
131 scoped_ptr
<net::MockCachingHostResolver
> host_resolver_
;
134 //------------------------------------------------------------------------------
136 TEST_F(PredictorTest
, StartupShutdownTest
) {
137 Predictor
testing_master(true, true);
138 testing_master
.Shutdown();
142 TEST_F(PredictorTest
, ShutdownWhenResolutionIsPendingTest
) {
143 scoped_ptr
<net::HostResolver
> host_resolver(new net::HangingHostResolver());
145 Predictor
testing_master(true, true);
146 testing_master
.SetHostResolver(host_resolver
.get());
148 GURL
localhost("http://localhost:80");
150 names
.push_back(localhost
);
152 testing_master
.ResolveList(names
, UrlInfo::PAGE_SCAN_MOTIVATED
);
154 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
155 FROM_HERE
, base::MessageLoop::QuitClosure(),
156 base::TimeDelta::FromMilliseconds(500));
157 base::MessageLoop::current()->Run();
159 EXPECT_FALSE(testing_master
.WasFound(localhost
));
161 testing_master
.Shutdown();
163 // Clean up after ourselves.
164 base::MessageLoop::current()->RunUntilIdle();
167 TEST_F(PredictorTest
, SingleLookupTest
) {
168 Predictor
testing_master(true, true);
169 testing_master
.SetHostResolver(host_resolver_
.get());
171 GURL
goog("http://www.google.com:80");
174 names
.push_back(goog
);
176 // Try to flood the predictor with many concurrent requests.
177 for (int i
= 0; i
< 10; i
++)
178 testing_master
.ResolveList(names
, UrlInfo::PAGE_SCAN_MOTIVATED
);
180 WaitForResolution(&testing_master
, names
);
182 EXPECT_TRUE(testing_master
.WasFound(goog
));
184 base::MessageLoop::current()->RunUntilIdle();
186 EXPECT_GT(testing_master
.peak_pending_lookups(), names
.size() / 2);
187 EXPECT_LE(testing_master
.peak_pending_lookups(), names
.size());
188 EXPECT_LE(testing_master
.peak_pending_lookups(),
189 testing_master
.max_concurrent_dns_lookups());
191 testing_master
.Shutdown();
194 TEST_F(PredictorTest
, ConcurrentLookupTest
) {
195 host_resolver_
->rules()->AddSimulatedFailure("*.notfound");
197 Predictor
testing_master(true, true);
198 testing_master
.SetHostResolver(host_resolver_
.get());
200 GURL
goog("http://www.google.com:80"),
201 goog2("http://gmail.google.com.com:80"),
202 goog3("http://mail.google.com:80"),
203 goog4("http://gmail.com:80");
204 GURL
bad1("http://bad1.notfound:80"),
205 bad2("http://bad2.notfound:80");
208 names
.push_back(goog
);
209 names
.push_back(goog3
);
210 names
.push_back(bad1
);
211 names
.push_back(goog2
);
212 names
.push_back(bad2
);
213 names
.push_back(goog4
);
214 names
.push_back(goog
);
216 // Try to flood the predictor with many concurrent requests.
217 for (int i
= 0; i
< 10; i
++)
218 testing_master
.ResolveList(names
, UrlInfo::PAGE_SCAN_MOTIVATED
);
220 WaitForResolution(&testing_master
, names
);
222 EXPECT_TRUE(testing_master
.WasFound(goog
));
223 EXPECT_TRUE(testing_master
.WasFound(goog3
));
224 EXPECT_TRUE(testing_master
.WasFound(goog2
));
225 EXPECT_TRUE(testing_master
.WasFound(goog4
));
226 EXPECT_FALSE(testing_master
.WasFound(bad1
));
227 EXPECT_FALSE(testing_master
.WasFound(bad2
));
229 base::MessageLoop::current()->RunUntilIdle();
231 EXPECT_FALSE(testing_master
.WasFound(bad1
));
232 EXPECT_FALSE(testing_master
.WasFound(bad2
));
234 EXPECT_LE(testing_master
.peak_pending_lookups(), names
.size());
235 EXPECT_LE(testing_master
.peak_pending_lookups(),
236 testing_master
.max_concurrent_dns_lookups());
238 testing_master
.Shutdown();
241 TEST_F(PredictorTest
, MassiveConcurrentLookupTest
) {
242 host_resolver_
->rules()->AddSimulatedFailure("*.notfound");
244 Predictor
testing_master(true, true);
245 testing_master
.SetHostResolver(host_resolver_
.get());
248 for (int i
= 0; i
< 100; i
++)
249 names
.push_back(GURL(
250 "http://host" + base::IntToString(i
) + ".notfound:80"));
252 // Try to flood the predictor with many concurrent requests.
253 for (int i
= 0; i
< 10; i
++)
254 testing_master
.ResolveList(names
, UrlInfo::PAGE_SCAN_MOTIVATED
);
256 WaitForResolution(&testing_master
, names
);
258 base::MessageLoop::current()->RunUntilIdle();
260 EXPECT_LE(testing_master
.peak_pending_lookups(), names
.size());
261 EXPECT_LE(testing_master
.peak_pending_lookups(),
262 testing_master
.max_concurrent_dns_lookups());
264 testing_master
.Shutdown();
267 //------------------------------------------------------------------------------
268 // Functions to help synthesize and test serializations of subresource referrer
271 // Return a motivation_list if we can find one for the given motivating_host (or
272 // NULL if a match is not found).
273 static const base::ListValue
* FindSerializationMotivation(
274 const GURL
& motivation
,
275 const base::ListValue
* referral_list
) {
276 CHECK_LT(0u, referral_list
->GetSize()); // Room for version.
277 int format_version
= -1;
278 CHECK(referral_list
->GetInteger(0, &format_version
));
279 CHECK_EQ(Predictor::kPredictorReferrerVersion
, format_version
);
280 const base::ListValue
* motivation_list(NULL
);
281 for (size_t i
= 1; i
< referral_list
->GetSize(); ++i
) {
282 referral_list
->GetList(i
, &motivation_list
);
283 std::string existing_spec
;
284 EXPECT_TRUE(motivation_list
->GetString(0, &existing_spec
));
285 if (motivation
== GURL(existing_spec
))
286 return motivation_list
;
291 static base::ListValue
* FindSerializationMotivation(
292 const GURL
& motivation
,
293 base::ListValue
* referral_list
) {
294 return const_cast<base::ListValue
*>(FindSerializationMotivation(
295 motivation
, static_cast<const base::ListValue
*>(referral_list
)));
298 // Create a new empty serialization list.
299 static base::ListValue
* NewEmptySerializationList() {
300 base::ListValue
* list
= new base::ListValue
;
302 new base::FundamentalValue(Predictor::kPredictorReferrerVersion
));
306 // Add a motivating_url and a subresource_url to a serialized list, using
307 // this given latency. This is a helper function for quickly building these
309 static void AddToSerializedList(const GURL
& motivation
,
310 const GURL
& subresource
,
312 base::ListValue
* referral_list
) {
313 // Find the motivation if it is already used.
314 base::ListValue
* motivation_list
= FindSerializationMotivation(motivation
,
316 if (!motivation_list
) {
317 // This is the first mention of this motivation, so build a list.
318 motivation_list
= new base::ListValue
;
319 motivation_list
->Append(new base::StringValue(motivation
.spec()));
320 // Provide empty subresource list.
321 motivation_list
->Append(new base::ListValue());
323 // ...and make it part of the serialized referral_list.
324 referral_list
->Append(motivation_list
);
327 base::ListValue
* subresource_list(NULL
);
328 // 0 == url; 1 == subresource_list.
329 EXPECT_TRUE(motivation_list
->GetList(1, &subresource_list
));
331 // We won't bother to check for the subresource being there already. Worst
332 // case, during deserialization, the latency value we supply plus the
333 // existing value(s) will be added to the referrer.
335 subresource_list
->Append(new base::StringValue(subresource
.spec()));
336 subresource_list
->Append(new base::FundamentalValue(use_rate
));
339 // For a given motivation, and subresource, find what latency is currently
340 // listed. This assume a well formed serialization, which has at most one such
341 // entry for any pair of names. If no such pair is found, then return false.
342 // Data is written into use_rate arguments.
343 static bool GetDataFromSerialization(const GURL
& motivation
,
344 const GURL
& subresource
,
345 const base::ListValue
& referral_list
,
347 const base::ListValue
* motivation_list
=
348 FindSerializationMotivation(motivation
, &referral_list
);
349 if (!motivation_list
)
351 const base::ListValue
* subresource_list
;
352 EXPECT_TRUE(motivation_list
->GetList(1, &subresource_list
));
353 for (size_t i
= 0; i
< subresource_list
->GetSize();) {
354 std::string url_spec
;
355 EXPECT_TRUE(subresource_list
->GetString(i
++, &url_spec
));
356 EXPECT_TRUE(subresource_list
->GetDouble(i
++, use_rate
));
357 if (subresource
== GURL(url_spec
)) {
364 //------------------------------------------------------------------------------
366 // Make sure nil referral lists really have no entries, and no latency listed.
367 TEST_F(PredictorTest
, ReferrerSerializationNilTest
) {
368 Predictor
predictor(true, true);
369 predictor
.SetHostResolver(host_resolver_
.get());
371 scoped_ptr
<base::ListValue
> referral_list(NewEmptySerializationList());
372 predictor
.SerializeReferrers(referral_list
.get());
373 EXPECT_EQ(1U, referral_list
->GetSize());
374 EXPECT_FALSE(GetDataFromSerialization(
375 GURL("http://a.com:79"), GURL("http://b.com:78"),
376 *referral_list
.get(), NULL
));
378 predictor
.Shutdown();
381 // Make sure that when a serialization list includes a value, that it can be
382 // deserialized into the database, and can be extracted back out via
383 // serialization without being changed.
384 TEST_F(PredictorTest
, ReferrerSerializationSingleReferrerTest
) {
385 Predictor
predictor(true, true);
386 predictor
.SetHostResolver(host_resolver_
.get());
387 const GURL
motivation_url("http://www.google.com:91");
388 const GURL
subresource_url("http://icons.google.com:90");
389 const double kUseRate
= 23.4;
390 scoped_ptr
<base::ListValue
> referral_list(NewEmptySerializationList());
392 AddToSerializedList(motivation_url
, subresource_url
,
393 kUseRate
, referral_list
.get());
395 predictor
.DeserializeReferrers(*referral_list
.get());
397 base::ListValue recovered_referral_list
;
398 predictor
.SerializeReferrers(&recovered_referral_list
);
399 EXPECT_EQ(2U, recovered_referral_list
.GetSize());
401 EXPECT_TRUE(GetDataFromSerialization(
402 motivation_url
, subresource_url
, recovered_referral_list
, &rate
));
403 EXPECT_EQ(rate
, kUseRate
);
405 predictor
.Shutdown();
408 // Check that GetHtmlReferrerLists() doesn't crash when given duplicated
409 // domains for referring URL, and that it sorts the results in the
411 TEST_F(PredictorTest
, GetHtmlReferrerLists
) {
412 Predictor
predictor(true, true);
413 predictor
.SetHostResolver(host_resolver_
.get());
414 const double kUseRate
= 23.4;
415 scoped_ptr
<base::ListValue
> referral_list(NewEmptySerializationList());
418 GURL("http://d.google.com/x1"),
419 GURL("http://foo.com/"),
420 kUseRate
, referral_list
.get());
422 // Duplicated hostname (d.google.com). This should not cause any crashes
423 // (i.e. crbug.com/116345)
425 GURL("http://d.google.com/x2"),
426 GURL("http://foo.com/"),
427 kUseRate
, referral_list
.get());
430 GURL("http://a.yahoo.com/y"),
431 GURL("http://foo1.com/"),
432 kUseRate
, referral_list
.get());
435 GURL("http://b.google.com/x3"),
436 GURL("http://foo2.com/"),
437 kUseRate
, referral_list
.get());
440 GURL("http://d.yahoo.com/x5"),
441 GURL("http://i.like.turtles/"),
442 kUseRate
, referral_list
.get());
445 GURL("http://c.yahoo.com/x4"),
446 GURL("http://foo3.com/"),
447 kUseRate
, referral_list
.get());
449 predictor
.DeserializeReferrers(*referral_list
.get());
452 predictor
.GetHtmlReferrerLists(&html
);
454 // The lexicographic sorting of hostnames would be:
461 // However we expect to sort them by domain in the output:
469 html
.find("<td rowspan=1>http://b.google.com/x3"),
470 html
.find("<td rowspan=1>http://d.google.com/x1"),
471 html
.find("<td rowspan=1>http://d.google.com/x2"),
472 html
.find("<td rowspan=1>http://a.yahoo.com/y"),
473 html
.find("<td rowspan=1>http://c.yahoo.com/x4"),
474 html
.find("<td rowspan=1>http://d.yahoo.com/x5"),
477 // Make sure things appeared in the expected order.
478 for (size_t i
= 1; i
< arraysize(pos
); ++i
) {
479 EXPECT_LT(pos
[i
- 1], pos
[i
]) << "Mismatch for pos[" << i
<< "]";
482 predictor
.Shutdown();
485 // Verify that two floats are within 1% of each other in value.
486 #define EXPECT_SIMILAR(a, b) do { \
487 double espilon_ratio = 1.01; \
489 espilon_ratio = 1 / espilon_ratio; \
490 EXPECT_LT(a, espilon_ratio * (b)); \
491 EXPECT_GT((a) * espilon_ratio, b); \
495 // Make sure the Trim() functionality works as expected.
496 TEST_F(PredictorTest
, ReferrerSerializationTrimTest
) {
497 Predictor
predictor(true, true);
498 predictor
.SetHostResolver(host_resolver_
.get());
499 GURL
motivation_url("http://www.google.com:110");
501 GURL
icon_subresource_url("http://icons.google.com:111");
502 const double kRateIcon
= 16.0 * Predictor::kDiscardableExpectedValue
;
503 GURL
img_subresource_url("http://img.google.com:118");
504 const double kRateImg
= 8.0 * Predictor::kDiscardableExpectedValue
;
506 scoped_ptr
<base::ListValue
> referral_list(NewEmptySerializationList());
508 motivation_url
, icon_subresource_url
, kRateIcon
, referral_list
.get());
510 motivation_url
, img_subresource_url
, kRateImg
, referral_list
.get());
512 predictor
.DeserializeReferrers(*referral_list
.get());
514 base::ListValue recovered_referral_list
;
515 predictor
.SerializeReferrers(&recovered_referral_list
);
516 EXPECT_EQ(2U, recovered_referral_list
.GetSize());
518 EXPECT_TRUE(GetDataFromSerialization(
519 motivation_url
, icon_subresource_url
, recovered_referral_list
,
521 EXPECT_SIMILAR(rate
, kRateIcon
);
523 EXPECT_TRUE(GetDataFromSerialization(
524 motivation_url
, img_subresource_url
, recovered_referral_list
, &rate
));
525 EXPECT_SIMILAR(rate
, kRateImg
);
527 // Each time we Trim 24 times, the user_rate figures should reduce by a factor
528 // of two, until they are small, and then a trim will delete the whole entry.
529 for (int i
= 0; i
< 24; ++i
)
530 predictor
.TrimReferrersNow();
531 predictor
.SerializeReferrers(&recovered_referral_list
);
532 EXPECT_EQ(2U, recovered_referral_list
.GetSize());
533 EXPECT_TRUE(GetDataFromSerialization(
534 motivation_url
, icon_subresource_url
, recovered_referral_list
, &rate
));
535 EXPECT_SIMILAR(rate
, kRateIcon
/ 2);
537 EXPECT_TRUE(GetDataFromSerialization(
538 motivation_url
, img_subresource_url
, recovered_referral_list
, &rate
));
539 EXPECT_SIMILAR(rate
, kRateImg
/ 2);
541 for (int i
= 0; i
< 24; ++i
)
542 predictor
.TrimReferrersNow();
543 predictor
.SerializeReferrers(&recovered_referral_list
);
544 EXPECT_EQ(2U, recovered_referral_list
.GetSize());
545 EXPECT_TRUE(GetDataFromSerialization(
546 motivation_url
, icon_subresource_url
, recovered_referral_list
, &rate
));
547 EXPECT_SIMILAR(rate
, kRateIcon
/ 4);
548 EXPECT_TRUE(GetDataFromSerialization(
549 motivation_url
, img_subresource_url
, recovered_referral_list
, &rate
));
550 EXPECT_SIMILAR(rate
, kRateImg
/ 4);
552 for (int i
= 0; i
< 24; ++i
)
553 predictor
.TrimReferrersNow();
554 predictor
.SerializeReferrers(&recovered_referral_list
);
555 EXPECT_EQ(2U, recovered_referral_list
.GetSize());
556 EXPECT_TRUE(GetDataFromSerialization(
557 motivation_url
, icon_subresource_url
, recovered_referral_list
, &rate
));
558 EXPECT_SIMILAR(rate
, kRateIcon
/ 8);
560 // Img is below threshold, and so it gets deleted.
561 EXPECT_FALSE(GetDataFromSerialization(
562 motivation_url
, img_subresource_url
, recovered_referral_list
, &rate
));
564 for (int i
= 0; i
< 24; ++i
)
565 predictor
.TrimReferrersNow();
566 predictor
.SerializeReferrers(&recovered_referral_list
);
567 // Icon is also trimmed away, so entire set gets discarded.
568 EXPECT_EQ(1U, recovered_referral_list
.GetSize());
569 EXPECT_FALSE(GetDataFromSerialization(
570 motivation_url
, icon_subresource_url
, recovered_referral_list
, &rate
));
571 EXPECT_FALSE(GetDataFromSerialization(
572 motivation_url
, img_subresource_url
, recovered_referral_list
, &rate
));
574 predictor
.Shutdown();
578 TEST_F(PredictorTest
, PriorityQueuePushPopTest
) {
579 Predictor::HostNameQueue queue
;
581 GURL
first("http://first:80"), second("http://second:90");
583 // First check high priority queue FIFO functionality.
584 EXPECT_TRUE(queue
.IsEmpty());
585 queue
.Push(first
, UrlInfo::LEARNED_REFERAL_MOTIVATED
);
586 EXPECT_FALSE(queue
.IsEmpty());
587 queue
.Push(second
, UrlInfo::MOUSE_OVER_MOTIVATED
);
588 EXPECT_FALSE(queue
.IsEmpty());
589 EXPECT_EQ(queue
.Pop(), first
);
590 EXPECT_FALSE(queue
.IsEmpty());
591 EXPECT_EQ(queue
.Pop(), second
);
592 EXPECT_TRUE(queue
.IsEmpty());
594 // Then check low priority queue FIFO functionality.
595 queue
.Push(first
, UrlInfo::PAGE_SCAN_MOTIVATED
);
596 EXPECT_FALSE(queue
.IsEmpty());
597 queue
.Push(second
, UrlInfo::OMNIBOX_MOTIVATED
);
598 EXPECT_FALSE(queue
.IsEmpty());
599 EXPECT_EQ(queue
.Pop(), first
);
600 EXPECT_FALSE(queue
.IsEmpty());
601 EXPECT_EQ(queue
.Pop(), second
);
602 EXPECT_TRUE(queue
.IsEmpty());
605 TEST_F(PredictorTest
, PriorityQueueReorderTest
) {
606 Predictor::HostNameQueue queue
;
608 // Push all the low priority items.
609 GURL
low1("http://low1:80"),
610 low2("http://low2:80"),
611 low3("http://low3:443"),
612 low4("http://low4:80"),
613 low5("http://low5:80"),
614 hi1("http://hi1:80"),
615 hi2("http://hi2:80"),
616 hi3("http://hi3:80");
618 EXPECT_TRUE(queue
.IsEmpty());
619 queue
.Push(low1
, UrlInfo::PAGE_SCAN_MOTIVATED
);
620 queue
.Push(low2
, UrlInfo::UNIT_TEST_MOTIVATED
);
621 queue
.Push(low3
, UrlInfo::LINKED_MAX_MOTIVATED
);
622 queue
.Push(low4
, UrlInfo::OMNIBOX_MOTIVATED
);
623 queue
.Push(low5
, UrlInfo::STARTUP_LIST_MOTIVATED
);
624 queue
.Push(low4
, UrlInfo::OMNIBOX_MOTIVATED
);
626 // Push all the high prority items
627 queue
.Push(hi1
, UrlInfo::LEARNED_REFERAL_MOTIVATED
);
628 queue
.Push(hi2
, UrlInfo::STATIC_REFERAL_MOTIVATED
);
629 queue
.Push(hi3
, UrlInfo::MOUSE_OVER_MOTIVATED
);
631 // Check that high priority stuff comes out first, and in FIFO order.
632 EXPECT_EQ(queue
.Pop(), hi1
);
633 EXPECT_EQ(queue
.Pop(), hi2
);
634 EXPECT_EQ(queue
.Pop(), hi3
);
636 // ...and then low priority strings.
637 EXPECT_EQ(queue
.Pop(), low1
);
638 EXPECT_EQ(queue
.Pop(), low2
);
639 EXPECT_EQ(queue
.Pop(), low3
);
640 EXPECT_EQ(queue
.Pop(), low4
);
641 EXPECT_EQ(queue
.Pop(), low5
);
642 EXPECT_EQ(queue
.Pop(), low4
);
644 EXPECT_TRUE(queue
.IsEmpty());
647 TEST_F(PredictorTest
, CanonicalizeUrl
) {
648 // Base case, only handles HTTP and HTTPS.
649 EXPECT_EQ(GURL(), Predictor::CanonicalizeUrl(GURL("ftp://anything")));
651 // Remove path testing.
652 GURL
long_url("http://host:999/path?query=value");
653 EXPECT_EQ(Predictor::CanonicalizeUrl(long_url
), long_url
.GetWithEmptyPath());
655 // Default port cannoncalization.
656 GURL
implied_port("http://test");
657 GURL
explicit_port("http://test:80");
658 EXPECT_EQ(Predictor::CanonicalizeUrl(implied_port
),
659 Predictor::CanonicalizeUrl(explicit_port
));
661 // Port is still maintained.
662 GURL
port_80("http://test:80");
663 GURL
port_90("http://test:90");
664 EXPECT_NE(Predictor::CanonicalizeUrl(port_80
),
665 Predictor::CanonicalizeUrl(port_90
));
667 // Host is still maintained.
668 GURL
host_1("http://test_1");
669 GURL
host_2("http://test_2");
670 EXPECT_NE(Predictor::CanonicalizeUrl(host_1
),
671 Predictor::CanonicalizeUrl(host_2
));
673 // Scheme is maintained (mismatch identified).
674 GURL
http("http://test");
675 GURL
https("https://test");
676 EXPECT_NE(Predictor::CanonicalizeUrl(http
),
677 Predictor::CanonicalizeUrl(https
));
680 GURL
long_https("https://host:999/path?query=value");
681 EXPECT_EQ(Predictor::CanonicalizeUrl(long_https
),
682 long_https
.GetWithEmptyPath());
685 TEST_F(PredictorTest
, DiscardPredictorResults
) {
686 SimplePredictor
predictor(true, true);
687 predictor
.SetHostResolver(host_resolver_
.get());
688 base::ListValue referral_list
;
689 predictor
.SerializeReferrers(&referral_list
);
690 EXPECT_EQ(1U, referral_list
.GetSize());
692 GURL
host_1("http://test_1");
693 GURL
host_2("http://test_2");
694 predictor
.LearnFromNavigation(host_1
, host_2
);
696 predictor
.SerializeReferrers(&referral_list
);
697 EXPECT_EQ(2U, referral_list
.GetSize());
699 predictor
.DiscardAllResults();
700 predictor
.SerializeReferrers(&referral_list
);
701 EXPECT_EQ(1U, referral_list
.GetSize());
703 predictor
.Shutdown();
706 class TestPredictorObserver
: public PredictorObserver
{
708 // PredictorObserver implementation:
709 void OnPreconnectUrl(const GURL
& url
,
710 const GURL
& first_party_for_cookies
,
711 UrlInfo::ResolutionMotivation motivation
,
712 int count
) override
{
713 preconnected_urls_
.push_back(url
);
716 std::vector
<GURL
> preconnected_urls_
;
719 // Tests that preconnects apply the HSTS list.
720 TEST_F(PredictorTest
, HSTSRedirect
) {
721 const GURL
kHttpUrl("http://example.com");
722 const GURL
kHttpsUrl("https://example.com");
724 const base::Time expiry
=
725 base::Time::Now() + base::TimeDelta::FromSeconds(1000);
726 net::TransportSecurityState state
;
727 state
.AddHSTS(kHttpUrl
.host(), expiry
, false);
729 Predictor
predictor(true, true);
730 TestPredictorObserver observer
;
731 predictor
.SetObserver(&observer
);
732 predictor
.SetTransportSecurityState(&state
);
734 predictor
.PreconnectUrl(kHttpUrl
, GURL(), UrlInfo::OMNIBOX_MOTIVATED
, true,
736 ASSERT_EQ(1u, observer
.preconnected_urls_
.size());
737 EXPECT_EQ(kHttpsUrl
, observer
.preconnected_urls_
[0]);
739 predictor
.Shutdown();
742 // Tests that preconnecting a URL on the HSTS list preconnects the subresources
743 // for the SSL version.
744 TEST_F(PredictorTest
, HSTSRedirectSubresources
) {
745 const GURL
kHttpUrl("http://example.com");
746 const GURL
kHttpsUrl("https://example.com");
747 const GURL
kSubresourceUrl("https://images.example.com");
748 const double kUseRate
= 23.4;
750 const base::Time expiry
=
751 base::Time::Now() + base::TimeDelta::FromSeconds(1000);
752 net::TransportSecurityState state
;
753 state
.AddHSTS(kHttpUrl
.host(), expiry
, false);
755 SimplePredictor
predictor(true, true);
756 TestPredictorObserver observer
;
757 predictor
.SetObserver(&observer
);
758 predictor
.SetTransportSecurityState(&state
);
760 scoped_ptr
<base::ListValue
> referral_list(NewEmptySerializationList());
762 kHttpsUrl
, kSubresourceUrl
, kUseRate
, referral_list
.get());
763 predictor
.DeserializeReferrers(*referral_list
.get());
765 predictor
.PreconnectUrlAndSubresources(kHttpUrl
, GURL());
766 ASSERT_EQ(2u, observer
.preconnected_urls_
.size());
767 EXPECT_EQ(kHttpsUrl
, observer
.preconnected_urls_
[0]);
768 EXPECT_EQ(kSubresourceUrl
, observer
.preconnected_urls_
[1]);
770 predictor
.Shutdown();
773 TEST_F(PredictorTest
, NoProxyService
) {
774 // Don't actually try to resolve names.
775 Predictor::set_max_parallel_resolves(0);
777 Predictor
testing_master(true, true);
779 GURL
goog("http://www.google.com:80");
780 testing_master
.Resolve(goog
, UrlInfo::OMNIBOX_MOTIVATED
);
781 EXPECT_FALSE(testing_master
.work_queue_
.IsEmpty());
783 testing_master
.Shutdown();
786 TEST_F(PredictorTest
, ProxyDefinitelyEnabled
) {
787 // Don't actually try to resolve names.
788 Predictor::set_max_parallel_resolves(0);
790 Predictor
testing_master(true, true);
792 net::ProxyConfig config
;
793 config
.proxy_rules().ParseFromString("http=socks://localhost:12345");
794 scoped_ptr
<net::ProxyService
> proxy_service(
795 net::ProxyService::CreateFixed(config
));
796 testing_master
.proxy_service_
= proxy_service
.get();
798 GURL
goog("http://www.google.com:80");
799 testing_master
.Resolve(goog
, UrlInfo::OMNIBOX_MOTIVATED
);
801 // Proxy is definitely in use, so there is no need to pre-resolve the domain.
802 EXPECT_TRUE(testing_master
.work_queue_
.IsEmpty());
804 testing_master
.Shutdown();
807 TEST_F(PredictorTest
, ProxyDefinitelyNotEnabled
) {
808 // Don't actually try to resolve names.
809 Predictor::set_max_parallel_resolves(0);
811 Predictor
testing_master(true, true);
812 net::ProxyConfig config
= net::ProxyConfig::CreateDirect();
813 scoped_ptr
<net::ProxyService
> proxy_service(
814 net::ProxyService::CreateFixed(config
));
815 testing_master
.proxy_service_
= proxy_service
.get();
817 GURL
goog("http://www.google.com:80");
818 testing_master
.Resolve(goog
, UrlInfo::OMNIBOX_MOTIVATED
);
820 // Proxy is not in use, so the name has been registered for pre-resolve.
821 EXPECT_FALSE(testing_master
.work_queue_
.IsEmpty());
823 testing_master
.Shutdown();
826 TEST_F(PredictorTest
, ProxyMaybeEnabled
) {
827 // Don't actually try to resolve names.
828 Predictor::set_max_parallel_resolves(0);
830 Predictor
testing_master(true, true);
831 net::ProxyConfig config
= net::ProxyConfig::CreateFromCustomPacURL(GURL(
832 "http://foopy/proxy.pac"));
833 scoped_ptr
<net::ProxyService
> proxy_service(
834 net::ProxyService::CreateFixed(config
));
835 testing_master
.proxy_service_
= proxy_service
.get();
837 GURL
goog("http://www.google.com:80");
838 testing_master
.Resolve(goog
, UrlInfo::OMNIBOX_MOTIVATED
);
840 // Proxy may not be in use (the PAC script has not yet been evaluated), so the
841 // name has been registered for pre-resolve.
842 EXPECT_FALSE(testing_master
.work_queue_
.IsEmpty());
844 testing_master
.Shutdown();
847 } // namespace chrome_browser_net