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 "net/http/transport_security_state.h"
25 #include "testing/gmock/include/gmock/gmock.h"
26 #include "testing/gtest/include/gtest/gtest.h"
29 using base::TimeDelta;
30 using content::BrowserThread;
32 namespace chrome_browser_net {
34 class WaitForResolutionHelper;
36 typedef base::RepeatingTimer<WaitForResolutionHelper> HelperTimer;
38 class WaitForResolutionHelper {
40 WaitForResolutionHelper(Predictor* predictor, const UrlList& hosts,
41 HelperTimer* timer, int checks_until_quit)
42 : predictor_(predictor),
45 checks_until_quit_(checks_until_quit) {
48 void CheckIfResolutionsDone() {
49 if (--checks_until_quit_ > 0) {
50 for (UrlList::const_iterator i = hosts_.begin(); i != hosts_.end(); ++i)
51 if (predictor_->GetResolutionDuration(*i) ==
52 UrlInfo::NullDuration())
53 return; // We don't have resolution for that host.
56 // When all hostnames have been resolved, or we've hit the limit,
59 base::MessageLoop::current()->Quit();
65 Predictor* predictor_;
68 int checks_until_quit_;
71 class PredictorTest : public testing::Test {
74 : ui_thread_(BrowserThread::UI, &loop_),
75 io_thread_(BrowserThread::IO, &loop_),
76 host_resolver_(new net::MockCachingHostResolver()) {
80 virtual void SetUp() {
82 net::EnsureWinsockInit();
84 Predictor::set_max_parallel_resolves(
85 Predictor::kMaxSpeculativeParallelResolves);
86 Predictor::set_max_queueing_delay(
87 Predictor::kMaxSpeculativeResolveQueueDelayMs);
88 // Since we are using a caching HostResolver, the following latencies will
89 // only be incurred by the first request, after which the result will be
90 // cached internally by |host_resolver_|.
91 net::RuleBasedHostResolverProc* rules = host_resolver_->rules();
92 rules->AddRuleWithLatency("www.google.com", "127.0.0.1", 50);
93 rules->AddRuleWithLatency("gmail.google.com.com", "127.0.0.1", 70);
94 rules->AddRuleWithLatency("mail.google.com", "127.0.0.1", 44);
95 rules->AddRuleWithLatency("gmail.com", "127.0.0.1", 63);
98 void WaitForResolution(Predictor* predictor, const UrlList& hosts) {
99 HelperTimer* timer = new HelperTimer();
100 // By default allow the loop to run for a minute -- 600 iterations.
101 timer->Start(FROM_HERE, TimeDelta::FromMilliseconds(100),
102 new WaitForResolutionHelper(predictor, hosts, timer, 600),
103 &WaitForResolutionHelper::CheckIfResolutionsDone);
104 base::MessageLoop::current()->Run();
107 void WaitForResolutionWithLimit(
108 Predictor* predictor, const UrlList& hosts, int limit) {
109 HelperTimer* timer = new HelperTimer();
110 timer->Start(FROM_HERE, TimeDelta::FromMilliseconds(100),
111 new WaitForResolutionHelper(predictor, hosts, timer, limit),
112 &WaitForResolutionHelper::CheckIfResolutionsDone);
113 base::MessageLoop::current()->Run();
117 // IMPORTANT: do not move this below |host_resolver_|; the host resolver
118 // must not outlive the message loop, otherwise bad things can happen
119 // (like posting to a deleted message loop).
120 base::MessageLoopForUI loop_;
121 content::TestBrowserThread ui_thread_;
122 content::TestBrowserThread io_thread_;
125 scoped_ptr<net::MockCachingHostResolver> host_resolver_;
128 //------------------------------------------------------------------------------
130 TEST_F(PredictorTest, StartupShutdownTest) {
131 Predictor testing_master(true);
132 testing_master.Shutdown();
136 TEST_F(PredictorTest, ShutdownWhenResolutionIsPendingTest) {
137 scoped_ptr<net::HostResolver> host_resolver(new net::HangingHostResolver());
139 Predictor testing_master(true);
140 testing_master.SetHostResolver(host_resolver.get());
142 GURL localhost("http://localhost:80");
144 names.push_back(localhost);
146 testing_master.ResolveList(names, UrlInfo::PAGE_SCAN_MOTIVATED);
148 base::MessageLoop::current()->PostDelayedTask(
150 base::MessageLoop::QuitClosure(),
151 base::TimeDelta::FromMilliseconds(500));
152 base::MessageLoop::current()->Run();
154 EXPECT_FALSE(testing_master.WasFound(localhost));
156 testing_master.Shutdown();
158 // Clean up after ourselves.
159 base::MessageLoop::current()->RunUntilIdle();
162 TEST_F(PredictorTest, SingleLookupTest) {
163 Predictor testing_master(true);
164 testing_master.SetHostResolver(host_resolver_.get());
166 GURL goog("http://www.google.com:80");
169 names.push_back(goog);
171 // Try to flood the predictor with many concurrent requests.
172 for (int i = 0; i < 10; i++)
173 testing_master.ResolveList(names, UrlInfo::PAGE_SCAN_MOTIVATED);
175 WaitForResolution(&testing_master, names);
177 EXPECT_TRUE(testing_master.WasFound(goog));
179 base::MessageLoop::current()->RunUntilIdle();
181 EXPECT_GT(testing_master.peak_pending_lookups(), names.size() / 2);
182 EXPECT_LE(testing_master.peak_pending_lookups(), names.size());
183 EXPECT_LE(testing_master.peak_pending_lookups(),
184 testing_master.max_concurrent_dns_lookups());
186 testing_master.Shutdown();
189 TEST_F(PredictorTest, ConcurrentLookupTest) {
190 host_resolver_->rules()->AddSimulatedFailure("*.notfound");
192 Predictor testing_master(true);
193 testing_master.SetHostResolver(host_resolver_.get());
195 GURL goog("http://www.google.com:80"),
196 goog2("http://gmail.google.com.com:80"),
197 goog3("http://mail.google.com:80"),
198 goog4("http://gmail.com:80");
199 GURL bad1("http://bad1.notfound:80"),
200 bad2("http://bad2.notfound:80");
203 names.push_back(goog);
204 names.push_back(goog3);
205 names.push_back(bad1);
206 names.push_back(goog2);
207 names.push_back(bad2);
208 names.push_back(goog4);
209 names.push_back(goog);
211 // Try to flood the predictor with many concurrent requests.
212 for (int i = 0; i < 10; i++)
213 testing_master.ResolveList(names, UrlInfo::PAGE_SCAN_MOTIVATED);
215 WaitForResolution(&testing_master, names);
217 EXPECT_TRUE(testing_master.WasFound(goog));
218 EXPECT_TRUE(testing_master.WasFound(goog3));
219 EXPECT_TRUE(testing_master.WasFound(goog2));
220 EXPECT_TRUE(testing_master.WasFound(goog4));
221 EXPECT_FALSE(testing_master.WasFound(bad1));
222 EXPECT_FALSE(testing_master.WasFound(bad2));
224 base::MessageLoop::current()->RunUntilIdle();
226 EXPECT_FALSE(testing_master.WasFound(bad1));
227 EXPECT_FALSE(testing_master.WasFound(bad2));
229 EXPECT_LE(testing_master.peak_pending_lookups(), names.size());
230 EXPECT_LE(testing_master.peak_pending_lookups(),
231 testing_master.max_concurrent_dns_lookups());
233 testing_master.Shutdown();
236 TEST_F(PredictorTest, MassiveConcurrentLookupTest) {
237 host_resolver_->rules()->AddSimulatedFailure("*.notfound");
239 Predictor testing_master(true);
240 testing_master.SetHostResolver(host_resolver_.get());
243 for (int i = 0; i < 100; i++)
244 names.push_back(GURL(
245 "http://host" + base::IntToString(i) + ".notfound:80"));
247 // Try to flood the predictor with many concurrent requests.
248 for (int i = 0; i < 10; i++)
249 testing_master.ResolveList(names, UrlInfo::PAGE_SCAN_MOTIVATED);
251 WaitForResolution(&testing_master, names);
253 base::MessageLoop::current()->RunUntilIdle();
255 EXPECT_LE(testing_master.peak_pending_lookups(), names.size());
256 EXPECT_LE(testing_master.peak_pending_lookups(),
257 testing_master.max_concurrent_dns_lookups());
259 testing_master.Shutdown();
262 //------------------------------------------------------------------------------
263 // Functions to help synthesize and test serializations of subresource referrer
266 // Return a motivation_list if we can find one for the given motivating_host (or
267 // NULL if a match is not found).
268 static const base::ListValue* FindSerializationMotivation(
269 const GURL& motivation,
270 const base::ListValue* referral_list) {
271 CHECK_LT(0u, referral_list->GetSize()); // Room for version.
272 int format_version = -1;
273 CHECK(referral_list->GetInteger(0, &format_version));
274 CHECK_EQ(Predictor::kPredictorReferrerVersion, format_version);
275 const base::ListValue* motivation_list(NULL);
276 for (size_t i = 1; i < referral_list->GetSize(); ++i) {
277 referral_list->GetList(i, &motivation_list);
278 std::string existing_spec;
279 EXPECT_TRUE(motivation_list->GetString(0, &existing_spec));
280 if (motivation == GURL(existing_spec))
281 return motivation_list;
286 static base::ListValue* FindSerializationMotivation(
287 const GURL& motivation,
288 base::ListValue* referral_list) {
289 return const_cast<base::ListValue*>(FindSerializationMotivation(
290 motivation, static_cast<const base::ListValue*>(referral_list)));
293 // Create a new empty serialization list.
294 static base::ListValue* NewEmptySerializationList() {
295 base::ListValue* list = new base::ListValue;
297 new base::FundamentalValue(Predictor::kPredictorReferrerVersion));
301 // Add a motivating_url and a subresource_url to a serialized list, using
302 // this given latency. This is a helper function for quickly building these
304 static void AddToSerializedList(const GURL& motivation,
305 const GURL& subresource,
307 base::ListValue* referral_list) {
308 // Find the motivation if it is already used.
309 base::ListValue* motivation_list = FindSerializationMotivation(motivation,
311 if (!motivation_list) {
312 // This is the first mention of this motivation, so build a list.
313 motivation_list = new base::ListValue;
314 motivation_list->Append(new base::StringValue(motivation.spec()));
315 // Provide empty subresource list.
316 motivation_list->Append(new base::ListValue());
318 // ...and make it part of the serialized referral_list.
319 referral_list->Append(motivation_list);
322 base::ListValue* subresource_list(NULL);
323 // 0 == url; 1 == subresource_list.
324 EXPECT_TRUE(motivation_list->GetList(1, &subresource_list));
326 // We won't bother to check for the subresource being there already. Worst
327 // case, during deserialization, the latency value we supply plus the
328 // existing value(s) will be added to the referrer.
330 subresource_list->Append(new base::StringValue(subresource.spec()));
331 subresource_list->Append(new base::FundamentalValue(use_rate));
334 // For a given motivation, and subresource, find what latency is currently
335 // listed. This assume a well formed serialization, which has at most one such
336 // entry for any pair of names. If no such pair is found, then return false.
337 // Data is written into use_rate arguments.
338 static bool GetDataFromSerialization(const GURL& motivation,
339 const GURL& subresource,
340 const base::ListValue& referral_list,
342 const base::ListValue* motivation_list =
343 FindSerializationMotivation(motivation, &referral_list);
344 if (!motivation_list)
346 const base::ListValue* subresource_list;
347 EXPECT_TRUE(motivation_list->GetList(1, &subresource_list));
348 for (size_t i = 0; i < subresource_list->GetSize();) {
349 std::string url_spec;
350 EXPECT_TRUE(subresource_list->GetString(i++, &url_spec));
351 EXPECT_TRUE(subresource_list->GetDouble(i++, use_rate));
352 if (subresource == GURL(url_spec)) {
359 //------------------------------------------------------------------------------
361 // Make sure nil referral lists really have no entries, and no latency listed.
362 TEST_F(PredictorTest, ReferrerSerializationNilTest) {
363 Predictor predictor(true);
364 predictor.SetHostResolver(host_resolver_.get());
366 scoped_ptr<base::ListValue> referral_list(NewEmptySerializationList());
367 predictor.SerializeReferrers(referral_list.get());
368 EXPECT_EQ(1U, referral_list->GetSize());
369 EXPECT_FALSE(GetDataFromSerialization(
370 GURL("http://a.com:79"), GURL("http://b.com:78"),
371 *referral_list.get(), NULL));
373 predictor.Shutdown();
376 // Make sure that when a serialization list includes a value, that it can be
377 // deserialized into the database, and can be extracted back out via
378 // serialization without being changed.
379 TEST_F(PredictorTest, ReferrerSerializationSingleReferrerTest) {
380 Predictor predictor(true);
381 predictor.SetHostResolver(host_resolver_.get());
382 const GURL motivation_url("http://www.google.com:91");
383 const GURL subresource_url("http://icons.google.com:90");
384 const double kUseRate = 23.4;
385 scoped_ptr<base::ListValue> referral_list(NewEmptySerializationList());
387 AddToSerializedList(motivation_url, subresource_url,
388 kUseRate, referral_list.get());
390 predictor.DeserializeReferrers(*referral_list.get());
392 base::ListValue recovered_referral_list;
393 predictor.SerializeReferrers(&recovered_referral_list);
394 EXPECT_EQ(2U, recovered_referral_list.GetSize());
396 EXPECT_TRUE(GetDataFromSerialization(
397 motivation_url, subresource_url, recovered_referral_list, &rate));
398 EXPECT_EQ(rate, kUseRate);
400 predictor.Shutdown();
403 // Check that GetHtmlReferrerLists() doesn't crash when given duplicated
404 // domains for referring URL, and that it sorts the results in the
406 TEST_F(PredictorTest, GetHtmlReferrerLists) {
407 Predictor predictor(true);
408 predictor.SetHostResolver(host_resolver_.get());
409 const double kUseRate = 23.4;
410 scoped_ptr<base::ListValue> referral_list(NewEmptySerializationList());
413 GURL("http://d.google.com/x1"),
414 GURL("http://foo.com/"),
415 kUseRate, referral_list.get());
417 // Duplicated hostname (d.google.com). This should not cause any crashes
418 // (i.e. crbug.com/116345)
420 GURL("http://d.google.com/x2"),
421 GURL("http://foo.com/"),
422 kUseRate, referral_list.get());
425 GURL("http://a.yahoo.com/y"),
426 GURL("http://foo1.com/"),
427 kUseRate, referral_list.get());
430 GURL("http://b.google.com/x3"),
431 GURL("http://foo2.com/"),
432 kUseRate, referral_list.get());
435 GURL("http://d.yahoo.com/x5"),
436 GURL("http://i.like.turtles/"),
437 kUseRate, referral_list.get());
440 GURL("http://c.yahoo.com/x4"),
441 GURL("http://foo3.com/"),
442 kUseRate, referral_list.get());
444 predictor.DeserializeReferrers(*referral_list.get());
447 predictor.GetHtmlReferrerLists(&html);
449 // The lexicographic sorting of hostnames would be:
456 // However we expect to sort them by domain in the output:
464 html.find("<td rowspan=1>http://b.google.com/x3"),
465 html.find("<td rowspan=1>http://d.google.com/x1"),
466 html.find("<td rowspan=1>http://d.google.com/x2"),
467 html.find("<td rowspan=1>http://a.yahoo.com/y"),
468 html.find("<td rowspan=1>http://c.yahoo.com/x4"),
469 html.find("<td rowspan=1>http://d.yahoo.com/x5"),
472 // Make sure things appeared in the expected order.
473 for (size_t i = 1; i < arraysize(pos); ++i) {
474 EXPECT_LT(pos[i - 1], pos[i]) << "Mismatch for pos[" << i << "]";
477 predictor.Shutdown();
480 // Verify that two floats are within 1% of each other in value.
481 #define EXPECT_SIMILAR(a, b) do { \
482 double espilon_ratio = 1.01; \
484 espilon_ratio = 1 / espilon_ratio; \
485 EXPECT_LT(a, espilon_ratio * (b)); \
486 EXPECT_GT((a) * espilon_ratio, b); \
490 // Make sure the Trim() functionality works as expected.
491 TEST_F(PredictorTest, ReferrerSerializationTrimTest) {
492 Predictor predictor(true);
493 predictor.SetHostResolver(host_resolver_.get());
494 GURL motivation_url("http://www.google.com:110");
496 GURL icon_subresource_url("http://icons.google.com:111");
497 const double kRateIcon = 16.0 * Predictor::kDiscardableExpectedValue;
498 GURL img_subresource_url("http://img.google.com:118");
499 const double kRateImg = 8.0 * Predictor::kDiscardableExpectedValue;
501 scoped_ptr<base::ListValue> referral_list(NewEmptySerializationList());
503 motivation_url, icon_subresource_url, kRateIcon, referral_list.get());
505 motivation_url, img_subresource_url, kRateImg, referral_list.get());
507 predictor.DeserializeReferrers(*referral_list.get());
509 base::ListValue recovered_referral_list;
510 predictor.SerializeReferrers(&recovered_referral_list);
511 EXPECT_EQ(2U, recovered_referral_list.GetSize());
513 EXPECT_TRUE(GetDataFromSerialization(
514 motivation_url, icon_subresource_url, recovered_referral_list,
516 EXPECT_SIMILAR(rate, kRateIcon);
518 EXPECT_TRUE(GetDataFromSerialization(
519 motivation_url, img_subresource_url, recovered_referral_list, &rate));
520 EXPECT_SIMILAR(rate, kRateImg);
522 // Each time we Trim 24 times, the user_rate figures should reduce by a factor
523 // of two, until they are small, and then a trim will delete the whole entry.
524 for (int i = 0; i < 24; ++i)
525 predictor.TrimReferrersNow();
526 predictor.SerializeReferrers(&recovered_referral_list);
527 EXPECT_EQ(2U, recovered_referral_list.GetSize());
528 EXPECT_TRUE(GetDataFromSerialization(
529 motivation_url, icon_subresource_url, recovered_referral_list, &rate));
530 EXPECT_SIMILAR(rate, kRateIcon / 2);
532 EXPECT_TRUE(GetDataFromSerialization(
533 motivation_url, img_subresource_url, recovered_referral_list, &rate));
534 EXPECT_SIMILAR(rate, kRateImg / 2);
536 for (int i = 0; i < 24; ++i)
537 predictor.TrimReferrersNow();
538 predictor.SerializeReferrers(&recovered_referral_list);
539 EXPECT_EQ(2U, recovered_referral_list.GetSize());
540 EXPECT_TRUE(GetDataFromSerialization(
541 motivation_url, icon_subresource_url, recovered_referral_list, &rate));
542 EXPECT_SIMILAR(rate, kRateIcon / 4);
543 EXPECT_TRUE(GetDataFromSerialization(
544 motivation_url, img_subresource_url, recovered_referral_list, &rate));
545 EXPECT_SIMILAR(rate, kRateImg / 4);
547 for (int i = 0; i < 24; ++i)
548 predictor.TrimReferrersNow();
549 predictor.SerializeReferrers(&recovered_referral_list);
550 EXPECT_EQ(2U, recovered_referral_list.GetSize());
551 EXPECT_TRUE(GetDataFromSerialization(
552 motivation_url, icon_subresource_url, recovered_referral_list, &rate));
553 EXPECT_SIMILAR(rate, kRateIcon / 8);
555 // Img is below threshold, and so it gets deleted.
556 EXPECT_FALSE(GetDataFromSerialization(
557 motivation_url, img_subresource_url, recovered_referral_list, &rate));
559 for (int i = 0; i < 24; ++i)
560 predictor.TrimReferrersNow();
561 predictor.SerializeReferrers(&recovered_referral_list);
562 // Icon is also trimmed away, so entire set gets discarded.
563 EXPECT_EQ(1U, recovered_referral_list.GetSize());
564 EXPECT_FALSE(GetDataFromSerialization(
565 motivation_url, icon_subresource_url, recovered_referral_list, &rate));
566 EXPECT_FALSE(GetDataFromSerialization(
567 motivation_url, img_subresource_url, recovered_referral_list, &rate));
569 predictor.Shutdown();
573 TEST_F(PredictorTest, PriorityQueuePushPopTest) {
574 Predictor::HostNameQueue queue;
576 GURL first("http://first:80"), second("http://second:90");
578 // First check high priority queue FIFO functionality.
579 EXPECT_TRUE(queue.IsEmpty());
580 queue.Push(first, UrlInfo::LEARNED_REFERAL_MOTIVATED);
581 EXPECT_FALSE(queue.IsEmpty());
582 queue.Push(second, UrlInfo::MOUSE_OVER_MOTIVATED);
583 EXPECT_FALSE(queue.IsEmpty());
584 EXPECT_EQ(queue.Pop(), first);
585 EXPECT_FALSE(queue.IsEmpty());
586 EXPECT_EQ(queue.Pop(), second);
587 EXPECT_TRUE(queue.IsEmpty());
589 // Then check low priority queue FIFO functionality.
590 queue.Push(first, UrlInfo::PAGE_SCAN_MOTIVATED);
591 EXPECT_FALSE(queue.IsEmpty());
592 queue.Push(second, UrlInfo::OMNIBOX_MOTIVATED);
593 EXPECT_FALSE(queue.IsEmpty());
594 EXPECT_EQ(queue.Pop(), first);
595 EXPECT_FALSE(queue.IsEmpty());
596 EXPECT_EQ(queue.Pop(), second);
597 EXPECT_TRUE(queue.IsEmpty());
600 TEST_F(PredictorTest, PriorityQueueReorderTest) {
601 Predictor::HostNameQueue queue;
603 // Push all the low priority items.
604 GURL low1("http://low1:80"),
605 low2("http://low2:80"),
606 low3("http://low3:443"),
607 low4("http://low4:80"),
608 low5("http://low5:80"),
609 hi1("http://hi1:80"),
610 hi2("http://hi2:80"),
611 hi3("http://hi3:80");
613 EXPECT_TRUE(queue.IsEmpty());
614 queue.Push(low1, UrlInfo::PAGE_SCAN_MOTIVATED);
615 queue.Push(low2, UrlInfo::UNIT_TEST_MOTIVATED);
616 queue.Push(low3, UrlInfo::LINKED_MAX_MOTIVATED);
617 queue.Push(low4, UrlInfo::OMNIBOX_MOTIVATED);
618 queue.Push(low5, UrlInfo::STARTUP_LIST_MOTIVATED);
619 queue.Push(low4, UrlInfo::OMNIBOX_MOTIVATED);
621 // Push all the high prority items
622 queue.Push(hi1, UrlInfo::LEARNED_REFERAL_MOTIVATED);
623 queue.Push(hi2, UrlInfo::STATIC_REFERAL_MOTIVATED);
624 queue.Push(hi3, UrlInfo::MOUSE_OVER_MOTIVATED);
626 // Check that high priority stuff comes out first, and in FIFO order.
627 EXPECT_EQ(queue.Pop(), hi1);
628 EXPECT_EQ(queue.Pop(), hi2);
629 EXPECT_EQ(queue.Pop(), hi3);
631 // ...and then low priority strings.
632 EXPECT_EQ(queue.Pop(), low1);
633 EXPECT_EQ(queue.Pop(), low2);
634 EXPECT_EQ(queue.Pop(), low3);
635 EXPECT_EQ(queue.Pop(), low4);
636 EXPECT_EQ(queue.Pop(), low5);
637 EXPECT_EQ(queue.Pop(), low4);
639 EXPECT_TRUE(queue.IsEmpty());
642 TEST_F(PredictorTest, CanonicalizeUrl) {
643 // Base case, only handles HTTP and HTTPS.
644 EXPECT_EQ(GURL(), Predictor::CanonicalizeUrl(GURL("ftp://anything")));
646 // Remove path testing.
647 GURL long_url("http://host:999/path?query=value");
648 EXPECT_EQ(Predictor::CanonicalizeUrl(long_url), long_url.GetWithEmptyPath());
650 // Default port cannoncalization.
651 GURL implied_port("http://test");
652 GURL explicit_port("http://test:80");
653 EXPECT_EQ(Predictor::CanonicalizeUrl(implied_port),
654 Predictor::CanonicalizeUrl(explicit_port));
656 // Port is still maintained.
657 GURL port_80("http://test:80");
658 GURL port_90("http://test:90");
659 EXPECT_NE(Predictor::CanonicalizeUrl(port_80),
660 Predictor::CanonicalizeUrl(port_90));
662 // Host is still maintained.
663 GURL host_1("http://test_1");
664 GURL host_2("http://test_2");
665 EXPECT_NE(Predictor::CanonicalizeUrl(host_1),
666 Predictor::CanonicalizeUrl(host_2));
668 // Scheme is maintained (mismatch identified).
669 GURL http("http://test");
670 GURL https("https://test");
671 EXPECT_NE(Predictor::CanonicalizeUrl(http),
672 Predictor::CanonicalizeUrl(https));
675 GURL long_https("https://host:999/path?query=value");
676 EXPECT_EQ(Predictor::CanonicalizeUrl(long_https),
677 long_https.GetWithEmptyPath());
680 TEST_F(PredictorTest, DiscardPredictorResults) {
681 Predictor predictor(true);
682 predictor.SetHostResolver(host_resolver_.get());
683 base::ListValue referral_list;
684 predictor.SerializeReferrers(&referral_list);
685 EXPECT_EQ(1U, referral_list.GetSize());
687 GURL host_1("http://test_1");
688 GURL host_2("http://test_2");
689 predictor.LearnFromNavigation(host_1, host_2);
691 predictor.SerializeReferrers(&referral_list);
692 EXPECT_EQ(2U, referral_list.GetSize());
694 predictor.DiscardAllResults();
695 predictor.SerializeReferrers(&referral_list);
696 EXPECT_EQ(1U, referral_list.GetSize());
698 predictor.Shutdown();
701 class TestPredictorObserver : public PredictorObserver {
703 // PredictorObserver implementation:
704 virtual void OnPreconnectUrl(const GURL& url,
705 const GURL& first_party_for_cookies,
706 UrlInfo::ResolutionMotivation motivation,
707 int count) OVERRIDE {
708 preconnected_urls_.push_back(url);
711 std::vector<GURL> preconnected_urls_;
714 // Tests that preconnects apply the HSTS list.
715 TEST_F(PredictorTest, HSTSRedirect) {
716 const GURL kHttpUrl("http://example.com");
717 const GURL kHttpsUrl("https://example.com");
719 const base::Time expiry =
720 base::Time::Now() + base::TimeDelta::FromSeconds(1000);
721 net::TransportSecurityState state;
722 state.AddHSTS(kHttpUrl.host(), expiry, false);
724 Predictor predictor(true);
725 TestPredictorObserver observer;
726 predictor.SetObserver(&observer);
727 predictor.SetTransportSecurityState(&state);
729 predictor.PreconnectUrl(kHttpUrl, GURL(), UrlInfo::OMNIBOX_MOTIVATED, 2);
730 ASSERT_EQ(1u, observer.preconnected_urls_.size());
731 EXPECT_EQ(kHttpsUrl, observer.preconnected_urls_[0]);
733 predictor.Shutdown();
736 // Tests that preconnecting a URL on the HSTS list preconnects the subresources
737 // for the SSL version.
738 TEST_F(PredictorTest, HSTSRedirectSubresources) {
739 const GURL kHttpUrl("http://example.com");
740 const GURL kHttpsUrl("https://example.com");
741 const GURL kSubresourceUrl("https://images.example.com");
742 const double kUseRate = 23.4;
744 const base::Time expiry =
745 base::Time::Now() + base::TimeDelta::FromSeconds(1000);
746 net::TransportSecurityState state;
747 state.AddHSTS(kHttpUrl.host(), expiry, false);
749 Predictor predictor(true);
750 TestPredictorObserver observer;
751 predictor.SetObserver(&observer);
752 predictor.SetTransportSecurityState(&state);
754 scoped_ptr<base::ListValue> referral_list(NewEmptySerializationList());
756 kHttpsUrl, kSubresourceUrl, kUseRate, referral_list.get());
757 predictor.DeserializeReferrers(*referral_list.get());
759 predictor.PreconnectUrlAndSubresources(kHttpUrl, GURL());
760 ASSERT_EQ(2u, observer.preconnected_urls_.size());
761 EXPECT_EQ(kHttpsUrl, observer.preconnected_urls_[0]);
762 EXPECT_EQ(kSubresourceUrl, observer.preconnected_urls_[1]);
764 predictor.Shutdown();
767 #if defined(OS_ANDROID) || defined(OS_IOS)
768 // Tests for the predictor with a proxy advisor
770 class TestProxyAdvisor : public ProxyAdvisor {
773 : ProxyAdvisor(NULL, NULL),
776 would_proxy_count_(0) {
779 virtual ~TestProxyAdvisor() {}
781 virtual void Advise(const GURL& url,
782 UrlInfo::ResolutionMotivation motivation,
783 bool is_preconnect) OVERRIDE {
787 virtual bool WouldProxyURL(const GURL& url) OVERRIDE {
788 ++would_proxy_count_;
794 int would_proxy_count_;
797 TEST_F(PredictorTest, SingleLookupTestWithDisabledAdvisor) {
798 Predictor testing_master(true);
799 TestProxyAdvisor* advisor = new TestProxyAdvisor();
800 testing_master.SetHostResolver(host_resolver_.get());
801 testing_master.proxy_advisor_.reset(advisor);
803 GURL goog("http://www.google.com:80");
805 advisor->would_proxy_ = false;
808 names.push_back(goog);
809 testing_master.ResolveList(names, UrlInfo::PAGE_SCAN_MOTIVATED);
811 WaitForResolution(&testing_master, names);
812 EXPECT_TRUE(testing_master.WasFound(goog));
813 EXPECT_EQ(advisor->would_proxy_count_, 1);
814 EXPECT_EQ(advisor->advise_count_, 1);
816 base::MessageLoop::current()->RunUntilIdle();
818 testing_master.Shutdown();
821 TEST_F(PredictorTest, SingleLookupTestWithEnabledAdvisor) {
822 Predictor testing_master(true);
823 testing_master.SetHostResolver(host_resolver_.get());
824 TestProxyAdvisor* advisor = new TestProxyAdvisor();
825 testing_master.proxy_advisor_.reset(advisor);
827 GURL goog("http://www.google.com:80");
829 advisor->would_proxy_ = true;
832 names.push_back(goog);
834 testing_master.ResolveList(names, UrlInfo::PAGE_SCAN_MOTIVATED);
836 // Attempt to resolve a few times.
837 WaitForResolutionWithLimit(&testing_master, names, 10);
839 // Because the advisor indicated that the url would be proxied,
840 // no resolution should have occurred.
841 EXPECT_FALSE(testing_master.WasFound(goog));
842 EXPECT_EQ(advisor->would_proxy_count_, 1);
843 EXPECT_EQ(advisor->advise_count_, 1);
845 base::MessageLoop::current()->RunUntilIdle();
847 testing_master.Shutdown();
850 TEST_F(PredictorTest, TestSimplePreconnectAdvisor) {
851 Predictor testing_master(true);
852 testing_master.SetHostResolver(host_resolver_.get());
853 TestProxyAdvisor* advisor = new TestProxyAdvisor();
854 testing_master.proxy_advisor_.reset(advisor);
856 GURL goog("http://www.google.com:80");
858 testing_master.PreconnectUrl(goog, goog, UrlInfo::OMNIBOX_MOTIVATED, 2);
860 EXPECT_EQ(advisor->would_proxy_count_, 0);
861 EXPECT_EQ(advisor->advise_count_, 1);
863 testing_master.Shutdown();
866 #endif // defined(OS_ANDROID) || defined(OS_IOS)
868 } // namespace chrome_browser_net