Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / search / instant_search_prerenderer_unittest.cc
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_search_prerenderer.h"
6
7 #include "base/basictypes.h"
8 #include "base/compiler_specific.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/metrics/field_trial.h"
11 #include "base/strings/string16.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "chrome/browser/autocomplete/autocomplete_match.h"
14 #include "chrome/browser/prerender/prerender_contents.h"
15 #include "chrome/browser/prerender/prerender_handle.h"
16 #include "chrome/browser/prerender/prerender_manager.h"
17 #include "chrome/browser/prerender/prerender_manager_factory.h"
18 #include "chrome/browser/prerender/prerender_origin.h"
19 #include "chrome/browser/prerender/prerender_tab_helper.h"
20 #include "chrome/browser/prerender/prerender_tracker.h"
21 #include "chrome/browser/profiles/profile.h"
22 #include "chrome/browser/search/instant_service.h"
23 #include "chrome/browser/search/instant_unittest_base.h"
24 #include "chrome/browser/search/search.h"
25 #include "chrome/browser/ui/search/search_tab_helper.h"
26 #include "chrome/browser/ui/tabs/tab_strip_model.h"
27 #include "chrome/common/render_messages.h"
28 #include "content/public/browser/navigation_controller.h"
29 #include "content/public/browser/web_contents.h"
30 #include "content/public/common/url_constants.h"
31 #include "content/public/test/mock_render_process_host.h"
32 #include "ipc/ipc_message.h"
33 #include "ipc/ipc_test_sink.h"
34 #include "ui/gfx/size.h"
35
36 using base::ASCIIToUTF16;
37
38 namespace {
39
40 using content::Referrer;
41 using prerender::Origin;
42 using prerender::PrerenderContents;
43 using prerender::PrerenderHandle;
44 using prerender::PrerenderManager;
45 using prerender::PrerenderManagerFactory;
46 using prerender::PrerenderTabHelper;
47
48 class DummyPrerenderContents : public PrerenderContents {
49  public:
50   DummyPrerenderContents(
51       PrerenderManager* prerender_manager,
52       Profile* profile,
53       const GURL& url,
54       const Referrer& referrer,
55       Origin origin,
56       bool call_did_finish_load,
57       const content::SessionStorageNamespaceMap& session_storage_namespace_map);
58
59   virtual void StartPrerendering(
60       int ALLOW_UNUSED creator_child_id,
61       const gfx::Size& ALLOW_UNUSED size,
62       content::SessionStorageNamespace* session_storage_namespace) OVERRIDE;
63   virtual bool GetChildId(int* child_id) const OVERRIDE;
64   virtual bool GetRouteId(int* route_id) const OVERRIDE;
65
66  private:
67   Profile* profile_;
68   const GURL url_;
69   bool call_did_finish_load_;
70   content::SessionStorageNamespaceMap session_storage_namespace_map_;
71
72   DISALLOW_COPY_AND_ASSIGN(DummyPrerenderContents);
73 };
74
75 class DummyPrerenderContentsFactory : public PrerenderContents::Factory {
76  public:
77   DummyPrerenderContentsFactory(
78       bool call_did_finish_load,
79       const content::SessionStorageNamespaceMap& session_storage_namespace_map)
80       : call_did_finish_load_(call_did_finish_load),
81         session_storage_namespace_map_(session_storage_namespace_map) {
82   }
83
84   virtual PrerenderContents* CreatePrerenderContents(
85       PrerenderManager* prerender_manager,
86       Profile* profile,
87       const GURL& url,
88       const Referrer& referrer,
89       Origin origin,
90       uint8 experiment_id) OVERRIDE;
91
92  private:
93   bool call_did_finish_load_;
94   content::SessionStorageNamespaceMap session_storage_namespace_map_;
95
96   DISALLOW_COPY_AND_ASSIGN(DummyPrerenderContentsFactory);
97 };
98
99 DummyPrerenderContents::DummyPrerenderContents(
100     PrerenderManager* prerender_manager,
101     Profile* profile,
102     const GURL& url,
103     const Referrer& referrer,
104     Origin origin,
105     bool call_did_finish_load,
106     const content::SessionStorageNamespaceMap& session_storage_namespace_map)
107     : PrerenderContents(prerender_manager, profile, url, referrer, origin,
108                         PrerenderManager::kNoExperiment),
109       profile_(profile),
110       url_(url),
111       call_did_finish_load_(call_did_finish_load),
112       session_storage_namespace_map_(session_storage_namespace_map) {
113 }
114
115 void DummyPrerenderContents::StartPrerendering(
116     int ALLOW_UNUSED creator_child_id,
117     const gfx::Size& ALLOW_UNUSED size,
118     content::SessionStorageNamespace* session_storage_namespace) {
119   prerender_contents_.reset(content::WebContents::CreateWithSessionStorage(
120       content::WebContents::CreateParams(profile_),
121       session_storage_namespace_map_));
122   PrerenderTabHelper::CreateForWebContentsWithPasswordManager(
123       prerender_contents_.get(), NULL);
124   content::NavigationController::LoadURLParams params(url_);
125   prerender_contents_->GetController().LoadURLWithParams(params);
126   SearchTabHelper::CreateForWebContents(prerender_contents_.get());
127
128   prerendering_has_started_ = true;
129   DCHECK(session_storage_namespace);
130   session_storage_namespace_id_ = session_storage_namespace->id();
131   NotifyPrerenderStart();
132
133   if (call_did_finish_load_)
134     DidFinishLoad(1, url_, true, NULL);
135 }
136
137 bool DummyPrerenderContents::GetChildId(int* child_id) const {
138   *child_id = 1;
139   return true;
140 }
141
142 bool DummyPrerenderContents::GetRouteId(int* route_id) const {
143   *route_id = 1;
144   return true;
145 }
146
147 PrerenderContents* DummyPrerenderContentsFactory::CreatePrerenderContents(
148     PrerenderManager* prerender_manager,
149     Profile* profile,
150     const GURL& url,
151     const Referrer& referrer,
152     Origin origin,
153     uint8 experiment_id) {
154   return new DummyPrerenderContents(prerender_manager, profile, url, referrer,
155                                     origin, call_did_finish_load_,
156                                     session_storage_namespace_map_);
157 }
158
159 }  // namespace
160
161 class InstantSearchPrerendererTest : public InstantUnitTestBase {
162  public:
163   InstantSearchPrerendererTest() {}
164
165  protected:
166   virtual void SetUp() OVERRIDE {
167     ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
168         "EmbeddedSearch", "Group1 strk:20 prefetch_results:1"));
169     InstantUnitTestBase::SetUp();
170   }
171
172   void Init(bool prerender_search_results_base_page,
173             bool call_did_finish_load) {
174     AddTab(browser(), GURL(content::kAboutBlankURL));
175
176     content::SessionStorageNamespaceMap session_storage_namespace_map;
177     session_storage_namespace_map[std::string()] =
178         GetActiveWebContents()->GetController().
179             GetDefaultSessionStorageNamespace();
180     PrerenderManagerFactory::GetForProfile(browser()->profile())->
181         SetPrerenderContentsFactory(
182             new DummyPrerenderContentsFactory(call_did_finish_load,
183                                               session_storage_namespace_map));
184
185     if (prerender_search_results_base_page) {
186       InstantSearchPrerenderer* prerenderer = GetInstantSearchPrerenderer();
187       prerenderer->Init(session_storage_namespace_map, gfx::Size(640, 480));
188       EXPECT_NE(static_cast<PrerenderHandle*>(NULL), prerender_handle());
189     }
190   }
191
192   InstantSearchPrerenderer* GetInstantSearchPrerenderer() {
193     return instant_service_->instant_search_prerenderer();
194   }
195
196   const GURL& GetPrerenderURL() {
197     return GetInstantSearchPrerenderer()->prerender_url_;
198   }
199
200   void SetLastQuery(const base::string16& query) {
201     GetInstantSearchPrerenderer()->last_instant_suggestion_ =
202         InstantSuggestion(query, std::string());
203   }
204
205   content::WebContents* prerender_contents() {
206     return GetInstantSearchPrerenderer()->prerender_contents();
207   }
208
209   bool MessageWasSent(uint32 id) {
210     content::MockRenderProcessHost* process =
211         static_cast<content::MockRenderProcessHost*>(
212             prerender_contents()->GetRenderViewHost()->GetProcess());
213     return process->sink().GetFirstMessageMatching(id) != NULL;
214   }
215
216   content::WebContents* GetActiveWebContents() const {
217     return browser()->tab_strip_model()->GetWebContentsAt(0);
218   }
219
220   PrerenderHandle* prerender_handle() {
221     return GetInstantSearchPrerenderer()->prerender_handle_.get();
222   }
223
224   void PrerenderSearchQuery(const base::string16& query) {
225     Init(true, true);
226     InstantSearchPrerenderer* prerenderer = GetInstantSearchPrerenderer();
227     prerenderer->Prerender(InstantSuggestion(query, std::string()));
228     CommitPendingLoad(&prerender_contents()->GetController());
229     EXPECT_TRUE(prerenderer->CanCommitQuery(GetActiveWebContents(), query));
230     EXPECT_NE(static_cast<PrerenderHandle*>(NULL), prerender_handle());
231   }
232 };
233
234 TEST_F(InstantSearchPrerendererTest, GetSearchTermsFromPrerenderedPage) {
235   Init(false, false);
236   InstantSearchPrerenderer* prerenderer = GetInstantSearchPrerenderer();
237   GURL url(GetPrerenderURL());
238   EXPECT_EQ(GURL("https://www.google.com/instant?ion=1&foo=foo#foo=foo&strk"),
239             url);
240   EXPECT_EQ(UTF16ToASCII(prerenderer->get_last_query()),
241             UTF16ToASCII(chrome::ExtractSearchTermsFromURL(profile(), url)));
242
243   // Assume the prerendered page prefetched search results for the query
244   // "flowers".
245   SetLastQuery(ASCIIToUTF16("flowers"));
246   EXPECT_EQ("flowers", UTF16ToASCII(prerenderer->get_last_query()));
247   EXPECT_EQ(UTF16ToASCII(prerenderer->get_last_query()),
248             UTF16ToASCII(chrome::ExtractSearchTermsFromURL(profile(), url)));
249 }
250
251 TEST_F(InstantSearchPrerendererTest, PrefetchSearchResults) {
252   Init(true, true);
253   EXPECT_TRUE(prerender_handle()->IsFinishedLoading());
254   InstantSearchPrerenderer* prerenderer = GetInstantSearchPrerenderer();
255   prerenderer->Prerender(
256       InstantSuggestion(ASCIIToUTF16("flowers"), std::string()));
257   EXPECT_EQ("flowers", UTF16ToASCII(prerenderer->get_last_query()));
258   EXPECT_TRUE(MessageWasSent(
259       ChromeViewMsg_SearchBoxSetSuggestionToPrefetch::ID));
260 }
261
262 TEST_F(InstantSearchPrerendererTest, DoNotPrefetchSearchResults) {
263   Init(true, false);
264   // Page hasn't finished loading yet.
265   EXPECT_FALSE(prerender_handle()->IsFinishedLoading());
266   InstantSearchPrerenderer* prerenderer = GetInstantSearchPrerenderer();
267   prerenderer->Prerender(
268       InstantSuggestion(ASCIIToUTF16("flowers"), std::string()));
269   EXPECT_EQ("", UTF16ToASCII(prerenderer->get_last_query()));
270   EXPECT_FALSE(MessageWasSent(
271       ChromeViewMsg_SearchBoxSetSuggestionToPrefetch::ID));
272 }
273
274 TEST_F(InstantSearchPrerendererTest, CanCommitQuery) {
275   Init(true, true);
276   InstantSearchPrerenderer* prerenderer = GetInstantSearchPrerenderer();
277   base::string16 query = ASCIIToUTF16("flowers");
278   prerenderer->Prerender(InstantSuggestion(query, std::string()));
279   EXPECT_TRUE(prerenderer->CanCommitQuery(GetActiveWebContents(), query));
280
281   // Make sure InstantSearchPrerenderer::CanCommitQuery() returns false for
282   // invalid search queries.
283   EXPECT_FALSE(prerenderer->CanCommitQuery(GetActiveWebContents(),
284                                            ASCIIToUTF16("joy")));
285   EXPECT_FALSE(prerenderer->CanCommitQuery(GetActiveWebContents(),
286                                            base::string16()));
287 }
288
289 TEST_F(InstantSearchPrerendererTest, CommitQuery) {
290   base::string16 query = ASCIIToUTF16("flowers");
291   PrerenderSearchQuery(query);
292   InstantSearchPrerenderer* prerenderer = GetInstantSearchPrerenderer();
293   prerenderer->Commit(query);
294   EXPECT_TRUE(MessageWasSent(ChromeViewMsg_SearchBoxSubmit::ID));
295 }
296
297 TEST_F(InstantSearchPrerendererTest, CancelPrerenderRequestOnTabChangeEvent) {
298   Init(true, true);
299   EXPECT_NE(static_cast<PrerenderHandle*>(NULL), prerender_handle());
300
301   // Add a new tab to deactivate the current tab.
302   AddTab(browser(), GURL(content::kAboutBlankURL));
303   EXPECT_EQ(2, browser()->tab_strip_model()->count());
304
305   // Make sure the pending prerender request is cancelled.
306   EXPECT_EQ(static_cast<PrerenderHandle*>(NULL), prerender_handle());
307 }
308
309 TEST_F(InstantSearchPrerendererTest, CancelPendingPrerenderRequest) {
310   Init(true, true);
311   EXPECT_NE(static_cast<PrerenderHandle*>(NULL), prerender_handle());
312
313   InstantSearchPrerenderer* prerenderer = GetInstantSearchPrerenderer();
314   prerenderer->Cancel();
315   EXPECT_EQ(static_cast<PrerenderHandle*>(NULL), prerender_handle());
316 }
317
318 TEST_F(InstantSearchPrerendererTest, PrerenderingAllowed) {
319   Init(true, true);
320   InstantSearchPrerenderer* prerenderer = GetInstantSearchPrerenderer();
321   content::WebContents* active_tab = GetActiveWebContents();
322   EXPECT_EQ(GURL(content::kAboutBlankURL), active_tab->GetURL());
323
324   // Allow prerendering only for search type AutocompleteMatch suggestions.
325   AutocompleteMatch search_type_match(NULL, 1100, false,
326                                       AutocompleteMatchType::SEARCH_SUGGEST);
327   EXPECT_TRUE(AutocompleteMatch::IsSearchType(search_type_match.type));
328   EXPECT_TRUE(prerenderer->IsAllowed(search_type_match, active_tab));
329
330   AutocompleteMatch url_type_match(NULL, 1100, true,
331                                    AutocompleteMatchType::URL_WHAT_YOU_TYPED);
332   EXPECT_FALSE(AutocompleteMatch::IsSearchType(url_type_match.type));
333   EXPECT_FALSE(prerenderer->IsAllowed(url_type_match, active_tab));
334
335   // Search results page supports Instant search. InstantSearchPrerenderer is
336   // used only when the underlying page doesn't support Instant.
337   NavigateAndCommitActiveTab(GURL("https://www.google.com/alt#quux=foo&strk"));
338   active_tab = GetActiveWebContents();
339   EXPECT_FALSE(chrome::ExtractSearchTermsFromURL(profile(),
340                                                  active_tab->GetURL()).empty());
341   EXPECT_FALSE(chrome::ShouldPrefetchSearchResultsOnSRP());
342   EXPECT_FALSE(prerenderer->IsAllowed(search_type_match, active_tab));
343 }
344
345 TEST_F(InstantSearchPrerendererTest, UsePrerenderPage) {
346   PrerenderSearchQuery(ASCIIToUTF16("foo"));
347
348   // Open a search results page. A prerendered page exists for |url|. Make sure
349   // the browser swaps the current tab contents with the prerendered contents.
350   GURL url("https://www.google.com/alt#quux=foo&strk");
351   browser()->OpenURL(content::OpenURLParams(url, Referrer(), CURRENT_TAB,
352                                             content::PAGE_TRANSITION_TYPED,
353                                             false));
354   EXPECT_EQ(GetPrerenderURL(), GetActiveWebContents()->GetURL());
355   EXPECT_EQ(static_cast<PrerenderHandle*>(NULL), prerender_handle());
356 }
357
358 TEST_F(InstantSearchPrerendererTest, PrerenderRequestCancelled) {
359   PrerenderSearchQuery(ASCIIToUTF16("foo"));
360
361   // Cancel the prerender request.
362   InstantSearchPrerenderer* prerenderer = GetInstantSearchPrerenderer();
363   prerenderer->Cancel();
364   EXPECT_EQ(static_cast<PrerenderHandle*>(NULL), prerender_handle());
365
366   // Open a search results page. Prerendered page does not exists for |url|.
367   // Make sure the browser navigates the current tab to this |url|.
368   GURL url("https://www.google.com/alt#quux=foo&strk");
369   browser()->OpenURL(content::OpenURLParams(url, Referrer(), CURRENT_TAB,
370                                             content::PAGE_TRANSITION_TYPED,
371                                             false));
372   EXPECT_NE(GetPrerenderURL(), GetActiveWebContents()->GetURL());
373   EXPECT_EQ(url, GetActiveWebContents()->GetURL());
374 }
375
376 TEST_F(InstantSearchPrerendererTest,
377        CancelPrerenderRequest_SearchQueryMistmatch) {
378   PrerenderSearchQuery(ASCIIToUTF16("foo"));
379
380   // Open a search results page. Committed query("pen") doesn't match with the
381   // prerendered search query("foo"). Make sure the InstantSearchPrerenderer
382   // cancels the active prerender request and the browser navigates the active
383   // tab to this |url|.
384   GURL url("https://www.google.com/alt#quux=pen&strk");
385   browser()->OpenURL(content::OpenURLParams(url, Referrer(), CURRENT_TAB,
386                                             content::PAGE_TRANSITION_TYPED,
387                                             false));
388   EXPECT_NE(GetPrerenderURL(), GetActiveWebContents()->GetURL());
389   EXPECT_EQ(url, GetActiveWebContents()->GetURL());
390   EXPECT_EQ(static_cast<PrerenderHandle*>(NULL), prerender_handle());
391 }
392
393 TEST_F(InstantSearchPrerendererTest,
394        CancelPrerenderRequest_EmptySearchQueryCommitted) {
395   PrerenderSearchQuery(ASCIIToUTF16("foo"));
396
397   // Open a search results page. Make sure the InstantSearchPrerenderer cancels
398   // the active prerender request upon the receipt of empty search query.
399   GURL url("https://www.google.com/alt#quux=&strk");
400   browser()->OpenURL(content::OpenURLParams(url, Referrer(), CURRENT_TAB,
401                                             content::PAGE_TRANSITION_TYPED,
402                                             false));
403   EXPECT_NE(GetPrerenderURL(), GetActiveWebContents()->GetURL());
404   EXPECT_EQ(url, GetActiveWebContents()->GetURL());
405   EXPECT_EQ(static_cast<PrerenderHandle*>(NULL), prerender_handle());
406 }
407
408 class ReuseInstantSearchBasePageTest : public InstantSearchPrerendererTest {
409   public:
410    ReuseInstantSearchBasePageTest() {}
411
412   protected:
413    virtual void SetUp() OVERRIDE {
414     ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
415         "EmbeddedSearch",
416         "Group1 strk:20 prefetch_results:1 reuse_instant_search_base_page:1"));
417     InstantUnitTestBase::SetUp();
418    }
419 };
420
421 TEST_F(ReuseInstantSearchBasePageTest, CanCommitQuery) {
422   Init(true, true);
423   InstantSearchPrerenderer* prerenderer = GetInstantSearchPrerenderer();
424   base::string16 query = ASCIIToUTF16("flowers");
425   prerenderer->Prerender(InstantSuggestion(query, std::string()));
426   EXPECT_TRUE(prerenderer->CanCommitQuery(GetActiveWebContents(), query));
427
428   // When the Instant search base page has finished loading,
429   // InstantSearchPrerenderer can commit any search query to the prerendered
430   // page (even if it doesn't match the last known suggestion query).
431   EXPECT_TRUE(prerenderer->CanCommitQuery(GetActiveWebContents(),
432                                            ASCIIToUTF16("joy")));
433   // Invalid search query committed.
434   EXPECT_FALSE(prerenderer->CanCommitQuery(GetActiveWebContents(),
435                                            base::string16()));
436 }
437
438 TEST_F(ReuseInstantSearchBasePageTest,
439        CanCommitQuery_InstantSearchBasePageLoadInProgress) {
440   Init(true, false);
441   InstantSearchPrerenderer* prerenderer = GetInstantSearchPrerenderer();
442   base::string16 query = ASCIIToUTF16("flowers");
443   prerenderer->Prerender(InstantSuggestion(query, std::string()));
444
445   // When the Instant search base page hasn't finished loading,
446   // InstantSearchPrerenderer cannot commit any search query to the base page.
447   EXPECT_FALSE(prerenderer->CanCommitQuery(GetActiveWebContents(), query));
448   EXPECT_FALSE(prerenderer->CanCommitQuery(GetActiveWebContents(),
449                                            ASCIIToUTF16("joy")));
450 }
451
452 #if !defined(OS_IOS) && !defined(OS_ANDROID)
453 class TestUsePrerenderPage : public InstantSearchPrerendererTest {
454  protected:
455   virtual void SetUp() OVERRIDE {
456     // Disable query extraction flag in field trials.
457     ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
458         "EmbeddedSearch",
459         "Group1 strk:20 query_extraction:0 prefetch_results:1"));
460     InstantUnitTestBase::SetUpWithoutQueryExtraction();
461   }
462 };
463
464 TEST_F(TestUsePrerenderPage, ExtractSearchTermsAndUsePrerenderPage) {
465   PrerenderSearchQuery(ASCIIToUTF16("foo"));
466
467   // Open a search results page. Query extraction flag is disabled in field
468   // trials. Search results page URL does not contain search terms replacement
469   // key. Make sure UsePrerenderedPage() extracts the search terms from the URL
470   // and uses the prerendered page contents.
471   GURL url("https://www.google.com/alt#quux=foo");
472   browser()->OpenURL(content::OpenURLParams(url, Referrer(), CURRENT_TAB,
473                                             content::PAGE_TRANSITION_TYPED,
474                                             false));
475   EXPECT_EQ(GetPrerenderURL(), GetActiveWebContents()->GetURL());
476   EXPECT_EQ(static_cast<PrerenderHandle*>(NULL), prerender_handle());
477 }
478 #endif