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/instant_page.h"
      6 
      7 #include "base/command_line.h"
      8 #include "base/memory/scoped_ptr.h"
      9 #include "chrome/browser/ui/search/search_tab_helper.h"
     10 #include "chrome/common/chrome_switches.h"
     11 #include "chrome/common/render_messages.h"
     12 #include "chrome/common/url_constants.h"
     13 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
     14 #include "content/public/browser/navigation_controller.h"
     15 #include "content/public/browser/navigation_entry.h"
     16 #include "content/public/browser/web_contents.h"
     17 #include "content/public/test/mock_render_process_host.h"
     18 #include "ipc/ipc_test_sink.h"
     19 #include "testing/gmock/include/gmock/gmock.h"
     20 #include "testing/gtest/include/gtest/gtest.h"
     21 #include "url/gurl.h"
     22 
     23 class Profile;
     24 
     25 namespace {
     26 
     27 class FakePageDelegate : public InstantPage::Delegate {
     28  public:
     29   virtual ~FakePageDelegate() {
     30   }
     31 
     32   MOCK_METHOD2(InstantSupportDetermined,
     33                void(const content::WebContents* contents,
     34                     bool supports_instant));
     35   MOCK_METHOD1(InstantPageRenderProcessGone,
     36                void(const content::WebContents* contents));
     37   MOCK_METHOD2(InstantPageAboutToNavigateMainFrame,
     38                void(const content::WebContents* contents,
     39                     const GURL& url));
     40   MOCK_METHOD2(FocusOmnibox,
     41                void(const content::WebContents* contents,
     42                     OmniboxFocusState state));
     43   MOCK_METHOD5(NavigateToURL,
     44                void(const content::WebContents* contents,
     45                     const GURL& url,
     46                     content::PageTransition transition,
     47                     WindowOpenDisposition disposition,
     48                     bool is_search_type));
     49   MOCK_METHOD2(PasteIntoOmnibox,
     50                void(const content::WebContents* contents,
     51                     const string16& text));
     52   MOCK_METHOD1(DeleteMostVisitedItem, void(const GURL& url));
     53   MOCK_METHOD1(UndoMostVisitedDeletion, void(const GURL& url));
     54   MOCK_METHOD0(UndoAllMostVisitedDeletions, void());
     55   MOCK_METHOD1(InstantPageLoadFailed, void(content::WebContents* contents));
     56 };
     57 
     58 class FakePage : public InstantPage {
     59  public:
     60   FakePage(Delegate* delegate, const std::string& instant_url,
     61            Profile* profile, bool is_incognito);
     62   virtual ~FakePage();
     63 
     64   // InstantPage overrride.
     65   virtual bool ShouldProcessDeleteMostVisitedItem() OVERRIDE;
     66   virtual bool ShouldProcessUndoMostVisitedDeletion() OVERRIDE;
     67   virtual bool ShouldProcessUndoAllMostVisitedDeletions() OVERRIDE;
     68 
     69   void set_should_handle_messages(bool should_handle_messages);
     70 
     71   using InstantPage::SetContents;
     72 
     73  private:
     74   // Initialized to true to handle the messages sent by the renderer.
     75   bool should_handle_messages_;
     76 
     77   DISALLOW_COPY_AND_ASSIGN(FakePage);
     78 };
     79 
     80 FakePage::FakePage(Delegate* delegate, const std::string& instant_url,
     81                    Profile* profile, bool is_incognito)
     82     : InstantPage(delegate, instant_url, profile, is_incognito),
     83       should_handle_messages_(true) {
     84 }
     85 
     86 FakePage::~FakePage() {
     87 }
     88 
     89 bool FakePage::ShouldProcessDeleteMostVisitedItem() {
     90   return should_handle_messages_;
     91 }
     92 
     93 bool FakePage::ShouldProcessUndoMostVisitedDeletion() {
     94   return should_handle_messages_;
     95 }
     96 
     97 bool FakePage::ShouldProcessUndoAllMostVisitedDeletions() {
     98   return should_handle_messages_;
     99 }
    100 
    101 void FakePage::set_should_handle_messages(bool should_handle_messages) {
    102   should_handle_messages_ = should_handle_messages;
    103 }
    104 
    105 }  // namespace
    106 
    107 class InstantPageTest : public ChromeRenderViewHostTestHarness {
    108  public:
    109   virtual void SetUp() OVERRIDE;
    110 
    111   bool MessageWasSent(uint32 id) {
    112     return process()->sink().GetFirstMessageMatching(id) != NULL;
    113   }
    114 
    115   scoped_ptr<FakePage> page;
    116   FakePageDelegate delegate;
    117 };
    118 
    119 void InstantPageTest::SetUp() {
    120   CommandLine::ForCurrentProcess()->AppendSwitch(
    121       switches::kEnableInstantExtendedAPI);
    122   ChromeRenderViewHostTestHarness::SetUp();
    123   SearchTabHelper::CreateForWebContents(web_contents());
    124 }
    125 
    126 TEST_F(InstantPageTest, IsLocal) {
    127   page.reset(new FakePage(&delegate, "", NULL, false));
    128   EXPECT_FALSE(page->supports_instant());
    129   EXPECT_FALSE(page->IsLocal());
    130   page->SetContents(web_contents());
    131   NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl));
    132   EXPECT_TRUE(page->IsLocal());
    133   NavigateAndCommit(GURL("http://example.com"));
    134   EXPECT_FALSE(page->IsLocal());
    135 }
    136 
    137 TEST_F(InstantPageTest, DetermineIfPageSupportsInstant_Local) {
    138   page.reset(new FakePage(&delegate, "", NULL, false));
    139   EXPECT_FALSE(page->supports_instant());
    140   page->SetContents(web_contents());
    141   NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl));
    142   EXPECT_TRUE(page->IsLocal());
    143   EXPECT_CALL(delegate, InstantSupportDetermined(web_contents(), true))
    144       .Times(1);
    145   SearchTabHelper::FromWebContents(web_contents())->
    146       DetermineIfPageSupportsInstant();
    147   EXPECT_TRUE(page->supports_instant());
    148 }
    149 
    150 TEST_F(InstantPageTest, DetermineIfPageSupportsInstant_NonLocal) {
    151   page.reset(new FakePage(&delegate, "", NULL, false));
    152   EXPECT_FALSE(page->supports_instant());
    153   page->SetContents(web_contents());
    154   NavigateAndCommit(GURL("chrome-search://foo/bar"));
    155   EXPECT_FALSE(page->IsLocal());
    156   process()->sink().ClearMessages();
    157   SearchTabHelper::FromWebContents(web_contents())->
    158       DetermineIfPageSupportsInstant();
    159   const IPC::Message* message = process()->sink().GetFirstMessageMatching(
    160       ChromeViewMsg_DetermineIfPageSupportsInstant::ID);
    161   ASSERT_TRUE(message != NULL);
    162   EXPECT_EQ(web_contents()->GetRoutingID(), message->routing_id());
    163 }
    164 
    165 TEST_F(InstantPageTest, DispatchRequestToDeleteMostVisitedItem) {
    166   page.reset(new FakePage(&delegate, "", NULL, false));
    167   page->SetContents(web_contents());
    168   NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl));
    169   GURL item_url("www.foo.com");
    170   int page_id = web_contents()->GetController().GetActiveEntry()->GetPageID();
    171   EXPECT_CALL(delegate, DeleteMostVisitedItem(item_url)).Times(1);
    172   EXPECT_TRUE(page->OnMessageReceived(
    173       ChromeViewHostMsg_SearchBoxDeleteMostVisitedItem(rvh()->GetRoutingID(),
    174                                                        page_id, item_url)));
    175 }
    176 
    177 TEST_F(InstantPageTest, DispatchRequestToUndoMostVisitedDeletion) {
    178   page.reset(new FakePage(&delegate, "", NULL, false));
    179   page->SetContents(web_contents());
    180   NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl));
    181   GURL item_url("www.foo.com");
    182   int page_id = web_contents()->GetController().GetActiveEntry()->GetPageID();
    183   EXPECT_CALL(delegate, UndoMostVisitedDeletion(item_url)).Times(1);
    184   EXPECT_TRUE(page->OnMessageReceived(
    185       ChromeViewHostMsg_SearchBoxUndoMostVisitedDeletion(rvh()->GetRoutingID(),
    186                                                          page_id, item_url)));
    187 }
    188 
    189 TEST_F(InstantPageTest, DispatchRequestToUndoAllMostVisitedDeletions) {
    190   page.reset(new FakePage(&delegate, "", NULL, false));
    191   page->SetContents(web_contents());
    192   NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl));
    193   int page_id = web_contents()->GetController().GetActiveEntry()->GetPageID();
    194   EXPECT_CALL(delegate, UndoAllMostVisitedDeletions()).Times(1);
    195   EXPECT_TRUE(page->OnMessageReceived(
    196       ChromeViewHostMsg_SearchBoxUndoAllMostVisitedDeletions(
    197           rvh()->GetRoutingID(), page_id)));
    198 }
    199 
    200 TEST_F(InstantPageTest, IgnoreMessageReceivedFromIncognitoPage) {
    201   page.reset(new FakePage(&delegate, "", NULL, true));
    202   page->SetContents(web_contents());
    203   NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl));
    204   GURL item_url("www.foo.com");
    205   int page_id = web_contents()->GetController().GetActiveEntry()->GetPageID();
    206 
    207   EXPECT_CALL(delegate, DeleteMostVisitedItem(item_url)).Times(0);
    208   EXPECT_FALSE(page->OnMessageReceived(
    209       ChromeViewHostMsg_SearchBoxDeleteMostVisitedItem(rvh()->GetRoutingID(),
    210                                                        page_id,
    211                                                        item_url)));
    212 
    213   EXPECT_CALL(delegate, UndoMostVisitedDeletion(item_url)).Times(0);
    214   EXPECT_FALSE(page->OnMessageReceived(
    215       ChromeViewHostMsg_SearchBoxUndoMostVisitedDeletion(rvh()->GetRoutingID(),
    216                                                          page_id,
    217                                                          item_url)));
    218 
    219   EXPECT_CALL(delegate, UndoAllMostVisitedDeletions()).Times(0);
    220   EXPECT_FALSE(page->OnMessageReceived(
    221       ChromeViewHostMsg_SearchBoxUndoAllMostVisitedDeletions(
    222           rvh()->GetRoutingID(), page_id)));
    223 }
    224 
    225 TEST_F(InstantPageTest, IgnoreMessageIfThePageIsNotActive) {
    226   page.reset(new FakePage(&delegate, "", NULL, false));
    227   page->SetContents(web_contents());
    228   NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl));
    229   GURL item_url("www.foo.com");
    230   int inactive_page_id = 1999;
    231 
    232   EXPECT_CALL(delegate, DeleteMostVisitedItem(item_url)).Times(0);
    233   EXPECT_TRUE(page->OnMessageReceived(
    234       ChromeViewHostMsg_SearchBoxDeleteMostVisitedItem(rvh()->GetRoutingID(),
    235                                                        inactive_page_id,
    236                                                        item_url)));
    237 
    238   EXPECT_CALL(delegate, UndoMostVisitedDeletion(item_url)).Times(0);
    239   EXPECT_TRUE(page->OnMessageReceived(
    240       ChromeViewHostMsg_SearchBoxUndoMostVisitedDeletion(rvh()->GetRoutingID(),
    241                                                          inactive_page_id,
    242                                                          item_url)));
    243 
    244   EXPECT_CALL(delegate, UndoAllMostVisitedDeletions()).Times(0);
    245   EXPECT_TRUE(page->OnMessageReceived(
    246       ChromeViewHostMsg_SearchBoxUndoAllMostVisitedDeletions(
    247           rvh()->GetRoutingID(), inactive_page_id)));
    248 }
    249 
    250 TEST_F(InstantPageTest, IgnoreMessageReceivedFromThePage) {
    251   page.reset(new FakePage(&delegate, "", NULL, false));
    252   page->SetContents(web_contents());
    253 
    254   // Ignore the messages received from the page.
    255   page->set_should_handle_messages(false);
    256   NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl));
    257   GURL item_url("www.foo.com");
    258   int page_id = web_contents()->GetController().GetActiveEntry()->GetPageID();
    259 
    260   EXPECT_CALL(delegate, DeleteMostVisitedItem(item_url)).Times(0);
    261   EXPECT_TRUE(page->OnMessageReceived(
    262       ChromeViewHostMsg_SearchBoxDeleteMostVisitedItem(rvh()->GetRoutingID(),
    263                                                        page_id, item_url)));
    264 
    265   EXPECT_CALL(delegate, UndoMostVisitedDeletion(item_url)).Times(0);
    266   EXPECT_TRUE(page->OnMessageReceived(
    267       ChromeViewHostMsg_SearchBoxUndoMostVisitedDeletion(rvh()->GetRoutingID(),
    268                                                          page_id, item_url)));
    269 
    270   EXPECT_CALL(delegate, UndoAllMostVisitedDeletions()).Times(0);
    271   EXPECT_TRUE(page->OnMessageReceived(
    272       ChromeViewHostMsg_SearchBoxUndoAllMostVisitedDeletions(
    273           rvh()->GetRoutingID(), page_id)));
    274 }
    275 
    276 TEST_F(InstantPageTest, PageURLDoesntBelongToInstantRenderer) {
    277   page.reset(new FakePage(&delegate, "", NULL, false));
    278   EXPECT_FALSE(page->supports_instant());
    279   NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl));
    280   page->SetContents(web_contents());
    281 
    282   // Navigate to a page URL that doesn't belong to Instant renderer.
    283   // SearchTabHelper::DeterminerIfPageSupportsInstant() should return
    284   // immediately without dispatching any message to the renderer.
    285   NavigateAndCommit(GURL("http://www.example.com"));
    286   EXPECT_FALSE(page->IsLocal());
    287   process()->sink().ClearMessages();
    288   EXPECT_CALL(delegate, InstantSupportDetermined(web_contents(), false))
    289       .Times(1);
    290 
    291   SearchTabHelper::FromWebContents(web_contents())->
    292       DetermineIfPageSupportsInstant();
    293   const IPC::Message* message = process()->sink().GetFirstMessageMatching(
    294       ChromeViewMsg_DetermineIfPageSupportsInstant::ID);
    295   ASSERT_TRUE(message == NULL);
    296   EXPECT_FALSE(page->supports_instant());
    297 }
    298 
    299 // Test to verify that ChromeViewMsg_DetermineIfPageSupportsInstant message
    300 // reply handler updates the instant support state in InstantPage.
    301 TEST_F(InstantPageTest, PageSupportsInstant) {
    302   page.reset(new FakePage(&delegate, "", NULL, false));
    303   EXPECT_FALSE(page->supports_instant());
    304   page->SetContents(web_contents());
    305   NavigateAndCommit(GURL("chrome-search://foo/bar"));
    306   process()->sink().ClearMessages();
    307   SearchTabHelper::FromWebContents(web_contents())->
    308       DetermineIfPageSupportsInstant();
    309   const IPC::Message* message = process()->sink().GetFirstMessageMatching(
    310       ChromeViewMsg_DetermineIfPageSupportsInstant::ID);
    311   ASSERT_TRUE(message != NULL);
    312   EXPECT_EQ(web_contents()->GetRoutingID(), message->routing_id());
    313 
    314   EXPECT_CALL(delegate, InstantSupportDetermined(web_contents(), true))
    315       .Times(1);
    316 
    317   // Assume the page supports instant. Invoke the message reply handler to make
    318   // sure the InstantPage is notified about the instant support state.
    319   const content::NavigationEntry* entry =
    320       web_contents()->GetController().GetActiveEntry();
    321   EXPECT_TRUE(entry);
    322   SearchTabHelper::FromWebContents(web_contents())->
    323       OnInstantSupportDetermined(entry->GetPageID(), true);
    324   EXPECT_TRUE(page->supports_instant());
    325 }
    326 
    327 TEST_F(InstantPageTest, AppropriateMessagesSentToIncognitoPages) {
    328   page.reset(new FakePage(&delegate, "", NULL, true));
    329   page->SetContents(web_contents());
    330   NavigateAndCommit(GURL(chrome::kChromeSearchLocalNtpUrl));
    331   process()->sink().ClearMessages();
    332 
    333   // Incognito pages should get these messages.
    334   page->sender()->Submit(string16());
    335   EXPECT_TRUE(MessageWasSent(ChromeViewMsg_SearchBoxSubmit::ID));
    336   page->sender()->SetOmniboxBounds(gfx::Rect());
    337   EXPECT_TRUE(MessageWasSent(ChromeViewMsg_SearchBoxMarginChange::ID));
    338   page->sender()->ToggleVoiceSearch();
    339   EXPECT_TRUE(MessageWasSent(ChromeViewMsg_SearchBoxToggleVoiceSearch::ID));
    340 
    341   // Incognito pages should not get any others.
    342   page->sender()->SetFontInformation(string16(), 0);
    343   EXPECT_FALSE(MessageWasSent(ChromeViewMsg_SearchBoxFontInformation::ID));
    344 
    345   page->sender()->SendThemeBackgroundInfo(ThemeBackgroundInfo());
    346   EXPECT_FALSE(MessageWasSent(ChromeViewMsg_SearchBoxThemeChanged::ID));
    347 
    348   page->sender()->FocusChanged(
    349       OMNIBOX_FOCUS_NONE, OMNIBOX_FOCUS_CHANGE_EXPLICIT);
    350   EXPECT_FALSE(MessageWasSent(ChromeViewMsg_SearchBoxFocusChanged::ID));
    351 
    352   page->sender()->SetInputInProgress(false);
    353   EXPECT_FALSE(MessageWasSent(ChromeViewMsg_SearchBoxSetInputInProgress::ID));
    354 
    355   page->sender()->SendMostVisitedItems(std::vector<InstantMostVisitedItem>());
    356   EXPECT_FALSE(MessageWasSent(
    357       ChromeViewMsg_SearchBoxMostVisitedItemsChanged::ID));
    358 }
    359