search_unittest.cc revision 3551c9c881056c480085172ff9840cab31610854
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.new_tab_url = "http://foo.com/newtab?strk";
249    data.alternate_urls.push_back("http://foo.com/alt#quux={searchTerms}");
250    data.search_terms_replacement_key = "strk";
251
252    TemplateURL* template_url = new TemplateURL(profile(), data);
253    // Takes ownership of |template_url|.
254    template_url_service->Add(template_url);
255    template_url_service->SetDefaultSearchProvider(template_url);
256  }
257
258  // Build an Instant URL with or without a valid search terms replacement key
259  // as per |has_search_term_replacement_key|. Set that URL as the instant URL
260  // for the default search provider.
261  void SetDefaultInstantTemplateUrl(bool has_search_term_replacement_key) {
262    TemplateURLService* template_url_service =
263        TemplateURLServiceFactory::GetForProfile(profile());
264
265    static const char kInstantURLWithStrk[] =
266        "http://foo.com/instant?foo=foo#foo=foo&strk";
267    static const char kInstantURLNoStrk[] =
268        "http://foo.com/instant?foo=foo#foo=foo";
269
270    TemplateURLData data;
271    data.SetURL("http://foo.com/url?bar={searchTerms}");
272    data.instant_url = (has_search_term_replacement_key ?
273        kInstantURLWithStrk : kInstantURLNoStrk);
274    data.search_terms_replacement_key = "strk";
275
276    TemplateURL* template_url = new TemplateURL(profile(), data);
277    // Takes ownership of |template_url|.
278    template_url_service->Add(template_url);
279    template_url_service->SetDefaultSearchProvider(template_url);
280  }
281
282  bool InInstantProcess(const content::WebContents* contents) {
283    InstantService* instant_service =
284        InstantServiceFactory::GetForProfile(profile());
285    return instant_service->IsInstantProcess(
286        contents->GetRenderProcessHost()->GetID());
287  }
288
289  scoped_ptr<base::FieldTrialList> field_trial_list_;
290};
291
292struct SearchTestCase {
293  const char* url;
294  bool expected_result;
295  const char* comment;
296};
297
298TEST_F(SearchTest, ShouldAssignURLToInstantRendererExtendedDisabled) {
299  DisableInstantExtendedAPIForTesting();
300
301  const SearchTestCase kTestCases[] = {
302    {"chrome-search://foo/bar",                 false,  ""},
303    {"http://foo.com/instant",                  false,  ""},
304    {"http://foo.com/instant?foo=bar",          false,  ""},
305    {"https://foo.com/instant",                 false,  ""},
306    {"https://foo.com/instant#foo=bar",         false,  ""},
307    {"HtTpS://fOo.CoM/instant",                 false,  ""},
308    {"http://foo.com:80/instant",               false,  ""},
309    {"invalid URL",                             false, "Invalid URL"},
310    {"unknown://scheme/path",                   false, "Unknown scheme"},
311    {"ftp://foo.com/instant",                   false, "Non-HTTP scheme"},
312    {"http://sub.foo.com/instant",              false, "Non-exact host"},
313    {"http://foo.com:26/instant",               false, "Non-default port"},
314    {"http://foo.com/instant/bar",              false, "Non-exact path"},
315    {"http://foo.com/Instant",                  false, "Case sensitive path"},
316    {"http://foo.com/",                         false, "Non-exact path"},
317    {"https://foo.com/",                        false, "Non-exact path"},
318    {"https://foo.com/url?strk",                false, "Non-extended mode"},
319    {"https://foo.com/alt?strk",                false, "Non-extended mode"},
320  };
321
322  for (size_t i = 0; i < arraysize(kTestCases); ++i) {
323    const SearchTestCase& test = kTestCases[i];
324    EXPECT_EQ(test.expected_result,
325              ShouldAssignURLToInstantRenderer(GURL(test.url), profile()))
326        << test.url << " " << test.comment;
327  }
328}
329
330TEST_F(SearchTest, ShouldAssignURLToInstantRendererExtendedEnabled) {
331  EnableInstantExtendedAPIForTesting();
332
333  const SearchTestCase kTestCases[] = {
334    {chrome::kChromeSearchLocalNtpUrl, true,  ""},
335    {"https://foo.com/instant?strk",   true,  ""},
336    {"https://foo.com/instant#strk",   true,  ""},
337    {"https://foo.com/instant?strk=0", true,  ""},
338    {"https://foo.com/url?strk",       true,  ""},
339    {"https://foo.com/alt?strk",       true,  ""},
340    {"http://foo.com/instant",         false, "Non-HTTPS"},
341    {"http://foo.com/instant?strk",    false, "Non-HTTPS"},
342    {"http://foo.com/instant?strk=1",  false, "Non-HTTPS"},
343    {"https://foo.com/instant",        false, "No search terms replacement"},
344    {"https://foo.com/?strk",          false, "Non-exact path"},
345  };
346
347  for (size_t i = 0; i < arraysize(kTestCases); ++i) {
348    const SearchTestCase& test = kTestCases[i];
349    EXPECT_EQ(test.expected_result,
350              ShouldAssignURLToInstantRenderer(GURL(test.url), profile()))
351        << test.url << " " << test.comment;
352  }
353}
354
355TEST_F(SearchTest, ShouldUseProcessPerSiteForInstantURL) {
356  EnableInstantExtendedAPIForTesting();
357
358  const SearchTestCase kTestCases[] = {
359    {"chrome-search://local-ntp",      true,  "Local NTP"},
360    {"chrome-search://online-ntp",     true,  "Online NTP"},
361    {"invalid-scheme://local-ntp",     false, "Invalid Local NTP URL"},
362    {"invalid-scheme://online-ntp",    false, "Invalid Online NTP URL"},
363    {"chrome-search://foo.com",        false, "Search result page"},
364    {"https://foo.com/instant?strk",   false,  ""},
365    {"https://foo.com/instant#strk",   false,  ""},
366    {"https://foo.com/instant?strk=0", false,  ""},
367    {"https://foo.com/url?strk",       false,  ""},
368    {"https://foo.com/alt?strk",       false,  ""},
369    {"http://foo.com/instant",         false,  "Non-HTTPS"},
370    {"http://foo.com/instant?strk",    false,  "Non-HTTPS"},
371    {"http://foo.com/instant?strk=1",  false,  "Non-HTTPS"},
372    {"https://foo.com/instant",        false,  "No search terms replacement"},
373    {"https://foo.com/?strk",          false,  "Non-exact path"},
374  };
375
376  for (size_t i = 0; i < arraysize(kTestCases); ++i) {
377    const SearchTestCase& test = kTestCases[i];
378    EXPECT_EQ(test.expected_result,
379              ShouldUseProcessPerSiteForInstantURL(GURL(test.url), profile()))
380        << test.url << " " << test.comment;
381  }
382}
383
384// Each test case represents a navigation to |start_url| followed by a
385// navigation to |end_url|. We will check whether each navigation lands in an
386// Instant process, and also whether the navigation from start to end re-uses
387// the same SiteInstance (and hence the same RenderViewHost, etc.).
388const struct ProcessIsolationTestCase {
389  const char* description;
390  const char* start_url;
391  bool start_in_instant_process;
392  const char* end_url;
393  bool end_in_instant_process;
394  bool same_site_instance;
395} kProcessIsolationTestCases[] = {
396  {"Local NTP -> SRP",
397   "chrome-search://local-ntp",       true,
398   "https://foo.com/url?strk",        true,   false },
399  {"Local NTP -> Regular",
400   "chrome-search://local-ntp",       true,
401   "https://foo.com/other",           false,  false },
402  {"Remote NTP -> SRP",
403   "https://foo.com/instant?strk",    true,
404   "https://foo.com/url?strk",        true,   false },
405  {"Remote NTP -> Regular",
406   "https://foo.com/instant?strk",    true,
407   "https://foo.com/other",           false,  false },
408  {"SRP -> SRP",
409   "https://foo.com/url?strk",        true,
410   "https://foo.com/url?strk",        true,   true  },
411  {"SRP -> Regular",
412   "https://foo.com/url?strk",        true,
413   "https://foo.com/other",           false,  false },
414  {"Regular -> SRP",
415   "https://foo.com/other",           false,
416   "https://foo.com/url?strk",        true,   false },
417};
418
419TEST_F(SearchTest, ProcessIsolation) {
420  EnableInstantExtendedAPIForTesting();
421
422  for (size_t i = 0; i < arraysize(kProcessIsolationTestCases); ++i) {
423    const ProcessIsolationTestCase& test = kProcessIsolationTestCases[i];
424    AddTab(browser(), GURL("chrome://blank"));
425    const content::WebContents* contents =
426        browser()->tab_strip_model()->GetActiveWebContents();
427
428    // Navigate to start URL.
429    NavigateAndCommitActiveTab(GURL(test.start_url));
430    EXPECT_EQ(test.start_in_instant_process, InInstantProcess(contents))
431        << test.description;
432
433    // Save state.
434    const scoped_refptr<content::SiteInstance> start_site_instance =
435        contents->GetSiteInstance();
436    const content::RenderProcessHost* start_rph =
437        contents->GetRenderProcessHost();
438    const content::RenderViewHost* start_rvh =
439        contents->GetRenderViewHost();
440
441    // Navigate to end URL.
442    NavigateAndCommitActiveTab(GURL(test.end_url));
443    EXPECT_EQ(test.end_in_instant_process, InInstantProcess(contents))
444        << test.description;
445
446    EXPECT_EQ(test.same_site_instance,
447              start_site_instance == contents->GetSiteInstance())
448        << test.description;
449    EXPECT_EQ(test.same_site_instance,
450              start_rvh == contents->GetRenderViewHost())
451        << test.description;
452    EXPECT_EQ(test.same_site_instance,
453              start_rph == contents->GetRenderProcessHost())
454        << test.description;
455  }
456}
457
458TEST_F(SearchTest, ProcessIsolation_RendererInitiated) {
459  EnableInstantExtendedAPIForTesting();
460
461  for (size_t i = 0; i < arraysize(kProcessIsolationTestCases); ++i) {
462    const ProcessIsolationTestCase& test = kProcessIsolationTestCases[i];
463    AddTab(browser(), GURL("chrome://blank"));
464    content::WebContents* contents =
465        browser()->tab_strip_model()->GetActiveWebContents();
466
467    // Navigate to start URL.
468    NavigateAndCommitActiveTab(GURL(test.start_url));
469    EXPECT_EQ(test.start_in_instant_process, InInstantProcess(contents))
470        << test.description;
471
472    // Save state.
473    const scoped_refptr<content::SiteInstance> start_site_instance =
474        contents->GetSiteInstance();
475    const content::RenderProcessHost* start_rph =
476        contents->GetRenderProcessHost();
477    const content::RenderViewHost* start_rvh =
478        contents->GetRenderViewHost();
479
480    // Navigate to end URL via a renderer-initiated navigation.
481    content::NavigationController* controller = &contents->GetController();
482    content::NavigationController::LoadURLParams load_params(
483        GURL(test.end_url));
484    load_params.is_renderer_initiated = true;
485    load_params.transition_type = content::PAGE_TRANSITION_LINK;
486
487    controller->LoadURLWithParams(load_params);
488    CommitPendingLoad(controller);
489    EXPECT_EQ(test.end_in_instant_process, InInstantProcess(contents))
490        << test.description;
491
492    EXPECT_EQ(test.same_site_instance,
493              start_site_instance == contents->GetSiteInstance())
494        << test.description;
495    EXPECT_EQ(test.same_site_instance,
496              start_rvh == contents->GetRenderViewHost())
497        << test.description;
498    EXPECT_EQ(test.same_site_instance,
499              start_rph == contents->GetRenderProcessHost())
500        << test.description;
501  }
502}
503
504const SearchTestCase kInstantNTPTestCases[] = {
505  {"https://foo.com/instant?strk",         true,  "Valid Instant URL"},
506  {"https://foo.com/instant#strk",         true,  "Valid Instant URL"},
507  {"https://foo.com/url?strk",             true,  "Valid search URL"},
508  {"https://foo.com/url#strk",             true,  "Valid search URL"},
509  {"https://foo.com/alt?strk",             true,  "Valid alternative URL"},
510  {"https://foo.com/alt#strk",             true,  "Valid alternative URL"},
511  {"https://foo.com/url?strk&bar=",        true,  "No query terms"},
512  {"https://foo.com/url?strk&q=abc",       true,  "No query terms key"},
513  {"https://foo.com/url?strk#bar=abc",     true,  "Query terms key in ref"},
514  {"https://foo.com/url?strk&bar=abc",     false, "Has query terms"},
515  {"http://foo.com/instant?strk=1",        false, "Insecure URL"},
516  {"https://foo.com/instant",              false, "No search term replacement"},
517  {"chrome://blank/",                      false, "Chrome scheme"},
518  {"chrome-search://foo",                  false, "Chrome-search scheme"},
519  {chrome::kChromeSearchLocalNtpUrl,       true,  "Local new tab page"},
520  {"https://bar.com/instant?strk=1",       false, "Random non-search page"},
521};
522
523TEST_F(SearchTest, InstantNTPExtendedEnabled) {
524  EnableInstantExtendedAPIForTesting();
525  AddTab(browser(), GURL("chrome://blank"));
526  for (size_t i = 0; i < arraysize(kInstantNTPTestCases); ++i) {
527    const SearchTestCase& test = kInstantNTPTestCases[i];
528    NavigateAndCommitActiveTab(GURL(test.url));
529    const content::WebContents* contents =
530        browser()->tab_strip_model()->GetWebContentsAt(0);
531    EXPECT_EQ(test.expected_result, IsInstantNTP(contents))
532        << test.url << " " << test.comment;
533  }
534}
535
536TEST_F(SearchTest, InstantNTPExtendedDisabled) {
537  AddTab(browser(), GURL("chrome://blank"));
538  for (size_t i = 0; i < arraysize(kInstantNTPTestCases); ++i) {
539    const SearchTestCase& test = kInstantNTPTestCases[i];
540    NavigateAndCommitActiveTab(GURL(test.url));
541    const content::WebContents* contents =
542        browser()->tab_strip_model()->GetWebContentsAt(0);
543    EXPECT_FALSE(IsInstantNTP(contents)) << test.url << " " << test.comment;
544  }
545}
546
547TEST_F(SearchTest, InstantNTPCustomNavigationEntry) {
548  EnableInstantExtendedAPIForTesting();
549  AddTab(browser(), GURL("chrome://blank"));
550  for (size_t i = 0; i < arraysize(kInstantNTPTestCases); ++i) {
551    const SearchTestCase& test = kInstantNTPTestCases[i];
552    NavigateAndCommitActiveTab(GURL(test.url));
553    content::WebContents* contents =
554        browser()->tab_strip_model()->GetWebContentsAt(0);
555    content::NavigationController& controller = contents->GetController();
556    controller.SetTransientEntry(
557        controller.CreateNavigationEntry(GURL("chrome://blank"),
558                                         content::Referrer(),
559                                         content::PAGE_TRANSITION_LINK,
560                                         false,
561                                         std::string(),
562                                         contents->GetBrowserContext()));
563    // The active entry is chrome://blank and not an NTP.
564    EXPECT_FALSE(IsInstantNTP(contents));
565    EXPECT_EQ(test.expected_result,
566              NavEntryIsInstantNTP(contents,
567                                   controller.GetLastCommittedEntry()))
568        << test.url << " " << test.comment;
569  }
570}
571
572TEST_F(SearchTest, GetInstantURLExtendedEnabled) {
573  // Instant is disabled, so no Instant URL.
574  EXPECT_EQ(GURL(), GetInstantURL(profile(), kDisableStartMargin));
575
576  // Enable Instant. Still no Instant URL because "strk" is missing.
577  EnableInstantExtendedAPIForTesting();
578  SetDefaultInstantTemplateUrl(false);
579  EXPECT_EQ(GURL(), GetInstantURL(profile(), kDisableStartMargin));
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));
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));
592
593  // Disable suggest. No Instant URL.
594  profile()->GetPrefs()->SetBoolean(prefs::kSearchSuggestEnabled, false);
595  EXPECT_EQ(GURL(), GetInstantURL(profile(), kDisableStartMargin));
596}
597
598TEST_F(SearchTest, StartMarginCGI) {
599  // Instant is disabled, so no Instant URL.
600  EXPECT_EQ(GURL(), GetInstantURL(profile(), kDisableStartMargin));
601
602  // Enable Instant. No margin.
603  EnableInstantExtendedAPIForTesting();
604  profile()->GetPrefs()->SetBoolean(prefs::kSearchSuggestEnabled, true);
605
606  EXPECT_EQ(GURL("https://foo.com/instant?foo=foo#foo=foo&strk"),
607            GetInstantURL(profile(), kDisableStartMargin));
608
609  // With start margin.
610  EXPECT_EQ(GURL("https://foo.com/instant?es_sm=10&foo=foo#foo=foo&strk"),
611            GetInstantURL(profile(), 10));
612}
613
614TEST_F(SearchTest, CommandLineOverrides) {
615  EnableInstantExtendedAPIForTesting();
616
617  GURL local_instant_url(GetLocalInstantURL(profile()));
618  EXPECT_EQ(GURL(chrome::kChromeSearchLocalNtpUrl), local_instant_url);
619
620  TemplateURLService* template_url_service =
621      TemplateURLServiceFactory::GetForProfile(profile());
622  TemplateURLData data;
623  data.SetURL("{google:baseURL}search?q={searchTerms}");
624  data.instant_url = "{google:baseURL}webhp?strk";
625  data.search_terms_replacement_key = "strk";
626  TemplateURL* template_url = new TemplateURL(profile(), data);
627  // Takes ownership of |template_url|.
628  template_url_service->Add(template_url);
629  template_url_service->SetDefaultSearchProvider(template_url);
630
631  // By default, Instant Extended forces the instant URL to be HTTPS, so even if
632  // we set a Google base URL that is HTTP, we should get an HTTPS URL.
633  UIThreadSearchTermsData::SetGoogleBaseURL("http://www.foo.com/");
634  GURL instant_url(GetInstantURL(profile(), kDisableStartMargin));
635  ASSERT_TRUE(instant_url.is_valid());
636  EXPECT_EQ("https://www.foo.com/webhp?strk", instant_url.spec());
637
638  // However, if the Google base URL is specified on the command line, the
639  // instant URL should just use it, even if it's HTTP.
640  UIThreadSearchTermsData::SetGoogleBaseURL(std::string());
641  CommandLine::ForCurrentProcess()->AppendSwitchASCII(switches::kGoogleBaseURL,
642                                                      "http://www.bar.com/");
643  instant_url = GetInstantURL(profile(), kDisableStartMargin);
644  ASSERT_TRUE(instant_url.is_valid());
645  EXPECT_EQ("http://www.bar.com/webhp?strk", instant_url.spec());
646
647  // Similarly, setting a Google base URL on the command line should allow you
648  // to get the Google version of the local NTP, even though search provider's
649  // URL doesn't contain "google".
650  local_instant_url = GetLocalInstantURL(profile());
651  EXPECT_EQ(GURL(chrome::kChromeSearchLocalNtpUrl), local_instant_url);
652
653  // If we specify extra search query params, they should be inserted into the
654  // query portion of the instant URL.
655  CommandLine::ForCurrentProcess()->AppendSwitchASCII(
656      switches::kExtraSearchQueryParams, "a=b");
657  instant_url = GetInstantURL(profile(), kDisableStartMargin);
658  ASSERT_TRUE(instant_url.is_valid());
659  EXPECT_EQ("http://www.bar.com/webhp?a=b&strk", instant_url.spec());
660}
661
662TEST_F(SearchTest, ShouldShowInstantNTP_Default) {
663  EnableInstantExtendedAPIForTesting();
664  EXPECT_TRUE(ShouldShowInstantNTP());
665}
666
667TEST_F(SearchTest, ShouldShowInstantNTP_DisabledViaFinch) {
668  EnableInstantExtendedAPIForTesting();
669  ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial("InstantExtended",
670      "Group1 show_ntp:0"));
671  EXPECT_FALSE(ShouldShowInstantNTP());
672}
673
674TEST_F(SearchTest, ShouldShowInstantNTP_DisabledByUseCacheableNTPFinchFlag) {
675  EnableInstantExtendedAPIForTesting();
676  ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial("InstantExtended",
677      "Group1 use_cacheable_ntp:1"));
678  EXPECT_FALSE(ShouldShowInstantNTP());
679}
680
681TEST_F(SearchTest, ShouldUseCacheableNTP_Default) {
682  EnableInstantExtendedAPIForTesting();
683  EXPECT_FALSE(ShouldUseCacheableNTP());
684}
685
686TEST_F(SearchTest, ShouldUseCacheableNTP_EnabledViaFinch) {
687  EnableInstantExtendedAPIForTesting();
688  ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial("InstantExtended",
689      "Group1 use_cacheable_ntp:1"));
690  EXPECT_TRUE(ShouldUseCacheableNTP());
691}
692
693TEST_F(SearchTest, IsNTPURL) {
694  GURL invalid_url;
695  GURL ntp_url(chrome::kChromeUINewTabURL);
696  GURL local_ntp_url(GetLocalInstantURL(profile()));
697
698  EXPECT_FALSE(chrome::IsNTPURL(invalid_url, profile()));
699  EXPECT_FALSE(chrome::IsNTPURL(local_ntp_url, profile()));
700
701  EXPECT_TRUE(chrome::IsNTPURL(ntp_url, NULL));
702  EXPECT_FALSE(chrome::IsNTPURL(local_ntp_url, NULL));
703
704  // Enable Instant. No margin.
705  EnableInstantExtendedAPIForTesting();
706  profile()->GetPrefs()->SetBoolean(prefs::kSearchSuggestEnabled, true);
707  GURL remote_ntp_url(GetInstantURL(profile(), kDisableStartMargin));
708  GURL search_url_with_search_terms("https://foo.com/url?strk&bar=abc");
709  GURL search_url_without_search_terms("https://foo.com/url?strk&bar");
710
711  EXPECT_FALSE(chrome::IsNTPURL(ntp_url, profile()));
712  EXPECT_TRUE(chrome::IsNTPURL(local_ntp_url, profile()));
713  EXPECT_TRUE(chrome::IsNTPURL(remote_ntp_url, profile()));
714  EXPECT_FALSE(chrome::IsNTPURL(search_url_with_search_terms, profile()));
715  EXPECT_TRUE(chrome::IsNTPURL(search_url_without_search_terms, profile()));
716
717  EXPECT_FALSE(chrome::IsNTPURL(ntp_url, NULL));
718  EXPECT_FALSE(chrome::IsNTPURL(local_ntp_url, NULL));
719  EXPECT_FALSE(chrome::IsNTPURL(remote_ntp_url, NULL));
720  EXPECT_FALSE(chrome::IsNTPURL(search_url_with_search_terms, NULL));
721  EXPECT_FALSE(chrome::IsNTPURL(search_url_without_search_terms, NULL));
722}
723
724}  // namespace chrome
725