Commit a8960461 authored by lukasza's avatar lukasza Committed by Commit bot

OOPIF support for testRunner.dumpAsText and similar layout dumps.

Layout Tests dump page contents (to compare against expected results).
The dump can include frame contents (i.e. dump as text, dump as markup,
dump scroll positions with extra flavors like dump as printed, dump line
box trees, etc.).  Since renderer process is (for security / by design)
not able to see frame contents of remote frames, it means that old
Layout Tests code is not able to dump frame contents when site isolation
is enabled (i.e. when running with --additional-drt-flag=--site-per-process).

This CL is a step toward making layout tests compatible with site
isolation.  After this CL, if recursing over all frames is required,
then BlinkTestRunner::CaptureDump will ask the browser process for
stiching together the frame contents, before continuing with the other
dump flavors in BlinkTestRunner::OnLayoutDumpCompleted.

The above means testRunner.notifyDone() might no longer perform dumps
synchronously.  This is okay, because:

  - The dumps were already performed asynchronously in some cases:
    - pixel dumps (i.e. see how dumping is resumed after
      BlinkTestRunner::CaptureDumpPixels aka OnPixelsDumpCompleted),
    - ShouldDumpBackForwardList (i.e. see how dumping is resumed after
      BlinkTestRunner::OnSessionHistory),
    - the case where notifyDone is called from a secondary window (i.e.
      see how BlinkTestRunner::TestFinished asks the browser to continue
      in the main window).

  - The synchronous dumps are still performed if the test didn't ask for
    recursing over all the frames.  Retaining the synchronous behavior
    in this case is needed, because in some tests the dump is captured
    while the frame is being detached (and would no longer be present
    after an extra hop to the browser process).

This CL doesn't affect the following dump modes (which for now remain
potentially incompatible with OOPIFs): dump as audio, dump as custom
text, dump pixels, dump back/forward list).  Additionally, setting and
reading of dump modes is done in a renderer process (which can be
incompatible with OOPIFs when testRunner.dumpAsText() and
testRunner.notifyDone() are called in cross-site frames running in
different renderer processes).

BUG=477150
CQ_INCLUDE_TRYBOTS=tryserver.blink:linux_blink_rel

Review URL: https://codereview.chromium.org/1589643003

