Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(122)

Side by Side Diff: content/browser/download/mhtml_generation_browsertest.cc

Issue 2540483002: Allow Offline MHTML save operations to succeed even with missing frames.
Patch Set: Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <stdint.h> 5 #include <stdint.h>
6 #include <memory> 6 #include <memory>
7 7
8 #include "base/bind.h" 8 #include "base/bind.h"
9 #include "base/callback.h" 9 #include "base/callback.h"
10 #include "base/files/file_path.h" 10 #include "base/files/file_path.h"
11 #include "base/files/file_util.h" 11 #include "base/files/file_util.h"
12 #include "base/files/scoped_temp_dir.h" 12 #include "base/files/scoped_temp_dir.h"
13 #include "base/macros.h" 13 #include "base/macros.h"
14 #include "base/run_loop.h" 14 #include "base/run_loop.h"
15 #include "base/strings/utf_string_conversions.h" 15 #include "base/strings/utf_string_conversions.h"
16 #include "base/test/histogram_tester.h" 16 #include "base/test/histogram_tester.h"
17 #include "base/threading/thread_restrictions.h" 17 #include "base/threading/thread_restrictions.h"
18 #include "content/browser/frame_host/frame_tree_node.h"
18 #include "content/browser/renderer_host/render_process_host_impl.h" 19 #include "content/browser/renderer_host/render_process_host_impl.h"
20 #include "content/browser/web_contents/web_contents_impl.h"
19 #include "content/common/frame_messages.h" 21 #include "content/common/frame_messages.h"
20 #include "content/public/browser/render_process_host.h" 22 #include "content/public/browser/render_process_host.h"
21 #include "content/public/browser/web_contents.h"
22 #include "content/public/common/mhtml_generation_params.h" 23 #include "content/public/common/mhtml_generation_params.h"
23 #include "content/public/test/browser_test_utils.h" 24 #include "content/public/test/browser_test_utils.h"
24 #include "content/public/test/content_browser_test.h" 25 #include "content/public/test/content_browser_test.h"
25 #include "content/public/test/content_browser_test_utils.h" 26 #include "content/public/test/content_browser_test_utils.h"
26 #include "content/public/test/test_utils.h" 27 #include "content/public/test/test_utils.h"
27 #include "content/shell/browser/shell.h" 28 #include "content/shell/browser/shell.h"
28 #include "net/base/filename_util.h" 29 #include "net/base/filename_util.h"
29 #include "net/dns/mock_host_resolver.h" 30 #include "net/dns/mock_host_resolver.h"
30 #include "net/test/embedded_test_server/embedded_test_server.h" 31 #include "net/test/embedded_test_server/embedded_test_server.h"
31 #include "testing/gmock/include/gmock/gmock.h" 32 #include "testing/gmock/include/gmock/gmock.h"
(...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after
215 216
216 // Tests that generating a MHTML does create contents. 217 // Tests that generating a MHTML does create contents.
217 // Note that the actual content of the file is not tested, the purpose of this 218 // Note that the actual content of the file is not tested, the purpose of this
218 // test is to ensure we were successful in creating the MHTML data from the 219 // test is to ensure we were successful in creating the MHTML data from the
219 // renderer. 220 // renderer.
220 IN_PROC_BROWSER_TEST_F(MHTMLGenerationTest, GenerateMHTML) { 221 IN_PROC_BROWSER_TEST_F(MHTMLGenerationTest, GenerateMHTML) {
221 base::FilePath path(temp_dir_.GetPath()); 222 base::FilePath path(temp_dir_.GetPath());
222 path = path.Append(FILE_PATH_LITERAL("test.mht")); 223 path = path.Append(FILE_PATH_LITERAL("test.mht"));
223 224
224 GenerateMHTML(path, embedded_test_server()->GetURL("/simple_page.html")); 225 GenerateMHTML(path, embedded_test_server()->GetURL("/simple_page.html"));
226
227 // Checks that no other test failure was detected so far.
225 ASSERT_FALSE(HasFailure()); 228 ASSERT_FALSE(HasFailure());
226 229
227 // Make sure the actual generated file has some contents. 230 // Make sure the actual generated file has some contents.
228 EXPECT_GT(file_size(), 0); // Verify the size reported by the callback. 231 EXPECT_GT(file_size(), 0); // Verify the size reported by the callback.
229 EXPECT_GT(ReadFileSizeFromDisk(path), 100); // Verify the actual file size. 232 EXPECT_GT(ReadFileSizeFromDisk(path), 100); // Verify the actual file size.
230 233
231 { 234 {
232 base::ThreadRestrictions::ScopedAllowIO allow_io_for_content_verification; 235 base::ThreadRestrictions::ScopedAllowIO allow_io_for_content_verification;
233 std::string mhtml; 236 std::string mhtml;
234 ASSERT_TRUE(base::ReadFileToString(path, &mhtml)); 237 ASSERT_TRUE(base::ReadFileToString(path, &mhtml));
235 EXPECT_THAT(mhtml, 238 EXPECT_THAT(mhtml,
236 HasSubstr("Content-Transfer-Encoding: quoted-printable")); 239 HasSubstr("Content-Transfer-Encoding: quoted-printable"));
237 } 240 }
238 241
239 // Checks that the final status reported to UMA is correct. 242 // Checks that the final status reported to UMA is correct.
240 histogram_tester()->ExpectUniqueSample( 243 histogram_tester()->ExpectUniqueSample(
241 "PageSerialization.MhtmlGeneration.FinalSaveStatus", 244 "PageSerialization.MhtmlGeneration.FinalSaveStatus",
242 static_cast<int>(MhtmlSaveStatus::SUCCESS), 1); 245 static_cast<int>(MhtmlSaveStatus::SUCCESS), 1);
243 } 246 }
244 247
248 // Removes all children of the root tree node once the first MHTML serialization
249 // response (regarding the main frame) is received from the renderer but before
250 // that message is actually handled by the browser UI thread.
251 class ChildFrameRemoverFilter : public BrowserMessageFilter {
252 public:
253 ChildFrameRemoverFilter(WebContentsImpl* web_contents)
254 : BrowserMessageFilter(FrameMsgStart), web_contents_(web_contents) {}
Łukasz Anforowicz 2016/11/28 22:15:37 nit: DCHECK(web_contents_) ?
carlosk 2016/11/29 02:11:20 Done.
255
256 protected:
257 ~ChildFrameRemoverFilter() override {}
258
259 private:
260 bool OnMessageReceived(const IPC::Message& message) override {
Łukasz Anforowicz 2016/11/28 22:15:37 nit: DCHECK_CURRENTLY_ON(BrowserThread::IO) ?
carlosk 2016/11/29 02:11:20 Done.
261 if (message.type() == FrameHostMsg_SerializeAsMHTMLResponse::ID) {
262 if (!already_received_response_) {
263 already_received_response_ = true;
264 BrowserThread::PostTask(
265 BrowserThread::UI, FROM_HERE,
266 base::Bind(&ChildFrameRemoverFilter::RemoveAllChildFrames,
267 base::Unretained(this)));
268 } else {
269 ADD_FAILURE()
270 << "Should not receive another MHTML serialization response";
271 }
272 }
273 return false;
274 }
275
276 void RemoveAllChildFrames() {
Łukasz Anforowicz 2016/11/28 22:15:37 nit: DCHECK_CURRENTLY_ON(BrowserThread::UI) ? (th
carlosk 2016/11/29 02:11:20 Agreed and done. Also added these checks to the ot
277 int tree_node_count = 1;
278 for (auto tree_node : web_contents_->GetFrameTree()->Nodes())
279 tree_node_count += tree_node->child_count();
280 // Note: at least 2 children nodes are needed to test all code paths.
281 ASSERT_GE(tree_node_count, 3);
282 FrameTreeNode* root = web_contents_->GetFrameTree()->root();
283 while (root->child_count())
284 root->RemoveChild(root->child_at(root->child_count() - 1));
Łukasz Anforowicz 2016/11/28 22:15:37 Is it okay to instead call root->RemoveChild(0)?
carlosk 2016/11/29 02:11:20 This was just my ODD of always removing vector ele
Łukasz Anforowicz 2016/11/29 19:18:13 Thanks. I see now that the simpler code might be
285 ASSERT_EQ(0u, root->child_count());
286 }
287
288 WebContentsImpl* web_contents_;
289 bool already_received_response_ = false;
290
291 DISALLOW_COPY_AND_ASSIGN(ChildFrameRemoverFilter);
292 };
293
294 // Tests that if child frames are removed while saving a MHTML page the
295 // operation fails by default.
296 IN_PROC_BROWSER_TEST_F(MHTMLGenerationTest, FailDueToMissingIframe) {
297 NavigateToURL(shell(),
Łukasz Anforowicz 2016/11/28 22:15:37 nit: ASSERT_TRUE(NavigateToURL(...) (this will al
carlosk 2016/11/29 02:11:20 Done for all calls of this function.
298 embedded_test_server()->GetURL("/site_per_process_main.html"));
299
300 scoped_refptr<BrowserMessageFilter> filter = new ChildFrameRemoverFilter(
301 static_cast<WebContentsImpl*>(shell()->web_contents()));
302 shell()->web_contents()->GetRenderProcessHost()->AddFilter(filter.get());
303
304 base::FilePath path(temp_dir_.GetPath());
305 path = path.Append(FILE_PATH_LITERAL("test.mht"));
306
307 MHTMLGenerationParams params(path);
308
309 // Verifies the default is to not ignore missing iframes.
310 ASSERT_FALSE(params.ignore_missing_frames);
311
312 GenerateMHTMLForCurrentPage(params);
313
314 // Checks that no other test failure was detected so far.
315 ASSERT_FALSE(HasFailure());
316
317 // Verify the size reported by the callback is negative (an error happened).
318 EXPECT_LT(file_size(), 0);
319
320 // Checks that the final status reported to UMA is correct.
321 histogram_tester()->ExpectUniqueSample(
322 "PageSerialization.MhtmlGeneration.FinalSaveStatus",
323 static_cast<int>(MhtmlSaveStatus::FRAME_NO_LONGER_EXISTS), 1);
324 }
325
326 // Tests that a MHTML save operation does not fail when frames are removed if
327 // the caller configures it to ignore missing frames.
328 IN_PROC_BROWSER_TEST_F(MHTMLGenerationTest, SucceedIgnoringMissingIframe) {
329 NavigateToURL(shell(),
Łukasz Anforowicz 2016/11/28 22:15:37 nit: ASSERT_TRUE(NavigateToURL(...)
carlosk 2016/11/29 02:11:20 Done.
330 embedded_test_server()->GetURL("/site_per_process_main.html"));
331
332 scoped_refptr<BrowserMessageFilter> filter = new ChildFrameRemoverFilter(
333 static_cast<WebContentsImpl*>(shell()->web_contents()));
334 shell()->web_contents()->GetRenderProcessHost()->AddFilter(filter.get());
335
336 base::FilePath path(temp_dir_.GetPath());
337 path = path.Append(FILE_PATH_LITERAL("test.mht"));
338
339 MHTMLGenerationParams params(path);
340
341 // Enables the ignoring of missing iframes.
342 params.ignore_missing_frames = true;
343
344 GenerateMHTMLForCurrentPage(params);
345
346 // Checks that no other test failure was detected so far.
347 ASSERT_FALSE(HasFailure());
348
349 // Verify the size reported by the callback is positive.
350 EXPECT_GT(file_size(), 0);
351
352 // Checks that the final status reported to UMA is correct.
353 histogram_tester()->ExpectUniqueSample(
354 "PageSerialization.MhtmlGeneration.FinalSaveStatus",
355 static_cast<int>(MhtmlSaveStatus::SUCCESS), 1);
356 }
357
245 class GenerateMHTMLAndExitRendererMessageFilter : public BrowserMessageFilter { 358 class GenerateMHTMLAndExitRendererMessageFilter : public BrowserMessageFilter {
246 public: 359 public:
247 GenerateMHTMLAndExitRendererMessageFilter( 360 GenerateMHTMLAndExitRendererMessageFilter(
248 RenderProcessHostImpl* render_process_host) 361 RenderProcessHostImpl* render_process_host)
249 : BrowserMessageFilter(FrameMsgStart), 362 : BrowserMessageFilter(FrameMsgStart),
250 render_process_host_(render_process_host) {} 363 render_process_host_(render_process_host) {}
251 364
252 protected: 365 protected:
253 ~GenerateMHTMLAndExitRendererMessageFilter() override {} 366 ~GenerateMHTMLAndExitRendererMessageFilter() override {}
254 367
(...skipping 389 matching lines...) Expand 10 before | Expand all | Expand 10 after
644 757
645 // Make sure that URLs of both frames are present 758 // Make sure that URLs of both frames are present
646 // (note that these are single-line regexes). 759 // (note that these are single-line regexes).
647 EXPECT_THAT( 760 EXPECT_THAT(
648 mhtml, 761 mhtml,
649 ContainsRegex("Content-Location:.*/frame_tree/page_with_one_frame.html")); 762 ContainsRegex("Content-Location:.*/frame_tree/page_with_one_frame.html"));
650 EXPECT_THAT(mhtml, ContainsRegex("Content-Location:.*/title1.html")); 763 EXPECT_THAT(mhtml, ContainsRegex("Content-Location:.*/title1.html"));
651 } 764 }
652 765
653 } // namespace content 766 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698