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