Cr-Commit-Position: refs/heads/master@{#371896}
parent dfd23e82
......@@ -29,6 +29,9 @@ component("test_runner") {
"gamepad_controller.h",
"gc_controller.cc",
"gc_controller.h",
"layout_dump.cc",
"layout_dump.h",
"layout_dump_flags.h",
"mock_color_chooser.cc",
"mock_color_chooser.h",
"mock_credential_manager_client.cc",
......
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/test_runner/layout_dump.h"
#include "base/logging.h"
#include "base/strings/stringprintf.h"
#include "third_party/WebKit/public/platform/WebSize.h"
#include "third_party/WebKit/public/platform/WebString.h"
#include "third_party/WebKit/public/web/WebDocument.h"
#include "third_party/WebKit/public/web/WebElement.h"
#include "third_party/WebKit/public/web/WebFrame.h"
#include "third_party/WebKit/public/web/WebLocalFrame.h"
namespace test_runner {
using blink::WebFrame;
using blink::WebLocalFrame;
using blink::WebSize;
namespace {
std::string DumpFrameHeaderIfNeeded(WebFrame* frame) {
std::string result;
// Add header for all but the main frame. Skip empty frames.
if (frame->parent() && !frame->document().documentElement().isNull()) {
result.append("\n--------\nFrame: '");
result.append(frame->uniqueName().utf8());
result.append("'\n--------\n");
}
return result;
}
std::string DumpFrameScrollPosition(WebFrame* frame) {
std::string result;
WebSize offset = frame->scrollOffset();
if (offset.width > 0 || offset.height > 0) {
if (frame->parent()) {
result =
std::string("frame '") + frame->uniqueName().utf8().data() + "' ";
}
base::StringAppendF(&result, "scrolled to %d,%d\n", offset.width,
offset.height);
}
return result;
}
} // namespace
std::string DumpLayout(WebLocalFrame* frame, const LayoutDumpFlags& flags) {
DCHECK(frame);
std::string result;
switch (flags.main_dump_mode) {
case LayoutDumpMode::DUMP_AS_TEXT:
result = DumpFrameHeaderIfNeeded(frame);
if (flags.dump_as_printed && frame->document().isHTMLDocument()) {
result +=
frame->layoutTreeAsText(WebFrame::LayoutAsTextPrinting).utf8();
} else {
result += frame->document().contentAsTextForTesting().utf8();
}
result += "\n";
break;
case LayoutDumpMode::DUMP_AS_MARKUP:
DCHECK(!flags.dump_as_printed);
result = DumpFrameHeaderIfNeeded(frame);
result += frame->contentAsMarkup().utf8();
result += "\n";
break;
case LayoutDumpMode::DUMP_SCROLL_POSITIONS:
if (frame->parent() == nullptr) {
WebFrame::LayoutAsTextControls layout_text_behavior =
WebFrame::LayoutAsTextNormal;
if (flags.dump_as_printed)
layout_text_behavior |= WebFrame::LayoutAsTextPrinting;
if (flags.debug_render_tree)
layout_text_behavior |= WebFrame::LayoutAsTextDebug;
if (flags.dump_line_box_trees)
layout_text_behavior |= WebFrame::LayoutAsTextWithLineTrees;
result = frame->layoutTreeAsText(layout_text_behavior).utf8();
}
result += DumpFrameScrollPosition(frame);
break;
default:
DCHECK(false) << static_cast<int>(flags.main_dump_mode);
result = "";
break;
}
return result;
}
} // namespace test_runner
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_TEST_RUNNER_LAYOUT_DUMP_H_
#define COMPONENTS_TEST_RUNNER_LAYOUT_DUMP_H_
#include <string>
#include "components/test_runner/layout_dump_flags.h"
#include "components/test_runner/test_runner_export.h"
namespace blink {
class WebLocalFrame;
} // namespace blink
namespace test_runner {
TEST_RUNNER_EXPORT std::string DumpLayout(blink::WebLocalFrame* frame,
const LayoutDumpFlags& flags);
} // namespace test_runner
#endif // COMPONENTS_TEST_RUNNER_LAYOUT_DUMP_H_
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_TEST_RUNNER_LAYOUT_DUMP_FLAGS_H_
#define COMPONENTS_TEST_RUNNER_LAYOUT_DUMP_FLAGS_H_
namespace test_runner {
enum class LayoutDumpMode {
DUMP_AS_TEXT,
DUMP_AS_MARKUP,
DUMP_SCROLL_POSITIONS
};
struct LayoutDumpFlags {
LayoutDumpMode main_dump_mode;
bool dump_as_printed;
bool dump_child_frames;
bool dump_line_box_trees;
bool debug_render_tree;
};
} // namespace test_runner
#endif // COMPONENTS_TEST_RUNNER_LAYOUT_DUMP_FLAGS_H_
......@@ -1863,6 +1863,36 @@ void TestRunner::GetAudioData(std::vector<unsigned char>* buffer_view) const {
*buffer_view = audio_data_;
}
LayoutDumpFlags TestRunner::GetLayoutDumpFlags() {
LayoutDumpFlags result;
if (shouldDumpAsText()) {
result.main_dump_mode = LayoutDumpMode::DUMP_AS_TEXT;
result.dump_child_frames = shouldDumpChildFramesAsText();
} else if (shouldDumpAsMarkup()) {
result.main_dump_mode = LayoutDumpMode::DUMP_AS_MARKUP;
result.dump_child_frames = shouldDumpChildFramesAsMarkup();
} else {
result.main_dump_mode = LayoutDumpMode::DUMP_SCROLL_POSITIONS;
result.dump_child_frames = shouldDumpChildFrameScrollPositions();
}
result.dump_as_printed = isPrinting();
result.dump_line_box_trees = result.debug_render_tree = false;
return result;
}
bool TestRunner::HasCustomTextDump(std::string* custom_text_dump) const {
if (shouldDumpAsCustomText()) {
*custom_text_dump = customDumpText();
return true;
}
return false;
}
bool TestRunner::shouldDumpFrameLoadCallbacks() const {
return test_is_running_ && dump_frame_load_callbacks_;
}
......
......@@ -56,6 +56,9 @@
'gamepad_controller.h',
'gc_controller.cc',
'gc_controller.h',
'layout_dump.cc',
'layout_dump.h',
'layout_dump_flags.h',
'mock_color_chooser.cc',
'mock_color_chooser.h',
'mock_credential_manager_client.cc',
......
......@@ -72,6 +72,8 @@ class TestRunner : public WebTestRunner,
bool ShouldStayOnPageAfterHandlingBeforeUnload() const override;
bool ShouldDumpAsAudio() const override;
void GetAudioData(std::vector<unsigned char>* buffer_view) const override;
LayoutDumpFlags GetLayoutDumpFlags() override;
bool HasCustomTextDump(std::string* custom_text_dump) const override;
bool ShouldDumpBackForwardList() const override;
blink::WebContentSettingsClient* GetWebContentSettings() const override;
......
......@@ -21,6 +21,7 @@
#include "base/trace_event/trace_event.h"
#include "components/test_runner/accessibility_controller.h"
#include "components/test_runner/event_sender.h"
#include "components/test_runner/layout_dump.h"
#include "components/test_runner/mock_color_chooser.h"
#include "components/test_runner/mock_credential_manager_client.h"
#include "components/test_runner/mock_screen_orientation_client.h"
......@@ -289,90 +290,20 @@ const char* WebNavigationPolicyToString(blink::WebNavigationPolicy policy) {
}
}
std::string DumpFrameHeaderIfNeeded(blink::WebFrame* frame) {
std::string result;
// Add header for all but the main frame. Skip empty frames.
if (frame->parent() && !frame->document().documentElement().isNull()) {
result.append("\n--------\nFrame: '");
result.append(frame->uniqueName().utf8().data());
result.append("'\n--------\n");
}
return result;
}
std::string DumpFramesAsMarkup(blink::WebFrame* frame, bool recursive) {
std::string result = DumpFrameHeaderIfNeeded(frame);
result.append(frame->contentAsMarkup().utf8());
result.append("\n");
if (recursive) {
for (blink::WebFrame* child = frame->firstChild(); child;
child = child->nextSibling())
result.append(DumpFramesAsMarkup(child, recursive));
}
return result;
}
std::string DumpDocumentText(blink::WebFrame* frame) {
return frame->document().contentAsTextForTesting().utf8();
}
std::string DumpFramesAsText(blink::WebFrame* frame, bool recursive) {
std::string result = DumpFrameHeaderIfNeeded(frame);
result.append(DumpDocumentText(frame));
result.append("\n");
if (recursive) {
for (blink::WebFrame* child = frame->firstChild(); child;
child = child->nextSibling())
result.append(DumpFramesAsText(child, recursive));
}
return result;
}
std::string DumpFramesAsPrintedText(blink::WebFrame* frame, bool recursive) {
// Cannot do printed format for anything other than HTML
if (!frame->document().isHTMLDocument())
return std::string();
std::string result = DumpFrameHeaderIfNeeded(frame);
result.append(
frame->layoutTreeAsText(blink::WebFrame::LayoutAsTextPrinting).utf8());
result.append("\n");
std::string DumpDeepLayout(blink::WebFrame* frame,
LayoutDumpFlags flags,
bool recursive) {
std::string result = DumpLayout(frame->toWebLocalFrame(), flags);
if (recursive) {
for (blink::WebFrame* child = frame->firstChild(); child;
child = child->nextSibling())
result.append(DumpFramesAsPrintedText(child, recursive));
result.append(DumpDeepLayout(child, flags, recursive));
}
return result;
}
std::string DumpFrameScrollPosition(blink::WebFrame* frame, bool recursive) {
std::string result;
blink::WebSize offset = frame->scrollOffset();
if (offset.width > 0 || offset.height > 0) {
if (frame->parent()) {
result =
std::string("frame '") + frame->uniqueName().utf8().data() + "' ";
}
base::StringAppendF(
&result, "scrolled to %d,%d\n", offset.width, offset.height);
}
if (!recursive)
return result;
for (blink::WebFrame* child = frame->firstChild(); child;
child = child->nextSibling())
result += DumpFrameScrollPosition(child, recursive);
return result;
}
std::string DumpAllBackForwardLists(TestInterfaces* interfaces,
WebTestDelegate* delegate) {
std::string result;
......@@ -488,50 +419,27 @@ void WebTestProxyBase::ShowValidationMessage(
std::string WebTestProxyBase::CaptureTree(
bool debug_render_tree,
bool dump_line_box_trees) {
bool should_dump_custom_text =
test_interfaces_->GetTestRunner()->shouldDumpAsCustomText();
bool should_dump_as_text =
test_interfaces_->GetTestRunner()->shouldDumpAsText();
bool should_dump_as_markup =
test_interfaces_->GetTestRunner()->shouldDumpAsMarkup();
bool should_dump_as_printed = test_interfaces_->GetTestRunner()->isPrinting();
TestRunner* test_runner = test_interfaces_->GetTestRunner();
blink::WebFrame* frame = GetWebView()->mainFrame();
std::string data_utf8;
if (should_dump_custom_text) {
if (test_runner->shouldDumpAsCustomText()) {
// Append a newline for the test driver.
data_utf8 = test_interfaces_->GetTestRunner()->customDumpText() + "\n";
} else if (should_dump_as_text) {
bool recursive =
test_interfaces_->GetTestRunner()->shouldDumpChildFramesAsText();
data_utf8 = should_dump_as_printed ?
DumpFramesAsPrintedText(frame, recursive) :
DumpFramesAsText(frame, recursive);
} else if (should_dump_as_markup) {
bool recursive =
test_interfaces_->GetTestRunner()->shouldDumpChildFramesAsMarkup();
// Append a newline for the test driver.
data_utf8 = DumpFramesAsMarkup(frame, recursive);
} else {
bool recursive = test_interfaces_->GetTestRunner()
->shouldDumpChildFrameScrollPositions();
blink::WebFrame::LayoutAsTextControls layout_text_behavior =
blink::WebFrame::LayoutAsTextNormal;
if (should_dump_as_printed)
layout_text_behavior |= blink::WebFrame::LayoutAsTextPrinting;
if (debug_render_tree)
layout_text_behavior |= blink::WebFrame::LayoutAsTextDebug;
if (dump_line_box_trees)
layout_text_behavior |= blink::WebFrame::LayoutAsTextWithLineTrees;
data_utf8 = frame->layoutTreeAsText(layout_text_behavior).utf8();
data_utf8 += DumpFrameScrollPosition(frame, recursive);
LayoutDumpFlags flags = test_runner->GetLayoutDumpFlags();
data_utf8 = DumpDeepLayout(frame, flags, flags.dump_child_frames);
}
if (test_interfaces_->GetTestRunner()->ShouldDumpBackForwardList())
data_utf8 += DumpAllBackForwardLists(test_interfaces_, delegate_);
data_utf8 += DumpBackForwardLists();
return data_utf8;
}
std::string WebTestProxyBase::DumpBackForwardLists() {
return DumpAllBackForwardLists(test_interfaces_, delegate_);
}
void WebTestProxyBase::DrawSelectionRect(SkCanvas* canvas) {
// See if we need to draw the selection bounds rect. Selection bounds
// rect is the rect enclosing the (possibly transformed) selection.
......
......@@ -114,6 +114,7 @@ class TEST_RUNNER_EXPORT WebTestProxyBase {
void MoveValidationMessage(const blink::WebRect& anchor_in_root_view);
std::string CaptureTree(bool debug_render_tree, bool dump_line_box_trees);
std::string DumpBackForwardLists();
void CapturePixelsForPrinting(
const base::Callback<void(const SkBitmap&)>& callback);
void CopyImageAtAndCapturePixels(
......
......@@ -5,8 +5,11 @@
#ifndef COMPONENTS_TEST_RUNNER_WEB_TEST_RUNNER_H_
#define COMPONENTS_TEST_RUNNER_WEB_TEST_RUNNER_H_
#include <string>
#include <vector>
#include "components/test_runner/layout_dump_flags.h"
namespace blink {
class WebContentSettingsClient;
}
......@@ -28,6 +31,15 @@ class WebTestRunner {
virtual bool ShouldDumpAsAudio() const = 0;
virtual void GetAudioData(std::vector<unsigned char>* buffer_view) const = 0;
// Gets layout dump flags (i.e. dump-as-text or dump-as-markup) requested
// by the test (i.e. via testRunner.dumpAsText() called from javascript).
virtual LayoutDumpFlags GetLayoutDumpFlags() = 0;
// If custom text dump is present (i.e. if testRunner.setCustomTextOutput has
// been called from javascript), then returns |true| and populates the
// |custom_text_dump| argument. Otherwise returns |false|.
virtual bool HasCustomTextDump(std::string* custom_text_dump) const = 0;
// Returns true if the call to WebTestProxy::captureTree will invoke
// WebTestDelegate::captureHistoryForWindow.
virtual bool ShouldDumpBackForwardList() const = 0;
......
......@@ -26,6 +26,7 @@ include_rules = [
"+components/crash",
"+components/devtools_discovery",
"+components/devtools_http_handler",
"+components/test_runner/layout_dump_flags.h", # POD only.
"+components/url_formatter",
# For enabling media related features.
......
......@@ -7,11 +7,13 @@
#include <stddef.h>
#include <iostream>
#include <utility>
#include "base/base64.h"
#include "base/callback.h"
#include "base/command_line.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/string_number_conversions.h"
......@@ -25,6 +27,7 @@
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_types.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/render_widget_host.h"
......@@ -47,9 +50,27 @@
namespace content {
namespace {
const int kTestSVGWindowWidthDip = 480;
const int kTestSVGWindowHeightDip = 360;
void AppendLayoutDumpForFrame(
const std::map<int, std::string>& frame_to_layout_dump_map,
std::string* stitched_layout_dump,
RenderFrameHost* target) {
auto it = frame_to_layout_dump_map.find(target->GetFrameTreeNodeId());
// No match will happen if frames have been added since OnInitiateLayoutDump.
if (it == frame_to_layout_dump_map.end())
return;
const std::string& dump = it->second;
stitched_layout_dump->append(dump);
}
} // namespace
// BlinkTestResultPrinter ----------------------------------------------------
BlinkTestResultPrinter::BlinkTestResultPrinter(std::ostream* output,
......@@ -257,6 +278,7 @@ bool BlinkTestController::PrepareForLayoutTest(
expected_pixel_hash_ = expected_pixel_hash;
test_url_ = test_url;
printer_->reset();
frame_to_layout_dump_map_.clear();
ShellBrowserContext* browser_context =
ShellContentBrowserClient::Get()->browser_context();
if (test_url.spec().find("compositing/") != std::string::npos)
......@@ -392,6 +414,8 @@ bool BlinkTestController::OnMessageReceived(const IPC::Message& message) {
IPC_BEGIN_MESSAGE_MAP(BlinkTestController, message)
IPC_MESSAGE_HANDLER(ShellViewHostMsg_PrintMessage, OnPrintMessage)
IPC_MESSAGE_HANDLER(ShellViewHostMsg_TextDump, OnTextDump)
IPC_MESSAGE_HANDLER(ShellViewHostMsg_InitiateLayoutDump,
OnInitiateLayoutDump)
IPC_MESSAGE_HANDLER(ShellViewHostMsg_ImageDump, OnImageDump)
IPC_MESSAGE_HANDLER(ShellViewHostMsg_AudioDump, OnAudioDump)
IPC_MESSAGE_HANDLER(ShellViewHostMsg_OverridePreferences,
......@@ -422,6 +446,19 @@ bool BlinkTestController::OnMessageReceived(const IPC::Message& message) {
return handled;
}
bool BlinkTestController::OnMessageReceived(
const IPC::Message& message,
RenderFrameHost* render_frame_host) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(BlinkTestController, message,
render_frame_host)
IPC_MESSAGE_HANDLER(ShellViewHostMsg_LayoutDumpResponse,
OnLayoutDumpResponse)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
void BlinkTestController::PluginCrashed(const base::FilePath& plugin_path,
base::ProcessId plugin_pid) {
DCHECK(CalledOnValidThread());
......@@ -597,6 +634,42 @@ void BlinkTestController::OnTextDump(const std::string& dump) {
printer_->PrintTextFooter();
}
void BlinkTestController::OnInitiateLayoutDump(
test_runner::LayoutDumpFlags layout_dump_flags) {
DCHECK(layout_dump_flags.dump_child_frames);
pending_layout_dumps_ = main_window_->web_contents()->SendToAllFrames(
new ShellViewMsg_LayoutDumpRequest(MSG_ROUTING_NONE, layout_dump_flags));
}
void BlinkTestController::OnLayoutDumpResponse(RenderFrameHost* sender,
const std::string& dump) {
// Store the result.
auto pair = frame_to_layout_dump_map_.insert(
std::make_pair(sender->GetFrameTreeNodeId(), dump));
bool insertion_took_place = pair.second;
DCHECK(insertion_took_place);
// See if we need to wait for more responses.
pending_layout_dumps_--;
DCHECK_LE(0, pending_layout_dumps_);
if (pending_layout_dumps_ > 0)
return;
// Stitch the frame-specific results in the right order.
// TODO(lukasza): Replace with a for loop similar to crrev.com/1612503003.
std::string stitched_layout_dump;
main_window_->web_contents()->ForEachFrame(base::Bind(
&AppendLayoutDumpForFrame,
base::ConstRef(frame_to_layout_dump_map_),
&stitched_layout_dump));
// Continue finishing the test.
RenderViewHost* render_view_host =
main_window_->web_contents()->GetRenderViewHost();
render_view_host->Send(new ShellViewMsg_LayoutDumpCompleted(
render_view_host->GetRoutingID(), stitched_layout_dump));
}
void BlinkTestController::OnPrintMessage(const std::string& message) {
printer_->AddMessageRaw(message);
}
......
......@@ -5,6 +5,7 @@
#ifndef CONTENT_SHELL_BROWSER_BLINK_TEST_CONTROLLER_H_
#define CONTENT_SHELL_BROWSER_BLINK_TEST_CONTROLLER_H_
#include <map>
#include <ostream>
#include <string>
......@@ -15,6 +16,7 @@
#include "base/synchronization/lock.h"
#include "base/threading/non_thread_safe.h"
#include "build/build_config.h"
#include "components/test_runner/layout_dump_flags.h"
#include "content/public/browser/bluetooth_chooser.h"
#include "content/public/browser/gpu_data_manager_observer.h"
#include "content/public/browser/notification_observer.h"
......@@ -38,6 +40,7 @@ namespace content {
class LayoutTestBluetoothChooserFactory;
class LayoutTestDevToolsFrontend;
class RenderFrameHost;
class Shell;
#if defined(OS_ANDROID)
......@@ -144,6 +147,8 @@ class BlinkTestController : public base::NonThreadSafe,
// WebContentsObserver implementation.
bool OnMessageReceived(const IPC::Message& message) override;
bool OnMessageReceived(const IPC::Message& message,
RenderFrameHost* render_frame_host) override;
void PluginCrashed(const base::FilePath& plugin_path,
base::ProcessId plugin_pid) override;
void RenderViewCreated(RenderViewHost* render_view_host) override;
......@@ -174,6 +179,8 @@ class BlinkTestController : public base::NonThreadSafe,
void OnAudioDump(const std::vector<unsigned char>& audio_dump);
void OnImageDump(const std::string& actual_pixel_hash, const SkBitmap& image);
void OnTextDump(const std::string& dump);
void OnInitiateLayoutDump(test_runner::LayoutDumpFlags layout_dump_flags);
void OnLayoutDumpResponse(RenderFrameHost* sender, const std::string& dump);
void OnPrintMessage(const std::string& message);
void OnOverridePreferences(const WebPreferences& prefs);
void OnTestFinished();
......@@ -233,6 +240,11 @@ class BlinkTestController : public base::NonThreadSafe,
scoped_ptr<LayoutTestBluetoothChooserFactory> bluetooth_chooser_factory_;
// Map from frame_tree_node_id into frame-specific dumps.
std::map<int, std::string> frame_to_layout_dump_map_;
// Number of ShellViewHostMsg_LayoutDumpResponse messages we are waiting for.
int pending_layout_dumps_;
#if defined(OS_ANDROID)
// Because of the nested message pump implementation, Android needs to allow
// waiting on the UI thread while layout tests are being ran.
......
......@@ -6,6 +6,7 @@
#include <string>
#include <vector>
#include "components/test_runner/layout_dump_flags.h"
#include "content/public/common/common_param_traits.h"
#include "content/public/common/page_state.h"
#include "content/shell/common/leak_detection_result.h"
......@@ -27,6 +28,19 @@ IPC_STRUCT_TRAITS_MEMBER(expected_pixel_hash)
IPC_STRUCT_TRAITS_MEMBER(initial_size)
IPC_STRUCT_TRAITS_END()
IPC_ENUM_TRAITS_MIN_MAX_VALUE(
test_runner::LayoutDumpMode,
test_runner::LayoutDumpMode::DUMP_AS_TEXT,
test_runner::LayoutDumpMode::DUMP_SCROLL_POSITIONS)
IPC_STRUCT_TRAITS_BEGIN(test_runner::LayoutDumpFlags)
IPC_STRUCT_TRAITS_MEMBER(main_dump_mode)
IPC_STRUCT_TRAITS_MEMBER(dump_as_printed)
IPC_STRUCT_TRAITS_MEMBER(dump_child_frames)
IPC_STRUCT_TRAITS_MEMBER(dump_line_box_trees)
IPC_STRUCT_TRAITS_MEMBER(debug_render_tree)
IPC_STRUCT_TRAITS_END()
// Tells the renderer to reset all test runners.
IPC_MESSAGE_ROUTED0(ShellViewMsg_Reset)
......@@ -54,10 +68,29 @@ IPC_MESSAGE_ROUTED3(
IPC_MESSAGE_ROUTED0(ShellViewMsg_TryLeakDetection)
// Asks a frame to dump its contents into a string and send them back over IPC.
IPC_MESSAGE_ROUTED1(ShellViewMsg_LayoutDumpRequest,
test_runner::LayoutDumpFlags)
// Notifies BlinkTestRunner that the layout dump has completed
// (and that it can proceed with finishing up the test).
IPC_MESSAGE_ROUTED1(ShellViewMsg_LayoutDumpCompleted,
std::string /* completed/stitched layout dump */)
// Send a text dump of the WebContents to the render host.
IPC_MESSAGE_ROUTED1(ShellViewHostMsg_TextDump,
std::string /* dump */)
// Asks the browser process to perform a layout dump (potentially spanning
// multiple cross-process frames) using the given flags. This triggers
// multiple ShellViewMsg_LayoutDumpRequest / ShellViewHostMsg_LayoutDumpResponse
// messages and ends with sending of ShellViewMsg_LayoutDumpCompleted.
IPC_MESSAGE_ROUTED1(ShellViewHostMsg_InitiateLayoutDump,
test_runner::LayoutDumpFlags)
// Sends a layout dump of a frame (response to ShellViewMsg_LayoutDumpRequest).
IPC_MESSAGE_ROUTED1(ShellViewHostMsg_LayoutDumpResponse, std::string /* dump */)
// Send an image dump of the WebContents to the render host.
IPC_MESSAGE_ROUTED2(ShellViewHostMsg_ImageDump,
std::string /* actual pixel hash */,
......
......@@ -30,6 +30,8 @@
#include "components/plugins/renderer/plugin_placeholder.h"
#include "components/test_runner/app_banner_client.h"
#include "components/test_runner/gamepad_controller.h"
#include "components/test_runner/layout_dump.h"
#include "components/test_runner/layout_dump_flags.h"
#include "components/test_runner/mock_screen_orientation_client.h"
#include "components/test_runner/test_interfaces.h"
#include "components/test_runner/web_task.h"
......@@ -819,6 +821,7 @@ bool BlinkTestRunner::OnMessageReceived(const IPC::Message& message) {
IPC_MESSAGE_HANDLER(ShellViewMsg_TryLeakDetection, OnTryLeakDetection)
IPC_MESSAGE_HANDLER(ShellViewMsg_ReplyBluetoothManualChooserEvents,
OnReplyBluetoothManualChooserEvents)
IPC_MESSAGE_HANDLER(ShellViewMsg_LayoutDumpCompleted, OnLayoutDumpCompleted)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
......@@ -887,33 +890,70 @@ void BlinkTestRunner::CaptureDump() {
std::vector<unsigned char> vector_data;
interfaces->TestRunner()->GetAudioData(&vector_data);
Send(new ShellViewHostMsg_AudioDump(routing_id(), vector_data));
} else {
const base::CommandLine& command_line =
*base::CommandLine::ForCurrentProcess();
Send(new ShellViewHostMsg_TextDump(
routing_id(), proxy()->CaptureTree(
false, command_line.HasSwitch(switches::kDumpLineBoxTrees))));
if (test_config_.enable_pixel_dumping &&
interfaces->TestRunner()->ShouldGeneratePixelResults()) {
CHECK(render_view()->GetWebView()->isAcceleratedCompositingActive());
proxy()->CapturePixelsAsync(base::Bind(
&BlinkTestRunner::CaptureDumpPixels, base::Unretained(this)));
return;
}
CaptureDumpContinued();
return;
}
#ifndef NDEBUG
// Force a layout/paint by the end of the test to ensure test coverage of
// incremental painting.
proxy()->LayoutAndPaintAsyncThen(base::Bind(
&BlinkTestRunner::CaptureDumpComplete, base::Unretained(this)));
std::string custom_text_dump;
if (interfaces->TestRunner()->HasCustomTextDump(&custom_text_dump)) {
Send(new ShellViewHostMsg_TextDump(routing_id(), custom_text_dump + "\n"));
CaptureDumpContinued();
return;
}
test_runner::LayoutDumpFlags layout_dump_flags =
interfaces->TestRunner()->GetLayoutDumpFlags();
layout_dump_flags.dump_line_box_trees =
base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDumpLineBoxTrees);
if (!layout_dump_flags.dump_child_frames) {
std::string layout_dump = DumpLayout(
render_view()->GetMainRenderFrame()->GetWebFrame(), layout_dump_flags);
OnLayoutDumpCompleted(layout_dump);
return;
}
Send(
new ShellViewHostMsg_InitiateLayoutDump(routing_id(), layout_dump_flags));
// OnLayoutDumpCompleted will be eventually called by an IPC from the browser.
}
void BlinkTestRunner::OnLayoutDumpCompleted(std::string completed_layout_dump) {
test_runner::WebTestInterfaces* interfaces =
LayoutTestRenderProcessObserver::GetInstance()->test_interfaces();
if (interfaces->TestRunner()->ShouldDumpBackForwardList()) {
completed_layout_dump.append(proxy()->DumpBackForwardLists());
}
Send(new ShellViewHostMsg_TextDump(routing_id(), completed_layout_dump));
CaptureDumpContinued();
}
void BlinkTestRunner::CaptureDumpContinued() {
test_runner::WebTestInterfaces* interfaces =
LayoutTestRenderProcessObserver::GetInstance()->test_interfaces();
if (test_config_.enable_pixel_dumping &&
interfaces->TestRunner()->ShouldGeneratePixelResults() &&
!interfaces->TestRunner()->ShouldDumpAsAudio()) {
CHECK(render_view()->GetWebView()->isAcceleratedCompositingActive());
proxy()->CapturePixelsAsync(base::Bind(
&BlinkTestRunner::OnPixelsDumpCompleted, base::Unretained(this)));
return;
}
#ifndef NDEBUG
// Force a layout/paint by the end of the test to ensure test coverage of
// incremental painting.
proxy()->LayoutAndPaintAsyncThen(base::Bind(
&BlinkTestRunner::CaptureDumpComplete, base::Unretained(this)));
#else
CaptureDumpComplete();
#endif
}
void BlinkTestRunner::CaptureDumpPixels(const SkBitmap& snapshot) {
void BlinkTestRunner::OnPixelsDumpCompleted(const SkBitmap& snapshot) {
DCHECK_NE(0, snapshot.info().width());
DCHECK_NE(0, snapshot.info().height());
......
......@@ -41,6 +41,8 @@ class LeakDetector;
struct LeakDetectionResult;
// This is the renderer side of the webkit test runner.
// TODO(lukasza): Rename to LayoutTestRenderViewObserver for consistency with
// LayoutTestRenderFrameObserver.
class BlinkTestRunner : public RenderViewObserver,
public RenderViewObserverTracker<BlinkTestRunner>,
public test_runner::WebTestDelegate {
......@@ -177,7 +179,9 @@ class BlinkTestRunner : public RenderViewObserver,
// After finishing the test, retrieves the audio, text, and pixel dumps from
// the TestRunner library and sends them to the browser process.
void CaptureDump();
void CaptureDumpPixels(const SkBitmap& snapshot);
void OnLayoutDumpCompleted(std::string completed_layout_dump);
void CaptureDumpContinued();
void OnPixelsDumpCompleted(const SkBitmap& snapshot);
void CaptureDumpComplete();
test_runner::WebTestProxyBase* proxy_;
......
......@@ -4,10 +4,16 @@
#include "content/shell/renderer/layout_test/layout_test_render_frame_observer.h"
#include <string>
#include "components/test_runner/layout_dump.h"
#include "components/test_runner/layout_dump_flags.h"
#include "components/test_runner/web_test_interfaces.h"
#include "components/test_runner/web_test_runner.h"
#include "content/public/renderer/render_frame.h"
#include "content/shell/common/shell_messages.h"
#include "content/shell/renderer/layout_test/layout_test_render_process_observer.h"
#include "ipc/ipc_message_macros.h"
#include "third_party/WebKit/public/web/WebLocalFrame.h"
namespace content {
......@@ -22,4 +28,22 @@ LayoutTestRenderFrameObserver::LayoutTestRenderFrameObserver(
->GetWebContentSettings());
}
bool LayoutTestRenderFrameObserver::OnMessageReceived(
const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(LayoutTestRenderFrameObserver, message)
IPC_MESSAGE_HANDLER(ShellViewMsg_LayoutDumpRequest, OnLayoutDumpRequest)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
void LayoutTestRenderFrameObserver::OnLayoutDumpRequest(
test_runner::LayoutDumpFlags layout_dump_flags) {
std::string dump =
test_runner::DumpLayout(render_frame()->GetWebFrame(), layout_dump_flags);
Send(new ShellViewHostMsg_LayoutDumpResponse(routing_id(), dump));
}
} // namespace content
......@@ -6,8 +6,13 @@
#define CONTENT_SHELL_RENDERER_LAYOUT_TEST_LAYOUT_TEST_RENDER_FRAME_OBSERVER_H_
#include "base/macros.h"
#include "components/test_runner/layout_dump_flags.h"
#include "content/public/renderer/render_frame_observer.h"
namespace IPC {
class Message;
} // namespace IPC
namespace content {
class RenderFrame;
......@@ -16,7 +21,11 @@ class LayoutTestRenderFrameObserver : public RenderFrameObserver {
explicit LayoutTestRenderFrameObserver(RenderFrame* render_frame);
~LayoutTestRenderFrameObserver() override {}
bool OnMessageReceived(const IPC::Message& message) override;
private:
void OnLayoutDumpRequest(test_runner::LayoutDumpFlags layout_dump_flags);
DISALLOW_COPY_AND_ASSIGN(LayoutTestRenderFrameObserver);
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment