• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "chrome/browser/ui/search/search_tab_helper.h"
6 
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/sync/profile_sync_service.h"
16 #include "chrome/browser/sync/profile_sync_service_factory.h"
17 #include "chrome/browser/sync/profile_sync_service_mock.h"
18 #include "chrome/browser/ui/search/search_ipc_router.h"
19 #include "chrome/browser/ui/tabs/tab_strip_model.h"
20 #include "chrome/common/chrome_switches.h"
21 #include "chrome/common/ntp_logging_events.h"
22 #include "chrome/common/omnibox_focus_state.h"
23 #include "chrome/common/render_messages.h"
24 #include "chrome/common/url_constants.h"
25 #include "chrome/test/base/browser_with_test_window_test.h"
26 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
27 #include "chrome/test/base/testing_profile.h"
28 #include "chrome/test/base/ui_test_utils.h"
29 #include "content/public/browser/navigation_controller.h"
30 #include "content/public/browser/navigation_entry.h"
31 #include "content/public/browser/web_contents.h"
32 #include "content/public/test/mock_render_process_host.h"
33 #include "grit/generated_resources.h"
34 #include "ipc/ipc_message.h"
35 #include "ipc/ipc_test_sink.h"
36 #include "net/base/net_errors.h"
37 #include "testing/gmock/include/gmock/gmock.h"
38 #include "testing/gtest/include/gtest/gtest.h"
39 #include "ui/base/l10n/l10n_util.h"
40 #include "url/gurl.h"
41 
42 using testing::Return;
43 
44 namespace {
45 
46 class MockSearchIPCRouterDelegate : public SearchIPCRouter::Delegate {
47  public:
~MockSearchIPCRouterDelegate()48   virtual ~MockSearchIPCRouterDelegate() {}
49 
50   MOCK_METHOD1(OnInstantSupportDetermined, void(bool supports_instant));
51   MOCK_METHOD1(OnSetVoiceSearchSupport, void(bool supports_voice_search));
52   MOCK_METHOD1(FocusOmnibox, void(OmniboxFocusState state));
53   MOCK_METHOD3(NavigateToURL, void(const GURL&, WindowOpenDisposition, bool));
54   MOCK_METHOD1(OnDeleteMostVisitedItem, void(const GURL& url));
55   MOCK_METHOD1(OnUndoMostVisitedDeletion, void(const GURL& url));
56   MOCK_METHOD0(OnUndoAllMostVisitedDeletions, void());
57   MOCK_METHOD1(OnLogEvent, void(NTPLoggingEventType event));
58   MOCK_METHOD2(OnLogMostVisitedImpression,
59                void(int position, const base::string16& provider));
60   MOCK_METHOD2(OnLogMostVisitedNavigation,
61                void(int position, const base::string16& provider));
62   MOCK_METHOD1(PasteIntoOmnibox, void(const base::string16&));
63   MOCK_METHOD1(OnChromeIdentityCheck, void(const base::string16& identity));
64 };
65 
66 }  // namespace
67 
68 class SearchTabHelperTest : public ChromeRenderViewHostTestHarness {
69  public:
SetUp()70   virtual void SetUp() {
71     ChromeRenderViewHostTestHarness::SetUp();
72     SearchTabHelper::CreateForWebContents(web_contents());
73   }
74 
CreateBrowserContext()75   virtual content::BrowserContext* CreateBrowserContext() OVERRIDE {
76     TestingProfile::Builder builder;
77     builder.AddTestingFactory(SigninManagerFactory::GetInstance(),
78                               FakeSigninManagerBase::Build);
79     builder.AddTestingFactory(
80         ProfileSyncServiceFactory::GetInstance(),
81         ProfileSyncServiceMock::BuildMockProfileSyncService);
82     return builder.Build().release();
83   }
84 
85   // Creates a sign-in manager for tests.  If |username| is not empty, the
86   // testing profile of the WebContents will be connected to the given account.
87   // The account can be configured to |sync_history| or not.
CreateSigninManager(const std::string & username,bool sync_history)88   void CreateSigninManager(const std::string& username, bool sync_history) {
89     SigninManagerBase* signin_manager = static_cast<SigninManagerBase*>(
90         SigninManagerFactory::GetForProfile(profile()));
91 
92     if (!username.empty()) {
93       ASSERT_TRUE(signin_manager);
94       signin_manager->SetAuthenticatedUsername(username);
95     }
96 
97     ProfileSyncServiceMock* sync_service = static_cast<ProfileSyncServiceMock*>(
98         ProfileSyncServiceFactory::GetInstance()->GetForProfile(profile()));
99 
100     EXPECT_CALL(*sync_service, sync_initialized()).WillRepeatedly(Return(true));
101     syncer::ModelTypeSet result;
102     if (sync_history) {
103       result.Put(syncer::HISTORY_DELETE_DIRECTIVES);
104     }
105     EXPECT_CALL(*sync_service, GetActiveDataTypes())
106         .WillRepeatedly(Return(result));
107   }
108 
MessageWasSent(uint32 id)109   bool MessageWasSent(uint32 id) {
110     return process()->sink().GetFirstMessageMatching(id) != NULL;
111   }
112 
mock_delegate()113   MockSearchIPCRouterDelegate* mock_delegate() { return &delegate_; }
114 
115  private:
116   MockSearchIPCRouterDelegate delegate_;
117 };
118 
TEST_F(SearchTabHelperTest,DetermineIfPageSupportsInstant_Local)119 TEST_F(SearchTabHelperTest, DetermineIfPageSupportsInstant_Local) {
120   NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl));
121   EXPECT_CALL(*mock_delegate(), OnInstantSupportDetermined(true)).Times(0);
122 
123   SearchTabHelper* search_tab_helper =
124       SearchTabHelper::FromWebContents(web_contents());
125   ASSERT_NE(static_cast<SearchTabHelper*>(NULL), search_tab_helper);
126   search_tab_helper->ipc_router().set_delegate_for_testing(mock_delegate());
127   search_tab_helper->DetermineIfPageSupportsInstant();
128 }
129 
TEST_F(SearchTabHelperTest,DetermineIfPageSupportsInstant_NonLocal)130 TEST_F(SearchTabHelperTest, DetermineIfPageSupportsInstant_NonLocal) {
131   NavigateAndCommit(GURL("chrome-search://foo/bar"));
132   process()->sink().ClearMessages();
133   EXPECT_CALL(*mock_delegate(), OnInstantSupportDetermined(true)).Times(1);
134 
135   SearchTabHelper* search_tab_helper =
136       SearchTabHelper::FromWebContents(web_contents());
137   ASSERT_NE(static_cast<SearchTabHelper*>(NULL), search_tab_helper);
138   search_tab_helper->ipc_router().set_delegate_for_testing(mock_delegate());
139   search_tab_helper->DetermineIfPageSupportsInstant();
140   ASSERT_TRUE(MessageWasSent(ChromeViewMsg_DetermineIfPageSupportsInstant::ID));
141 
142   scoped_ptr<IPC::Message> response(
143       new ChromeViewHostMsg_InstantSupportDetermined(
144           web_contents()->GetRoutingID(),
145           search_tab_helper->ipc_router().page_seq_no_for_testing(),
146           true));
147   search_tab_helper->ipc_router().OnMessageReceived(*response);
148 }
149 
TEST_F(SearchTabHelperTest,PageURLDoesntBelongToInstantRenderer)150 TEST_F(SearchTabHelperTest, PageURLDoesntBelongToInstantRenderer) {
151   // Navigate to a page URL that doesn't belong to Instant renderer.
152   // SearchTabHelper::DeterminerIfPageSupportsInstant() should return
153   // immediately without dispatching any message to the renderer.
154   NavigateAndCommit(GURL("http://www.example.com"));
155   process()->sink().ClearMessages();
156   EXPECT_CALL(*mock_delegate(), OnInstantSupportDetermined(false)).Times(0);
157 
158   SearchTabHelper* search_tab_helper =
159       SearchTabHelper::FromWebContents(web_contents());
160   ASSERT_NE(static_cast<SearchTabHelper*>(NULL), search_tab_helper);
161   search_tab_helper->ipc_router().set_delegate_for_testing(mock_delegate());
162   search_tab_helper->DetermineIfPageSupportsInstant();
163   ASSERT_FALSE(MessageWasSent(
164       ChromeViewMsg_DetermineIfPageSupportsInstant::ID));
165 }
166 
TEST_F(SearchTabHelperTest,OnChromeIdentityCheckMatch)167 TEST_F(SearchTabHelperTest, OnChromeIdentityCheckMatch) {
168   NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl));
169   CreateSigninManager(std::string("foo@bar.com"), true);
170   SearchTabHelper* search_tab_helper =
171       SearchTabHelper::FromWebContents(web_contents());
172   ASSERT_NE(static_cast<SearchTabHelper*>(NULL), search_tab_helper);
173 
174   const base::string16 test_identity = base::ASCIIToUTF16("foo@bar.com");
175   search_tab_helper->OnChromeIdentityCheck(test_identity);
176 
177   const IPC::Message* message = process()->sink().GetUniqueMessageMatching(
178       ChromeViewMsg_ChromeIdentityCheckResult::ID);
179   ASSERT_TRUE(message != NULL);
180 
181   ChromeViewMsg_ChromeIdentityCheckResult::Param params;
182   ChromeViewMsg_ChromeIdentityCheckResult::Read(message, &params);
183   EXPECT_EQ(test_identity, params.a);
184   ASSERT_TRUE(params.b);
185 }
186 
TEST_F(SearchTabHelperTest,OnChromeIdentityCheckMismatch)187 TEST_F(SearchTabHelperTest, OnChromeIdentityCheckMismatch) {
188   NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl));
189   CreateSigninManager(std::string("foo@bar.com"), true);
190   SearchTabHelper* search_tab_helper =
191       SearchTabHelper::FromWebContents(web_contents());
192   ASSERT_NE(static_cast<SearchTabHelper*>(NULL), search_tab_helper);
193 
194   const base::string16 test_identity = base::ASCIIToUTF16("bar@foo.com");
195   search_tab_helper->OnChromeIdentityCheck(test_identity);
196 
197   const IPC::Message* message = process()->sink().GetUniqueMessageMatching(
198       ChromeViewMsg_ChromeIdentityCheckResult::ID);
199   ASSERT_TRUE(message != NULL);
200 
201   ChromeViewMsg_ChromeIdentityCheckResult::Param params;
202   ChromeViewMsg_ChromeIdentityCheckResult::Read(message, &params);
203   EXPECT_EQ(test_identity, params.a);
204   ASSERT_FALSE(params.b);
205 }
206 
TEST_F(SearchTabHelperTest,OnChromeIdentityCheckSignedOutMatch)207 TEST_F(SearchTabHelperTest, OnChromeIdentityCheckSignedOutMatch) {
208   NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl));
209   // This test does not sign in.
210   ProfileSyncServiceMock* sync_service = static_cast<ProfileSyncServiceMock*>(
211       ProfileSyncServiceFactory::GetInstance()->GetForProfile(profile()));
212   EXPECT_CALL(*sync_service, sync_initialized()).WillRepeatedly(Return(false));
213   SearchTabHelper* search_tab_helper =
214       SearchTabHelper::FromWebContents(web_contents());
215   ASSERT_NE(static_cast<SearchTabHelper*>(NULL), search_tab_helper);
216 
217   const base::string16 test_identity;
218   search_tab_helper->OnChromeIdentityCheck(test_identity);
219 
220   const IPC::Message* message = process()->sink().GetUniqueMessageMatching(
221       ChromeViewMsg_ChromeIdentityCheckResult::ID);
222   ASSERT_TRUE(message != NULL);
223 
224   ChromeViewMsg_ChromeIdentityCheckResult::Param params;
225   ChromeViewMsg_ChromeIdentityCheckResult::Read(message, &params);
226   EXPECT_EQ(test_identity, params.a);
227   ASSERT_FALSE(params.b);
228 }
229 
TEST_F(SearchTabHelperTest,OnChromeIdentityCheckSignedOutMismatch)230 TEST_F(SearchTabHelperTest, OnChromeIdentityCheckSignedOutMismatch) {
231   NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl));
232   // This test does not sign in.
233   ProfileSyncServiceMock* sync_service = static_cast<ProfileSyncServiceMock*>(
234       ProfileSyncServiceFactory::GetInstance()->GetForProfile(profile()));
235   EXPECT_CALL(*sync_service, sync_initialized()).WillRepeatedly(Return(false));
236   SearchTabHelper* search_tab_helper =
237       SearchTabHelper::FromWebContents(web_contents());
238   ASSERT_NE(static_cast<SearchTabHelper*>(NULL), search_tab_helper);
239 
240   const base::string16 test_identity = base::ASCIIToUTF16("bar@foo.com");
241   search_tab_helper->OnChromeIdentityCheck(test_identity);
242 
243   const IPC::Message* message = process()->sink().GetUniqueMessageMatching(
244       ChromeViewMsg_ChromeIdentityCheckResult::ID);
245   ASSERT_TRUE(message != NULL);
246 
247   ChromeViewMsg_ChromeIdentityCheckResult::Param params;
248   ChromeViewMsg_ChromeIdentityCheckResult::Read(message, &params);
249   EXPECT_EQ(test_identity, params.a);
250   ASSERT_FALSE(params.b);
251 }
252 
TEST_F(SearchTabHelperTest,OnChromeIdentityCheckMatchNotSyncing)253 TEST_F(SearchTabHelperTest, OnChromeIdentityCheckMatchNotSyncing) {
254   NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl));
255   CreateSigninManager(std::string("foo@bar.com"), false);
256   SearchTabHelper* search_tab_helper =
257       SearchTabHelper::FromWebContents(web_contents());
258   ASSERT_NE(static_cast<SearchTabHelper*>(NULL), search_tab_helper);
259 
260   const base::string16 test_identity = base::ASCIIToUTF16("foo@bar.com");
261   search_tab_helper->OnChromeIdentityCheck(test_identity);
262 
263   const IPC::Message* message = process()->sink().GetUniqueMessageMatching(
264       ChromeViewMsg_ChromeIdentityCheckResult::ID);
265   ASSERT_TRUE(message != NULL);
266 
267   ChromeViewMsg_ChromeIdentityCheckResult::Param params;
268   ChromeViewMsg_ChromeIdentityCheckResult::Read(message, &params);
269   EXPECT_EQ(test_identity, params.a);
270   ASSERT_FALSE(params.b);
271 }
272 
273 class TabTitleObserver : public content::WebContentsObserver {
274  public:
TabTitleObserver(content::WebContents * contents)275   explicit TabTitleObserver(content::WebContents* contents)
276       : WebContentsObserver(contents) {}
277 
title_on_start()278   base::string16 title_on_start() { return title_on_start_; }
title_on_commit()279   base::string16 title_on_commit() { return title_on_commit_; }
280 
281  private:
DidStartProvisionalLoadForFrame(int64,int64,bool,const GURL &,bool,bool,content::RenderViewHost *)282   virtual void DidStartProvisionalLoadForFrame(
283       int64 /* frame_id */,
284       int64 /* parent_frame_id */,
285       bool /* is_main_frame */,
286       const GURL& /* validated_url */,
287       bool /* is_error_page */,
288       bool /* is_iframe_srcdoc */,
289       content::RenderViewHost* /* render_view_host */) OVERRIDE {
290     title_on_start_ = web_contents()->GetTitle();
291   }
292 
DidNavigateMainFrame(const content::LoadCommittedDetails &,const content::FrameNavigateParams &)293   virtual void DidNavigateMainFrame(
294       const content::LoadCommittedDetails& /* details */,
295       const content::FrameNavigateParams& /* params */) OVERRIDE {
296     title_on_commit_ = web_contents()->GetTitle();
297   }
298 
299   base::string16 title_on_start_;
300   base::string16 title_on_commit_;
301 };
302 
TEST_F(SearchTabHelperTest,TitleIsSetForNTP)303 TEST_F(SearchTabHelperTest, TitleIsSetForNTP) {
304   TabTitleObserver title_observer(web_contents());
305   NavigateAndCommit(GURL(chrome::kChromeUINewTabURL));
306   const base::string16 title = l10n_util::GetStringUTF16(IDS_NEW_TAB_TITLE);
307   EXPECT_EQ(title, title_observer.title_on_start());
308   EXPECT_EQ(title, title_observer.title_on_commit());
309   EXPECT_EQ(title, web_contents()->GetTitle());
310 }
311 
312 class SearchTabHelperWindowTest : public BrowserWithTestWindowTest {
313  protected:
SetUp()314   virtual void SetUp() OVERRIDE {
315     BrowserWithTestWindowTest::SetUp();
316     TemplateURLServiceFactory::GetInstance()->SetTestingFactoryAndUse(
317         profile(), &TemplateURLServiceFactory::BuildInstanceFor);
318     TemplateURLService* template_url_service =
319         TemplateURLServiceFactory::GetForProfile(profile());
320     ui_test_utils::WaitForTemplateURLServiceToLoad(template_url_service);
321 
322     TemplateURLData data;
323     data.SetURL("http://foo.com/url?bar={searchTerms}");
324     data.instant_url = "http://foo.com/instant?"
325         "{google:omniboxStartMarginParameter}{google:forceInstantResults}"
326         "foo=foo#foo=foo&strk";
327     data.new_tab_url = std::string("https://foo.com/newtab?strk");
328     data.alternate_urls.push_back("http://foo.com/alt#quux={searchTerms}");
329     data.search_terms_replacement_key = "strk";
330 
331     TemplateURL* template_url = new TemplateURL(data);
332     template_url_service->Add(template_url);
333     template_url_service->SetUserSelectedDefaultSearchProvider(template_url);
334   }
335 };
336 
TEST_F(SearchTabHelperWindowTest,OnProvisionalLoadFailRedirectNTPToLocal)337 TEST_F(SearchTabHelperWindowTest, OnProvisionalLoadFailRedirectNTPToLocal) {
338   AddTab(browser(), GURL(chrome::kChromeUINewTabURL));
339   content::WebContents* contents =
340         browser()->tab_strip_model()->GetWebContentsAt(0);
341   content::NavigationController* controller = &contents->GetController();
342 
343   SearchTabHelper* search_tab_helper =
344       SearchTabHelper::FromWebContents(contents);
345   ASSERT_NE(static_cast<SearchTabHelper*>(NULL), search_tab_helper);
346 
347   // A failed provisional load of a cacheable NTP should be redirected to local
348   // NTP.
349   const GURL cacheableNTPURL = chrome::GetNewTabPageURL(profile());
350   search_tab_helper->DidFailProvisionalLoad(1, base::string16(), true,
351       cacheableNTPURL, 1, base::string16(), NULL);
352   CommitPendingLoad(controller);
353   EXPECT_EQ(GURL(chrome::kChromeSearchLocalNtpUrl),
354                  controller->GetLastCommittedEntry()->GetURL());
355 }
356 
TEST_F(SearchTabHelperWindowTest,OnProvisionalLoadFailDontRedirectIfAborted)357 TEST_F(SearchTabHelperWindowTest, OnProvisionalLoadFailDontRedirectIfAborted) {
358   AddTab(browser(), GURL("chrome://blank"));
359   content::WebContents* contents =
360         browser()->tab_strip_model()->GetWebContentsAt(0);
361   content::NavigationController* controller = &contents->GetController();
362 
363   SearchTabHelper* search_tab_helper =
364       SearchTabHelper::FromWebContents(contents);
365   ASSERT_NE(static_cast<SearchTabHelper*>(NULL), search_tab_helper);
366 
367   // A failed provisional load of a cacheable NTP should be redirected to local
368   // NTP.
369   const GURL cacheableNTPURL = chrome::GetNewTabPageURL(profile());
370   search_tab_helper->DidFailProvisionalLoad(1, base::string16(), true,
371       cacheableNTPURL, net::ERR_ABORTED, base::string16(), NULL);
372   CommitPendingLoad(controller);
373   EXPECT_EQ(GURL("chrome://blank"),
374                  controller->GetLastCommittedEntry()->GetURL());
375 }
376 
TEST_F(SearchTabHelperWindowTest,OnProvisionalLoadFailDontRedirectNonNTP)377 TEST_F(SearchTabHelperWindowTest, OnProvisionalLoadFailDontRedirectNonNTP) {
378   AddTab(browser(), GURL(chrome::kChromeUINewTabURL));
379   content::WebContents* contents =
380         browser()->tab_strip_model()->GetWebContentsAt(0);
381   content::NavigationController* controller = &contents->GetController();
382 
383   SearchTabHelper* search_tab_helper =
384       SearchTabHelper::FromWebContents(contents);
385   ASSERT_NE(static_cast<SearchTabHelper*>(NULL), search_tab_helper);
386 
387   // Any other web page shouldn't be redirected when provisional load fails.
388   search_tab_helper->DidFailProvisionalLoad(1, base::string16(), true,
389       GURL("http://www.example.com"), 1, base::string16(), NULL);
390   CommitPendingLoad(controller);
391   EXPECT_NE(GURL(chrome::kChromeSearchLocalNtpUrl),
392                  controller->GetLastCommittedEntry()->GetURL());
393 }
394