1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <time.h>
6
7 #include <algorithm>
8 #include <sstream>
9 #include <string>
10
11 #include "base/memory/scoped_ptr.h"
12 #include "base/message_loop.h"
13 #include "base/string_number_conversions.h"
14 #include "base/timer.h"
15 #include "base/values.h"
16 #include "chrome/browser/net/predictor_api.h"
17 #include "chrome/browser/net/url_info.h"
18 #include "chrome/common/net/predictor_common.h"
19 #include "content/browser/browser_thread.h"
20 #include "net/base/address_list.h"
21 #include "net/base/mock_host_resolver.h"
22 #include "net/base/winsock_init.h"
23 #include "testing/gtest/include/gtest/gtest.h"
24
25 using base::Time;
26 using base::TimeDelta;
27
28 namespace chrome_browser_net {
29
30 class WaitForResolutionHelper;
31
32 typedef base::RepeatingTimer<WaitForResolutionHelper> HelperTimer;
33
34 class WaitForResolutionHelper {
35 public:
WaitForResolutionHelper(Predictor * predictor,const UrlList & hosts,HelperTimer * timer)36 WaitForResolutionHelper(Predictor* predictor, const UrlList& hosts,
37 HelperTimer* timer)
38 : predictor_(predictor),
39 hosts_(hosts),
40 timer_(timer) {
41 }
42
Run()43 void Run() {
44 for (UrlList::const_iterator i = hosts_.begin(); i != hosts_.end(); ++i)
45 if (predictor_->GetResolutionDuration(*i) ==
46 UrlInfo::kNullDuration)
47 return; // We don't have resolution for that host.
48
49 // When all hostnames have been resolved, exit the loop.
50 timer_->Stop();
51 MessageLoop::current()->Quit();
52 delete timer_;
53 delete this;
54 }
55
56 private:
57 Predictor* predictor_;
58 const UrlList hosts_;
59 HelperTimer* timer_;
60 };
61
62 class PredictorTest : public testing::Test {
63 public:
PredictorTest()64 PredictorTest()
65 : io_thread_(BrowserThread::IO, &loop_),
66 host_resolver_(new net::MockCachingHostResolver()),
67 default_max_queueing_delay_(TimeDelta::FromMilliseconds(
68 PredictorInit::kMaxSpeculativeResolveQueueDelayMs)) {
69 }
70
71 protected:
SetUp()72 virtual void SetUp() {
73 #if defined(OS_WIN)
74 net::EnsureWinsockInit();
75 #endif
76 // Since we are using a caching HostResolver, the following latencies will
77 // only be incurred by the first request, after which the result will be
78 // cached internally by |host_resolver_|.
79 net::RuleBasedHostResolverProc* rules = host_resolver_->rules();
80 rules->AddRuleWithLatency("www.google.com", "127.0.0.1", 50);
81 rules->AddRuleWithLatency("gmail.google.com.com", "127.0.0.1", 70);
82 rules->AddRuleWithLatency("mail.google.com", "127.0.0.1", 44);
83 rules->AddRuleWithLatency("gmail.com", "127.0.0.1", 63);
84 }
85
WaitForResolution(Predictor * predictor,const UrlList & hosts)86 void WaitForResolution(Predictor* predictor, const UrlList& hosts) {
87 HelperTimer* timer = new HelperTimer();
88 timer->Start(TimeDelta::FromMilliseconds(100),
89 new WaitForResolutionHelper(predictor, hosts, timer),
90 &WaitForResolutionHelper::Run);
91 MessageLoop::current()->Run();
92 }
93
94 private:
95 // IMPORTANT: do not move this below |host_resolver_|; the host resolver
96 // must not outlive the message loop, otherwise bad things can happen
97 // (like posting to a deleted message loop).
98 MessageLoop loop_;
99 BrowserThread io_thread_;
100
101 protected:
102 scoped_ptr<net::MockCachingHostResolver> host_resolver_;
103
104 // Shorthand to access TimeDelta of PredictorInit::kMaxQueueingDelayMs.
105 // (It would be a static constant... except style rules preclude that :-/ ).
106 const TimeDelta default_max_queueing_delay_;
107 };
108
109 //------------------------------------------------------------------------------
110
TEST_F(PredictorTest,StartupShutdownTest)111 TEST_F(PredictorTest, StartupShutdownTest) {
112 scoped_refptr<Predictor> testing_master(
113 new Predictor(host_resolver_.get(),
114 default_max_queueing_delay_,
115 PredictorInit::kMaxSpeculativeParallelResolves,
116 false));
117 testing_master->Shutdown();
118 }
119
120
TEST_F(PredictorTest,ShutdownWhenResolutionIsPendingTest)121 TEST_F(PredictorTest, ShutdownWhenResolutionIsPendingTest) {
122 scoped_refptr<net::WaitingHostResolverProc> resolver_proc(
123 new net::WaitingHostResolverProc(NULL));
124 host_resolver_->Reset(resolver_proc);
125
126 scoped_refptr<Predictor> testing_master(
127 new Predictor(host_resolver_.get(),
128 default_max_queueing_delay_,
129 PredictorInit::kMaxSpeculativeParallelResolves,
130 false));
131
132 GURL localhost("http://localhost:80");
133 UrlList names;
134 names.push_back(localhost);
135
136 testing_master->ResolveList(names, UrlInfo::PAGE_SCAN_MOTIVATED);
137
138 MessageLoop::current()->PostDelayedTask(FROM_HERE,
139 new MessageLoop::QuitTask(), 500);
140 MessageLoop::current()->Run();
141
142 EXPECT_FALSE(testing_master->WasFound(localhost));
143
144 testing_master->Shutdown();
145
146 // Clean up after ourselves.
147 resolver_proc->Signal();
148 MessageLoop::current()->RunAllPending();
149 }
150
TEST_F(PredictorTest,SingleLookupTest)151 TEST_F(PredictorTest, SingleLookupTest) {
152 scoped_refptr<Predictor> testing_master(
153 new Predictor(host_resolver_.get(),
154 default_max_queueing_delay_,
155 PredictorInit::kMaxSpeculativeParallelResolves,
156 false));
157
158 GURL goog("http://www.google.com:80");
159
160 UrlList names;
161 names.push_back(goog);
162
163 // Try to flood the predictor with many concurrent requests.
164 for (int i = 0; i < 10; i++)
165 testing_master->ResolveList(names, UrlInfo::PAGE_SCAN_MOTIVATED);
166
167 WaitForResolution(testing_master, names);
168
169 EXPECT_TRUE(testing_master->WasFound(goog));
170
171 MessageLoop::current()->RunAllPending();
172
173 EXPECT_GT(testing_master->peak_pending_lookups(), names.size() / 2);
174 EXPECT_LE(testing_master->peak_pending_lookups(), names.size());
175 EXPECT_LE(testing_master->peak_pending_lookups(),
176 testing_master->max_concurrent_dns_lookups());
177
178 testing_master->Shutdown();
179 }
180
TEST_F(PredictorTest,ConcurrentLookupTest)181 TEST_F(PredictorTest, ConcurrentLookupTest) {
182 host_resolver_->rules()->AddSimulatedFailure("*.notfound");
183
184 scoped_refptr<Predictor> testing_master(
185 new Predictor(host_resolver_.get(),
186 default_max_queueing_delay_,
187 PredictorInit::kMaxSpeculativeParallelResolves,
188 false));
189
190 GURL goog("http://www.google.com:80"),
191 goog2("http://gmail.google.com.com:80"),
192 goog3("http://mail.google.com:80"),
193 goog4("http://gmail.com:80");
194 GURL bad1("http://bad1.notfound:80"),
195 bad2("http://bad2.notfound:80");
196
197 UrlList names;
198 names.push_back(goog);
199 names.push_back(goog3);
200 names.push_back(bad1);
201 names.push_back(goog2);
202 names.push_back(bad2);
203 names.push_back(goog4);
204 names.push_back(goog);
205
206 // Try to flood the predictor with many concurrent requests.
207 for (int i = 0; i < 10; i++)
208 testing_master->ResolveList(names, UrlInfo::PAGE_SCAN_MOTIVATED);
209
210 WaitForResolution(testing_master, names);
211
212 EXPECT_TRUE(testing_master->WasFound(goog));
213 EXPECT_TRUE(testing_master->WasFound(goog3));
214 EXPECT_TRUE(testing_master->WasFound(goog2));
215 EXPECT_TRUE(testing_master->WasFound(goog4));
216 EXPECT_FALSE(testing_master->WasFound(bad1));
217 EXPECT_FALSE(testing_master->WasFound(bad2));
218
219 MessageLoop::current()->RunAllPending();
220
221 EXPECT_FALSE(testing_master->WasFound(bad1));
222 EXPECT_FALSE(testing_master->WasFound(bad2));
223
224 EXPECT_LE(testing_master->peak_pending_lookups(), names.size());
225 EXPECT_LE(testing_master->peak_pending_lookups(),
226 testing_master->max_concurrent_dns_lookups());
227
228 testing_master->Shutdown();
229 }
230
TEST_F(PredictorTest,MassiveConcurrentLookupTest)231 TEST_F(PredictorTest, MassiveConcurrentLookupTest) {
232 host_resolver_->rules()->AddSimulatedFailure("*.notfound");
233
234 scoped_refptr<Predictor> testing_master(
235 new Predictor(host_resolver_.get(),
236 default_max_queueing_delay_,
237 PredictorInit::kMaxSpeculativeParallelResolves,
238 false));
239
240 UrlList names;
241 for (int i = 0; i < 100; i++)
242 names.push_back(GURL(
243 "http://host" + base::IntToString(i) + ".notfound:80"));
244
245 // Try to flood the predictor with many concurrent requests.
246 for (int i = 0; i < 10; i++)
247 testing_master->ResolveList(names, UrlInfo::PAGE_SCAN_MOTIVATED);
248
249 WaitForResolution(testing_master, names);
250
251 MessageLoop::current()->RunAllPending();
252
253 EXPECT_LE(testing_master->peak_pending_lookups(), names.size());
254 EXPECT_LE(testing_master->peak_pending_lookups(),
255 testing_master->max_concurrent_dns_lookups());
256
257 testing_master->Shutdown();
258 }
259
260 //------------------------------------------------------------------------------
261 // Functions to help synthesize and test serializations of subresource referrer
262 // lists.
263
264 // Return a motivation_list if we can find one for the given motivating_host (or
265 // NULL if a match is not found).
FindSerializationMotivation(const GURL & motivation,const ListValue & referral_list)266 static ListValue* FindSerializationMotivation(
267 const GURL& motivation, const ListValue& referral_list) {
268 CHECK_LT(0u, referral_list.GetSize()); // Room for version.
269 int format_version = -1;
270 CHECK(referral_list.GetInteger(0, &format_version));
271 CHECK_EQ(Predictor::PREDICTOR_REFERRER_VERSION, format_version);
272 ListValue* motivation_list(NULL);
273 for (size_t i = 1; i < referral_list.GetSize(); ++i) {
274 referral_list.GetList(i, &motivation_list);
275 std::string existing_spec;
276 EXPECT_TRUE(motivation_list->GetString(0, &existing_spec));
277 if (motivation == GURL(existing_spec))
278 return motivation_list;
279 }
280 return NULL;
281 }
282
283 // Create a new empty serialization list.
NewEmptySerializationList()284 static ListValue* NewEmptySerializationList() {
285 ListValue* list = new ListValue;
286 list->Append(new FundamentalValue(Predictor::PREDICTOR_REFERRER_VERSION));
287 return list;
288 }
289
290 // Add a motivating_url and a subresource_url to a serialized list, using
291 // this given latency. This is a helper function for quickly building these
292 // lists.
AddToSerializedList(const GURL & motivation,const GURL & subresource,double use_rate,ListValue * referral_list)293 static void AddToSerializedList(const GURL& motivation,
294 const GURL& subresource,
295 double use_rate,
296 ListValue* referral_list ) {
297 // Find the motivation if it is already used.
298 ListValue* motivation_list = FindSerializationMotivation(motivation,
299 *referral_list);
300 if (!motivation_list) {
301 // This is the first mention of this motivation, so build a list.
302 motivation_list = new ListValue;
303 motivation_list->Append(new StringValue(motivation.spec()));
304 // Provide empty subresource list.
305 motivation_list->Append(new ListValue());
306
307 // ...and make it part of the serialized referral_list.
308 referral_list->Append(motivation_list);
309 }
310
311 ListValue* subresource_list(NULL);
312 // 0 == url; 1 == subresource_list.
313 EXPECT_TRUE(motivation_list->GetList(1, &subresource_list));
314
315 // We won't bother to check for the subresource being there already. Worst
316 // case, during deserialization, the latency value we supply plus the
317 // existing value(s) will be added to the referrer.
318
319 subresource_list->Append(new StringValue(subresource.spec()));
320 subresource_list->Append(new FundamentalValue(use_rate));
321 }
322
323 static const int kLatencyNotFound = -1;
324
325 // For a given motivation, and subresource, find what latency is currently
326 // listed. This assume a well formed serialization, which has at most one such
327 // entry for any pair of names. If no such pair is found, then return false.
328 // Data is written into use_rate arguments.
GetDataFromSerialization(const GURL & motivation,const GURL & subresource,const ListValue & referral_list,double * use_rate)329 static bool GetDataFromSerialization(const GURL& motivation,
330 const GURL& subresource,
331 const ListValue& referral_list,
332 double* use_rate) {
333 ListValue* motivation_list = FindSerializationMotivation(motivation,
334 referral_list);
335 if (!motivation_list)
336 return false;
337 ListValue* subresource_list;
338 EXPECT_TRUE(motivation_list->GetList(1, &subresource_list));
339 for (size_t i = 0; i < subresource_list->GetSize();) {
340 std::string url_spec;
341 EXPECT_TRUE(subresource_list->GetString(i++, &url_spec));
342 EXPECT_TRUE(subresource_list->GetDouble(i++, use_rate));
343 if (subresource == GURL(url_spec)) {
344 return true;
345 }
346 }
347 return false;
348 }
349
350 //------------------------------------------------------------------------------
351
352 // Make sure nil referral lists really have no entries, and no latency listed.
TEST_F(PredictorTest,ReferrerSerializationNilTest)353 TEST_F(PredictorTest, ReferrerSerializationNilTest) {
354 scoped_refptr<Predictor> predictor(
355 new Predictor(host_resolver_.get(),
356 default_max_queueing_delay_,
357 PredictorInit::kMaxSpeculativeParallelResolves,
358 false));
359 scoped_ptr<ListValue> referral_list(NewEmptySerializationList());
360 predictor->SerializeReferrers(referral_list.get());
361 EXPECT_EQ(1U, referral_list->GetSize());
362 EXPECT_FALSE(GetDataFromSerialization(
363 GURL("http://a.com:79"), GURL("http://b.com:78"),
364 *referral_list.get(), NULL));
365
366 predictor->Shutdown();
367 }
368
369 // Make sure that when a serialization list includes a value, that it can be
370 // deserialized into the database, and can be extracted back out via
371 // serialization without being changed.
TEST_F(PredictorTest,ReferrerSerializationSingleReferrerTest)372 TEST_F(PredictorTest, ReferrerSerializationSingleReferrerTest) {
373 scoped_refptr<Predictor> predictor(
374 new Predictor(host_resolver_.get(),
375 default_max_queueing_delay_,
376 PredictorInit::kMaxSpeculativeParallelResolves,
377 false));
378 const GURL motivation_url("http://www.google.com:91");
379 const GURL subresource_url("http://icons.google.com:90");
380 const double kUseRate = 23.4;
381 scoped_ptr<ListValue> referral_list(NewEmptySerializationList());
382
383 AddToSerializedList(motivation_url, subresource_url,
384 kUseRate, referral_list.get());
385
386 predictor->DeserializeReferrers(*referral_list.get());
387
388 ListValue recovered_referral_list;
389 predictor->SerializeReferrers(&recovered_referral_list);
390 EXPECT_EQ(2U, recovered_referral_list.GetSize());
391 double rate;
392 EXPECT_TRUE(GetDataFromSerialization(
393 motivation_url, subresource_url, recovered_referral_list, &rate));
394 EXPECT_EQ(rate, kUseRate);
395
396 predictor->Shutdown();
397 }
398
399 // Verify that two floats are within 1% of each other in value.
400 #define EXPECT_SIMILAR(a, b) do { \
401 double espilon_ratio = 1.01; \
402 if ((a) < 0.) \
403 espilon_ratio = 1 / espilon_ratio; \
404 EXPECT_LT(a, espilon_ratio * (b)); \
405 EXPECT_GT((a) * espilon_ratio, b); \
406 } while (0)
407
408
409 // Make sure the Trim() functionality works as expected.
TEST_F(PredictorTest,ReferrerSerializationTrimTest)410 TEST_F(PredictorTest, ReferrerSerializationTrimTest) {
411 scoped_refptr<Predictor> predictor(
412 new Predictor(host_resolver_.get(),
413 default_max_queueing_delay_,
414 PredictorInit::kMaxSpeculativeParallelResolves,
415 false));
416 GURL motivation_url("http://www.google.com:110");
417
418 GURL icon_subresource_url("http://icons.google.com:111");
419 const double kRateIcon = 16.0 * Predictor::kDiscardableExpectedValue;
420 GURL img_subresource_url("http://img.google.com:118");
421 const double kRateImg = 8.0 * Predictor::kDiscardableExpectedValue;
422
423 scoped_ptr<ListValue> referral_list(NewEmptySerializationList());
424 AddToSerializedList(
425 motivation_url, icon_subresource_url, kRateIcon, referral_list.get());
426 AddToSerializedList(
427 motivation_url, img_subresource_url, kRateImg, referral_list.get());
428
429 predictor->DeserializeReferrers(*referral_list.get());
430
431 ListValue recovered_referral_list;
432 predictor->SerializeReferrers(&recovered_referral_list);
433 EXPECT_EQ(2U, recovered_referral_list.GetSize());
434 double rate;
435 EXPECT_TRUE(GetDataFromSerialization(
436 motivation_url, icon_subresource_url, recovered_referral_list,
437 &rate));
438 EXPECT_SIMILAR(rate, kRateIcon);
439
440 EXPECT_TRUE(GetDataFromSerialization(
441 motivation_url, img_subresource_url, recovered_referral_list, &rate));
442 EXPECT_SIMILAR(rate, kRateImg);
443
444 // Each time we Trim 24 times, the user_rate figures should reduce by a factor
445 // of two, until they are small, and then a trim will delete the whole entry.
446 for (int i = 0; i < 24; ++i)
447 predictor->TrimReferrersNow();
448 predictor->SerializeReferrers(&recovered_referral_list);
449 EXPECT_EQ(2U, recovered_referral_list.GetSize());
450 EXPECT_TRUE(GetDataFromSerialization(
451 motivation_url, icon_subresource_url, recovered_referral_list, &rate));
452 EXPECT_SIMILAR(rate, kRateIcon / 2);
453
454 EXPECT_TRUE(GetDataFromSerialization(
455 motivation_url, img_subresource_url, recovered_referral_list, &rate));
456 EXPECT_SIMILAR(rate, kRateImg / 2);
457
458 for (int i = 0; i < 24; ++i)
459 predictor->TrimReferrersNow();
460 predictor->SerializeReferrers(&recovered_referral_list);
461 EXPECT_EQ(2U, recovered_referral_list.GetSize());
462 EXPECT_TRUE(GetDataFromSerialization(
463 motivation_url, icon_subresource_url, recovered_referral_list, &rate));
464 EXPECT_SIMILAR(rate, kRateIcon / 4);
465 EXPECT_TRUE(GetDataFromSerialization(
466 motivation_url, img_subresource_url, recovered_referral_list, &rate));
467 EXPECT_SIMILAR(rate, kRateImg / 4);
468
469 for (int i = 0; i < 24; ++i)
470 predictor->TrimReferrersNow();
471 predictor->SerializeReferrers(&recovered_referral_list);
472 EXPECT_EQ(2U, recovered_referral_list.GetSize());
473 EXPECT_TRUE(GetDataFromSerialization(
474 motivation_url, icon_subresource_url, recovered_referral_list, &rate));
475 EXPECT_SIMILAR(rate, kRateIcon / 8);
476
477 // Img is below threshold, and so it gets deleted.
478 EXPECT_FALSE(GetDataFromSerialization(
479 motivation_url, img_subresource_url, recovered_referral_list, &rate));
480
481 for (int i = 0; i < 24; ++i)
482 predictor->TrimReferrersNow();
483 predictor->SerializeReferrers(&recovered_referral_list);
484 // Icon is also trimmed away, so entire set gets discarded.
485 EXPECT_EQ(1U, recovered_referral_list.GetSize());
486 EXPECT_FALSE(GetDataFromSerialization(
487 motivation_url, icon_subresource_url, recovered_referral_list, &rate));
488 EXPECT_FALSE(GetDataFromSerialization(
489 motivation_url, img_subresource_url, recovered_referral_list, &rate));
490
491 predictor->Shutdown();
492 }
493
494
TEST_F(PredictorTest,PriorityQueuePushPopTest)495 TEST_F(PredictorTest, PriorityQueuePushPopTest) {
496 Predictor::HostNameQueue queue;
497
498 GURL first("http://first:80"), second("http://second:90");
499
500 // First check high priority queue FIFO functionality.
501 EXPECT_TRUE(queue.IsEmpty());
502 queue.Push(first, UrlInfo::LEARNED_REFERAL_MOTIVATED);
503 EXPECT_FALSE(queue.IsEmpty());
504 queue.Push(second, UrlInfo::MOUSE_OVER_MOTIVATED);
505 EXPECT_FALSE(queue.IsEmpty());
506 EXPECT_EQ(queue.Pop(), first);
507 EXPECT_FALSE(queue.IsEmpty());
508 EXPECT_EQ(queue.Pop(), second);
509 EXPECT_TRUE(queue.IsEmpty());
510
511 // Then check low priority queue FIFO functionality.
512 queue.Push(first, UrlInfo::PAGE_SCAN_MOTIVATED);
513 EXPECT_FALSE(queue.IsEmpty());
514 queue.Push(second, UrlInfo::OMNIBOX_MOTIVATED);
515 EXPECT_FALSE(queue.IsEmpty());
516 EXPECT_EQ(queue.Pop(), first);
517 EXPECT_FALSE(queue.IsEmpty());
518 EXPECT_EQ(queue.Pop(), second);
519 EXPECT_TRUE(queue.IsEmpty());
520 }
521
TEST_F(PredictorTest,PriorityQueueReorderTest)522 TEST_F(PredictorTest, PriorityQueueReorderTest) {
523 Predictor::HostNameQueue queue;
524
525 // Push all the low priority items.
526 GURL low1("http://low1:80"),
527 low2("http://low2:80"),
528 low3("http://low3:443"),
529 low4("http://low4:80"),
530 low5("http://low5:80"),
531 hi1("http://hi1:80"),
532 hi2("http://hi2:80"),
533 hi3("http://hi3:80");
534
535 EXPECT_TRUE(queue.IsEmpty());
536 queue.Push(low1, UrlInfo::PAGE_SCAN_MOTIVATED);
537 queue.Push(low2, UrlInfo::UNIT_TEST_MOTIVATED);
538 queue.Push(low3, UrlInfo::LINKED_MAX_MOTIVATED);
539 queue.Push(low4, UrlInfo::OMNIBOX_MOTIVATED);
540 queue.Push(low5, UrlInfo::STARTUP_LIST_MOTIVATED);
541 queue.Push(low4, UrlInfo::OMNIBOX_MOTIVATED);
542
543 // Push all the high prority items
544 queue.Push(hi1, UrlInfo::LEARNED_REFERAL_MOTIVATED);
545 queue.Push(hi2, UrlInfo::STATIC_REFERAL_MOTIVATED);
546 queue.Push(hi3, UrlInfo::MOUSE_OVER_MOTIVATED);
547
548 // Check that high priority stuff comes out first, and in FIFO order.
549 EXPECT_EQ(queue.Pop(), hi1);
550 EXPECT_EQ(queue.Pop(), hi2);
551 EXPECT_EQ(queue.Pop(), hi3);
552
553 // ...and then low priority strings.
554 EXPECT_EQ(queue.Pop(), low1);
555 EXPECT_EQ(queue.Pop(), low2);
556 EXPECT_EQ(queue.Pop(), low3);
557 EXPECT_EQ(queue.Pop(), low4);
558 EXPECT_EQ(queue.Pop(), low5);
559 EXPECT_EQ(queue.Pop(), low4);
560
561 EXPECT_TRUE(queue.IsEmpty());
562 }
563
TEST_F(PredictorTest,CanonicalizeUrl)564 TEST_F(PredictorTest, CanonicalizeUrl) {
565 // Base case, only handles HTTP and HTTPS.
566 EXPECT_EQ(GURL(), Predictor::CanonicalizeUrl(GURL("ftp://anything")));
567
568 // Remove path testing.
569 GURL long_url("http://host:999/path?query=value");
570 EXPECT_EQ(Predictor::CanonicalizeUrl(long_url), long_url.GetWithEmptyPath());
571
572 // Default port cannoncalization.
573 GURL implied_port("http://test");
574 GURL explicit_port("http://test:80");
575 EXPECT_EQ(Predictor::CanonicalizeUrl(implied_port),
576 Predictor::CanonicalizeUrl(explicit_port));
577
578 // Port is still maintained.
579 GURL port_80("http://test:80");
580 GURL port_90("http://test:90");
581 EXPECT_NE(Predictor::CanonicalizeUrl(port_80),
582 Predictor::CanonicalizeUrl(port_90));
583
584 // Host is still maintained.
585 GURL host_1("http://test_1");
586 GURL host_2("http://test_2");
587 EXPECT_NE(Predictor::CanonicalizeUrl(host_1),
588 Predictor::CanonicalizeUrl(host_2));
589
590 // Scheme is maintained (mismatch identified).
591 GURL http("http://test");
592 GURL https("https://test");
593 EXPECT_NE(Predictor::CanonicalizeUrl(http),
594 Predictor::CanonicalizeUrl(https));
595
596 // Https works fine.
597 GURL long_https("https://host:999/path?query=value");
598 EXPECT_EQ(Predictor::CanonicalizeUrl(long_https),
599 long_https.GetWithEmptyPath());
600 }
601
TEST_F(PredictorTest,DiscardPredictorResults)602 TEST_F(PredictorTest, DiscardPredictorResults) {
603 scoped_refptr<Predictor> predictor(
604 new Predictor(host_resolver_.get(),
605 default_max_queueing_delay_,
606 PredictorInit::kMaxSpeculativeParallelResolves,
607 false));
608 ListValue referral_list;
609 predictor->SerializeReferrers(&referral_list);
610 EXPECT_EQ(1U, referral_list.GetSize());
611
612 GURL host_1("http://test_1");
613 GURL host_2("http://test_2");
614 predictor->LearnFromNavigation(host_1, host_2);
615
616 predictor->SerializeReferrers(&referral_list);
617 EXPECT_EQ(2U, referral_list.GetSize());
618
619 predictor->DiscardAllResults();
620 predictor->SerializeReferrers(&referral_list);
621 EXPECT_EQ(1U, referral_list.GetSize());
622
623 predictor->Shutdown();
624 }
625
626 } // namespace chrome_browser_net
627