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 "base/time/time.h"
12 #include "chrome/browser/prerender/prerender_manager.h"
13 #include "chrome/browser/prerender/prerender_manager_factory.h"
14 #include "chrome/browser/search/instant_unittest_base.h"
15 #include "chrome/browser/search/search.h"
16 #include "chrome/browser/search_engines/template_url_service_factory.h"
17 #include "chrome/browser/signin/fake_signin_manager_builder.h"
18 #include "chrome/browser/signin/signin_manager_factory.h"
19 #include "chrome/browser/sync/profile_sync_service.h"
20 #include "chrome/browser/sync/profile_sync_service_factory.h"
21 #include "chrome/browser/sync/profile_sync_service_mock.h"
22 #include "chrome/browser/ui/search/search_ipc_router.h"
23 #include "chrome/browser/ui/tabs/tab_strip_model.h"
24 #include "chrome/common/chrome_switches.h"
25 #include "chrome/common/ntp_logging_events.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/omnibox/common/omnibox_focus_state.h"
34 #include "components/search_engines/template_url_service.h"
35 #include "content/public/browser/navigation_controller.h"
36 #include "content/public/browser/navigation_entry.h"
37 #include "content/public/browser/web_contents.h"
38 #include "content/public/test/mock_render_process_host.h"
39 #include "ipc/ipc_message.h"
40 #include "ipc/ipc_test_sink.h"
41 #include "net/base/net_errors.h"
42 #include "testing/gmock/include/gmock/gmock.h"
43 #include "testing/gtest/include/gtest/gtest.h"
44 #include "ui/base/l10n/l10n_util.h"
49 using testing::Return
;
53 class MockSearchIPCRouterDelegate
: public SearchIPCRouter::Delegate
{
55 virtual ~MockSearchIPCRouterDelegate() {}
57 MOCK_METHOD1(OnInstantSupportDetermined
, void(bool supports_instant
));
58 MOCK_METHOD1(OnSetVoiceSearchSupport
, void(bool supports_voice_search
));
59 MOCK_METHOD1(FocusOmnibox
, void(OmniboxFocusState state
));
60 MOCK_METHOD3(NavigateToURL
, void(const GURL
&, WindowOpenDisposition
, bool));
61 MOCK_METHOD1(OnDeleteMostVisitedItem
, void(const GURL
& url
));
62 MOCK_METHOD1(OnUndoMostVisitedDeletion
, void(const GURL
& url
));
63 MOCK_METHOD0(OnUndoAllMostVisitedDeletions
, void());
64 MOCK_METHOD2(OnLogEvent
, void(NTPLoggingEventType event
,
65 base::TimeDelta time
));
66 MOCK_METHOD2(OnLogMostVisitedImpression
,
67 void(int position
, const base::string16
& provider
));
68 MOCK_METHOD2(OnLogMostVisitedNavigation
,
69 void(int position
, const base::string16
& provider
));
70 MOCK_METHOD1(PasteIntoOmnibox
, void(const base::string16
&));
71 MOCK_METHOD1(OnChromeIdentityCheck
, void(const base::string16
& identity
));
72 MOCK_METHOD0(OnHistorySyncCheck
, void());
77 class SearchTabHelperTest
: public ChromeRenderViewHostTestHarness
{
79 void SetUp() override
{
80 ChromeRenderViewHostTestHarness::SetUp();
81 SearchTabHelper::CreateForWebContents(web_contents());
84 content::BrowserContext
* CreateBrowserContext() override
{
85 TestingProfile::Builder builder
;
86 builder
.AddTestingFactory(SigninManagerFactory::GetInstance(),
87 BuildFakeSigninManagerBase
);
88 builder
.AddTestingFactory(
89 ProfileSyncServiceFactory::GetInstance(),
90 ProfileSyncServiceMock::BuildMockProfileSyncService
);
91 return builder
.Build().release();
94 // Creates a sign-in manager for tests. If |username| is not empty, the
95 // testing profile of the WebContents will be connected to the given account.
96 void CreateSigninManager(const std::string
& username
) {
97 SigninManagerBase
* signin_manager
= static_cast<SigninManagerBase
*>(
98 SigninManagerFactory::GetForProfile(profile()));
100 if (!username
.empty()) {
101 ASSERT_TRUE(signin_manager
);
102 signin_manager
->SetAuthenticatedAccountInfo(username
, username
);
106 // Configure the account to |sync_history| or not.
107 void SetHistorySync(bool sync_history
) {
108 ProfileSyncServiceMock
* sync_service
= static_cast<ProfileSyncServiceMock
*>(
109 ProfileSyncServiceFactory::GetInstance()->GetForProfile(profile()));
111 syncer::ModelTypeSet result
;
113 result
.Put(syncer::HISTORY_DELETE_DIRECTIVES
);
115 EXPECT_CALL(*sync_service
, GetPreferredDataTypes())
116 .WillRepeatedly(Return(result
));
119 bool MessageWasSent(uint32 id
) {
120 return process()->sink().GetFirstMessageMatching(id
) != NULL
;
123 MockSearchIPCRouterDelegate
* mock_delegate() { return &delegate_
; }
126 MockSearchIPCRouterDelegate delegate_
;
129 TEST_F(SearchTabHelperTest
, DetermineIfPageSupportsInstant_Local
) {
130 NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl
));
131 EXPECT_CALL(*mock_delegate(), OnInstantSupportDetermined(true)).Times(0);
133 SearchTabHelper
* search_tab_helper
=
134 SearchTabHelper::FromWebContents(web_contents());
135 ASSERT_NE(static_cast<SearchTabHelper
*>(NULL
), search_tab_helper
);
136 search_tab_helper
->ipc_router().set_delegate_for_testing(mock_delegate());
137 search_tab_helper
->DetermineIfPageSupportsInstant();
140 TEST_F(SearchTabHelperTest
, DetermineIfPageSupportsInstant_NonLocal
) {
141 NavigateAndCommit(GURL("chrome-search://foo/bar"));
142 process()->sink().ClearMessages();
143 EXPECT_CALL(*mock_delegate(), OnInstantSupportDetermined(true)).Times(1);
145 SearchTabHelper
* search_tab_helper
=
146 SearchTabHelper::FromWebContents(web_contents());
147 ASSERT_NE(static_cast<SearchTabHelper
*>(NULL
), search_tab_helper
);
148 search_tab_helper
->ipc_router().set_delegate_for_testing(mock_delegate());
149 search_tab_helper
->DetermineIfPageSupportsInstant();
150 ASSERT_TRUE(MessageWasSent(ChromeViewMsg_DetermineIfPageSupportsInstant::ID
));
152 scoped_ptr
<IPC::Message
> response(
153 new ChromeViewHostMsg_InstantSupportDetermined(
154 web_contents()->GetRoutingID(),
155 search_tab_helper
->ipc_router().page_seq_no_for_testing(),
157 search_tab_helper
->ipc_router().OnMessageReceived(*response
);
160 TEST_F(SearchTabHelperTest
, PageURLDoesntBelongToInstantRenderer
) {
161 // Navigate to a page URL that doesn't belong to Instant renderer.
162 // SearchTabHelper::DeterminerIfPageSupportsInstant() should return
163 // immediately without dispatching any message to the renderer.
164 NavigateAndCommit(GURL("http://www.example.com"));
165 process()->sink().ClearMessages();
166 EXPECT_CALL(*mock_delegate(), OnInstantSupportDetermined(false)).Times(0);
168 SearchTabHelper
* search_tab_helper
=
169 SearchTabHelper::FromWebContents(web_contents());
170 ASSERT_NE(static_cast<SearchTabHelper
*>(NULL
), search_tab_helper
);
171 search_tab_helper
->ipc_router().set_delegate_for_testing(mock_delegate());
172 search_tab_helper
->DetermineIfPageSupportsInstant();
173 ASSERT_FALSE(MessageWasSent(
174 ChromeViewMsg_DetermineIfPageSupportsInstant::ID
));
177 TEST_F(SearchTabHelperTest
, OnChromeIdentityCheckMatch
) {
178 NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl
));
179 CreateSigninManager(std::string("foo@bar.com"));
180 SearchTabHelper
* search_tab_helper
=
181 SearchTabHelper::FromWebContents(web_contents());
182 ASSERT_NE(static_cast<SearchTabHelper
*>(NULL
), search_tab_helper
);
184 const base::string16 test_identity
= base::ASCIIToUTF16("foo@bar.com");
185 search_tab_helper
->OnChromeIdentityCheck(test_identity
);
187 const IPC::Message
* message
= process()->sink().GetUniqueMessageMatching(
188 ChromeViewMsg_ChromeIdentityCheckResult::ID
);
189 ASSERT_TRUE(message
!= NULL
);
191 ChromeViewMsg_ChromeIdentityCheckResult::Param params
;
192 ChromeViewMsg_ChromeIdentityCheckResult::Read(message
, ¶ms
);
193 EXPECT_EQ(test_identity
, base::get
<0>(params
));
194 ASSERT_TRUE(base::get
<1>(params
));
197 TEST_F(SearchTabHelperTest
, OnChromeIdentityCheckMatchSlightlyDifferentGmail
) {
198 NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl
));
199 CreateSigninManager(std::string("foobar123@gmail.com"));
200 SearchTabHelper
* search_tab_helper
=
201 SearchTabHelper::FromWebContents(web_contents());
202 ASSERT_NE(static_cast<SearchTabHelper
*>(NULL
), search_tab_helper
);
204 // For gmail, canonicalization is done so that email addresses have a
206 const base::string16 test_identity
=
207 base::ASCIIToUTF16("Foo.Bar.123@gmail.com");
208 search_tab_helper
->OnChromeIdentityCheck(test_identity
);
210 const IPC::Message
* message
= process()->sink().GetUniqueMessageMatching(
211 ChromeViewMsg_ChromeIdentityCheckResult::ID
);
212 ASSERT_TRUE(message
!= NULL
);
214 ChromeViewMsg_ChromeIdentityCheckResult::Param params
;
215 ChromeViewMsg_ChromeIdentityCheckResult::Read(message
, ¶ms
);
216 EXPECT_EQ(test_identity
, base::get
<0>(params
));
217 ASSERT_TRUE(base::get
<1>(params
));
220 TEST_F(SearchTabHelperTest
, OnChromeIdentityCheckMatchSlightlyDifferentGmail2
) {
221 NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl
));
223 CreateSigninManager(std::string("chrome.guy.7FOREVER"));
224 SearchTabHelper
* search_tab_helper
=
225 SearchTabHelper::FromWebContents(web_contents());
226 ASSERT_NE(static_cast<SearchTabHelper
*>(NULL
), search_tab_helper
);
228 // For gmail/googlemail, canonicalization is done so that email addresses have
230 const base::string16 test_identity
=
231 base::ASCIIToUTF16("chromeguy7forever@googlemail.com");
232 search_tab_helper
->OnChromeIdentityCheck(test_identity
);
234 const IPC::Message
* message
= process()->sink().GetUniqueMessageMatching(
235 ChromeViewMsg_ChromeIdentityCheckResult::ID
);
236 ASSERT_TRUE(message
!= NULL
);
238 ChromeViewMsg_ChromeIdentityCheckResult::Param params
;
239 ChromeViewMsg_ChromeIdentityCheckResult::Read(message
, ¶ms
);
240 EXPECT_EQ(test_identity
, base::get
<0>(params
));
241 ASSERT_TRUE(base::get
<1>(params
));
244 TEST_F(SearchTabHelperTest
, OnChromeIdentityCheckMismatch
) {
245 NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl
));
246 CreateSigninManager(std::string("foo@bar.com"));
247 SearchTabHelper
* search_tab_helper
=
248 SearchTabHelper::FromWebContents(web_contents());
249 ASSERT_NE(static_cast<SearchTabHelper
*>(NULL
), search_tab_helper
);
251 const base::string16 test_identity
= base::ASCIIToUTF16("bar@foo.com");
252 search_tab_helper
->OnChromeIdentityCheck(test_identity
);
254 const IPC::Message
* message
= process()->sink().GetUniqueMessageMatching(
255 ChromeViewMsg_ChromeIdentityCheckResult::ID
);
256 ASSERT_TRUE(message
!= NULL
);
258 ChromeViewMsg_ChromeIdentityCheckResult::Param params
;
259 ChromeViewMsg_ChromeIdentityCheckResult::Read(message
, ¶ms
);
260 EXPECT_EQ(test_identity
, base::get
<0>(params
));
261 ASSERT_FALSE(base::get
<1>(params
));
264 TEST_F(SearchTabHelperTest
, OnChromeIdentityCheckSignedOutMismatch
) {
265 NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl
));
266 // This test does not sign in.
267 SearchTabHelper
* search_tab_helper
=
268 SearchTabHelper::FromWebContents(web_contents());
269 ASSERT_NE(static_cast<SearchTabHelper
*>(NULL
), search_tab_helper
);
271 const base::string16 test_identity
= base::ASCIIToUTF16("bar@foo.com");
272 search_tab_helper
->OnChromeIdentityCheck(test_identity
);
274 const IPC::Message
* message
= process()->sink().GetUniqueMessageMatching(
275 ChromeViewMsg_ChromeIdentityCheckResult::ID
);
276 ASSERT_TRUE(message
!= NULL
);
278 ChromeViewMsg_ChromeIdentityCheckResult::Param params
;
279 ChromeViewMsg_ChromeIdentityCheckResult::Read(message
, ¶ms
);
280 EXPECT_EQ(test_identity
, base::get
<0>(params
));
281 ASSERT_FALSE(base::get
<1>(params
));
284 TEST_F(SearchTabHelperTest
, OnHistorySyncCheckSyncing
) {
285 NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl
));
286 SetHistorySync(true);
287 SearchTabHelper
* search_tab_helper
=
288 SearchTabHelper::FromWebContents(web_contents());
289 ASSERT_NE(static_cast<SearchTabHelper
*>(NULL
), search_tab_helper
);
291 search_tab_helper
->OnHistorySyncCheck();
293 const IPC::Message
* message
= process()->sink().GetUniqueMessageMatching(
294 ChromeViewMsg_HistorySyncCheckResult::ID
);
295 ASSERT_TRUE(message
!= NULL
);
297 ChromeViewMsg_HistorySyncCheckResult::Param params
;
298 ChromeViewMsg_HistorySyncCheckResult::Read(message
, ¶ms
);
299 ASSERT_TRUE(base::get
<0>(params
));
302 TEST_F(SearchTabHelperTest
, OnHistorySyncCheckNotSyncing
) {
303 NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl
));
304 SetHistorySync(false);
305 SearchTabHelper
* search_tab_helper
=
306 SearchTabHelper::FromWebContents(web_contents());
307 ASSERT_NE(static_cast<SearchTabHelper
*>(NULL
), search_tab_helper
);
309 search_tab_helper
->OnHistorySyncCheck();
311 const IPC::Message
* message
= process()->sink().GetUniqueMessageMatching(
312 ChromeViewMsg_HistorySyncCheckResult::ID
);
313 ASSERT_TRUE(message
!= NULL
);
315 ChromeViewMsg_HistorySyncCheckResult::Param params
;
316 ChromeViewMsg_HistorySyncCheckResult::Read(message
, ¶ms
);
317 ASSERT_FALSE(base::get
<0>(params
));
320 class TabTitleObserver
: public content::WebContentsObserver
{
322 explicit TabTitleObserver(content::WebContents
* contents
)
323 : WebContentsObserver(contents
) {}
325 base::string16
title_on_start() { return title_on_start_
; }
326 base::string16
title_on_commit() { return title_on_commit_
; }
329 void DidStartProvisionalLoadForFrame(
330 content::RenderFrameHost
* /* render_frame_host */,
331 const GURL
& /* validated_url */,
332 bool /* is_error_page */,
333 bool /* is_iframe_srcdoc */) override
{
334 title_on_start_
= web_contents()->GetTitle();
337 void DidNavigateMainFrame(
338 const content::LoadCommittedDetails
& /* details */,
339 const content::FrameNavigateParams
& /* params */) override
{
340 title_on_commit_
= web_contents()->GetTitle();
343 base::string16 title_on_start_
;
344 base::string16 title_on_commit_
;
347 TEST_F(SearchTabHelperTest
, TitleIsSetForNTP
) {
348 TabTitleObserver
title_observer(web_contents());
349 NavigateAndCommit(GURL(chrome::kChromeUINewTabURL
));
350 const base::string16 title
= l10n_util::GetStringUTF16(IDS_NEW_TAB_TITLE
);
351 EXPECT_EQ(title
, title_observer
.title_on_start());
352 EXPECT_EQ(title
, title_observer
.title_on_commit());
353 EXPECT_EQ(title
, web_contents()->GetTitle());
356 class SearchTabHelperWindowTest
: public BrowserWithTestWindowTest
{
358 void SetUp() override
{
359 BrowserWithTestWindowTest::SetUp();
360 TemplateURLServiceFactory::GetInstance()->SetTestingFactoryAndUse(
361 profile(), &TemplateURLServiceFactory::BuildInstanceFor
);
362 TemplateURLService
* template_url_service
=
363 TemplateURLServiceFactory::GetForProfile(profile());
364 ui_test_utils::WaitForTemplateURLServiceToLoad(template_url_service
);
366 TemplateURLData data
;
367 data
.SetURL("http://foo.com/url?bar={searchTerms}");
368 data
.instant_url
= "http://foo.com/instant?"
369 "{google:omniboxStartMarginParameter}{google:forceInstantResults}"
370 "foo=foo#foo=foo&strk";
371 data
.new_tab_url
= std::string("https://foo.com/newtab?strk");
372 data
.alternate_urls
.push_back("http://foo.com/alt#quux={searchTerms}");
373 data
.search_terms_replacement_key
= "strk";
375 TemplateURL
* template_url
= new TemplateURL(data
);
376 template_url_service
->Add(template_url
);
377 template_url_service
->SetUserSelectedDefaultSearchProvider(template_url
);
381 class SearchTabHelperPrerenderTest
: public InstantUnitTestBase
{
383 ~SearchTabHelperPrerenderTest() override
{}
386 void SetUp() override
{
387 ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
389 "Group1 espv:89 prefetch_results:1 "
390 "prerender_instant_url_on_omnibox_focus:1"));
391 InstantUnitTestBase::SetUp();
393 AddTab(browser(), GURL(chrome::kChromeUINewTabURL
));
394 SearchTabHelper::FromWebContents(web_contents())->set_omnibox_has_focus_fn(
396 SearchTabHelperPrerenderTest::omnibox_has_focus_
= true;
399 content::WebContents
* web_contents() {
400 return browser()->tab_strip_model()->GetActiveWebContents();
403 bool IsInstantURLMarkedForPrerendering() {
404 GURL
instant_url(search::GetSearchResultPrefetchBaseURL(profile()));
405 prerender::PrerenderManager
* prerender_manager
=
406 prerender::PrerenderManagerFactory::GetForProfile(profile());
407 return prerender_manager
->HasPrerenderedUrl(instant_url
, web_contents());
410 static bool omnibox_has_focus(OmniboxView
* omnibox
) {
411 return omnibox_has_focus_
;
414 static bool omnibox_has_focus_
;
417 bool SearchTabHelperPrerenderTest::omnibox_has_focus_
= true;
419 TEST_F(SearchTabHelperPrerenderTest
, OnOmniboxFocusPrerenderInstantURL
) {
420 SearchTabHelper
* search_tab_helper
=
421 SearchTabHelper::FromWebContents(web_contents());
422 search_tab_helper
->OmniboxFocusChanged(OMNIBOX_FOCUS_VISIBLE
,
423 OMNIBOX_FOCUS_CHANGE_EXPLICIT
);
424 ASSERT_TRUE(IsInstantURLMarkedForPrerendering());
425 search_tab_helper
->OmniboxFocusChanged(OMNIBOX_FOCUS_NONE
,
426 OMNIBOX_FOCUS_CHANGE_EXPLICIT
);
427 ASSERT_FALSE(IsInstantURLMarkedForPrerendering());
430 TEST_F(SearchTabHelperPrerenderTest
, OnTabActivatedPrerenderInstantURL
) {
431 SearchTabHelper
* search_tab_helper
=
432 SearchTabHelper::FromWebContents(web_contents());
433 search_tab_helper
->OnTabActivated();
434 ASSERT_TRUE(IsInstantURLMarkedForPrerendering());
437 TEST_F(SearchTabHelperPrerenderTest
,
438 OnTabActivatedNoPrerenderIfOmniboxBlurred
) {
439 SearchTabHelperPrerenderTest::omnibox_has_focus_
= false;
440 SearchTabHelper
* search_tab_helper
=
441 SearchTabHelper::FromWebContents(web_contents());
442 search_tab_helper
->OnTabActivated();
443 ASSERT_FALSE(IsInstantURLMarkedForPrerendering());