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/strings/utf_string_conversions.h"
10 #include "chrome/browser/search/search.h"
11 #include "chrome/browser/search_engines/template_url_service.h"
12 #include "chrome/browser/search_engines/template_url_service_factory.h"
13 #include "chrome/browser/signin/fake_signin_manager.h"
14 #include "chrome/browser/signin/signin_manager_factory.h"
15 #include "chrome/browser/ui/search/search_ipc_router.h"
16 #include "chrome/browser/ui/tabs/tab_strip_model.h"
17 #include "chrome/common/chrome_switches.h"
18 #include "chrome/common/ntp_logging_events.h"
19 #include "chrome/common/omnibox_focus_state.h"
20 #include "chrome/common/render_messages.h"
21 #include "chrome/common/url_constants.h"
22 #include "chrome/test/base/browser_with_test_window_test.h"
23 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
24 #include "chrome/test/base/testing_profile.h"
25 #include "chrome/test/base/ui_test_utils.h"
26 #include "content/public/browser/navigation_controller.h"
27 #include "content/public/browser/navigation_entry.h"
28 #include "content/public/browser/web_contents.h"
29 #include "content/public/test/mock_render_process_host.h"
30 #include "grit/generated_resources.h"
31 #include "ipc/ipc_message.h"
32 #include "ipc/ipc_test_sink.h"
33 #include "net/base/net_errors.h"
34 #include "testing/gmock/include/gmock/gmock.h"
35 #include "testing/gtest/include/gtest/gtest.h"
36 #include "ui/base/l10n/l10n_util.h"
41 class MockSearchIPCRouterDelegate
: public SearchIPCRouter::Delegate
{
43 virtual ~MockSearchIPCRouterDelegate() {}
45 MOCK_METHOD1(OnInstantSupportDetermined
, void(bool supports_instant
));
46 MOCK_METHOD1(OnSetVoiceSearchSupport
, void(bool supports_voice_search
));
47 MOCK_METHOD1(FocusOmnibox
, void(OmniboxFocusState state
));
48 MOCK_METHOD3(NavigateToURL
, void(const GURL
&, WindowOpenDisposition
, bool));
49 MOCK_METHOD1(OnDeleteMostVisitedItem
, void(const GURL
& url
));
50 MOCK_METHOD1(OnUndoMostVisitedDeletion
, void(const GURL
& url
));
51 MOCK_METHOD0(OnUndoAllMostVisitedDeletions
, void());
52 MOCK_METHOD1(OnLogEvent
, void(NTPLoggingEventType event
));
53 MOCK_METHOD2(OnLogImpression
, void(int position
,
54 const base::string16
& provider
));
55 MOCK_METHOD1(PasteIntoOmnibox
, void(const base::string16
&));
56 MOCK_METHOD1(OnChromeIdentityCheck
, void(const base::string16
& identity
));
61 class SearchTabHelperTest
: public ChromeRenderViewHostTestHarness
{
63 virtual void SetUp() {
64 ChromeRenderViewHostTestHarness::SetUp();
65 SearchTabHelper::CreateForWebContents(web_contents());
68 // Creates a sign-in manager for tests. If |username| is not empty, the
69 // testing profile of the WebContents will be connected to the given account.
70 void CreateSigninManager(const std::string
& username
) {
71 SigninManagerBase
* signin_manager
= static_cast<SigninManagerBase
*>(
72 SigninManagerFactory::GetInstance()->SetTestingFactoryAndUse(
73 profile(), FakeSigninManagerBase::Build
));
74 signin_manager
->Initialize(profile(), NULL
);
76 if (!username
.empty()) {
77 ASSERT_TRUE(signin_manager
);
78 signin_manager
->SetAuthenticatedUsername(username
);
82 bool MessageWasSent(uint32 id
) {
83 return process()->sink().GetFirstMessageMatching(id
) != NULL
;
86 MockSearchIPCRouterDelegate
* mock_delegate() { return &delegate_
; }
89 MockSearchIPCRouterDelegate delegate_
;
92 TEST_F(SearchTabHelperTest
, DetermineIfPageSupportsInstant_Local
) {
93 NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl
));
94 EXPECT_CALL(*mock_delegate(), OnInstantSupportDetermined(true)).Times(0);
96 SearchTabHelper
* search_tab_helper
=
97 SearchTabHelper::FromWebContents(web_contents());
98 ASSERT_NE(static_cast<SearchTabHelper
*>(NULL
), search_tab_helper
);
99 search_tab_helper
->ipc_router().set_delegate(mock_delegate());
100 search_tab_helper
->DetermineIfPageSupportsInstant();
103 TEST_F(SearchTabHelperTest
, DetermineIfPageSupportsInstant_NonLocal
) {
104 NavigateAndCommit(GURL("chrome-search://foo/bar"));
105 process()->sink().ClearMessages();
106 EXPECT_CALL(*mock_delegate(), OnInstantSupportDetermined(true)).Times(1);
108 SearchTabHelper
* search_tab_helper
=
109 SearchTabHelper::FromWebContents(web_contents());
110 ASSERT_NE(static_cast<SearchTabHelper
*>(NULL
), search_tab_helper
);
111 search_tab_helper
->ipc_router().set_delegate(mock_delegate());
112 search_tab_helper
->DetermineIfPageSupportsInstant();
113 ASSERT_TRUE(MessageWasSent(ChromeViewMsg_DetermineIfPageSupportsInstant::ID
));
115 scoped_ptr
<IPC::Message
> response(
116 new ChromeViewHostMsg_InstantSupportDetermined(
117 web_contents()->GetRoutingID(),
118 web_contents()->GetController().GetVisibleEntry()->GetPageID(),
120 search_tab_helper
->ipc_router().OnMessageReceived(*response
);
123 TEST_F(SearchTabHelperTest
, PageURLDoesntBelongToInstantRenderer
) {
124 // Navigate to a page URL that doesn't belong to Instant renderer.
125 // SearchTabHelper::DeterminerIfPageSupportsInstant() should return
126 // immediately without dispatching any message to the renderer.
127 NavigateAndCommit(GURL("http://www.example.com"));
128 process()->sink().ClearMessages();
129 EXPECT_CALL(*mock_delegate(), OnInstantSupportDetermined(false)).Times(0);
131 SearchTabHelper
* search_tab_helper
=
132 SearchTabHelper::FromWebContents(web_contents());
133 ASSERT_NE(static_cast<SearchTabHelper
*>(NULL
), search_tab_helper
);
134 search_tab_helper
->ipc_router().set_delegate(mock_delegate());
135 search_tab_helper
->DetermineIfPageSupportsInstant();
136 ASSERT_FALSE(MessageWasSent(
137 ChromeViewMsg_DetermineIfPageSupportsInstant::ID
));
140 TEST_F(SearchTabHelperTest
, OnChromeIdentityCheckMatch
) {
141 NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl
));
142 CreateSigninManager(std::string("foo@bar.com"));
143 SearchTabHelper
* search_tab_helper
=
144 SearchTabHelper::FromWebContents(web_contents());
145 ASSERT_NE(static_cast<SearchTabHelper
*>(NULL
), search_tab_helper
);
147 const base::string16 test_identity
= base::ASCIIToUTF16("foo@bar.com");
148 search_tab_helper
->OnChromeIdentityCheck(test_identity
);
150 const IPC::Message
* message
= process()->sink().GetUniqueMessageMatching(
151 ChromeViewMsg_ChromeIdentityCheckResult::ID
);
152 ASSERT_TRUE(message
!= NULL
);
154 ChromeViewMsg_ChromeIdentityCheckResult::Param params
;
155 ChromeViewMsg_ChromeIdentityCheckResult::Read(message
, ¶ms
);
156 EXPECT_EQ(test_identity
, params
.a
);
157 ASSERT_TRUE(params
.b
);
160 TEST_F(SearchTabHelperTest
, OnChromeIdentityCheckMismatch
) {
161 NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl
));
162 CreateSigninManager(std::string("foo@bar.com"));
163 SearchTabHelper
* search_tab_helper
=
164 SearchTabHelper::FromWebContents(web_contents());
165 ASSERT_NE(static_cast<SearchTabHelper
*>(NULL
), search_tab_helper
);
167 const base::string16 test_identity
= base::ASCIIToUTF16("bar@foo.com");
168 search_tab_helper
->OnChromeIdentityCheck(test_identity
);
170 const IPC::Message
* message
= process()->sink().GetUniqueMessageMatching(
171 ChromeViewMsg_ChromeIdentityCheckResult::ID
);
172 ASSERT_TRUE(message
!= NULL
);
174 ChromeViewMsg_ChromeIdentityCheckResult::Param params
;
175 ChromeViewMsg_ChromeIdentityCheckResult::Read(message
, ¶ms
);
176 EXPECT_EQ(test_identity
, params
.a
);
177 ASSERT_FALSE(params
.b
);
180 TEST_F(SearchTabHelperTest
, OnChromeIdentityCheckSignedOutMatch
) {
181 NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl
));
182 // This test does not sign in.
183 SearchTabHelper
* search_tab_helper
=
184 SearchTabHelper::FromWebContents(web_contents());
185 ASSERT_NE(static_cast<SearchTabHelper
*>(NULL
), search_tab_helper
);
187 const base::string16 test_identity
;
188 search_tab_helper
->OnChromeIdentityCheck(test_identity
);
190 const IPC::Message
* message
= process()->sink().GetUniqueMessageMatching(
191 ChromeViewMsg_ChromeIdentityCheckResult::ID
);
192 ASSERT_TRUE(message
!= NULL
);
194 ChromeViewMsg_ChromeIdentityCheckResult::Param params
;
195 ChromeViewMsg_ChromeIdentityCheckResult::Read(message
, ¶ms
);
196 EXPECT_EQ(test_identity
, params
.a
);
197 ASSERT_TRUE(params
.b
);
200 TEST_F(SearchTabHelperTest
, OnChromeIdentityCheckSignedOutMismatch
) {
201 NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl
));
202 // This test does not sign in.
203 SearchTabHelper
* search_tab_helper
=
204 SearchTabHelper::FromWebContents(web_contents());
205 ASSERT_NE(static_cast<SearchTabHelper
*>(NULL
), search_tab_helper
);
207 const base::string16 test_identity
= base::ASCIIToUTF16("bar@foo.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
, params
.a
);
217 ASSERT_FALSE(params
.b
);
220 class TabTitleObserver
: public content::WebContentsObserver
{
222 explicit TabTitleObserver(content::WebContents
* contents
)
223 : WebContentsObserver(contents
) {}
225 base::string16
title_on_start() { return title_on_start_
; }
226 base::string16
title_on_commit() { return title_on_commit_
; }
229 virtual void DidStartProvisionalLoadForFrame(
230 int64
/* frame_id */,
231 int64
/* parent_frame_id */,
232 bool /* is_main_frame */,
233 const GURL
& /* validated_url */,
234 bool /* is_error_page */,
235 bool /* is_iframe_srcdoc */,
236 content::RenderViewHost
* /* render_view_host */) OVERRIDE
{
237 title_on_start_
= web_contents()->GetTitle();
240 virtual void DidNavigateMainFrame(
241 const content::LoadCommittedDetails
& /* details */,
242 const content::FrameNavigateParams
& /* params */) OVERRIDE
{
243 title_on_commit_
= web_contents()->GetTitle();
246 base::string16 title_on_start_
;
247 base::string16 title_on_commit_
;
250 TEST_F(SearchTabHelperTest
, TitleIsSetForNTP
) {
251 TabTitleObserver
title_observer(web_contents());
252 NavigateAndCommit(GURL(chrome::kChromeUINewTabURL
));
253 const base::string16 title
= l10n_util::GetStringUTF16(IDS_NEW_TAB_TITLE
);
254 EXPECT_EQ(title
, title_observer
.title_on_start());
255 EXPECT_EQ(title
, title_observer
.title_on_commit());
256 EXPECT_EQ(title
, web_contents()->GetTitle());
259 class SearchTabHelperWindowTest
: public BrowserWithTestWindowTest
{
261 virtual void SetUp() OVERRIDE
{
262 BrowserWithTestWindowTest::SetUp();
263 TemplateURLServiceFactory::GetInstance()->SetTestingFactoryAndUse(
264 profile(), &TemplateURLServiceFactory::BuildInstanceFor
);
265 TemplateURLService
* template_url_service
=
266 TemplateURLServiceFactory::GetForProfile(profile());
267 ui_test_utils::WaitForTemplateURLServiceToLoad(template_url_service
);
269 TemplateURLData data
;
270 data
.SetURL("http://foo.com/url?bar={searchTerms}");
271 data
.instant_url
= "http://foo.com/instant?"
272 "{google:omniboxStartMarginParameter}{google:forceInstantResults}"
273 "foo=foo#foo=foo&strk";
274 data
.new_tab_url
= std::string("https://foo.com/newtab?strk");
275 data
.alternate_urls
.push_back("http://foo.com/alt#quux={searchTerms}");
276 data
.search_terms_replacement_key
= "strk";
278 TemplateURL
* template_url
= new TemplateURL(profile(), data
);
279 template_url_service
->Add(template_url
);
280 template_url_service
->SetDefaultSearchProvider(template_url
);
284 TEST_F(SearchTabHelperWindowTest
, OnProvisionalLoadFailRedirectNTPToLocal
) {
285 AddTab(browser(), GURL(chrome::kChromeUINewTabURL
));
286 content::WebContents
* contents
=
287 browser()->tab_strip_model()->GetWebContentsAt(0);
288 content::NavigationController
* controller
= &contents
->GetController();
290 SearchTabHelper
* search_tab_helper
=
291 SearchTabHelper::FromWebContents(contents
);
292 ASSERT_NE(static_cast<SearchTabHelper
*>(NULL
), search_tab_helper
);
294 // A failed provisional load of a cacheable NTP should be redirected to local
296 const GURL cacheableNTPURL
= chrome::GetNewTabPageURL(profile());
297 search_tab_helper
->DidFailProvisionalLoad(1, base::string16(), true,
298 cacheableNTPURL
, 1, base::string16(), NULL
);
299 CommitPendingLoad(controller
);
300 EXPECT_EQ(GURL(chrome::kChromeSearchLocalNtpUrl
),
301 controller
->GetLastCommittedEntry()->GetURL());
304 TEST_F(SearchTabHelperWindowTest
, OnProvisionalLoadFailDontRedirectIfAborted
) {
305 AddTab(browser(), GURL("chrome://blank"));
306 content::WebContents
* contents
=
307 browser()->tab_strip_model()->GetWebContentsAt(0);
308 content::NavigationController
* controller
= &contents
->GetController();
310 SearchTabHelper
* search_tab_helper
=
311 SearchTabHelper::FromWebContents(contents
);
312 ASSERT_NE(static_cast<SearchTabHelper
*>(NULL
), search_tab_helper
);
314 // A failed provisional load of a cacheable NTP should be redirected to local
316 const GURL cacheableNTPURL
= chrome::GetNewTabPageURL(profile());
317 search_tab_helper
->DidFailProvisionalLoad(1, base::string16(), true,
318 cacheableNTPURL
, net::ERR_ABORTED
, base::string16(), NULL
);
319 CommitPendingLoad(controller
);
320 EXPECT_EQ(GURL("chrome://blank"),
321 controller
->GetLastCommittedEntry()->GetURL());
324 TEST_F(SearchTabHelperWindowTest
, OnProvisionalLoadFailDontRedirectNonNTP
) {
325 AddTab(browser(), GURL(chrome::kChromeUINewTabURL
));
326 content::WebContents
* contents
=
327 browser()->tab_strip_model()->GetWebContentsAt(0);
328 content::NavigationController
* controller
= &contents
->GetController();
330 SearchTabHelper
* search_tab_helper
=
331 SearchTabHelper::FromWebContents(contents
);
332 ASSERT_NE(static_cast<SearchTabHelper
*>(NULL
), search_tab_helper
);
334 // Any other web page shouldn't be redirected when provisional load fails.
335 search_tab_helper
->DidFailProvisionalLoad(1, base::string16(), true,
336 GURL("http://www.example.com"), 1, base::string16(), NULL
);
337 CommitPendingLoad(controller
);
338 EXPECT_NE(GURL(chrome::kChromeSearchLocalNtpUrl
),
339 controller
->GetLastCommittedEntry()->GetURL());