1 // Copyright 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.
5 #include "chrome/browser/ui/search/search_tab_helper.h"
7 #include "base/command_line.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/metrics/field_trial.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "chrome/browser/prerender/prerender_manager.h"
12 #include "chrome/browser/prerender/prerender_manager_factory.h"
13 #include "chrome/browser/search/instant_unittest_base.h"
14 #include "chrome/browser/search/search.h"
15 #include "chrome/browser/search_engines/template_url_service_factory.h"
16 #include "chrome/browser/signin/fake_signin_manager.h"
17 #include "chrome/browser/signin/signin_manager_factory.h"
18 #include "chrome/browser/sync/profile_sync_service.h"
19 #include "chrome/browser/sync/profile_sync_service_factory.h"
20 #include "chrome/browser/sync/profile_sync_service_mock.h"
21 #include "chrome/browser/ui/search/search_ipc_router.h"
22 #include "chrome/browser/ui/tabs/tab_strip_model.h"
23 #include "chrome/common/chrome_switches.h"
24 #include "chrome/common/ntp_logging_events.h"
25 #include "chrome/common/omnibox_focus_state.h"
26 #include "chrome/common/render_messages.h"
27 #include "chrome/common/url_constants.h"
28 #include "chrome/grit/generated_resources.h"
29 #include "chrome/test/base/browser_with_test_window_test.h"
30 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
31 #include "chrome/test/base/testing_profile.h"
32 #include "chrome/test/base/ui_test_utils.h"
33 #include "components/search_engines/template_url_service.h"
34 #include "content/public/browser/navigation_controller.h"
35 #include "content/public/browser/navigation_entry.h"
36 #include "content/public/browser/web_contents.h"
37 #include "content/public/test/mock_render_process_host.h"
38 #include "ipc/ipc_message.h"
39 #include "ipc/ipc_test_sink.h"
40 #include "net/base/net_errors.h"
41 #include "testing/gmock/include/gmock/gmock.h"
42 #include "testing/gtest/include/gtest/gtest.h"
43 #include "ui/base/l10n/l10n_util.h"
48 using testing::Return
;
52 class MockSearchIPCRouterDelegate
: public SearchIPCRouter::Delegate
{
54 virtual ~MockSearchIPCRouterDelegate() {}
56 MOCK_METHOD1(OnInstantSupportDetermined
, void(bool supports_instant
));
57 MOCK_METHOD1(OnSetVoiceSearchSupport
, void(bool supports_voice_search
));
58 MOCK_METHOD1(FocusOmnibox
, void(OmniboxFocusState state
));
59 MOCK_METHOD3(NavigateToURL
, void(const GURL
&, WindowOpenDisposition
, bool));
60 MOCK_METHOD1(OnDeleteMostVisitedItem
, void(const GURL
& url
));
61 MOCK_METHOD1(OnUndoMostVisitedDeletion
, void(const GURL
& url
));
62 MOCK_METHOD0(OnUndoAllMostVisitedDeletions
, void());
63 MOCK_METHOD1(OnLogEvent
, void(NTPLoggingEventType event
));
64 MOCK_METHOD2(OnLogMostVisitedImpression
,
65 void(int position
, const base::string16
& provider
));
66 MOCK_METHOD2(OnLogMostVisitedNavigation
,
67 void(int position
, const base::string16
& provider
));
68 MOCK_METHOD1(PasteIntoOmnibox
, void(const base::string16
&));
69 MOCK_METHOD1(OnChromeIdentityCheck
, void(const base::string16
& identity
));
74 class SearchTabHelperTest
: public ChromeRenderViewHostTestHarness
{
76 virtual void SetUp() {
77 ChromeRenderViewHostTestHarness::SetUp();
78 SearchTabHelper::CreateForWebContents(web_contents());
81 virtual content::BrowserContext
* CreateBrowserContext() override
{
82 TestingProfile::Builder builder
;
83 builder
.AddTestingFactory(SigninManagerFactory::GetInstance(),
84 FakeSigninManagerBase::Build
);
85 builder
.AddTestingFactory(
86 ProfileSyncServiceFactory::GetInstance(),
87 ProfileSyncServiceMock::BuildMockProfileSyncService
);
88 return builder
.Build().release();
91 // Creates a sign-in manager for tests. If |username| is not empty, the
92 // testing profile of the WebContents will be connected to the given account.
93 // The account can be configured to |sync_history| or not.
94 void CreateSigninManager(const std::string
& username
, bool sync_history
) {
95 SigninManagerBase
* signin_manager
= static_cast<SigninManagerBase
*>(
96 SigninManagerFactory::GetForProfile(profile()));
98 if (!username
.empty()) {
99 ASSERT_TRUE(signin_manager
);
100 signin_manager
->SetAuthenticatedUsername(username
);
103 ProfileSyncServiceMock
* sync_service
= static_cast<ProfileSyncServiceMock
*>(
104 ProfileSyncServiceFactory::GetInstance()->GetForProfile(profile()));
106 EXPECT_CALL(*sync_service
, SyncActive()).WillRepeatedly(Return(true));
107 syncer::ModelTypeSet result
;
109 result
.Put(syncer::HISTORY_DELETE_DIRECTIVES
);
111 EXPECT_CALL(*sync_service
, GetActiveDataTypes())
112 .WillRepeatedly(Return(result
));
115 bool MessageWasSent(uint32 id
) {
116 return process()->sink().GetFirstMessageMatching(id
) != NULL
;
119 MockSearchIPCRouterDelegate
* mock_delegate() { return &delegate_
; }
122 MockSearchIPCRouterDelegate delegate_
;
125 TEST_F(SearchTabHelperTest
, DetermineIfPageSupportsInstant_Local
) {
126 NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl
));
127 EXPECT_CALL(*mock_delegate(), OnInstantSupportDetermined(true)).Times(0);
129 SearchTabHelper
* search_tab_helper
=
130 SearchTabHelper::FromWebContents(web_contents());
131 ASSERT_NE(static_cast<SearchTabHelper
*>(NULL
), search_tab_helper
);
132 search_tab_helper
->ipc_router().set_delegate_for_testing(mock_delegate());
133 search_tab_helper
->DetermineIfPageSupportsInstant();
136 TEST_F(SearchTabHelperTest
, DetermineIfPageSupportsInstant_NonLocal
) {
137 NavigateAndCommit(GURL("chrome-search://foo/bar"));
138 process()->sink().ClearMessages();
139 EXPECT_CALL(*mock_delegate(), OnInstantSupportDetermined(true)).Times(1);
141 SearchTabHelper
* search_tab_helper
=
142 SearchTabHelper::FromWebContents(web_contents());
143 ASSERT_NE(static_cast<SearchTabHelper
*>(NULL
), search_tab_helper
);
144 search_tab_helper
->ipc_router().set_delegate_for_testing(mock_delegate());
145 search_tab_helper
->DetermineIfPageSupportsInstant();
146 ASSERT_TRUE(MessageWasSent(ChromeViewMsg_DetermineIfPageSupportsInstant::ID
));
148 scoped_ptr
<IPC::Message
> response(
149 new ChromeViewHostMsg_InstantSupportDetermined(
150 web_contents()->GetRoutingID(),
151 search_tab_helper
->ipc_router().page_seq_no_for_testing(),
153 search_tab_helper
->ipc_router().OnMessageReceived(*response
);
156 TEST_F(SearchTabHelperTest
, PageURLDoesntBelongToInstantRenderer
) {
157 // Navigate to a page URL that doesn't belong to Instant renderer.
158 // SearchTabHelper::DeterminerIfPageSupportsInstant() should return
159 // immediately without dispatching any message to the renderer.
160 NavigateAndCommit(GURL("http://www.example.com"));
161 process()->sink().ClearMessages();
162 EXPECT_CALL(*mock_delegate(), OnInstantSupportDetermined(false)).Times(0);
164 SearchTabHelper
* search_tab_helper
=
165 SearchTabHelper::FromWebContents(web_contents());
166 ASSERT_NE(static_cast<SearchTabHelper
*>(NULL
), search_tab_helper
);
167 search_tab_helper
->ipc_router().set_delegate_for_testing(mock_delegate());
168 search_tab_helper
->DetermineIfPageSupportsInstant();
169 ASSERT_FALSE(MessageWasSent(
170 ChromeViewMsg_DetermineIfPageSupportsInstant::ID
));
173 TEST_F(SearchTabHelperTest
, OnChromeIdentityCheckMatch
) {
174 NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl
));
175 CreateSigninManager(std::string("foo@bar.com"), true);
176 SearchTabHelper
* search_tab_helper
=
177 SearchTabHelper::FromWebContents(web_contents());
178 ASSERT_NE(static_cast<SearchTabHelper
*>(NULL
), search_tab_helper
);
180 const base::string16 test_identity
= base::ASCIIToUTF16("foo@bar.com");
181 search_tab_helper
->OnChromeIdentityCheck(test_identity
);
183 const IPC::Message
* message
= process()->sink().GetUniqueMessageMatching(
184 ChromeViewMsg_ChromeIdentityCheckResult::ID
);
185 ASSERT_TRUE(message
!= NULL
);
187 ChromeViewMsg_ChromeIdentityCheckResult::Param params
;
188 ChromeViewMsg_ChromeIdentityCheckResult::Read(message
, ¶ms
);
189 EXPECT_EQ(test_identity
, params
.a
);
190 ASSERT_TRUE(params
.b
);
193 TEST_F(SearchTabHelperTest
, OnChromeIdentityCheckMismatch
) {
194 NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl
));
195 CreateSigninManager(std::string("foo@bar.com"), true);
196 SearchTabHelper
* search_tab_helper
=
197 SearchTabHelper::FromWebContents(web_contents());
198 ASSERT_NE(static_cast<SearchTabHelper
*>(NULL
), search_tab_helper
);
200 const base::string16 test_identity
= base::ASCIIToUTF16("bar@foo.com");
201 search_tab_helper
->OnChromeIdentityCheck(test_identity
);
203 const IPC::Message
* message
= process()->sink().GetUniqueMessageMatching(
204 ChromeViewMsg_ChromeIdentityCheckResult::ID
);
205 ASSERT_TRUE(message
!= NULL
);
207 ChromeViewMsg_ChromeIdentityCheckResult::Param params
;
208 ChromeViewMsg_ChromeIdentityCheckResult::Read(message
, ¶ms
);
209 EXPECT_EQ(test_identity
, params
.a
);
210 ASSERT_FALSE(params
.b
);
213 TEST_F(SearchTabHelperTest
, OnChromeIdentityCheckSignedOutMatch
) {
214 NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl
));
215 // This test does not sign in.
216 ProfileSyncServiceMock
* sync_service
= static_cast<ProfileSyncServiceMock
*>(
217 ProfileSyncServiceFactory::GetInstance()->GetForProfile(profile()));
218 EXPECT_CALL(*sync_service
, SyncActive()).WillRepeatedly(Return(false));
219 SearchTabHelper
* search_tab_helper
=
220 SearchTabHelper::FromWebContents(web_contents());
221 ASSERT_NE(static_cast<SearchTabHelper
*>(NULL
), search_tab_helper
);
223 const base::string16 test_identity
;
224 search_tab_helper
->OnChromeIdentityCheck(test_identity
);
226 const IPC::Message
* message
= process()->sink().GetUniqueMessageMatching(
227 ChromeViewMsg_ChromeIdentityCheckResult::ID
);
228 ASSERT_TRUE(message
!= NULL
);
230 ChromeViewMsg_ChromeIdentityCheckResult::Param params
;
231 ChromeViewMsg_ChromeIdentityCheckResult::Read(message
, ¶ms
);
232 EXPECT_EQ(test_identity
, params
.a
);
233 ASSERT_FALSE(params
.b
);
236 TEST_F(SearchTabHelperTest
, OnChromeIdentityCheckSignedOutMismatch
) {
237 NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl
));
238 // This test does not sign in.
239 ProfileSyncServiceMock
* sync_service
= static_cast<ProfileSyncServiceMock
*>(
240 ProfileSyncServiceFactory::GetInstance()->GetForProfile(profile()));
241 EXPECT_CALL(*sync_service
, SyncActive()).WillRepeatedly(Return(false));
242 SearchTabHelper
* search_tab_helper
=
243 SearchTabHelper::FromWebContents(web_contents());
244 ASSERT_NE(static_cast<SearchTabHelper
*>(NULL
), search_tab_helper
);
246 const base::string16 test_identity
= base::ASCIIToUTF16("bar@foo.com");
247 search_tab_helper
->OnChromeIdentityCheck(test_identity
);
249 const IPC::Message
* message
= process()->sink().GetUniqueMessageMatching(
250 ChromeViewMsg_ChromeIdentityCheckResult::ID
);
251 ASSERT_TRUE(message
!= NULL
);
253 ChromeViewMsg_ChromeIdentityCheckResult::Param params
;
254 ChromeViewMsg_ChromeIdentityCheckResult::Read(message
, ¶ms
);
255 EXPECT_EQ(test_identity
, params
.a
);
256 ASSERT_FALSE(params
.b
);
259 TEST_F(SearchTabHelperTest
, OnChromeIdentityCheckMatchNotSyncing
) {
260 NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl
));
261 CreateSigninManager(std::string("foo@bar.com"), false);
262 SearchTabHelper
* search_tab_helper
=
263 SearchTabHelper::FromWebContents(web_contents());
264 ASSERT_NE(static_cast<SearchTabHelper
*>(NULL
), search_tab_helper
);
266 const base::string16 test_identity
= base::ASCIIToUTF16("foo@bar.com");
267 search_tab_helper
->OnChromeIdentityCheck(test_identity
);
269 const IPC::Message
* message
= process()->sink().GetUniqueMessageMatching(
270 ChromeViewMsg_ChromeIdentityCheckResult::ID
);
271 ASSERT_TRUE(message
!= NULL
);
273 ChromeViewMsg_ChromeIdentityCheckResult::Param params
;
274 ChromeViewMsg_ChromeIdentityCheckResult::Read(message
, ¶ms
);
275 EXPECT_EQ(test_identity
, params
.a
);
276 ASSERT_FALSE(params
.b
);
279 class TabTitleObserver
: public content::WebContentsObserver
{
281 explicit TabTitleObserver(content::WebContents
* contents
)
282 : WebContentsObserver(contents
) {}
284 base::string16
title_on_start() { return title_on_start_
; }
285 base::string16
title_on_commit() { return title_on_commit_
; }
288 virtual void DidStartProvisionalLoadForFrame(
289 content::RenderFrameHost
* /* render_frame_host */,
290 const GURL
& /* validated_url */,
291 bool /* is_error_page */,
292 bool /* is_iframe_srcdoc */) override
{
293 title_on_start_
= web_contents()->GetTitle();
296 virtual void DidNavigateMainFrame(
297 const content::LoadCommittedDetails
& /* details */,
298 const content::FrameNavigateParams
& /* params */) override
{
299 title_on_commit_
= web_contents()->GetTitle();
302 base::string16 title_on_start_
;
303 base::string16 title_on_commit_
;
306 TEST_F(SearchTabHelperTest
, TitleIsSetForNTP
) {
307 TabTitleObserver
title_observer(web_contents());
308 NavigateAndCommit(GURL(chrome::kChromeUINewTabURL
));
309 const base::string16 title
= l10n_util::GetStringUTF16(IDS_NEW_TAB_TITLE
);
310 EXPECT_EQ(title
, title_observer
.title_on_start());
311 EXPECT_EQ(title
, title_observer
.title_on_commit());
312 EXPECT_EQ(title
, web_contents()->GetTitle());
315 class SearchTabHelperWindowTest
: public BrowserWithTestWindowTest
{
317 virtual void SetUp() override
{
318 BrowserWithTestWindowTest::SetUp();
319 TemplateURLServiceFactory::GetInstance()->SetTestingFactoryAndUse(
320 profile(), &TemplateURLServiceFactory::BuildInstanceFor
);
321 TemplateURLService
* template_url_service
=
322 TemplateURLServiceFactory::GetForProfile(profile());
323 ui_test_utils::WaitForTemplateURLServiceToLoad(template_url_service
);
325 TemplateURLData data
;
326 data
.SetURL("http://foo.com/url?bar={searchTerms}");
327 data
.instant_url
= "http://foo.com/instant?"
328 "{google:omniboxStartMarginParameter}{google:forceInstantResults}"
329 "foo=foo#foo=foo&strk";
330 data
.new_tab_url
= std::string("https://foo.com/newtab?strk");
331 data
.alternate_urls
.push_back("http://foo.com/alt#quux={searchTerms}");
332 data
.search_terms_replacement_key
= "strk";
334 TemplateURL
* template_url
= new TemplateURL(data
);
335 template_url_service
->Add(template_url
);
336 template_url_service
->SetUserSelectedDefaultSearchProvider(template_url
);
340 TEST_F(SearchTabHelperWindowTest
, OnProvisionalLoadFailRedirectNTPToLocal
) {
341 AddTab(browser(), GURL(chrome::kChromeUINewTabURL
));
342 content::WebContents
* contents
=
343 browser()->tab_strip_model()->GetWebContentsAt(0);
344 content::NavigationController
* controller
= &contents
->GetController();
346 SearchTabHelper
* search_tab_helper
=
347 SearchTabHelper::FromWebContents(contents
);
348 ASSERT_NE(static_cast<SearchTabHelper
*>(NULL
), search_tab_helper
);
350 // A failed provisional load of a cacheable NTP should be redirected to local
352 const GURL cacheableNTPURL
= chrome::GetNewTabPageURL(profile());
353 search_tab_helper
->DidFailProvisionalLoad(
354 contents
->GetMainFrame(), cacheableNTPURL
, 1, base::string16());
355 CommitPendingLoad(controller
);
356 EXPECT_EQ(GURL(chrome::kChromeSearchLocalNtpUrl
),
357 controller
->GetLastCommittedEntry()->GetURL());
360 TEST_F(SearchTabHelperWindowTest
, OnProvisionalLoadFailDontRedirectIfAborted
) {
361 AddTab(browser(), GURL("chrome://blank"));
362 content::WebContents
* contents
=
363 browser()->tab_strip_model()->GetWebContentsAt(0);
364 content::NavigationController
* controller
= &contents
->GetController();
366 SearchTabHelper
* search_tab_helper
=
367 SearchTabHelper::FromWebContents(contents
);
368 ASSERT_NE(static_cast<SearchTabHelper
*>(NULL
), search_tab_helper
);
370 // A failed provisional load of a cacheable NTP should be redirected to local
372 const GURL cacheableNTPURL
= chrome::GetNewTabPageURL(profile());
373 search_tab_helper
->DidFailProvisionalLoad(contents
->GetMainFrame(),
377 CommitPendingLoad(controller
);
378 EXPECT_EQ(GURL("chrome://blank"),
379 controller
->GetLastCommittedEntry()->GetURL());
382 TEST_F(SearchTabHelperWindowTest
, OnProvisionalLoadFailDontRedirectNonNTP
) {
383 AddTab(browser(), GURL(chrome::kChromeUINewTabURL
));
384 content::WebContents
* contents
=
385 browser()->tab_strip_model()->GetWebContentsAt(0);
386 content::NavigationController
* controller
= &contents
->GetController();
388 SearchTabHelper
* search_tab_helper
=
389 SearchTabHelper::FromWebContents(contents
);
390 ASSERT_NE(static_cast<SearchTabHelper
*>(NULL
), search_tab_helper
);
392 // Any other web page shouldn't be redirected when provisional load fails.
393 search_tab_helper
->DidFailProvisionalLoad(contents
->GetMainFrame(),
394 GURL("http://www.example.com"),
397 CommitPendingLoad(controller
);
398 EXPECT_NE(GURL(chrome::kChromeSearchLocalNtpUrl
),
399 controller
->GetLastCommittedEntry()->GetURL());
402 class SearchTabHelperPrerenderTest
: public InstantUnitTestBase
{
404 virtual ~SearchTabHelperPrerenderTest() {}
407 virtual void SetUp() override
{
408 ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
410 "Group1 espv:89 prefetch_results:1 "
411 "prerender_instant_url_on_omnibox_focus:1"));
412 InstantUnitTestBase::SetUp();
414 AddTab(browser(), GURL(chrome::kChromeUINewTabURL
));
415 prerender::PrerenderManagerFactory::GetForProfile(browser()->profile())->
416 OnCookieStoreLoaded();
417 SearchTabHelper::FromWebContents(web_contents())->set_omnibox_has_focus_fn(
419 SearchTabHelperPrerenderTest::omnibox_has_focus_
= true;
422 content::WebContents
* web_contents() {
423 return browser()->tab_strip_model()->GetActiveWebContents();
426 bool IsInstantURLMarkedForPrerendering() {
427 GURL
instant_url(chrome::GetSearchResultPrefetchBaseURL(profile()));
428 prerender::PrerenderManager
* prerender_manager
=
429 prerender::PrerenderManagerFactory::GetForProfile(profile());
430 return prerender_manager
->HasPrerenderedUrl(instant_url
, web_contents());
433 static bool omnibox_has_focus(OmniboxView
* omnibox
) {
434 return omnibox_has_focus_
;
437 static bool omnibox_has_focus_
;
440 bool SearchTabHelperPrerenderTest::omnibox_has_focus_
= true;
442 TEST_F(SearchTabHelperPrerenderTest
, OnOmniboxFocusPrerenderInstantURL
) {
443 SearchTabHelper
* search_tab_helper
=
444 SearchTabHelper::FromWebContents(web_contents());
445 search_tab_helper
->OmniboxFocusChanged(OMNIBOX_FOCUS_VISIBLE
,
446 OMNIBOX_FOCUS_CHANGE_EXPLICIT
);
447 ASSERT_TRUE(IsInstantURLMarkedForPrerendering());
448 search_tab_helper
->OmniboxFocusChanged(OMNIBOX_FOCUS_NONE
,
449 OMNIBOX_FOCUS_CHANGE_EXPLICIT
);
450 ASSERT_FALSE(IsInstantURLMarkedForPrerendering());
453 TEST_F(SearchTabHelperPrerenderTest
, OnTabActivatedPrerenderInstantURL
) {
454 SearchTabHelper
* search_tab_helper
=
455 SearchTabHelper::FromWebContents(web_contents());
456 search_tab_helper
->OnTabActivated();
457 ASSERT_TRUE(IsInstantURLMarkedForPrerendering());
460 TEST_F(SearchTabHelperPrerenderTest
,
461 OnTabActivatedNoPrerenderIfOmniboxBlurred
) {
462 SearchTabHelperPrerenderTest::omnibox_has_focus_
= false;
463 SearchTabHelper
* search_tab_helper
=
464 SearchTabHelper::FromWebContents(web_contents());
465 search_tab_helper
->OnTabActivated();
466 ASSERT_FALSE(IsInstantURLMarkedForPrerendering());