e8c1efa842f88161db78c748a9c0fdb0a3d5d965
[platform/framework/web/crosswalk.git] / src / components / dom_distiller / content / distiller_page_web_contents_browsertest.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 "base/memory/weak_ptr.h"
6 #include "base/path_service.h"
7 #include "base/run_loop.h"
8 #include "base/values.h"
9 #include "components/dom_distiller/content/distiller_page_web_contents.h"
10 #include "components/dom_distiller/content/web_contents_main_frame_observer.h"
11 #include "components/dom_distiller/core/distiller_page.h"
12 #include "content/public/browser/browser_context.h"
13 #include "content/public/browser/navigation_controller.h"
14 #include "content/public/browser/render_frame_host.h"
15 #include "content/public/browser/web_contents_observer.h"
16 #include "content/public/test/content_browser_test.h"
17 #include "content/shell/browser/shell.h"
18 #include "grit/component_resources.h"
19 #include "net/test/embedded_test_server/embedded_test_server.h"
20 #include "testing/gmock/include/gmock/gmock.h"
21 #include "ui/base/resource/resource_bundle.h"
22
23 using content::ContentBrowserTest;
24 using testing::ContainsRegex;
25 using testing::HasSubstr;
26 using testing::Not;
27
28 namespace dom_distiller {
29
30 const char* kSimpleArticlePath = "/simple_article.html";
31 const char* kVideoArticlePath = "/video_article.html";
32
33 class DistillerPageWebContentsTest : public ContentBrowserTest {
34  public:
35   // ContentBrowserTest:
36   virtual void SetUpOnMainThread() OVERRIDE {
37     AddComponentsResources();
38     SetUpTestServer();
39     ContentBrowserTest::SetUpOnMainThread();
40   }
41
42   void DistillPage(const base::Closure& quit_closure, const std::string& url) {
43     quit_closure_ = quit_closure;
44     distiller_page_->DistillPage(
45         embedded_test_server()->GetURL(url),
46         dom_distiller::proto::DomDistillerOptions(),
47         base::Bind(&DistillerPageWebContentsTest::OnPageDistillationFinished,
48                    this));
49   }
50
51   void OnPageDistillationFinished(scoped_ptr<DistilledPageInfo> distilled_page,
52                                   bool distillation_successful) {
53     page_info_ = distilled_page.Pass();
54     quit_closure_.Run();
55   }
56
57  private:
58   void AddComponentsResources() {
59     base::FilePath pak_file;
60     base::FilePath pak_dir;
61     PathService::Get(base::DIR_MODULE, &pak_dir);
62     pak_file = pak_dir.Append(FILE_PATH_LITERAL("components_resources.pak"));
63     ui::ResourceBundle::GetSharedInstance().AddDataPackFromPath(
64         pak_file, ui::SCALE_FACTOR_NONE);
65   }
66
67   void SetUpTestServer() {
68     base::FilePath path;
69     PathService::Get(base::DIR_SOURCE_ROOT, &path);
70     path = path.AppendASCII("components/test/data/dom_distiller");
71     embedded_test_server()->ServeFilesFromDirectory(path);
72     ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
73   }
74
75  protected:
76   void RunUseCurrentWebContentsTest(const std::string& url,
77                                     bool expect_new_web_contents,
78                                     bool setup_main_frame_observer,
79                                     bool wait_for_document_loaded);
80
81   DistillerPageWebContents* distiller_page_;
82   base::Closure quit_closure_;
83   scoped_ptr<DistilledPageInfo> page_info_;
84 };
85
86 // Use this class to be able to leak the WebContents, which is needed for when
87 // the current WebContents is used for distillation.
88 class TestDistillerPageWebContents : public DistillerPageWebContents {
89  public:
90   TestDistillerPageWebContents(
91       content::BrowserContext* browser_context,
92       scoped_ptr<SourcePageHandleWebContents> optional_web_contents_handle,
93       bool expect_new_web_contents)
94       : DistillerPageWebContents(browser_context,
95                                  optional_web_contents_handle.Pass()),
96         expect_new_web_contents_(expect_new_web_contents),
97         new_web_contents_created_(false) {}
98
99   virtual void CreateNewWebContents(const GURL& url) OVERRIDE {
100     ASSERT_EQ(true, expect_new_web_contents_);
101     new_web_contents_created_ = true;
102     // DistillerPageWebContents::CreateNewWebContents resets the scoped_ptr to
103     // the WebContents, so intentionally leak WebContents here, since it is
104     // owned by the shell.
105     content::WebContents* web_contents = web_contents_.release();
106     web_contents->GetLastCommittedURL();
107     DistillerPageWebContents::CreateNewWebContents(url);
108   }
109
110   virtual ~TestDistillerPageWebContents() {
111     if (!expect_new_web_contents_) {
112       // Intentionally leaking WebContents, since it is owned by the shell.
113       content::WebContents* web_contents = web_contents_.release();
114       web_contents->GetLastCommittedURL();
115     }
116   }
117
118   bool new_web_contents_created() { return new_web_contents_created_; }
119
120  private:
121   bool expect_new_web_contents_;
122   bool new_web_contents_created_;
123 };
124
125 // Helper class to know how far in the loading process the current WebContents
126 // has come. It will call the callback either after
127 // DidCommitProvisionalLoadForFrame or DocumentLoadedInFrame is called for the
128 // main frame, based on the value of |wait_for_document_loaded|.
129 class WebContentsMainFrameHelper : public content::WebContentsObserver {
130  public:
131   WebContentsMainFrameHelper(content::WebContents* web_contents,
132                              const base::Closure& callback,
133                              bool wait_for_document_loaded)
134       : web_contents_(web_contents),
135         callback_(callback),
136         wait_for_document_loaded_(wait_for_document_loaded) {
137     content::WebContentsObserver::Observe(web_contents);
138   }
139
140   virtual void DidCommitProvisionalLoadForFrame(
141       int64 frame_id,
142       const base::string16& frame_unique_name,
143       bool is_main_frame,
144       const GURL& url,
145       content::PageTransition transition_type,
146       content::RenderViewHost* render_view_host) OVERRIDE {
147     if (wait_for_document_loaded_)
148       return;
149     if (is_main_frame)
150       callback_.Run();
151   }
152
153   virtual void DocumentLoadedInFrame(
154       int64 frame_id,
155       content::RenderViewHost* render_view_host) OVERRIDE {
156     if (wait_for_document_loaded_) {
157       if (web_contents_ &&
158           frame_id == web_contents_->GetMainFrame()->GetRoutingID()) {
159         callback_.Run();
160       }
161     }
162   }
163
164  private:
165   content::WebContents* web_contents_;
166   base::Closure callback_;
167   bool wait_for_document_loaded_;
168 };
169
170 IN_PROC_BROWSER_TEST_F(DistillerPageWebContentsTest, BasicDistillationWorks) {
171   DistillerPageWebContents distiller_page(
172       shell()->web_contents()->GetBrowserContext(),
173       scoped_ptr<SourcePageHandleWebContents>());
174   distiller_page_ = &distiller_page;
175
176   base::RunLoop run_loop;
177   DistillPage(run_loop.QuitClosure(), kSimpleArticlePath);
178   run_loop.Run();
179
180   EXPECT_EQ("Test Page Title", page_info_.get()->title);
181   EXPECT_THAT(page_info_.get()->html, HasSubstr("Lorem ipsum"));
182   EXPECT_THAT(page_info_.get()->html, Not(HasSubstr("questionable content")));
183   EXPECT_EQ("", page_info_.get()->next_page_url);
184   EXPECT_EQ("", page_info_.get()->prev_page_url);
185 }
186
187 IN_PROC_BROWSER_TEST_F(DistillerPageWebContentsTest, HandlesRelativeLinks) {
188   DistillerPageWebContents distiller_page(
189       shell()->web_contents()->GetBrowserContext(),
190       scoped_ptr<SourcePageHandleWebContents>());
191   distiller_page_ = &distiller_page;
192
193   base::RunLoop run_loop;
194   DistillPage(run_loop.QuitClosure(), kSimpleArticlePath);
195   run_loop.Run();
196
197   // A relative link should've been updated.
198   EXPECT_THAT(page_info_.get()->html,
199               ContainsRegex("href=\"http://127.0.0.1:.*/relativelink.html\""));
200   EXPECT_THAT(page_info_.get()->html,
201               HasSubstr("href=\"http://www.google.com/absolutelink.html\""));
202 }
203
204 IN_PROC_BROWSER_TEST_F(DistillerPageWebContentsTest, HandlesRelativeImages) {
205   DistillerPageWebContents distiller_page(
206       shell()->web_contents()->GetBrowserContext(),
207       scoped_ptr<SourcePageHandleWebContents>());
208   distiller_page_ = &distiller_page;
209
210   base::RunLoop run_loop;
211   DistillPage(run_loop.QuitClosure(), kSimpleArticlePath);
212   run_loop.Run();
213
214   // A relative link should've been updated.
215   EXPECT_THAT(page_info_.get()->html,
216               ContainsRegex("src=\"http://127.0.0.1:.*/relativeimage.png\""));
217   EXPECT_THAT(page_info_.get()->html,
218               HasSubstr("src=\"http://www.google.com/absoluteimage.png\""));
219 }
220
221
222 IN_PROC_BROWSER_TEST_F(DistillerPageWebContentsTest, HandlesRelativeVideos) {
223   DistillerPageWebContents distiller_page(
224       shell()->web_contents()->GetBrowserContext(),
225       scoped_ptr<SourcePageHandleWebContents>());
226   distiller_page_ = &distiller_page;
227
228   base::RunLoop run_loop;
229   DistillPage(run_loop.QuitClosure(), kVideoArticlePath);
230   run_loop.Run();
231
232   // A relative source/track should've been updated.
233   EXPECT_THAT(
234       page_info_.get()->html,
235       ContainsRegex("src=\"http://127.0.0.1:.*/relative_video.mp4\""));
236   EXPECT_THAT(
237       page_info_.get()->html,
238       ContainsRegex("src=\"http://127.0.0.1:.*/relative_track_en.vtt\""));
239   EXPECT_THAT(
240       page_info_.get()->html,
241       HasSubstr("src=\"http://www.google.com/absolute_video.ogg\""));
242   EXPECT_THAT(
243       page_info_.get()->html,
244       HasSubstr("src=\"http://www.google.com/absolute_track_fr.vtt\""));
245 }
246
247 IN_PROC_BROWSER_TEST_F(DistillerPageWebContentsTest, VisibilityDetection) {
248   DistillerPageWebContents distiller_page(
249       shell()->web_contents()->GetBrowserContext(),
250       scoped_ptr<SourcePageHandleWebContents>());
251   distiller_page_ = &distiller_page;
252
253   // visble_style.html and invisible_style.html only differ by the visibility
254   // internal stylesheet.
255
256   {
257     base::RunLoop run_loop;
258     DistillPage(run_loop.QuitClosure(), "/visible_style.html");
259     run_loop.Run();
260     EXPECT_THAT(page_info_.get()->html, HasSubstr("Lorem ipsum"));
261   }
262
263   {
264     base::RunLoop run_loop;
265     DistillPage(run_loop.QuitClosure(), "/invisible_style.html");
266     run_loop.Run();
267     EXPECT_THAT(page_info_.get()->html, Not(HasSubstr("Lorem ipsum")));
268   }
269 }
270
271 IN_PROC_BROWSER_TEST_F(DistillerPageWebContentsTest,
272                        UsingCurrentWebContentsWrongUrl) {
273   std::string url("/bogus");
274   bool expect_new_web_contents = true;
275   bool setup_main_frame_observer = true;
276   bool wait_for_document_loaded = true;
277   RunUseCurrentWebContentsTest(url,
278                                expect_new_web_contents,
279                                setup_main_frame_observer,
280                                wait_for_document_loaded);
281 }
282
283 IN_PROC_BROWSER_TEST_F(DistillerPageWebContentsTest,
284                        UsingCurrentWebContentsNoMainFrameObserver) {
285   std::string url(kSimpleArticlePath);
286   bool expect_new_web_contents = true;
287   bool setup_main_frame_observer = false;
288   bool wait_for_document_loaded = true;
289   RunUseCurrentWebContentsTest(url,
290                                expect_new_web_contents,
291                                setup_main_frame_observer,
292                                wait_for_document_loaded);
293 }
294
295 IN_PROC_BROWSER_TEST_F(DistillerPageWebContentsTest,
296                        UsingCurrentWebContentsNotFinishedLoadingYet) {
297   std::string url(kSimpleArticlePath);
298   bool expect_new_web_contents = false;
299   bool setup_main_frame_observer = true;
300   bool wait_for_document_loaded = false;
301   RunUseCurrentWebContentsTest(url,
302                                expect_new_web_contents,
303                                setup_main_frame_observer,
304                                wait_for_document_loaded);
305 }
306
307 IN_PROC_BROWSER_TEST_F(DistillerPageWebContentsTest,
308                        UsingCurrentWebContentsReadyForDistillation) {
309   std::string url(kSimpleArticlePath);
310   bool expect_new_web_contents = false;
311   bool setup_main_frame_observer = true;
312   bool wait_for_document_loaded = true;
313   RunUseCurrentWebContentsTest(url,
314                                expect_new_web_contents,
315                                setup_main_frame_observer,
316                                wait_for_document_loaded);
317 }
318
319 void DistillerPageWebContentsTest::RunUseCurrentWebContentsTest(
320     const std::string& url,
321     bool expect_new_web_contents,
322     bool setup_main_frame_observer,
323     bool wait_for_document_loaded) {
324   content::WebContents* current_web_contents = shell()->web_contents();
325   if (setup_main_frame_observer) {
326     dom_distiller::WebContentsMainFrameObserver::CreateForWebContents(
327         current_web_contents);
328   }
329   base::RunLoop url_loaded_runner;
330   WebContentsMainFrameHelper main_frame_loaded(current_web_contents,
331                                                url_loaded_runner.QuitClosure(),
332                                                wait_for_document_loaded);
333   current_web_contents->GetController().LoadURL(
334       embedded_test_server()->GetURL(url),
335       content::Referrer(),
336       content::PAGE_TRANSITION_TYPED,
337       std::string());
338   url_loaded_runner.Run();
339
340   scoped_ptr<content::WebContents> old_web_contents_sptr(current_web_contents);
341   scoped_ptr<SourcePageHandleWebContents> source_page_handle(
342       new SourcePageHandleWebContents(old_web_contents_sptr.Pass()));
343
344   TestDistillerPageWebContents distiller_page(
345       shell()->web_contents()->GetBrowserContext(),
346       source_page_handle.Pass(),
347       expect_new_web_contents);
348   distiller_page_ = &distiller_page;
349
350   base::RunLoop run_loop;
351   DistillPage(run_loop.QuitClosure(), kSimpleArticlePath);
352   run_loop.Run();
353
354   // Sanity check of distillation process.
355   EXPECT_EQ(expect_new_web_contents, distiller_page.new_web_contents_created());
356   EXPECT_EQ("Test Page Title", page_info_.get()->title);
357 }
358
359 }  // namespace dom_distiller