| Index: components/html_viewer/html_frame_apptest.cc
|
| diff --git a/components/html_viewer/html_frame_apptest.cc b/components/html_viewer/html_frame_apptest.cc
|
| deleted file mode 100644
|
| index a52baad4b04cf46d5c561e3010d22bc9d77ec085..0000000000000000000000000000000000000000
|
| --- a/components/html_viewer/html_frame_apptest.cc
|
| +++ /dev/null
|
| @@ -1,492 +0,0 @@
|
| -// Copyright 2015 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 <stddef.h>
|
| -#include <stdint.h>
|
| -#include <utility>
|
| -
|
| -#include "base/auto_reset.h"
|
| -#include "base/bind.h"
|
| -#include "base/callback.h"
|
| -#include "base/command_line.h"
|
| -#include "base/json/json_reader.h"
|
| -#include "base/macros.h"
|
| -#include "base/run_loop.h"
|
| -#include "base/strings/stringprintf.h"
|
| -#include "base/test/test_timeouts.h"
|
| -#include "base/time/time.h"
|
| -#include "base/values.h"
|
| -#include "build/build_config.h"
|
| -#include "components/html_viewer/public/interfaces/test_html_viewer.mojom.h"
|
| -#include "components/mus/public/cpp/tests/window_server_test_base.h"
|
| -#include "components/mus/public/cpp/window.h"
|
| -#include "components/mus/public/cpp/window_tree_connection.h"
|
| -#include "components/web_view/frame.h"
|
| -#include "components/web_view/frame_connection.h"
|
| -#include "components/web_view/frame_tree.h"
|
| -#include "components/web_view/public/interfaces/frame.mojom.h"
|
| -#include "components/web_view/test_frame_tree_delegate.h"
|
| -#include "mojo/services/accessibility/public/interfaces/accessibility.mojom.h"
|
| -#include "net/test/embedded_test_server/embedded_test_server.h"
|
| -
|
| -using mus::mojom::WindowTreeClientPtr;
|
| -using mus::WindowServerTestBase;
|
| -using web_view::Frame;
|
| -using web_view::FrameConnection;
|
| -using web_view::FrameTree;
|
| -using web_view::FrameTreeDelegate;
|
| -using web_view::mojom::FrameClient;
|
| -
|
| -namespace mojo {
|
| -
|
| -namespace {
|
| -
|
| -const char kAddFrameWithEmptyPageScript[] =
|
| - "var iframe = document.createElement(\"iframe\");"
|
| - "iframe.src = \"http://127.0.0.1:%u/empty_page.html\";"
|
| - "document.body.appendChild(iframe);";
|
| -
|
| -void OnGotContentHandlerForRoot(bool* got_callback) {
|
| - *got_callback = true;
|
| - ignore_result(WindowServerTestBase::QuitRunLoop());
|
| -}
|
| -
|
| -mojo::Connection* ConnectionForFrame(Frame* frame) {
|
| - return static_cast<FrameConnection*>(frame->user_data())->connection();
|
| -}
|
| -
|
| -std::string GetFrameText(Connection* connection) {
|
| - html_viewer::TestHTMLViewerPtr test_html_viewer;
|
| - connection->ConnectToService(&test_html_viewer);
|
| - std::string result;
|
| - test_html_viewer->GetContentAsText([&result](const String& mojo_string) {
|
| - result = mojo_string;
|
| - ASSERT_TRUE(WindowServerTestBase::QuitRunLoop());
|
| - });
|
| - if (!WindowServerTestBase::DoRunLoopWithTimeout())
|
| - ADD_FAILURE() << "Timed out waiting for execute to complete";
|
| - // test_html_viewer.WaitForIncomingResponse();
|
| - return result;
|
| -}
|
| -
|
| -scoped_ptr<base::Value> ExecuteScript(Connection* connection,
|
| - const std::string& script) {
|
| - html_viewer::TestHTMLViewerPtr test_html_viewer;
|
| - connection->ConnectToService(&test_html_viewer);
|
| - scoped_ptr<base::Value> result;
|
| - test_html_viewer->ExecuteScript(script, [&result](const String& json_string) {
|
| - result = base::JSONReader::Read(json_string.To<std::string>());
|
| - ASSERT_TRUE(WindowServerTestBase::QuitRunLoop());
|
| - });
|
| - if (!WindowServerTestBase::DoRunLoopWithTimeout())
|
| - ADD_FAILURE() << "Timed out waiting for execute to complete";
|
| - return result;
|
| -}
|
| -
|
| -// FrameTreeDelegate that can block waiting for navigation to start.
|
| -class TestFrameTreeDelegateImpl : public web_view::TestFrameTreeDelegate {
|
| - public:
|
| - explicit TestFrameTreeDelegateImpl(mojo::Shell* shell)
|
| - : TestFrameTreeDelegate(shell), frame_tree_(nullptr) {}
|
| - ~TestFrameTreeDelegateImpl() override {}
|
| -
|
| - void set_frame_tree(FrameTree* frame_tree) { frame_tree_ = frame_tree; }
|
| -
|
| - // Resets the navigation state for |frame|.
|
| - void ClearGotNavigate(Frame* frame) { frames_navigated_.erase(frame); }
|
| -
|
| - // Waits until |frame| has |count| children and the last child has navigated.
|
| - bool WaitForChildFrameCount(Frame* frame, size_t count) {
|
| - if (DidChildNavigate(frame, count))
|
| - return true;
|
| -
|
| - waiting_for_frame_child_count_.reset(new FrameAndChildCount);
|
| - waiting_for_frame_child_count_->frame = frame;
|
| - waiting_for_frame_child_count_->count = count;
|
| -
|
| - return WindowServerTestBase::DoRunLoopWithTimeout();
|
| - }
|
| -
|
| - // Returns true if |frame| has navigated. If |frame| hasn't navigated runs
|
| - // a nested message loop until |frame| navigates.
|
| - bool WaitForFrameNavigation(Frame* frame) {
|
| - if (frames_navigated_.count(frame))
|
| - return true;
|
| -
|
| - frames_waiting_for_navigate_.insert(frame);
|
| - return WindowServerTestBase::DoRunLoopWithTimeout();
|
| - }
|
| -
|
| - // TestFrameTreeDelegate:
|
| - void DidStartNavigation(Frame* frame) override {
|
| - frames_navigated_.insert(frame);
|
| -
|
| - if (waiting_for_frame_child_count_ &&
|
| - DidChildNavigate(waiting_for_frame_child_count_->frame,
|
| - waiting_for_frame_child_count_->count)) {
|
| - waiting_for_frame_child_count_.reset();
|
| - ASSERT_TRUE(WindowServerTestBase::QuitRunLoop());
|
| - }
|
| -
|
| - if (frames_waiting_for_navigate_.count(frame)) {
|
| - frames_waiting_for_navigate_.erase(frame);
|
| - ignore_result(WindowServerTestBase::QuitRunLoop());
|
| - }
|
| - }
|
| -
|
| - private:
|
| - struct FrameAndChildCount {
|
| - Frame* frame;
|
| - size_t count;
|
| - };
|
| -
|
| - // Returns true if |frame| has |count| children and the last child frame
|
| - // has navigated.
|
| - bool DidChildNavigate(Frame* frame, size_t count) {
|
| - return ((frame->children().size() == count) &&
|
| - (frames_navigated_.count(frame->children()[count - 1])));
|
| - }
|
| -
|
| - FrameTree* frame_tree_;
|
| - // Any time DidStartNavigation() is invoked the frame is added here. Frames
|
| - // are inserted as void* as this does not track destruction of the frames.
|
| - std::set<void*> frames_navigated_;
|
| -
|
| - // The set of frames waiting for a navigation to occur.
|
| - std::set<Frame*> frames_waiting_for_navigate_;
|
| -
|
| - // Set of frames waiting for a certain number of children and navigation.
|
| - scoped_ptr<FrameAndChildCount> waiting_for_frame_child_count_;
|
| -
|
| - DISALLOW_COPY_AND_ASSIGN(TestFrameTreeDelegateImpl);
|
| -};
|
| -
|
| -} // namespace
|
| -
|
| -class HTMLFrameTest : public WindowServerTestBase {
|
| - public:
|
| - HTMLFrameTest() {}
|
| - ~HTMLFrameTest() override {}
|
| -
|
| - protected:
|
| - // Creates the frame tree showing an empty page at the root and adds (via
|
| - // script) a frame showing the same empty page.
|
| - Frame* LoadEmptyPageAndCreateFrame() {
|
| - mus::Window* embed_window = window_manager()->NewWindow();
|
| - frame_tree_delegate_.reset(new TestFrameTreeDelegateImpl(shell()));
|
| - FrameConnection* root_connection = InitFrameTree(
|
| - embed_window, "http://127.0.0.1:%u/empty_page2.html");
|
| - if (!root_connection) {
|
| - ADD_FAILURE() << "unable to establish root connection";
|
| - return nullptr;
|
| - }
|
| - const std::string frame_text = GetFrameText(root_connection->connection());
|
| - if (frame_text != "child2") {
|
| - ADD_FAILURE() << "unexpected text " << frame_text;
|
| - return nullptr;
|
| - }
|
| -
|
| - return CreateEmptyChildFrame(frame_tree_->root());
|
| - }
|
| -
|
| - Frame* CreateEmptyChildFrame(Frame* parent) {
|
| - const size_t initial_frame_count = parent->children().size();
|
| - // Dynamically add a new frame.
|
| - ExecuteScript(ConnectionForFrame(parent),
|
| - AddPortToString(kAddFrameWithEmptyPageScript));
|
| -
|
| - frame_tree_delegate_->WaitForChildFrameCount(parent,
|
| - initial_frame_count + 1);
|
| - if (HasFatalFailure())
|
| - return nullptr;
|
| -
|
| - return parent->FindFrame(parent->window()->children().back()->id());
|
| - }
|
| -
|
| - std::string AddPortToString(const std::string& string) {
|
| - const uint16_t assigned_port = http_server_->host_port_pair().port();
|
| - return base::StringPrintf(string.c_str(), assigned_port);
|
| - }
|
| -
|
| - mojo::URLRequestPtr BuildRequestForURL(const std::string& url_string) {
|
| - mojo::URLRequestPtr request(mojo::URLRequest::New());
|
| - request->url = mojo::String::From(AddPortToString(url_string));
|
| - return request;
|
| - }
|
| -
|
| - FrameConnection* InitFrameTree(mus::Window* view,
|
| - const std::string& url_string) {
|
| - frame_tree_delegate_.reset(new TestFrameTreeDelegateImpl(shell()));
|
| - scoped_ptr<FrameConnection> frame_connection(new FrameConnection);
|
| - bool got_callback = false;
|
| - frame_connection->Init(
|
| - shell(), BuildRequestForURL(url_string),
|
| - base::Bind(&OnGotContentHandlerForRoot, &got_callback));
|
| - ignore_result(WindowServerTestBase::DoRunLoopWithTimeout());
|
| - if (!got_callback)
|
| - return nullptr;
|
| - FrameConnection* result = frame_connection.get();
|
| - FrameClient* frame_client = frame_connection->frame_client();
|
| - WindowTreeClientPtr tree_client = frame_connection->GetWindowTreeClient();
|
| - frame_tree_.reset(new FrameTree(
|
| - result->GetContentHandlerID(), view, std::move(tree_client),
|
| - frame_tree_delegate_.get(), frame_client, std::move(frame_connection),
|
| - Frame::ClientPropertyMap(), base::TimeTicks::Now()));
|
| - frame_tree_delegate_->set_frame_tree(frame_tree_.get());
|
| - return result;
|
| - }
|
| -
|
| - // ViewManagerTest:
|
| - void SetUp() override {
|
| - WindowServerTestBase::SetUp();
|
| -
|
| - // Start a test server.
|
| - http_server_.reset(new net::EmbeddedTestServer);
|
| - http_server_->ServeFilesFromSourceDirectory(
|
| - "components/test/data/html_viewer");
|
| - ASSERT_TRUE(http_server_->Start());
|
| - }
|
| - void TearDown() override {
|
| - frame_tree_.reset();
|
| - http_server_.reset();
|
| - WindowServerTestBase::TearDown();
|
| - }
|
| -
|
| - scoped_ptr<net::EmbeddedTestServer> http_server_;
|
| - scoped_ptr<FrameTree> frame_tree_;
|
| -
|
| - scoped_ptr<TestFrameTreeDelegateImpl> frame_tree_delegate_;
|
| -
|
| - private:
|
| - DISALLOW_COPY_AND_ASSIGN(HTMLFrameTest);
|
| -};
|
| -
|
| -// Crashes on linux_chromium_rel_ng only. http://crbug.com/567337
|
| -#if defined(OS_LINUX)
|
| -#define MAYBE_PageWithSingleFrame DISABLED_PageWithSingleFrame
|
| -#else
|
| -#define MAYBE_PageWithSingleFrame PageWithSingleFrame
|
| -#endif
|
| -TEST_F(HTMLFrameTest, MAYBE_PageWithSingleFrame) {
|
| - mus::Window* embed_window = window_manager()->NewWindow();
|
| -
|
| - FrameConnection* root_connection = InitFrameTree(
|
| - embed_window, "http://127.0.0.1:%u/page_with_single_frame.html");
|
| - ASSERT_TRUE(root_connection);
|
| -
|
| - ASSERT_EQ("Page with single frame",
|
| - GetFrameText(root_connection->connection()));
|
| -
|
| - ASSERT_NO_FATAL_FAILURE(
|
| - frame_tree_delegate_->WaitForChildFrameCount(frame_tree_->root(), 1u));
|
| -
|
| - ASSERT_EQ(1u, embed_window->children().size());
|
| - Frame* child_frame =
|
| - frame_tree_->root()->FindFrame(embed_window->children()[0]->id());
|
| - ASSERT_TRUE(child_frame);
|
| -
|
| - ASSERT_EQ("child",
|
| - GetFrameText(static_cast<FrameConnection*>(child_frame->user_data())
|
| - ->connection()));
|
| -}
|
| -
|
| -// Creates two frames. The parent navigates the child frame by way of changing
|
| -// the location of the child frame.
|
| -// Crashes on linux_chromium_rel_ng only. http://crbug.com/567337
|
| -#if defined(OS_LINUX)
|
| -#define MAYBE_ChangeLocationOfChildFrame DISABLED_ChangeLocationOfChildFrame
|
| -#else
|
| -#define MAYBE_ChangeLocationOfChildFrame ChangeLocationOfChildFrame
|
| -#endif
|
| -TEST_F(HTMLFrameTest, MAYBE_ChangeLocationOfChildFrame) {
|
| - mus::Window* embed_window = window_manager()->NewWindow();
|
| -
|
| - ASSERT_TRUE(InitFrameTree(
|
| - embed_window, "http://127.0.0.1:%u/page_with_single_frame.html"));
|
| -
|
| - // page_with_single_frame contains a child frame. The child frame should
|
| - // create a new View and Frame.
|
| - ASSERT_NO_FATAL_FAILURE(
|
| - frame_tree_delegate_->WaitForChildFrameCount(frame_tree_->root(), 1u));
|
| -
|
| - Frame* child_frame = frame_tree_->root()->children().back();
|
| -
|
| - ASSERT_EQ("child",
|
| - GetFrameText(static_cast<FrameConnection*>(child_frame->user_data())
|
| - ->connection()));
|
| -
|
| - // Change the location and wait for the navigation to occur.
|
| - const char kNavigateFrame[] =
|
| - "window.frames[0].location = "
|
| - "'http://127.0.0.1:%u/empty_page2.html'";
|
| - frame_tree_delegate_->ClearGotNavigate(child_frame);
|
| - ExecuteScript(ConnectionForFrame(frame_tree_->root()),
|
| - AddPortToString(kNavigateFrame));
|
| - ASSERT_TRUE(frame_tree_delegate_->WaitForFrameNavigation(child_frame));
|
| -
|
| - // There should still only be one frame.
|
| - ASSERT_EQ(1u, frame_tree_->root()->children().size());
|
| -
|
| - // The navigation should have changed the text of the frame.
|
| - ASSERT_TRUE(child_frame->user_data());
|
| - ASSERT_EQ("child2",
|
| - GetFrameText(static_cast<FrameConnection*>(child_frame->user_data())
|
| - ->connection()));
|
| -}
|
| -
|
| -TEST_F(HTMLFrameTest, DynamicallyAddFrameAndVerifyParent) {
|
| - Frame* child_frame = LoadEmptyPageAndCreateFrame();
|
| - ASSERT_TRUE(child_frame);
|
| -
|
| - mojo::Connection* child_frame_connection = ConnectionForFrame(child_frame);
|
| -
|
| - ASSERT_EQ("child", GetFrameText(child_frame_connection));
|
| - // The child's parent should not be itself:
|
| - const char kGetWindowParentNameScript[] =
|
| - "window.parent == window ? 'parent is self' : 'parent not self';";
|
| - scoped_ptr<base::Value> parent_value(
|
| - ExecuteScript(child_frame_connection, kGetWindowParentNameScript));
|
| - ASSERT_TRUE(parent_value->IsType(base::Value::TYPE_LIST));
|
| - base::ListValue* parent_list;
|
| - ASSERT_TRUE(parent_value->GetAsList(&parent_list));
|
| - ASSERT_EQ(1u, parent_list->GetSize());
|
| - std::string parent_name;
|
| - ASSERT_TRUE(parent_list->GetString(0u, &parent_name));
|
| - EXPECT_EQ("parent not self", parent_name);
|
| -}
|
| -
|
| -TEST_F(HTMLFrameTest, DynamicallyAddFrameAndSeeNameChange) {
|
| - Frame* child_frame = LoadEmptyPageAndCreateFrame();
|
| - ASSERT_TRUE(child_frame);
|
| -
|
| - mojo::Connection* child_frame_connection = ConnectionForFrame(child_frame);
|
| -
|
| - // Change the name of the child's window.
|
| - ExecuteScript(child_frame_connection, "window.name = 'new_child';");
|
| -
|
| - // Eventually the parent should see the change. There is no convenient way
|
| - // to observe this change, so we repeatedly ask for it and timeout if we
|
| - // never get the right value.
|
| - const base::TimeTicks start_time(base::TimeTicks::Now());
|
| - std::string find_window_result;
|
| - do {
|
| - find_window_result.clear();
|
| - scoped_ptr<base::Value> script_value(
|
| - ExecuteScript(ConnectionForFrame(frame_tree_->root()),
|
| - "window.frames['new_child'] != null ? 'found frame' : "
|
| - "'unable to find frame';"));
|
| - if (script_value->IsType(base::Value::TYPE_LIST)) {
|
| - base::ListValue* script_value_as_list;
|
| - if (script_value->GetAsList(&script_value_as_list) &&
|
| - script_value_as_list->GetSize() == 1) {
|
| - script_value_as_list->GetString(0u, &find_window_result);
|
| - }
|
| - }
|
| - } while (find_window_result != "found frame" &&
|
| - base::TimeTicks::Now() - start_time <
|
| - TestTimeouts::action_timeout());
|
| - EXPECT_EQ("found frame", find_window_result);
|
| -}
|
| -
|
| -// Triggers dynamic addition and removal of a frame.
|
| -TEST_F(HTMLFrameTest, FrameTreeOfThreeLevels) {
|
| - // Create a child frame, and in that child frame create another child frame.
|
| - Frame* child_frame = LoadEmptyPageAndCreateFrame();
|
| - ASSERT_TRUE(child_frame);
|
| -
|
| - ASSERT_TRUE(CreateEmptyChildFrame(child_frame));
|
| -
|
| - // Make sure the parent can see the child and child's child. There is no
|
| - // convenient way to observe this change, so we repeatedly ask for it and
|
| - // timeout if we never get the right value.
|
| - const char kGetChildChildFrameCount[] =
|
| - "if (window.frames.length > 0)"
|
| - " window.frames[0].frames.length.toString();"
|
| - "else"
|
| - " '0';";
|
| - const base::TimeTicks start_time(base::TimeTicks::Now());
|
| - std::string child_child_frame_count;
|
| - do {
|
| - child_child_frame_count.clear();
|
| - scoped_ptr<base::Value> script_value(
|
| - ExecuteScript(ConnectionForFrame(frame_tree_->root()),
|
| - kGetChildChildFrameCount));
|
| - if (script_value->IsType(base::Value::TYPE_LIST)) {
|
| - base::ListValue* script_value_as_list;
|
| - if (script_value->GetAsList(&script_value_as_list) &&
|
| - script_value_as_list->GetSize() == 1) {
|
| - script_value_as_list->GetString(0u, &child_child_frame_count);
|
| - }
|
| - }
|
| - } while (child_child_frame_count != "1" &&
|
| - base::TimeTicks::Now() - start_time <
|
| - TestTimeouts::action_timeout());
|
| - EXPECT_EQ("1", child_child_frame_count);
|
| -
|
| - // Remove the child's child and make sure the root doesn't see it anymore.
|
| - const char kRemoveLastIFrame[] =
|
| - "document.body.removeChild(document.body.lastChild);";
|
| - ExecuteScript(ConnectionForFrame(child_frame), kRemoveLastIFrame);
|
| - do {
|
| - child_child_frame_count.clear();
|
| - scoped_ptr<base::Value> script_value(
|
| - ExecuteScript(ConnectionForFrame(frame_tree_->root()),
|
| - kGetChildChildFrameCount));
|
| - if (script_value->IsType(base::Value::TYPE_LIST)) {
|
| - base::ListValue* script_value_as_list;
|
| - if (script_value->GetAsList(&script_value_as_list) &&
|
| - script_value_as_list->GetSize() == 1) {
|
| - script_value_as_list->GetString(0u, &child_child_frame_count);
|
| - }
|
| - }
|
| - } while (child_child_frame_count != "0" &&
|
| - base::TimeTicks::Now() - start_time <
|
| - TestTimeouts::action_timeout());
|
| - ASSERT_EQ("0", child_child_frame_count);
|
| -}
|
| -
|
| -// Verifies PostMessage() works across frames.
|
| -TEST_F(HTMLFrameTest, PostMessage) {
|
| - Frame* child_frame = LoadEmptyPageAndCreateFrame();
|
| - ASSERT_TRUE(child_frame);
|
| -
|
| - mojo::Connection* child_frame_connection = ConnectionForFrame(child_frame);
|
| - ASSERT_EQ("child", GetFrameText(child_frame_connection));
|
| -
|
| - // Register an event handler in the child frame.
|
| - const char kRegisterPostMessageHandler[] =
|
| - "window.messageData = null;"
|
| - "function messageFunction(event) {"
|
| - " window.messageData = event.data;"
|
| - "}"
|
| - "window.addEventListener('message', messageFunction, false);";
|
| - ExecuteScript(child_frame_connection, kRegisterPostMessageHandler);
|
| -
|
| - // Post a message from the parent to the child.
|
| - const char kPostMessageFromParent[] =
|
| - "window.frames[0].postMessage('hello from parent', '*');";
|
| - ExecuteScript(ConnectionForFrame(frame_tree_->root()),
|
| - kPostMessageFromParent);
|
| -
|
| - // Wait for the child frame to see the message.
|
| - const base::TimeTicks start_time(base::TimeTicks::Now());
|
| - std::string message_in_child;
|
| - do {
|
| - const char kGetMessageData[] = "window.messageData;";
|
| - scoped_ptr<base::Value> script_value(
|
| - ExecuteScript(child_frame_connection, kGetMessageData));
|
| - if (script_value->IsType(base::Value::TYPE_LIST)) {
|
| - base::ListValue* script_value_as_list;
|
| - if (script_value->GetAsList(&script_value_as_list) &&
|
| - script_value_as_list->GetSize() == 1) {
|
| - script_value_as_list->GetString(0u, &message_in_child);
|
| - }
|
| - }
|
| - } while (message_in_child != "hello from parent" &&
|
| - base::TimeTicks::Now() - start_time <
|
| - TestTimeouts::action_timeout());
|
| - EXPECT_EQ("hello from parent", message_in_child);
|
| -}
|
| -
|
| -} // namespace mojo
|
|
|