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