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