- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / search / search_unittest.cc
1 // Copyright (c) 2013 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 "base/command_line.h"
6 #include "base/metrics/field_trial.h"
7 #include "base/metrics/histogram_base.h"
8 #include "base/metrics/histogram_samples.h"
9 #include "base/metrics/statistics_recorder.h"
10 #include "base/prefs/pref_service.h"
11 #include "chrome/browser/managed_mode/managed_mode_url_filter.h"
12 #include "chrome/browser/managed_mode/managed_user_service.h"
13 #include "chrome/browser/managed_mode/managed_user_service_factory.h"
14 #include "chrome/browser/search/instant_service.h"
15 #include "chrome/browser/search/instant_service_factory.h"
16 #include "chrome/browser/search/search.h"
17 #include "chrome/browser/search_engines/search_terms_data.h"
18 #include "chrome/browser/search_engines/template_url_service.h"
19 #include "chrome/browser/search_engines/template_url_service_factory.h"
20 #include "chrome/browser/ui/tabs/tab_strip_model.h"
21 #include "chrome/common/chrome_switches.h"
22 #include "chrome/common/pref_names.h"
23 #include "chrome/common/url_constants.h"
24 #include "chrome/test/base/browser_with_test_window_test.h"
25 #include "chrome/test/base/ui_test_utils.h"
26 #include "components/variations/entropy_provider.h"
27 #include "content/public/browser/render_process_host.h"
28 #include "content/public/browser/render_view_host.h"
29 #include "content/public/browser/site_instance.h"
30 #include "content/public/browser/web_contents.h"
31 #include "content/public/common/renderer_preferences.h"
32 #include "url/gurl.h"
33
34 namespace chrome {
35
36 class EmbeddedSearchFieldTrialTest : public testing::Test {
37  protected:
38   virtual void SetUp() {
39     field_trial_list_.reset(new base::FieldTrialList(
40         new metrics::SHA1EntropyProvider("42")));
41     base::StatisticsRecorder::Initialize();
42     ResetInstantExtendedOptInStateGateForTest();
43   }
44
45  private:
46   scoped_ptr<base::FieldTrialList> field_trial_list_;
47 };
48
49 TEST_F(EmbeddedSearchFieldTrialTest, GetFieldTrialInfoEmptyAndValid) {
50   FieldTrialFlags flags;
51   uint64 group_number = 0;
52
53   EXPECT_TRUE(GetFieldTrialInfo(&flags, &group_number));
54   EXPECT_EQ(0ul, group_number);
55   EXPECT_EQ(0ul, flags.size());
56
57   ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
58       "InstantExtended", "Group77"));
59   EXPECT_TRUE(GetFieldTrialInfo(&flags, &group_number));
60   EXPECT_EQ(77ul, group_number);
61   EXPECT_EQ(0ul, flags.size());
62 }
63
64 TEST_F(EmbeddedSearchFieldTrialTest, GetFieldTrialInfoInvalidNumber) {
65   FieldTrialFlags flags;
66   uint64 group_number = 0;
67
68   ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
69       "InstantExtended", "Group77.2"));
70   EXPECT_FALSE(GetFieldTrialInfo(&flags, &group_number));
71   EXPECT_EQ(0ul, group_number);
72   EXPECT_EQ(0ul, flags.size());
73 }
74
75 TEST_F(EmbeddedSearchFieldTrialTest, GetFieldTrialInfoInvalidName) {
76   FieldTrialFlags flags;
77   uint64 group_number = 0;
78
79   ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
80       "InstantExtended", "Invalid77"));
81   EXPECT_TRUE(GetFieldTrialInfo(&flags, &group_number));
82   EXPECT_EQ(0ul, group_number);
83   EXPECT_EQ(0ul, flags.size());
84 }
85
86 TEST_F(EmbeddedSearchFieldTrialTest, GetFieldTrialInfoValidGroup) {
87   FieldTrialFlags flags;
88   uint64 group_number = 0;
89
90   ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
91       "InstantExtended", "Group77"));
92   EXPECT_TRUE(GetFieldTrialInfo(&flags, &group_number));
93   EXPECT_EQ(77ul, group_number);
94   EXPECT_EQ(0ul, flags.size());
95 }
96
97 TEST_F(EmbeddedSearchFieldTrialTest, GetFieldTrialInfoValidFlag) {
98   FieldTrialFlags flags;
99   uint64 group_number = 0;
100
101   EXPECT_EQ(9999ul, GetUInt64ValueForFlagWithDefault("foo", 9999, flags));
102   ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
103       "InstantExtended", "Group77 foo:6"));
104   EXPECT_TRUE(GetFieldTrialInfo(&flags, &group_number));
105   EXPECT_EQ(77ul, group_number);
106   EXPECT_EQ(1ul, flags.size());
107   EXPECT_EQ(6ul, GetUInt64ValueForFlagWithDefault("foo", 9999, flags));
108 }
109
110 TEST_F(EmbeddedSearchFieldTrialTest, GetFieldTrialInfoNewName) {
111   FieldTrialFlags flags;
112   uint64 group_number = 0;
113
114   EXPECT_EQ(9999ul, GetUInt64ValueForFlagWithDefault("foo", 9999, flags));
115   ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
116       "EmbeddedSearch", "Group77 foo:6"));
117   EXPECT_TRUE(GetFieldTrialInfo(&flags, &group_number));
118   EXPECT_EQ(77ul, group_number);
119   EXPECT_EQ(1ul, flags.size());
120   EXPECT_EQ(6ul, GetUInt64ValueForFlagWithDefault("foo", 9999, flags));
121 }
122
123 TEST_F(EmbeddedSearchFieldTrialTest, GetFieldTrialInfoNewNameOverridesOld) {
124   FieldTrialFlags flags;
125   uint64 group_number = 0;
126
127   EXPECT_EQ(9999ul, GetUInt64ValueForFlagWithDefault("foo", 9999, flags));
128   ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
129       "EmbeddedSearch", "Group77 foo:6"));
130   ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
131       "InstantExtended", "Group78 foo:5"));
132   EXPECT_TRUE(GetFieldTrialInfo(&flags, &group_number));
133   EXPECT_EQ(77ul, group_number);
134   EXPECT_EQ(1ul, flags.size());
135   EXPECT_EQ(6ul, GetUInt64ValueForFlagWithDefault("foo", 9999, flags));
136 }
137
138 TEST_F(EmbeddedSearchFieldTrialTest, GetFieldTrialInfoLotsOfFlags) {
139   FieldTrialFlags flags;
140   uint64 group_number = 0;
141
142   ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
143       "InstantExtended", "Group77 bar:1 baz:7 cat:dogs"));
144   EXPECT_TRUE(GetFieldTrialInfo(&flags, &group_number));
145   EXPECT_EQ(77ul, group_number);
146   EXPECT_EQ(3ul, flags.size());
147   EXPECT_EQ(true, GetBoolValueForFlagWithDefault("bar", false, flags));
148   EXPECT_EQ(7ul, GetUInt64ValueForFlagWithDefault("baz", 0, flags));
149   EXPECT_EQ("dogs",
150             GetStringValueForFlagWithDefault("cat", std::string(), flags));
151   EXPECT_EQ("default",
152             GetStringValueForFlagWithDefault("moose", "default", flags));
153 }
154
155 TEST_F(EmbeddedSearchFieldTrialTest, GetFieldTrialInfoDisabled) {
156   FieldTrialFlags flags;
157   uint64 group_number = 0;
158
159   ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
160       "InstantExtended", "Group77 bar:1 baz:7 cat:dogs DISABLED"));
161   EXPECT_FALSE(GetFieldTrialInfo(&flags, &group_number));
162   EXPECT_EQ(0ul, group_number);
163   EXPECT_EQ(0ul, flags.size());
164 }
165
166 TEST_F(EmbeddedSearchFieldTrialTest, GetFieldTrialInfoControlFlags) {
167   FieldTrialFlags flags;
168   uint64 group_number = 0;
169
170   ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
171       "InstantExtended", "Control77 bar:1 baz:7 cat:dogs"));
172   EXPECT_TRUE(GetFieldTrialInfo(&flags, &group_number));
173   EXPECT_EQ(0ul, group_number);
174   EXPECT_EQ(3ul, flags.size());
175 }
176
177 class InstantExtendedAPIEnabledTest : public testing::Test {
178  public:
179   InstantExtendedAPIEnabledTest() : histogram_(NULL) {
180   }
181  protected:
182   virtual void SetUp() {
183     field_trial_list_.reset(new base::FieldTrialList(
184         new metrics::SHA1EntropyProvider("42")));
185     base::StatisticsRecorder::Initialize();
186     ResetInstantExtendedOptInStateGateForTest();
187     previous_metrics_count_.resize(INSTANT_EXTENDED_OPT_IN_STATE_ENUM_COUNT, 0);
188     base::HistogramBase* histogram = GetHistogram();
189     if (histogram) {
190       scoped_ptr<base::HistogramSamples> samples(histogram->SnapshotSamples());
191       if (samples.get()) {
192         for (int state = INSTANT_EXTENDED_NOT_SET;
193              state < INSTANT_EXTENDED_OPT_IN_STATE_ENUM_COUNT; ++state) {
194           previous_metrics_count_[state] = samples->GetCount(state);
195         }
196       }
197     }
198   }
199
200   virtual CommandLine* GetCommandLine() const {
201     return CommandLine::ForCurrentProcess();
202   }
203
204   void ValidateMetrics(base::HistogramBase::Sample value) {
205     base::HistogramBase* histogram = GetHistogram();
206     if (histogram) {
207       scoped_ptr<base::HistogramSamples> samples(histogram->SnapshotSamples());
208       if (samples.get()) {
209         for (int state = INSTANT_EXTENDED_NOT_SET;
210              state < INSTANT_EXTENDED_OPT_IN_STATE_ENUM_COUNT; ++state) {
211           if (state == value) {
212             EXPECT_EQ(previous_metrics_count_[state] + 1,
213                       samples->GetCount(state));
214           } else {
215             EXPECT_EQ(previous_metrics_count_[state], samples->GetCount(state));
216           }
217         }
218       }
219     }
220   }
221
222  private:
223   base::HistogramBase* GetHistogram() {
224     if (!histogram_) {
225       histogram_ = base::StatisticsRecorder::FindHistogram(
226           "InstantExtended.OptInState");
227     }
228     return histogram_;
229   }
230   base::HistogramBase* histogram_;
231   scoped_ptr<base::FieldTrialList> field_trial_list_;
232   std::vector<int> previous_metrics_count_;
233 };
234
235 TEST_F(InstantExtendedAPIEnabledTest, EnabledViaCommandLineFlag) {
236   GetCommandLine()->AppendSwitch(switches::kEnableInstantExtendedAPI);
237   EXPECT_TRUE(IsInstantExtendedAPIEnabled());
238 #if defined(OS_IOS) || defined(OS_ANDROID)
239   EXPECT_EQ(1ul, EmbeddedSearchPageVersion());
240 #else
241   EXPECT_EQ(2ul, EmbeddedSearchPageVersion());
242 #endif
243   ValidateMetrics(INSTANT_EXTENDED_OPT_IN);
244 }
245
246 TEST_F(InstantExtendedAPIEnabledTest, EnabledViaFinchFlag) {
247   ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial("InstantExtended",
248                                                      "Group1 espv:42"));
249   EXPECT_TRUE(IsInstantExtendedAPIEnabled());
250   EXPECT_EQ(42ul, EmbeddedSearchPageVersion());
251   ValidateMetrics(INSTANT_EXTENDED_NOT_SET);
252 }
253
254 TEST_F(InstantExtendedAPIEnabledTest, DisabledViaCommandLineFlag) {
255   GetCommandLine()->AppendSwitch(switches::kDisableInstantExtendedAPI);
256   ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial("InstantExtended",
257                                                      "Group1 espv:2"));
258   EXPECT_FALSE(IsInstantExtendedAPIEnabled());
259   EXPECT_EQ(0ul, EmbeddedSearchPageVersion());
260   ValidateMetrics(INSTANT_EXTENDED_OPT_OUT);
261 }
262
263 typedef InstantExtendedAPIEnabledTest ShouldHideTopVerbatimTest;
264
265 TEST_F(ShouldHideTopVerbatimTest, DoNotHideByDefault) {
266   ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
267       "InstantExtended", "Control"));
268   EXPECT_FALSE(ShouldHideTopVerbatimMatch());
269 }
270
271 TEST_F(ShouldHideTopVerbatimTest, DoNotHideInInstantExtended) {
272   ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
273       "InstantExtended", "Group1"));
274   EXPECT_FALSE(ShouldHideTopVerbatimMatch());
275 }
276
277 TEST_F(ShouldHideTopVerbatimTest, EnableByFlagInInstantExtended) {
278   ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
279       "InstantExtended", "Group1 hide_verbatim:1"));
280   EXPECT_TRUE(ShouldHideTopVerbatimMatch());
281 }
282
283 TEST_F(ShouldHideTopVerbatimTest, EnableByFlagOutsideInstantExtended) {
284   ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
285       "InstantExtended", "Controll1 hide_verbatim:1"));
286   EXPECT_TRUE(ShouldHideTopVerbatimMatch());
287 }
288
289 TEST_F(ShouldHideTopVerbatimTest, DisableByFlag) {
290   ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
291       "InstantExtended", "Group1 hide_verbatim:0"));
292   EXPECT_FALSE(ShouldHideTopVerbatimMatch());
293 }
294
295 typedef InstantExtendedAPIEnabledTest ShouldSuppressInstantExtendedOnSRPTest;
296
297 TEST_F(ShouldSuppressInstantExtendedOnSRPTest, NotSet) {
298   ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
299       "InstantExtended", "Group1 espv:2"));
300   EXPECT_FALSE(ShouldSuppressInstantExtendedOnSRP());
301   EXPECT_TRUE(IsInstantExtendedAPIEnabled());
302   EXPECT_TRUE(IsQueryExtractionEnabled());
303   EXPECT_EQ(2ul, EmbeddedSearchPageVersion());
304 }
305
306 TEST_F(ShouldSuppressInstantExtendedOnSRPTest, NotSuppressOnSRP) {
307   ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
308       "InstantExtended", "Group1 espv:2 suppress_on_srp:0"));
309   EXPECT_FALSE(ShouldSuppressInstantExtendedOnSRP());
310   EXPECT_TRUE(IsInstantExtendedAPIEnabled());
311   EXPECT_TRUE(IsQueryExtractionEnabled());
312   EXPECT_EQ(2ul, EmbeddedSearchPageVersion());
313 }
314
315 TEST_F(ShouldSuppressInstantExtendedOnSRPTest, SuppressOnSRP) {
316   ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
317       "InstantExtended", "Group1 espv:2 suppress_on_srp:1"));
318   EXPECT_TRUE(ShouldSuppressInstantExtendedOnSRP());
319   EXPECT_TRUE(IsInstantExtendedAPIEnabled());
320   EXPECT_FALSE(IsQueryExtractionEnabled());
321   EXPECT_EQ(2ul, EmbeddedSearchPageVersion());
322 }
323
324 class SearchTest : public BrowserWithTestWindowTest {
325  protected:
326   virtual void SetUp() OVERRIDE {
327     BrowserWithTestWindowTest::SetUp();
328     field_trial_list_.reset(new base::FieldTrialList(
329         new metrics::SHA1EntropyProvider("42")));
330     TemplateURLServiceFactory::GetInstance()->SetTestingFactoryAndUse(
331         profile(), &TemplateURLServiceFactory::BuildInstanceFor);
332     TemplateURLService* template_url_service =
333         TemplateURLServiceFactory::GetForProfile(profile());
334     ui_test_utils::WaitForTemplateURLServiceToLoad(template_url_service);
335     SetSearchProvider(true, false);
336   }
337
338   void SetSearchProvider(bool set_ntp_url, bool insecure_ntp_url) {
339     TemplateURLService* template_url_service =
340         TemplateURLServiceFactory::GetForProfile(profile());
341     TemplateURLData data;
342     data.SetURL("http://foo.com/url?bar={searchTerms}");
343     data.instant_url = "http://foo.com/instant?"
344         "{google:omniboxStartMarginParameter}{google:forceInstantResults}"
345         "foo=foo#foo=foo&strk";
346     if (set_ntp_url) {
347       data.new_tab_url = (insecure_ntp_url ? "http" : "https") +
348           std::string("://foo.com/newtab?strk");
349     }
350     data.alternate_urls.push_back("http://foo.com/alt#quux={searchTerms}");
351     data.search_terms_replacement_key = "strk";
352
353     TemplateURL* template_url = new TemplateURL(profile(), data);
354     // Takes ownership of |template_url|.
355     template_url_service->Add(template_url);
356     template_url_service->SetDefaultSearchProvider(template_url);
357   }
358
359   // Build an Instant URL with or without a valid search terms replacement key
360   // as per |has_search_term_replacement_key|. Set that URL as the instant URL
361   // for the default search provider.
362   void SetDefaultInstantTemplateUrl(bool has_search_term_replacement_key) {
363     TemplateURLService* template_url_service =
364         TemplateURLServiceFactory::GetForProfile(profile());
365
366     static const char kInstantURLWithStrk[] =
367         "http://foo.com/instant?foo=foo#foo=foo&strk";
368     static const char kInstantURLNoStrk[] =
369         "http://foo.com/instant?foo=foo#foo=foo";
370
371     TemplateURLData data;
372     data.SetURL("http://foo.com/url?bar={searchTerms}");
373     data.instant_url = (has_search_term_replacement_key ?
374         kInstantURLWithStrk : kInstantURLNoStrk);
375     data.search_terms_replacement_key = "strk";
376
377     TemplateURL* template_url = new TemplateURL(profile(), data);
378     // Takes ownership of |template_url|.
379     template_url_service->Add(template_url);
380     template_url_service->SetDefaultSearchProvider(template_url);
381   }
382
383   bool InInstantProcess(const content::WebContents* contents) {
384     InstantService* instant_service =
385         InstantServiceFactory::GetForProfile(profile());
386     return instant_service->IsInstantProcess(
387         contents->GetRenderProcessHost()->GetID());
388   }
389
390   scoped_ptr<base::FieldTrialList> field_trial_list_;
391 };
392
393 struct SearchTestCase {
394   const char* url;
395   bool expected_result;
396   const char* comment;
397 };
398
399 TEST_F(SearchTest, ShouldAssignURLToInstantRendererExtendedDisabled) {
400   DisableInstantExtendedAPIForTesting();
401
402   const SearchTestCase kTestCases[] = {
403     {"chrome-search://foo/bar",                 false,  ""},
404     {"http://foo.com/instant",                  false,  ""},
405     {"http://foo.com/instant?foo=bar",          false,  ""},
406     {"https://foo.com/instant",                 false,  ""},
407     {"https://foo.com/instant#foo=bar",         false,  ""},
408     {"HtTpS://fOo.CoM/instant",                 false,  ""},
409     {"http://foo.com:80/instant",               false,  ""},
410     {"invalid URL",                             false, "Invalid URL"},
411     {"unknown://scheme/path",                   false, "Unknown scheme"},
412     {"ftp://foo.com/instant",                   false, "Non-HTTP scheme"},
413     {"http://sub.foo.com/instant",              false, "Non-exact host"},
414     {"http://foo.com:26/instant",               false, "Non-default port"},
415     {"http://foo.com/instant/bar",              false, "Non-exact path"},
416     {"http://foo.com/Instant",                  false, "Case sensitive path"},
417     {"http://foo.com/",                         false, "Non-exact path"},
418     {"https://foo.com/",                        false, "Non-exact path"},
419     {"https://foo.com/url?strk",                false, "Non-extended mode"},
420     {"https://foo.com/alt?strk",                false, "Non-extended mode"},
421   };
422
423   for (size_t i = 0; i < arraysize(kTestCases); ++i) {
424     const SearchTestCase& test = kTestCases[i];
425     EXPECT_EQ(test.expected_result,
426               ShouldAssignURLToInstantRenderer(GURL(test.url), profile()))
427         << test.url << " " << test.comment;
428   }
429 }
430
431 TEST_F(SearchTest, ShouldAssignURLToInstantRendererExtendedEnabled) {
432   EnableInstantExtendedAPIForTesting();
433
434   const SearchTestCase kTestCases[] = {
435     {chrome::kChromeSearchLocalNtpUrl, true,  ""},
436     {"https://foo.com/instant?strk",   true,  ""},
437     {"https://foo.com/instant#strk",   true,  ""},
438     {"https://foo.com/instant?strk=0", true,  ""},
439     {"https://foo.com/url?strk",       true,  ""},
440     {"https://foo.com/alt?strk",       true,  ""},
441     {"http://foo.com/instant",         false, "Non-HTTPS"},
442     {"http://foo.com/instant?strk",    false, "Non-HTTPS"},
443     {"http://foo.com/instant?strk=1",  false, "Non-HTTPS"},
444     {"https://foo.com/instant",        false, "No search terms replacement"},
445     {"https://foo.com/?strk",          false, "Non-exact path"},
446   };
447
448   for (size_t i = 0; i < arraysize(kTestCases); ++i) {
449     const SearchTestCase& test = kTestCases[i];
450     EXPECT_EQ(test.expected_result,
451               ShouldAssignURLToInstantRenderer(GURL(test.url), profile()))
452         << test.url << " " << test.comment;
453   }
454 }
455
456 TEST_F(SearchTest, ShouldAssignURLToInstantRendererExtendedEnabledNotOnSRP) {
457   ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
458       "InstantExtended", "Group1 espv:2 suppress_on_srp:1"));
459
460   const SearchTestCase kTestCases[] = {
461     {chrome::kChromeSearchLocalNtpUrl, true,  ""},
462     {"https://foo.com/instant?strk",   true,  ""},
463     {"https://foo.com/instant#strk",   true,  ""},
464     {"https://foo.com/instant?strk=0", true,  ""},
465     {"https://foo.com/url?strk",       false, "Disabled on SRP"},
466     {"https://foo.com/alt?strk",       false, "Disabled ON SRP"},
467     {"http://foo.com/instant",         false, "Non-HTTPS"},
468     {"http://foo.com/instant?strk",    false, "Non-HTTPS"},
469     {"http://foo.com/instant?strk=1",  false, "Non-HTTPS"},
470     {"https://foo.com/instant",        false, "No search terms replacement"},
471     {"https://foo.com/?strk",          false, "Non-exact path"},
472   };
473
474   for (size_t i = 0; i < arraysize(kTestCases); ++i) {
475     const SearchTestCase& test = kTestCases[i];
476     EXPECT_EQ(test.expected_result,
477               ShouldAssignURLToInstantRenderer(GURL(test.url), profile()))
478         << test.url << " " << test.comment;
479   }
480 }
481
482 TEST_F(SearchTest, ShouldUseProcessPerSiteForInstantURL) {
483   EnableInstantExtendedAPIForTesting();
484
485   const SearchTestCase kTestCases[] = {
486     {"chrome-search://local-ntp",      true,  "Local NTP"},
487     {"chrome-search://online-ntp",     true,  "Online NTP"},
488     {"invalid-scheme://local-ntp",     false, "Invalid Local NTP URL"},
489     {"invalid-scheme://online-ntp",    false, "Invalid Online NTP URL"},
490     {"chrome-search://foo.com",        false, "Search result page"},
491     {"https://foo.com/instant?strk",   false,  ""},
492     {"https://foo.com/instant#strk",   false,  ""},
493     {"https://foo.com/instant?strk=0", false,  ""},
494     {"https://foo.com/url?strk",       false,  ""},
495     {"https://foo.com/alt?strk",       false,  ""},
496     {"http://foo.com/instant",         false,  "Non-HTTPS"},
497     {"http://foo.com/instant?strk",    false,  "Non-HTTPS"},
498     {"http://foo.com/instant?strk=1",  false,  "Non-HTTPS"},
499     {"https://foo.com/instant",        false,  "No search terms replacement"},
500     {"https://foo.com/?strk",          false,  "Non-exact path"},
501   };
502
503   for (size_t i = 0; i < arraysize(kTestCases); ++i) {
504     const SearchTestCase& test = kTestCases[i];
505     EXPECT_EQ(test.expected_result,
506               ShouldUseProcessPerSiteForInstantURL(GURL(test.url), profile()))
507         << test.url << " " << test.comment;
508   }
509 }
510
511 // Each test case represents a navigation to |start_url| followed by a
512 // navigation to |end_url|. We will check whether each navigation lands in an
513 // Instant process, and also whether the navigation from start to end re-uses
514 // the same SiteInstance (and hence the same RenderViewHost, etc.).
515 const struct ProcessIsolationTestCase {
516   const char* description;
517   const char* start_url;
518   bool start_in_instant_process;
519   const char* end_url;
520   bool end_in_instant_process;
521   bool same_site_instance;
522 } kProcessIsolationTestCases[] = {
523   {"Local NTP -> SRP",
524    "chrome-search://local-ntp",       true,
525    "https://foo.com/url?strk",        true,   false },
526   {"Local NTP -> Regular",
527    "chrome-search://local-ntp",       true,
528    "https://foo.com/other",           false,  false },
529   {"Remote NTP -> SRP",
530    "https://foo.com/instant?strk",    true,
531    "https://foo.com/url?strk",        true,   false },
532   {"Remote NTP -> Regular",
533    "https://foo.com/instant?strk",    true,
534    "https://foo.com/other",           false,  false },
535   {"SRP -> SRP",
536    "https://foo.com/url?strk",        true,
537    "https://foo.com/url?strk",        true,   true  },
538   {"SRP -> Regular",
539    "https://foo.com/url?strk",        true,
540    "https://foo.com/other",           false,  false },
541   {"Regular -> SRP",
542    "https://foo.com/other",           false,
543    "https://foo.com/url?strk",        true,   false },
544 };
545
546 TEST_F(SearchTest, ProcessIsolation) {
547   EnableInstantExtendedAPIForTesting();
548
549   for (size_t i = 0; i < arraysize(kProcessIsolationTestCases); ++i) {
550     const ProcessIsolationTestCase& test = kProcessIsolationTestCases[i];
551     AddTab(browser(), GURL("chrome://blank"));
552     const content::WebContents* contents =
553         browser()->tab_strip_model()->GetActiveWebContents();
554
555     // Navigate to start URL.
556     NavigateAndCommitActiveTab(GURL(test.start_url));
557     EXPECT_EQ(test.start_in_instant_process, InInstantProcess(contents))
558         << test.description;
559
560     // Save state.
561     const scoped_refptr<content::SiteInstance> start_site_instance =
562         contents->GetSiteInstance();
563     const content::RenderProcessHost* start_rph =
564         contents->GetRenderProcessHost();
565     const content::RenderViewHost* start_rvh =
566         contents->GetRenderViewHost();
567
568     // Navigate to end URL.
569     NavigateAndCommitActiveTab(GURL(test.end_url));
570     EXPECT_EQ(test.end_in_instant_process, InInstantProcess(contents))
571         << test.description;
572
573     EXPECT_EQ(test.same_site_instance,
574               start_site_instance == contents->GetSiteInstance())
575         << test.description;
576     EXPECT_EQ(test.same_site_instance,
577               start_rvh == contents->GetRenderViewHost())
578         << test.description;
579     EXPECT_EQ(test.same_site_instance,
580               start_rph == contents->GetRenderProcessHost())
581         << test.description;
582   }
583 }
584
585 TEST_F(SearchTest, ProcessIsolation_RendererInitiated) {
586   EnableInstantExtendedAPIForTesting();
587
588   for (size_t i = 0; i < arraysize(kProcessIsolationTestCases); ++i) {
589     const ProcessIsolationTestCase& test = kProcessIsolationTestCases[i];
590     AddTab(browser(), GURL("chrome://blank"));
591     content::WebContents* contents =
592         browser()->tab_strip_model()->GetActiveWebContents();
593
594     // Navigate to start URL.
595     NavigateAndCommitActiveTab(GURL(test.start_url));
596     EXPECT_EQ(test.start_in_instant_process, InInstantProcess(contents))
597         << test.description;
598
599     // Save state.
600     const scoped_refptr<content::SiteInstance> start_site_instance =
601         contents->GetSiteInstance();
602     const content::RenderProcessHost* start_rph =
603         contents->GetRenderProcessHost();
604     const content::RenderViewHost* start_rvh =
605         contents->GetRenderViewHost();
606
607     // Navigate to end URL via a renderer-initiated navigation.
608     content::NavigationController* controller = &contents->GetController();
609     content::NavigationController::LoadURLParams load_params(
610         GURL(test.end_url));
611     load_params.is_renderer_initiated = true;
612     load_params.transition_type = content::PAGE_TRANSITION_LINK;
613
614     controller->LoadURLWithParams(load_params);
615     CommitPendingLoad(controller);
616     EXPECT_EQ(test.end_in_instant_process, InInstantProcess(contents))
617         << test.description;
618
619     EXPECT_EQ(test.same_site_instance,
620               start_site_instance == contents->GetSiteInstance())
621         << test.description;
622     EXPECT_EQ(test.same_site_instance,
623               start_rvh == contents->GetRenderViewHost())
624         << test.description;
625     EXPECT_EQ(test.same_site_instance,
626               start_rph == contents->GetRenderProcessHost())
627         << test.description;
628   }
629 }
630
631 const SearchTestCase kInstantNTPTestCases[] = {
632   {"https://foo.com/instant?strk",         true,  "Valid Instant URL"},
633   {"https://foo.com/instant#strk",         true,  "Valid Instant URL"},
634   {"https://foo.com/url?strk",             true,  "Valid search URL"},
635   {"https://foo.com/url#strk",             true,  "Valid search URL"},
636   {"https://foo.com/alt?strk",             true,  "Valid alternative URL"},
637   {"https://foo.com/alt#strk",             true,  "Valid alternative URL"},
638   {"https://foo.com/url?strk&bar=",        true,  "No query terms"},
639   {"https://foo.com/url?strk&q=abc",       true,  "No query terms key"},
640   {"https://foo.com/url?strk#bar=abc",     true,  "Query terms key in ref"},
641   {"https://foo.com/url?strk&bar=abc",     false, "Has query terms"},
642   {"http://foo.com/instant?strk=1",        false, "Insecure URL"},
643   {"https://foo.com/instant",              false, "No search term replacement"},
644   {"chrome://blank/",                      false, "Chrome scheme"},
645   {"chrome-search://foo",                  false, "Chrome-search scheme"},
646   {chrome::kChromeSearchLocalNtpUrl,       true,  "Local new tab page"},
647   {"https://bar.com/instant?strk=1",       false, "Random non-search page"},
648 };
649
650 TEST_F(SearchTest, InstantNTPExtendedEnabled) {
651   EnableInstantExtendedAPIForTesting();
652   AddTab(browser(), GURL("chrome://blank"));
653   for (size_t i = 0; i < arraysize(kInstantNTPTestCases); ++i) {
654     const SearchTestCase& test = kInstantNTPTestCases[i];
655     NavigateAndCommitActiveTab(GURL(test.url));
656     const content::WebContents* contents =
657         browser()->tab_strip_model()->GetWebContentsAt(0);
658     EXPECT_EQ(test.expected_result, IsInstantNTP(contents))
659         << test.url << " " << test.comment;
660   }
661 }
662
663 TEST_F(SearchTest, InstantNTPExtendedDisabled) {
664   AddTab(browser(), GURL("chrome://blank"));
665   for (size_t i = 0; i < arraysize(kInstantNTPTestCases); ++i) {
666     const SearchTestCase& test = kInstantNTPTestCases[i];
667     NavigateAndCommitActiveTab(GURL(test.url));
668     const content::WebContents* contents =
669         browser()->tab_strip_model()->GetWebContentsAt(0);
670     EXPECT_FALSE(IsInstantNTP(contents)) << test.url << " " << test.comment;
671   }
672 }
673
674 TEST_F(SearchTest, InstantNTPCustomNavigationEntry) {
675   EnableInstantExtendedAPIForTesting();
676   AddTab(browser(), GURL("chrome://blank"));
677   for (size_t i = 0; i < arraysize(kInstantNTPTestCases); ++i) {
678     const SearchTestCase& test = kInstantNTPTestCases[i];
679     NavigateAndCommitActiveTab(GURL(test.url));
680     content::WebContents* contents =
681         browser()->tab_strip_model()->GetWebContentsAt(0);
682     content::NavigationController& controller = contents->GetController();
683     controller.SetTransientEntry(
684         controller.CreateNavigationEntry(GURL("chrome://blank"),
685                                          content::Referrer(),
686                                          content::PAGE_TRANSITION_LINK,
687                                          false,
688                                          std::string(),
689                                          contents->GetBrowserContext()));
690     // The active entry is chrome://blank and not an NTP.
691     EXPECT_FALSE(IsInstantNTP(contents));
692     EXPECT_EQ(test.expected_result,
693               NavEntryIsInstantNTP(contents,
694                                    controller.GetLastCommittedEntry()))
695         << test.url << " " << test.comment;
696   }
697 }
698
699 TEST_F(SearchTest, InstantCacheableNTPNavigationEntry) {
700   EnableInstantExtendedAPIForTesting();
701   ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial("InstantExtended",
702       "Group1 use_cacheable_ntp:1"));
703
704   AddTab(browser(), GURL("chrome://blank"));
705   content::WebContents* contents =
706         browser()->tab_strip_model()->GetWebContentsAt(0);
707   content::NavigationController& controller = contents->GetController();
708   // Local NTP.
709   NavigateAndCommitActiveTab(GURL(chrome::kChromeSearchLocalNtpUrl));
710   EXPECT_TRUE(NavEntryIsInstantNTP(contents,
711                                    controller.GetLastCommittedEntry()));
712   // Instant page is not cacheable NTP.
713   NavigateAndCommitActiveTab(GetInstantURL(profile(), kDisableStartMargin,
714                                            false));
715   EXPECT_FALSE(NavEntryIsInstantNTP(contents,
716                                     controller.GetLastCommittedEntry()));
717   // Test Cacheable NTP
718   NavigateAndCommitActiveTab(chrome::GetNewTabPageURL(profile()));
719   EXPECT_TRUE(NavEntryIsInstantNTP(contents,
720                                    controller.GetLastCommittedEntry()));
721 }
722
723 TEST_F(SearchTest, UseLocalNTPInIncognito) {
724   EnableInstantExtendedAPIForTesting();
725   ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial("InstantExtended",
726       "Group1 use_cacheable_ntp:1"));
727   EXPECT_EQ(GURL(), chrome::GetNewTabPageURL(
728       profile()->GetOffTheRecordProfile()));
729 }
730
731 TEST_F(SearchTest, UseLocalNTPIfNTPURLIsInsecure) {
732   EnableInstantExtendedAPIForTesting();
733   ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial("InstantExtended",
734       "Group1 use_cacheable_ntp:1"));
735   // Set an insecure new tab page URL and verify that it's ignored.
736   SetSearchProvider(true, true);
737   EXPECT_EQ(GURL(chrome::kChromeSearchLocalNtpUrl),
738             chrome::GetNewTabPageURL(profile()));
739 }
740
741 TEST_F(SearchTest, UseLocalNTPIfNTPURLIsNotSet) {
742   EnableInstantExtendedAPIForTesting();
743   ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial("InstantExtended",
744       "Group1 use_cacheable_ntp:1"));
745   // Set an insecure new tab page URL and verify that it's ignored.
746   SetSearchProvider(false, true);
747   EXPECT_EQ(GURL(chrome::kChromeSearchLocalNtpUrl),
748             chrome::GetNewTabPageURL(profile()));
749 }
750
751 TEST_F(SearchTest, UseLocalNTPIfNTPURLIsBlockedForSupervisedUser) {
752   EnableInstantExtendedAPIForTesting();
753   ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial("InstantExtended",
754       "Group1 use_cacheable_ntp:1"));
755
756   // Block access to foo.com in the URL filter.
757   ManagedUserService* managed_user_service =
758       ManagedUserServiceFactory::GetForProfile(profile());
759   ManagedModeURLFilter* url_filter =
760       managed_user_service->GetURLFilterForUIThread();
761   std::map<std::string, bool> hosts;
762   hosts["foo.com"] = false;
763   url_filter->SetManualHosts(&hosts);
764
765   EXPECT_EQ(GURL(chrome::kChromeSearchLocalNtpUrl),
766             chrome::GetNewTabPageURL(profile()));
767   EXPECT_EQ(GURL(), GetInstantURL(profile(), kDisableStartMargin, false));
768 }
769
770 TEST_F(SearchTest, GetInstantURLExtendedEnabled) {
771   // Instant is disabled, so no Instant URL.
772   EXPECT_EQ(GURL(), GetInstantURL(profile(), kDisableStartMargin, false));
773
774   // Enable Instant. Still no Instant URL because "strk" is missing.
775   EnableInstantExtendedAPIForTesting();
776   SetDefaultInstantTemplateUrl(false);
777   EXPECT_EQ(GURL(), GetInstantURL(profile(), kDisableStartMargin, false));
778
779   // Set an Instant URL with a valid search terms replacement key.
780   SetDefaultInstantTemplateUrl(true);
781
782   // Now there should be a valid Instant URL. Note the HTTPS "upgrade".
783   EXPECT_EQ(GURL("https://foo.com/instant?foo=foo#foo=foo&strk"),
784             GetInstantURL(profile(), kDisableStartMargin, false));
785
786   // Enable suggest. No difference.
787   profile()->GetPrefs()->SetBoolean(prefs::kSearchSuggestEnabled, true);
788   EXPECT_EQ(GURL("https://foo.com/instant?foo=foo#foo=foo&strk"),
789             GetInstantURL(profile(), kDisableStartMargin, false));
790
791   // Disable suggest. No Instant URL.
792   profile()->GetPrefs()->SetBoolean(prefs::kSearchSuggestEnabled, false);
793   EXPECT_EQ(GURL(), GetInstantURL(profile(), kDisableStartMargin, false));
794 }
795
796 TEST_F(SearchTest, StartMarginCGI) {
797   // Instant is disabled, so no Instant URL.
798   EXPECT_EQ(GURL(), GetInstantURL(profile(), kDisableStartMargin, false));
799
800   // Enable Instant. No margin.
801   EnableInstantExtendedAPIForTesting();
802   profile()->GetPrefs()->SetBoolean(prefs::kSearchSuggestEnabled, true);
803
804   EXPECT_EQ(GURL("https://foo.com/instant?foo=foo#foo=foo&strk"),
805             GetInstantURL(profile(), kDisableStartMargin, false));
806
807   // With start margin.
808   EXPECT_EQ(GURL("https://foo.com/instant?es_sm=10&foo=foo#foo=foo&strk"),
809             GetInstantURL(profile(), 10, false));
810 }
811
812 TEST_F(SearchTest, InstantSearchEnabledCGI) {
813   EnableInstantExtendedAPIForTesting();
814
815   // Disable Instant Search.
816   // Make sure {google:forceInstantResults} is not set in the Instant URL.
817   EXPECT_EQ(GURL("https://foo.com/instant?foo=foo#foo=foo&strk"),
818             GetInstantURL(profile(), kDisableStartMargin, false));
819
820   // Enable Instant Search.
821   // Make sure {google:forceInstantResults} is set in the Instant URL.
822   EXPECT_EQ(GURL("https://foo.com/instant?ion=1&foo=foo#foo=foo&strk"),
823             GetInstantURL(profile(), kDisableStartMargin, true));
824 }
825
826 TEST_F(SearchTest, CommandLineOverrides) {
827   EnableInstantExtendedAPIForTesting();
828
829   GURL local_instant_url(GetLocalInstantURL(profile()));
830   EXPECT_EQ(GURL(chrome::kChromeSearchLocalNtpUrl), local_instant_url);
831
832   TemplateURLService* template_url_service =
833       TemplateURLServiceFactory::GetForProfile(profile());
834   TemplateURLData data;
835   data.SetURL("{google:baseURL}search?q={searchTerms}");
836   data.instant_url = "{google:baseURL}webhp?strk";
837   data.search_terms_replacement_key = "strk";
838   TemplateURL* template_url = new TemplateURL(profile(), data);
839   // Takes ownership of |template_url|.
840   template_url_service->Add(template_url);
841   template_url_service->SetDefaultSearchProvider(template_url);
842
843   // By default, Instant Extended forces the instant URL to be HTTPS, so even if
844   // we set a Google base URL that is HTTP, we should get an HTTPS URL.
845   UIThreadSearchTermsData::SetGoogleBaseURL("http://www.foo.com/");
846   GURL instant_url(GetInstantURL(profile(), kDisableStartMargin, false));
847   ASSERT_TRUE(instant_url.is_valid());
848   EXPECT_EQ("https://www.foo.com/webhp?strk", instant_url.spec());
849
850   // However, if the Google base URL is specified on the command line, the
851   // instant URL should just use it, even if it's HTTP.
852   UIThreadSearchTermsData::SetGoogleBaseURL(std::string());
853   CommandLine::ForCurrentProcess()->AppendSwitchASCII(switches::kGoogleBaseURL,
854                                                       "http://www.bar.com/");
855   instant_url = GetInstantURL(profile(), kDisableStartMargin, false);
856   ASSERT_TRUE(instant_url.is_valid());
857   EXPECT_EQ("http://www.bar.com/webhp?strk", instant_url.spec());
858
859   // Similarly, setting a Google base URL on the command line should allow you
860   // to get the Google version of the local NTP, even though search provider's
861   // URL doesn't contain "google".
862   local_instant_url = GetLocalInstantURL(profile());
863   EXPECT_EQ(GURL(chrome::kChromeSearchLocalNtpUrl), local_instant_url);
864
865   // If we specify extra search query params, they should be inserted into the
866   // query portion of the instant URL.
867   CommandLine::ForCurrentProcess()->AppendSwitchASCII(
868       switches::kExtraSearchQueryParams, "a=b");
869   instant_url = GetInstantURL(profile(), kDisableStartMargin, false);
870   ASSERT_TRUE(instant_url.is_valid());
871   EXPECT_EQ("http://www.bar.com/webhp?a=b&strk", instant_url.spec());
872 }
873
874 TEST_F(SearchTest, ShouldShowInstantNTP_Default) {
875   EnableInstantExtendedAPIForTesting();
876   EXPECT_TRUE(ShouldShowInstantNTP());
877 }
878
879 TEST_F(SearchTest, ShouldShowInstantNTP_DisabledViaFinch) {
880   EnableInstantExtendedAPIForTesting();
881   ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial("InstantExtended",
882       "Group1 show_ntp:0"));
883   EXPECT_FALSE(ShouldShowInstantNTP());
884 }
885
886 TEST_F(SearchTest, ShouldShowInstantNTP_DisabledByUseCacheableNTPFinchFlag) {
887   EnableInstantExtendedAPIForTesting();
888   ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial("InstantExtended",
889       "Group1 use_cacheable_ntp:1"));
890   EXPECT_FALSE(ShouldShowInstantNTP());
891 }
892
893 TEST_F(SearchTest, ShouldUseCacheableNTP_Default) {
894   EnableInstantExtendedAPIForTesting();
895   EXPECT_FALSE(ShouldUseCacheableNTP());
896 }
897
898 TEST_F(SearchTest, ShouldUseCacheableNTP_EnabledViaFinch) {
899   EnableInstantExtendedAPIForTesting();
900   ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial("InstantExtended",
901       "Group1 use_cacheable_ntp:1"));
902   EXPECT_TRUE(ShouldUseCacheableNTP());
903 }
904
905 TEST_F(SearchTest, ShouldUseCacheableNTP_EnabledViaCommandLine) {
906   EnableInstantExtendedAPIForTesting();
907   CommandLine::ForCurrentProcess()->
908       AppendSwitch(switches::kUseCacheableNewTabPage);
909   ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial("InstantExtended",
910       "Group1 use_cacheable_ntp:0"));
911   EXPECT_TRUE(ShouldUseCacheableNTP());
912 }
913
914 TEST_F(SearchTest, IsNTPURL) {
915   GURL invalid_url;
916   GURL ntp_url(chrome::kChromeUINewTabURL);
917   GURL local_ntp_url(GetLocalInstantURL(profile()));
918
919   EXPECT_FALSE(chrome::IsNTPURL(invalid_url, profile()));
920   EXPECT_FALSE(chrome::IsNTPURL(local_ntp_url, profile()));
921
922   EXPECT_TRUE(chrome::IsNTPURL(ntp_url, NULL));
923   EXPECT_FALSE(chrome::IsNTPURL(local_ntp_url, NULL));
924
925   // Enable Instant. No margin.
926   EnableInstantExtendedAPIForTesting();
927   profile()->GetPrefs()->SetBoolean(prefs::kSearchSuggestEnabled, true);
928   GURL remote_ntp_url(GetInstantURL(profile(), kDisableStartMargin, false));
929   GURL search_url_with_search_terms("https://foo.com/url?strk&bar=abc");
930   GURL search_url_without_search_terms("https://foo.com/url?strk&bar");
931
932   EXPECT_FALSE(chrome::IsNTPURL(ntp_url, profile()));
933   EXPECT_TRUE(chrome::IsNTPURL(local_ntp_url, profile()));
934   EXPECT_TRUE(chrome::IsNTPURL(remote_ntp_url, profile()));
935   EXPECT_FALSE(chrome::IsNTPURL(search_url_with_search_terms, profile()));
936   EXPECT_TRUE(chrome::IsNTPURL(search_url_without_search_terms, profile()));
937
938   EXPECT_FALSE(chrome::IsNTPURL(ntp_url, NULL));
939   EXPECT_FALSE(chrome::IsNTPURL(local_ntp_url, NULL));
940   EXPECT_FALSE(chrome::IsNTPURL(remote_ntp_url, NULL));
941   EXPECT_FALSE(chrome::IsNTPURL(search_url_with_search_terms, NULL));
942   EXPECT_FALSE(chrome::IsNTPURL(search_url_without_search_terms, NULL));
943 }
944
945 TEST_F(SearchTest, GetSearchURLs) {
946   std::vector<GURL> search_urls = GetSearchURLs(profile());
947   EXPECT_EQ(2U, search_urls.size());
948   EXPECT_EQ("http://foo.com/alt#quux=", search_urls[0].spec());
949   EXPECT_EQ("http://foo.com/url?bar=", search_urls[1].spec());
950 }
951
952 }  // namespace chrome