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