Home | History | Annotate | Download | only in search
      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/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"
     37 #include "url/gurl.h"
     38 
     39 namespace {
     40 
     41 class MockSearchIPCRouterDelegate : public SearchIPCRouter::Delegate {
     42  public:
     43   virtual ~MockSearchIPCRouterDelegate() {}
     44 
     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));
     57 };
     58 
     59 }  // namespace
     60 
     61 class SearchTabHelperTest : public ChromeRenderViewHostTestHarness {
     62  public:
     63   virtual void SetUp() {
     64     ChromeRenderViewHostTestHarness::SetUp();
     65     SearchTabHelper::CreateForWebContents(web_contents());
     66   }
     67 
     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);
     75 
     76     if (!username.empty()) {
     77       ASSERT_TRUE(signin_manager);
     78       signin_manager->SetAuthenticatedUsername(username);
     79     }
     80   }
     81 
     82   bool MessageWasSent(uint32 id) {
     83     return process()->sink().GetFirstMessageMatching(id) != NULL;
     84   }
     85 
     86   MockSearchIPCRouterDelegate* mock_delegate() { return &delegate_; }
     87 
     88  private:
     89   MockSearchIPCRouterDelegate delegate_;
     90 };
     91 
     92 TEST_F(SearchTabHelperTest, DetermineIfPageSupportsInstant_Local) {
     93   NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl));
     94   EXPECT_CALL(*mock_delegate(), OnInstantSupportDetermined(true)).Times(0);
     95 
     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();
    101 }
    102 
    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);
    107 
    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));
    114 
    115   scoped_ptr<IPC::Message> response(
    116       new ChromeViewHostMsg_InstantSupportDetermined(
    117           web_contents()->GetRoutingID(),
    118           web_contents()->GetController().GetVisibleEntry()->GetPageID(),
    119           true));
    120   search_tab_helper->ipc_router().OnMessageReceived(*response);
    121 }
    122 
    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);
    130 
    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));
    138 }
    139 
    140 TEST_F(SearchTabHelperTest, OnChromeIdentityCheckMatch) {
    141   NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl));
    142   CreateSigninManager(std::string("foo (at) bar.com"));
    143   SearchTabHelper* search_tab_helper =
    144       SearchTabHelper::FromWebContents(web_contents());
    145   ASSERT_NE(static_cast<SearchTabHelper*>(NULL), search_tab_helper);
    146 
    147   const base::string16 test_identity = ASCIIToUTF16("foo (at) bar.com");
    148   search_tab_helper->OnChromeIdentityCheck(test_identity);
    149 
    150   const IPC::Message* message = process()->sink().GetUniqueMessageMatching(
    151       ChromeViewMsg_ChromeIdentityCheckResult::ID);
    152   ASSERT_TRUE(message != NULL);
    153 
    154   ChromeViewMsg_ChromeIdentityCheckResult::Param params;
    155   ChromeViewMsg_ChromeIdentityCheckResult::Read(message, &params);
    156   EXPECT_EQ(test_identity, params.a);
    157   ASSERT_TRUE(params.b);
    158 }
    159 
    160 TEST_F(SearchTabHelperTest, OnChromeIdentityCheckMismatch) {
    161   NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl));
    162   CreateSigninManager(std::string("foo (at) bar.com"));
    163   SearchTabHelper* search_tab_helper =
    164       SearchTabHelper::FromWebContents(web_contents());
    165   ASSERT_NE(static_cast<SearchTabHelper*>(NULL), search_tab_helper);
    166 
    167   const base::string16 test_identity = ASCIIToUTF16("bar (at) foo.com");
    168   search_tab_helper->OnChromeIdentityCheck(test_identity);
    169 
    170   const IPC::Message* message = process()->sink().GetUniqueMessageMatching(
    171       ChromeViewMsg_ChromeIdentityCheckResult::ID);
    172   ASSERT_TRUE(message != NULL);
    173 
    174   ChromeViewMsg_ChromeIdentityCheckResult::Param params;
    175   ChromeViewMsg_ChromeIdentityCheckResult::Read(message, &params);
    176   EXPECT_EQ(test_identity, params.a);
    177   ASSERT_FALSE(params.b);
    178 }
    179 
    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);
    186 
    187   const base::string16 test_identity;
    188   search_tab_helper->OnChromeIdentityCheck(test_identity);
    189 
    190   const IPC::Message* message = process()->sink().GetUniqueMessageMatching(
    191       ChromeViewMsg_ChromeIdentityCheckResult::ID);
    192   ASSERT_TRUE(message != NULL);
    193 
    194   ChromeViewMsg_ChromeIdentityCheckResult::Param params;
    195   ChromeViewMsg_ChromeIdentityCheckResult::Read(message, &params);
    196   EXPECT_EQ(test_identity, params.a);
    197   ASSERT_TRUE(params.b);
    198 }
    199 
    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);
    206 
    207   const base::string16 test_identity = ASCIIToUTF16("bar (at) foo.com");
    208   search_tab_helper->OnChromeIdentityCheck(test_identity);
    209 
    210   const IPC::Message* message = process()->sink().GetUniqueMessageMatching(
    211       ChromeViewMsg_ChromeIdentityCheckResult::ID);
    212   ASSERT_TRUE(message != NULL);
    213 
    214   ChromeViewMsg_ChromeIdentityCheckResult::Param params;
    215   ChromeViewMsg_ChromeIdentityCheckResult::Read(message, &params);
    216   EXPECT_EQ(test_identity, params.a);
    217   ASSERT_FALSE(params.b);
    218 }
    219 
    220 class TabTitleObserver : public content::WebContentsObserver {
    221  public:
    222   explicit TabTitleObserver(content::WebContents* contents)
    223       : WebContentsObserver(contents) {}
    224 
    225   base::string16 title_on_start() { return title_on_start_; }
    226   base::string16 title_on_commit() { return title_on_commit_; }
    227 
    228  private:
    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();
    238   }
    239 
    240   virtual void DidNavigateMainFrame(
    241       const content::LoadCommittedDetails& /* details */,
    242       const content::FrameNavigateParams& /* params */) OVERRIDE {
    243     title_on_commit_ = web_contents()->GetTitle();
    244   }
    245 
    246   base::string16 title_on_start_;
    247   base::string16 title_on_commit_;
    248 };
    249 
    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());
    257 }
    258 
    259 class SearchTabHelperWindowTest : public BrowserWithTestWindowTest {
    260  protected:
    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);
    268 
    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";
    277 
    278     TemplateURL* template_url = new TemplateURL(profile(), data);
    279     template_url_service->Add(template_url);
    280     template_url_service->SetDefaultSearchProvider(template_url);
    281   }
    282 };
    283 
    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();
    289 
    290   SearchTabHelper* search_tab_helper =
    291       SearchTabHelper::FromWebContents(contents);
    292   ASSERT_NE(static_cast<SearchTabHelper*>(NULL), search_tab_helper);
    293 
    294   // A failed provisional load of a cacheable NTP should be redirected to local
    295   // NTP.
    296   const GURL cacheableNTPURL = chrome::GetNewTabPageURL(profile());
    297   search_tab_helper->DidFailProvisionalLoad(1, string16(), true,
    298       cacheableNTPURL, 1, string16(), NULL);
    299   CommitPendingLoad(controller);
    300   EXPECT_EQ(GURL(chrome::kChromeSearchLocalNtpUrl),
    301                  controller->GetLastCommittedEntry()->GetURL());
    302 }
    303 
    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();
    309 
    310   SearchTabHelper* search_tab_helper =
    311       SearchTabHelper::FromWebContents(contents);
    312   ASSERT_NE(static_cast<SearchTabHelper*>(NULL), search_tab_helper);
    313 
    314   // A failed provisional load of a cacheable NTP should be redirected to local
    315   // NTP.
    316   const GURL cacheableNTPURL = chrome::GetNewTabPageURL(profile());
    317   search_tab_helper->DidFailProvisionalLoad(1, string16(), true,
    318       cacheableNTPURL, net::ERR_ABORTED, string16(), NULL);
    319   CommitPendingLoad(controller);
    320   EXPECT_EQ(GURL("chrome://blank"),
    321                  controller->GetLastCommittedEntry()->GetURL());
    322 }
    323 
    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();
    329 
    330   SearchTabHelper* search_tab_helper =
    331       SearchTabHelper::FromWebContents(contents);
    332   ASSERT_NE(static_cast<SearchTabHelper*>(NULL), search_tab_helper);
    333 
    334   // Any other web page shouldn't be redirected when provisional load fails.
    335   search_tab_helper->DidFailProvisionalLoad(1, string16(), true,
    336       GURL("http://www.example.com"), 1, string16(), NULL);
    337   CommitPendingLoad(controller);
    338   EXPECT_NE(GURL(chrome::kChromeSearchLocalNtpUrl),
    339                  controller->GetLastCommittedEntry()->GetURL());
    340 }
    341