search_unittest.cc revision 2385ea399aae016c0806a4f9ef3c9cfe3d2a39df
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/search/instant_service.h"
12#include "chrome/browser/search/instant_service_factory.h"
13#include "chrome/browser/search/search.h"
14#include "chrome/browser/search_engines/search_terms_data.h"
15#include "chrome/browser/search_engines/template_url_service.h"
16#include "chrome/browser/search_engines/template_url_service_factory.h"
17#include "chrome/browser/ui/tabs/tab_strip_model.h"
18#include "chrome/common/chrome_switches.h"
19#include "chrome/common/metrics/entropy_provider.h"
20#include "chrome/common/pref_names.h"
21#include "chrome/common/url_constants.h"
22#include "chrome/test/base/browser_with_test_window_test.h"
23#include "chrome/test/base/ui_test_utils.h"
24#include "content/public/browser/render_process_host.h"
25#include "content/public/browser/render_view_host.h"
26#include "content/public/browser/site_instance.h"
27#include "content/public/browser/web_contents.h"
28#include "content/public/common/renderer_preferences.h"
29
30namespace chrome {
31
32TEST(EmbeddedSearchFieldTrialTest, GetFieldTrialInfoEmptyAndValid) {
33  FieldTrialFlags flags;
34  uint64 group_number = 0;
35
36  EXPECT_TRUE(GetFieldTrialInfo(std::string(), &flags, &group_number));
37  EXPECT_EQ(0ul, group_number);
38  EXPECT_EQ(0ul, flags.size());
39
40  EXPECT_TRUE(GetFieldTrialInfo("Group77", &flags, &group_number));
41  EXPECT_EQ(77ul, group_number);
42  EXPECT_EQ(0ul, flags.size());
43}
44
45TEST(EmbeddedSearchFieldTrialTest, GetFieldTrialInfoInvalidThenValid) {
46  FieldTrialFlags flags;
47  uint64 group_number = 0;
48
49  EXPECT_FALSE(GetFieldTrialInfo("Group77.2", &flags, &group_number));
50  EXPECT_EQ(0ul, group_number);
51  EXPECT_EQ(0ul, flags.size());
52
53  EXPECT_TRUE(GetFieldTrialInfo("Invalid77", &flags, &group_number));
54  EXPECT_EQ(0ul, group_number);
55  EXPECT_EQ(0ul, flags.size());
56
57  EXPECT_TRUE(GetFieldTrialInfo("Group77 ", &flags, &group_number));
58  EXPECT_EQ(77ul, group_number);
59  EXPECT_EQ(0ul, flags.size());
60}
61
62TEST(EmbeddedSearchFieldTrialTest, GetFieldTrialInfoValidFlag) {
63  FieldTrialFlags flags;
64  uint64 group_number = 0;
65
66  EXPECT_EQ(9999ul, GetUInt64ValueForFlagWithDefault("foo", 9999, flags));
67  EXPECT_TRUE(GetFieldTrialInfo("Group77 foo:6", &flags, &group_number));
68  EXPECT_EQ(77ul, group_number);
69  EXPECT_EQ(1ul, flags.size());
70  EXPECT_EQ(6ul, GetUInt64ValueForFlagWithDefault("foo", 9999, flags));
71}
72
73TEST(EmbeddedSearchFieldTrialTest, GetFieldTrialInfoLotsOfFlags) {
74  FieldTrialFlags flags;
75  uint64 group_number = 0;
76
77  EXPECT_TRUE(GetFieldTrialInfo(
78      "Group77 bar:1 baz:7 cat:dogs", &flags, &group_number));
79  EXPECT_EQ(77ul, group_number);
80  EXPECT_EQ(3ul, flags.size());
81  EXPECT_EQ(true, GetBoolValueForFlagWithDefault("bar", false, flags));
82  EXPECT_EQ(7ul, GetUInt64ValueForFlagWithDefault("baz", 0, flags));
83  EXPECT_EQ("dogs",
84            GetStringValueForFlagWithDefault("cat", std::string(), flags));
85  EXPECT_EQ("default",
86            GetStringValueForFlagWithDefault("moose", "default", flags));
87}
88
89TEST(EmbeddedSearchFieldTrialTest, GetFieldTrialInfoDisabled) {
90  FieldTrialFlags flags;
91  uint64 group_number = 0;
92
93  EXPECT_FALSE(GetFieldTrialInfo(
94      "Group77 bar:1 baz:7 cat:dogs DISABLED", &flags, &group_number));
95  EXPECT_EQ(0ul, group_number);
96  EXPECT_EQ(0ul, flags.size());
97}
98
99TEST(EmbeddedSearchFieldTrialTest, GetFieldTrialInfoControlFlags) {
100  FieldTrialFlags flags;
101  uint64 group_number = 0;
102
103  EXPECT_TRUE(GetFieldTrialInfo(
104      "Control77 bar:1 baz:7 cat:dogs", &flags, &group_number));
105  EXPECT_EQ(0ul, group_number);
106  EXPECT_EQ(3ul, flags.size());
107}
108
109class InstantExtendedAPIEnabledTest : public testing::Test {
110 public:
111  InstantExtendedAPIEnabledTest() : histogram_(NULL) {
112  }
113 protected:
114  virtual void SetUp() {
115    field_trial_list_.reset(new base::FieldTrialList(
116        new metrics::SHA1EntropyProvider("42")));
117    base::StatisticsRecorder::Initialize();
118    ResetInstantExtendedOptInStateGateForTest();
119    previous_metrics_count_.resize(INSTANT_EXTENDED_OPT_IN_STATE_ENUM_COUNT, 0);
120    base::HistogramBase* histogram = GetHistogram();
121    if (histogram) {
122      scoped_ptr<base::HistogramSamples> samples(histogram->SnapshotSamples());
123      if (samples.get()) {
124        for (int state = INSTANT_EXTENDED_NOT_SET;
125             state < INSTANT_EXTENDED_OPT_IN_STATE_ENUM_COUNT; ++state) {
126          previous_metrics_count_[state] = samples->GetCount(state);
127        }
128      }
129    }
130  }
131
132  virtual CommandLine* GetCommandLine() const {
133    return CommandLine::ForCurrentProcess();
134  }
135
136  void ValidateMetrics(base::HistogramBase::Sample value) {
137    base::HistogramBase* histogram = GetHistogram();
138    if (histogram) {
139      scoped_ptr<base::HistogramSamples> samples(histogram->SnapshotSamples());
140      if (samples.get()) {
141        for (int state = INSTANT_EXTENDED_NOT_SET;
142             state < INSTANT_EXTENDED_OPT_IN_STATE_ENUM_COUNT; ++state) {
143          if (state == value) {
144            EXPECT_EQ(previous_metrics_count_[state] + 1,
145                      samples->GetCount(state));
146          } else {
147            EXPECT_EQ(previous_metrics_count_[state], samples->GetCount(state));
148          }
149        }
150      }
151    }
152  }
153
154 private:
155  base::HistogramBase* GetHistogram() {
156    if (!histogram_) {
157      histogram_ = base::StatisticsRecorder::FindHistogram(
158          "InstantExtended.OptInState");
159    }
160    return histogram_;
161  }
162  base::HistogramBase* histogram_;
163  scoped_ptr<base::FieldTrialList> field_trial_list_;
164  std::vector<int> previous_metrics_count_;
165};
166
167TEST_F(InstantExtendedAPIEnabledTest, EnabledViaCommandLineFlag) {
168  GetCommandLine()->AppendSwitch(switches::kEnableInstantExtendedAPI);
169  EXPECT_TRUE(IsInstantExtendedAPIEnabled());
170#if defined(OS_IOS) || defined(OS_ANDROID)
171  EXPECT_EQ(1ul, EmbeddedSearchPageVersion());
172#else
173  EXPECT_EQ(2ul, EmbeddedSearchPageVersion());
174#endif
175  ValidateMetrics(INSTANT_EXTENDED_OPT_IN);
176}
177
178TEST_F(InstantExtendedAPIEnabledTest, EnabledViaFinchFlag) {
179  ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial("InstantExtended",
180                                                     "Group1 espv:42"));
181  EXPECT_TRUE(IsInstantExtendedAPIEnabled());
182  EXPECT_EQ(42ul, EmbeddedSearchPageVersion());
183  ValidateMetrics(INSTANT_EXTENDED_NOT_SET);
184}
185
186TEST_F(InstantExtendedAPIEnabledTest, DisabledViaCommandLineFlag) {
187  GetCommandLine()->AppendSwitch(switches::kDisableInstantExtendedAPI);
188  ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial("InstantExtended",
189                                                     "Group1 espv:2"));
190  EXPECT_FALSE(IsInstantExtendedAPIEnabled());
191  EXPECT_EQ(0ul, EmbeddedSearchPageVersion());
192  ValidateMetrics(INSTANT_EXTENDED_OPT_OUT);
193}
194
195typedef InstantExtendedAPIEnabledTest ShouldHideTopVerbatimTest;
196
197TEST_F(ShouldHideTopVerbatimTest, DoNotHideByDefault) {
198  ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
199      "InstantExtended", "Control"));
200  EXPECT_FALSE(ShouldHideTopVerbatimMatch());
201}
202
203TEST_F(ShouldHideTopVerbatimTest, DoNotHideInInstantExtended) {
204  ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
205      "InstantExtended", "Group1"));
206  EXPECT_FALSE(ShouldHideTopVerbatimMatch());
207}
208
209TEST_F(ShouldHideTopVerbatimTest, EnableByFlagInInstantExtended) {
210  ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
211      "InstantExtended", "Group1 hide_verbatim:1"));
212  EXPECT_TRUE(ShouldHideTopVerbatimMatch());
213}
214
215TEST_F(ShouldHideTopVerbatimTest, EnableByFlagOutsideInstantExtended) {
216  ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
217      "InstantExtended", "Controll1 hide_verbatim:1"));
218  EXPECT_TRUE(ShouldHideTopVerbatimMatch());
219}
220
221TEST_F(ShouldHideTopVerbatimTest, DisableByFlag) {
222  ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
223      "InstantExtended", "Group1 hide_verbatim:0"));
224  EXPECT_FALSE(ShouldHideTopVerbatimMatch());
225}
226
227class SearchTest : public BrowserWithTestWindowTest {
228 protected:
229  virtual void SetUp() OVERRIDE {
230    BrowserWithTestWindowTest::SetUp();
231    field_trial_list_.reset(new base::FieldTrialList(
232        new metrics::SHA1EntropyProvider("42")));
233    TemplateURLServiceFactory::GetInstance()->SetTestingFactoryAndUse(
234        profile(), &TemplateURLServiceFactory::BuildInstanceFor);
235    TemplateURLService* template_url_service =
236        TemplateURLServiceFactory::GetForProfile(profile());
237    ui_test_utils::WaitForTemplateURLServiceToLoad(template_url_service);
238    SetSearchProvider();
239  }
240
241  void SetSearchProvider() {
242    TemplateURLService* template_url_service =
243        TemplateURLServiceFactory::GetForProfile(profile());
244    TemplateURLData data;
245    data.SetURL("http://foo.com/url?bar={searchTerms}");
246    data.instant_url = "http://foo.com/instant?"
247        "{google:omniboxStartMarginParameter}foo=foo#foo=foo&strk";
248    data.alternate_urls.push_back("http://foo.com/alt#quux={searchTerms}");
249    data.search_terms_replacement_key = "strk";
250
251    TemplateURL* template_url = new TemplateURL(profile(), data);
252    // Takes ownership of |template_url|.
253    template_url_service->Add(template_url);
254    template_url_service->SetDefaultSearchProvider(template_url);
255  }
256
257  // Build an Instant URL with or without a valid search terms replacement key
258  // as per |has_search_term_replacement_key|. Set that URL as the instant URL
259  // for the default search provider.
260  void SetDefaultInstantTemplateUrl(bool has_search_term_replacement_key) {
261    TemplateURLService* template_url_service =
262        TemplateURLServiceFactory::GetForProfile(profile());
263
264    static const char kInstantURLWithStrk[] =
265        "http://foo.com/instant?foo=foo#foo=foo&strk";
266    static const char kInstantURLNoStrk[] =
267        "http://foo.com/instant?foo=foo#foo=foo";
268
269    TemplateURLData data;
270    data.SetURL("http://foo.com/url?bar={searchTerms}");
271    data.instant_url = (has_search_term_replacement_key ?
272        kInstantURLWithStrk : kInstantURLNoStrk);
273    data.search_terms_replacement_key = "strk";
274
275    TemplateURL* template_url = new TemplateURL(profile(), data);
276    // Takes ownership of |template_url|.
277    template_url_service->Add(template_url);
278    template_url_service->SetDefaultSearchProvider(template_url);
279  }
280
281  bool InInstantProcess(const content::WebContents* contents) {
282    InstantService* instant_service =
283        InstantServiceFactory::GetForProfile(profile());
284    return instant_service->IsInstantProcess(
285        contents->GetRenderProcessHost()->GetID());
286  }
287
288  scoped_ptr<base::FieldTrialList> field_trial_list_;
289};
290
291struct SearchTestCase {
292  const char* url;
293  bool expected_result;
294  const char* comment;
295};
296
297TEST_F(SearchTest, ShouldAssignURLToInstantRendererExtendedDisabled) {
298  DisableInstantExtendedAPIForTesting();
299
300  const SearchTestCase kTestCases[] = {
301    {"chrome-search://foo/bar",                 false,  ""},
302    {"http://foo.com/instant",                  false,  ""},
303    {"http://foo.com/instant?foo=bar",          false,  ""},
304    {"https://foo.com/instant",                 false,  ""},
305    {"https://foo.com/instant#foo=bar",         false,  ""},
306    {"HtTpS://fOo.CoM/instant",                 false,  ""},
307    {"http://foo.com:80/instant",               false,  ""},
308    {"invalid URL",                             false, "Invalid URL"},
309    {"unknown://scheme/path",                   false, "Unknown scheme"},
310    {"ftp://foo.com/instant",                   false, "Non-HTTP scheme"},
311    {"http://sub.foo.com/instant",              false, "Non-exact host"},
312    {"http://foo.com:26/instant",               false, "Non-default port"},
313    {"http://foo.com/instant/bar",              false, "Non-exact path"},
314    {"http://foo.com/Instant",                  false, "Case sensitive path"},
315    {"http://foo.com/",                         false, "Non-exact path"},
316    {"https://foo.com/",                        false, "Non-exact path"},
317    {"https://foo.com/url?strk",                false, "Non-extended mode"},
318    {"https://foo.com/alt?strk",                false, "Non-extended mode"},
319  };
320
321  for (size_t i = 0; i < arraysize(kTestCases); ++i) {
322    const SearchTestCase& test = kTestCases[i];
323    EXPECT_EQ(test.expected_result,
324              ShouldAssignURLToInstantRenderer(GURL(test.url), profile()))
325        << test.url << " " << test.comment;
326  }
327}
328
329TEST_F(SearchTest, ShouldAssignURLToInstantRendererExtendedEnabled) {
330  EnableInstantExtendedAPIForTesting();
331
332  const SearchTestCase kTestCases[] = {
333    {chrome::kChromeSearchLocalNtpUrl, true,  ""},
334    {"https://foo.com/instant?strk",   true,  ""},
335    {"https://foo.com/instant#strk",   true,  ""},
336    {"https://foo.com/instant?strk=0", true,  ""},
337    {"https://foo.com/url?strk",       true,  ""},
338    {"https://foo.com/alt?strk",       true,  ""},
339    {"http://foo.com/instant",         false, "Non-HTTPS"},
340    {"http://foo.com/instant?strk",    false, "Non-HTTPS"},
341    {"http://foo.com/instant?strk=1",  false, "Non-HTTPS"},
342    {"https://foo.com/instant",        false, "No search terms replacement"},
343    {"https://foo.com/?strk",          false, "Non-exact path"},
344  };
345
346  for (size_t i = 0; i < arraysize(kTestCases); ++i) {
347    const SearchTestCase& test = kTestCases[i];
348    EXPECT_EQ(test.expected_result,
349              ShouldAssignURLToInstantRenderer(GURL(test.url), profile()))
350        << test.url << " " << test.comment;
351  }
352}
353
354TEST_F(SearchTest, ShouldUseProcessPerSiteForInstantURL) {
355  EnableInstantExtendedAPIForTesting();
356
357  const SearchTestCase kTestCases[] = {
358    {"chrome-search://local-ntp",      true,  "Local NTP"},
359    {"chrome-search://online-ntp",     true,  "Online NTP"},
360    {"invalid-scheme://local-ntp",     false, "Invalid Local NTP URL"},
361    {"invalid-scheme://online-ntp",    false, "Invalid Online NTP URL"},
362    {"chrome-search://foo.com",        false, "Search result page"},
363    {"https://foo.com/instant?strk",   false,  ""},
364    {"https://foo.com/instant#strk",   false,  ""},
365    {"https://foo.com/instant?strk=0", false,  ""},
366    {"https://foo.com/url?strk",       false,  ""},
367    {"https://foo.com/alt?strk",       false,  ""},
368    {"http://foo.com/instant",         false,  "Non-HTTPS"},
369    {"http://foo.com/instant?strk",    false,  "Non-HTTPS"},
370    {"http://foo.com/instant?strk=1",  false,  "Non-HTTPS"},
371    {"https://foo.com/instant",        false,  "No search terms replacement"},
372    {"https://foo.com/?strk",          false,  "Non-exact path"},
373  };
374
375  for (size_t i = 0; i < arraysize(kTestCases); ++i) {
376    const SearchTestCase& test = kTestCases[i];
377    EXPECT_EQ(test.expected_result,
378              ShouldUseProcessPerSiteForInstantURL(GURL(test.url), profile()))
379        << test.url << " " << test.comment;
380  }
381}
382
383// Each test case represents a navigation to |start_url| followed by a
384// navigation to |end_url|. We will check whether each navigation lands in an
385// Instant process, and also whether the navigation from start to end re-uses
386// the same SiteInstance (and hence the same RenderViewHost, etc.).
387const struct ProcessIsolationTestCase {
388  const char* description;
389  const char* start_url;
390  bool start_in_instant_process;
391  const char* end_url;
392  bool end_in_instant_process;
393  bool same_site_instance;
394} kProcessIsolationTestCases[] = {
395  {"Local NTP -> SRP",
396   "chrome-search://local-ntp",       true,
397   "https://foo.com/url?strk",        true,   false },
398  {"Local NTP -> Regular",
399   "chrome-search://local-ntp",       true,
400   "https://foo.com/other",           false,  false },
401  {"Remote NTP -> SRP",
402   "https://foo.com/instant?strk",    true,
403   "https://foo.com/url?strk",        true,   false },
404  {"Remote NTP -> Regular",
405   "https://foo.com/instant?strk",    true,
406   "https://foo.com/other",           false,  false },
407  {"SRP -> SRP",
408   "https://foo.com/url?strk",        true,
409   "https://foo.com/url?strk",        true,   true  },
410  {"SRP -> Regular",
411   "https://foo.com/url?strk",        true,
412   "https://foo.com/other",           false,  false },
413  {"Regular -> SRP",
414   "https://foo.com/other",           false,
415   "https://foo.com/url?strk",        true,   false },
416};
417
418TEST_F(SearchTest, ProcessIsolation) {
419  EnableInstantExtendedAPIForTesting();
420
421  for (size_t i = 0; i < arraysize(kProcessIsolationTestCases); ++i) {
422    const ProcessIsolationTestCase& test = kProcessIsolationTestCases[i];
423    AddTab(browser(), GURL("chrome://blank"));
424    const content::WebContents* contents =
425        browser()->tab_strip_model()->GetActiveWebContents();
426
427    // Navigate to start URL.
428    NavigateAndCommitActiveTab(GURL(test.start_url));
429    EXPECT_EQ(test.start_in_instant_process, InInstantProcess(contents))
430        << test.description;
431
432    // Save state.
433    const scoped_refptr<content::SiteInstance> start_site_instance =
434        contents->GetSiteInstance();
435    const content::RenderProcessHost* start_rph =
436        contents->GetRenderProcessHost();
437    const content::RenderViewHost* start_rvh =
438        contents->GetRenderViewHost();
439
440    // Navigate to end URL.
441    NavigateAndCommitActiveTab(GURL(test.end_url));
442    EXPECT_EQ(test.end_in_instant_process, InInstantProcess(contents))
443        << test.description;
444
445    EXPECT_EQ(test.same_site_instance,
446              start_site_instance == contents->GetSiteInstance())
447        << test.description;
448    EXPECT_EQ(test.same_site_instance,
449              start_rvh == contents->GetRenderViewHost())
450        << test.description;
451    EXPECT_EQ(test.same_site_instance,
452              start_rph == contents->GetRenderProcessHost())
453        << test.description;
454  }
455}
456
457TEST_F(SearchTest, ProcessIsolation_RendererInitiated) {
458  EnableInstantExtendedAPIForTesting();
459
460  for (size_t i = 0; i < arraysize(kProcessIsolationTestCases); ++i) {
461    const ProcessIsolationTestCase& test = kProcessIsolationTestCases[i];
462    AddTab(browser(), GURL("chrome://blank"));
463    content::WebContents* contents =
464        browser()->tab_strip_model()->GetActiveWebContents();
465
466    // Navigate to start URL.
467    NavigateAndCommitActiveTab(GURL(test.start_url));
468    EXPECT_EQ(test.start_in_instant_process, InInstantProcess(contents))
469        << test.description;
470
471    // Save state.
472    const scoped_refptr<content::SiteInstance> start_site_instance =
473        contents->GetSiteInstance();
474    const content::RenderProcessHost* start_rph =
475        contents->GetRenderProcessHost();
476    const content::RenderViewHost* start_rvh =
477        contents->GetRenderViewHost();
478
479    // Navigate to end URL via a renderer-initiated navigation.
480    content::NavigationController* controller = &contents->GetController();
481    content::NavigationController::LoadURLParams load_params(
482        GURL(test.end_url));
483    load_params.is_renderer_initiated = true;
484    load_params.transition_type = content::PAGE_TRANSITION_LINK;
485
486    controller->LoadURLWithParams(load_params);
487    CommitPendingLoad(controller);
488    EXPECT_EQ(test.end_in_instant_process, InInstantProcess(contents))
489        << test.description;
490
491    EXPECT_EQ(test.same_site_instance,
492              start_site_instance == contents->GetSiteInstance())
493        << test.description;
494    EXPECT_EQ(test.same_site_instance,
495              start_rvh == contents->GetRenderViewHost())
496        << test.description;
497    EXPECT_EQ(test.same_site_instance,
498              start_rph == contents->GetRenderProcessHost())
499        << test.description;
500  }
501}
502
503const SearchTestCase kInstantNTPTestCases[] = {
504  {"https://foo.com/instant?strk",         true,  "Valid Instant URL"},
505  {"https://foo.com/instant#strk",         true,  "Valid Instant URL"},
506  {"https://foo.com/url?strk",             true,  "Valid search URL"},
507  {"https://foo.com/url#strk",             true,  "Valid search URL"},
508  {"https://foo.com/alt?strk",             true,  "Valid alternative URL"},
509  {"https://foo.com/alt#strk",             true,  "Valid alternative URL"},
510  {"https://foo.com/url?strk&bar=",        true,  "No query terms"},
511  {"https://foo.com/url?strk&q=abc",       true,  "No query terms key"},
512  {"https://foo.com/url?strk#bar=abc",     true,  "Query terms key in ref"},
513  {"https://foo.com/url?strk&bar=abc",     false, "Has query terms"},
514  {"http://foo.com/instant?strk=1",        false, "Insecure URL"},
515  {"https://foo.com/instant",              false, "No search term replacement"},
516  {"chrome://blank/",                      false, "Chrome scheme"},
517  {"chrome-search://foo",                  false, "Chrome-search scheme"},
518  {chrome::kChromeSearchLocalNtpUrl,       true,  "Local new tab page"},
519  {"https://bar.com/instant?strk=1",       false, "Random non-search page"},
520};
521
522TEST_F(SearchTest, InstantNTPExtendedEnabled) {
523  EnableInstantExtendedAPIForTesting();
524  AddTab(browser(), GURL("chrome://blank"));
525  for (size_t i = 0; i < arraysize(kInstantNTPTestCases); ++i) {
526    const SearchTestCase& test = kInstantNTPTestCases[i];
527    NavigateAndCommitActiveTab(GURL(test.url));
528    const content::WebContents* contents =
529        browser()->tab_strip_model()->GetWebContentsAt(0);
530    EXPECT_EQ(test.expected_result, IsInstantNTP(contents))
531        << test.url << " " << test.comment;
532  }
533}
534
535TEST_F(SearchTest, InstantNTPExtendedDisabled) {
536  AddTab(browser(), GURL("chrome://blank"));
537  for (size_t i = 0; i < arraysize(kInstantNTPTestCases); ++i) {
538    const SearchTestCase& test = kInstantNTPTestCases[i];
539    NavigateAndCommitActiveTab(GURL(test.url));
540    const content::WebContents* contents =
541        browser()->tab_strip_model()->GetWebContentsAt(0);
542    EXPECT_FALSE(IsInstantNTP(contents)) << test.url << " " << test.comment;
543  }
544}
545
546TEST_F(SearchTest, InstantNTPCustomNavigationEntry) {
547  EnableInstantExtendedAPIForTesting();
548  AddTab(browser(), GURL("chrome://blank"));
549  for (size_t i = 0; i < arraysize(kInstantNTPTestCases); ++i) {
550    const SearchTestCase& test = kInstantNTPTestCases[i];
551    NavigateAndCommitActiveTab(GURL(test.url));
552    content::WebContents* contents =
553        browser()->tab_strip_model()->GetWebContentsAt(0);
554    content::NavigationController& controller = contents->GetController();
555    controller.SetTransientEntry(
556        controller.CreateNavigationEntry(GURL("chrome://blank"),
557                                         content::Referrer(),
558                                         content::PAGE_TRANSITION_LINK,
559                                         false,
560                                         std::string(),
561                                         contents->GetBrowserContext()));
562    // The active entry is chrome://blank and not an NTP.
563    EXPECT_FALSE(IsInstantNTP(contents));
564    EXPECT_EQ(test.expected_result,
565              NavEntryIsInstantNTP(contents,
566                                   controller.GetLastCommittedEntry()))
567        << test.url << " " << test.comment;
568  }
569}
570
571TEST_F(SearchTest, GetInstantURLExtendedEnabled) {
572  // Instant is disabled, so no Instant URL.
573  EXPECT_EQ(GURL(), GetInstantURL(profile(), kDisableStartMargin));
574
575  // Enable Instant. Still no Instant URL because "strk" is missing.
576  EnableInstantExtendedAPIForTesting();
577  SetDefaultInstantTemplateUrl(false);
578  EXPECT_EQ(GURL(), GetInstantURL(profile(), kDisableStartMargin));
579
580  // Set an Instant URL with a valid search terms replacement key.
581  SetDefaultInstantTemplateUrl(true);
582
583  // Now there should be a valid Instant URL. Note the HTTPS "upgrade".
584  EXPECT_EQ(GURL("https://foo.com/instant?foo=foo#foo=foo&strk"),
585            GetInstantURL(profile(), kDisableStartMargin));
586
587  // Enable suggest. No difference.
588  profile()->GetPrefs()->SetBoolean(prefs::kSearchSuggestEnabled, true);
589  EXPECT_EQ(GURL("https://foo.com/instant?foo=foo#foo=foo&strk"),
590            GetInstantURL(profile(), kDisableStartMargin));
591
592  // Disable suggest. No Instant URL.
593  profile()->GetPrefs()->SetBoolean(prefs::kSearchSuggestEnabled, false);
594  EXPECT_EQ(GURL(), GetInstantURL(profile(), kDisableStartMargin));
595}
596
597TEST_F(SearchTest, StartMarginCGI) {
598  // Instant is disabled, so no Instant URL.
599  EXPECT_EQ(GURL(), GetInstantURL(profile(), kDisableStartMargin));
600
601  // Enable Instant. No margin.
602  EnableInstantExtendedAPIForTesting();
603  profile()->GetPrefs()->SetBoolean(prefs::kSearchSuggestEnabled, true);
604
605  EXPECT_EQ(GURL("https://foo.com/instant?foo=foo#foo=foo&strk"),
606            GetInstantURL(profile(), kDisableStartMargin));
607
608  // With start margin.
609  EXPECT_EQ(GURL("https://foo.com/instant?es_sm=10&foo=foo#foo=foo&strk"),
610            GetInstantURL(profile(), 10));
611}
612
613TEST_F(SearchTest, CommandLineOverrides) {
614  EnableInstantExtendedAPIForTesting();
615
616  GURL local_instant_url(GetLocalInstantURL(profile()));
617  EXPECT_EQ(GURL(chrome::kChromeSearchLocalNtpUrl), local_instant_url);
618
619  TemplateURLService* template_url_service =
620      TemplateURLServiceFactory::GetForProfile(profile());
621  TemplateURLData data;
622  data.SetURL("{google:baseURL}search?q={searchTerms}");
623  data.instant_url = "{google:baseURL}webhp?strk";
624  data.search_terms_replacement_key = "strk";
625  TemplateURL* template_url = new TemplateURL(profile(), data);
626  // Takes ownership of |template_url|.
627  template_url_service->Add(template_url);
628  template_url_service->SetDefaultSearchProvider(template_url);
629
630  // By default, Instant Extended forces the instant URL to be HTTPS, so even if
631  // we set a Google base URL that is HTTP, we should get an HTTPS URL.
632  UIThreadSearchTermsData::SetGoogleBaseURL("http://www.foo.com/");
633  GURL instant_url(GetInstantURL(profile(), kDisableStartMargin));
634  ASSERT_TRUE(instant_url.is_valid());
635  EXPECT_EQ("https://www.foo.com/webhp?strk", instant_url.spec());
636
637  // However, if the Google base URL is specified on the command line, the
638  // instant URL should just use it, even if it's HTTP.
639  UIThreadSearchTermsData::SetGoogleBaseURL(std::string());
640  CommandLine::ForCurrentProcess()->AppendSwitchASCII(switches::kGoogleBaseURL,
641                                                      "http://www.bar.com/");
642  instant_url = GetInstantURL(profile(), kDisableStartMargin);
643  ASSERT_TRUE(instant_url.is_valid());
644  EXPECT_EQ("http://www.bar.com/webhp?strk", instant_url.spec());
645
646  // Similarly, setting a Google base URL on the command line should allow you
647  // to get the Google version of the local NTP, even though search provider's
648  // URL doesn't contain "google".
649  local_instant_url = GetLocalInstantURL(profile());
650  EXPECT_EQ(GURL(chrome::kChromeSearchLocalNtpUrl), local_instant_url);
651
652  // If we specify extra search query params, they should be inserted into the
653  // query portion of the instant URL.
654  CommandLine::ForCurrentProcess()->AppendSwitchASCII(
655      switches::kExtraSearchQueryParams, "a=b");
656  instant_url = GetInstantURL(profile(), kDisableStartMargin);
657  ASSERT_TRUE(instant_url.is_valid());
658  EXPECT_EQ("http://www.bar.com/webhp?a=b&strk", instant_url.spec());
659}
660
661TEST_F(SearchTest, ShouldShowInstantNTP_Default) {
662  EnableInstantExtendedAPIForTesting();
663  EXPECT_TRUE(ShouldShowInstantNTP());
664}
665
666TEST_F(SearchTest, ShouldShowInstantNTP_DisabledViaFinch) {
667  EnableInstantExtendedAPIForTesting();
668  ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial("InstantExtended",
669                                                     "Group1 show_ntp:0"));
670  EXPECT_FALSE(ShouldShowInstantNTP());
671}
672
673TEST_F(SearchTest, ShouldShowInstantNTP_DisabledByInstantNewTabURLSwitch) {
674  EnableInstantExtendedAPIForTesting();
675  CommandLine::ForCurrentProcess()->AppendSwitchASCII(
676      switches::kInstantNewTabURL, "http://example.com/newtab");
677  EXPECT_FALSE(ShouldShowInstantNTP());
678}
679
680TEST_F(SearchTest, IsNTPURL) {
681  GURL invalid_url;
682  GURL ntp_url(chrome::kChromeUINewTabURL);
683  GURL local_ntp_url(GetLocalInstantURL(profile()));
684
685  EXPECT_FALSE(chrome::IsNTPURL(invalid_url, profile()));
686  EXPECT_FALSE(chrome::IsNTPURL(local_ntp_url, profile()));
687
688  EXPECT_TRUE(chrome::IsNTPURL(ntp_url, NULL));
689  EXPECT_FALSE(chrome::IsNTPURL(local_ntp_url, NULL));
690
691  // Enable Instant. No margin.
692  EnableInstantExtendedAPIForTesting();
693  profile()->GetPrefs()->SetBoolean(prefs::kSearchSuggestEnabled, true);
694  GURL remote_ntp_url(GetInstantURL(profile(), kDisableStartMargin));
695
696  EXPECT_FALSE(chrome::IsNTPURL(ntp_url, profile()));
697  EXPECT_TRUE(chrome::IsNTPURL(local_ntp_url, profile()));
698  EXPECT_TRUE(chrome::IsNTPURL(remote_ntp_url, profile()));
699
700  EXPECT_FALSE(chrome::IsNTPURL(ntp_url, NULL));
701  EXPECT_FALSE(chrome::IsNTPURL(local_ntp_url, NULL));
702  EXPECT_FALSE(chrome::IsNTPURL(remote_ntp_url, NULL));
703}
704
705}  // namespace chrome
706