blob: 88f38681ba7182b931fbe3e2714db9cc7326f3a2 [file] [log] [blame]
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/public/test/test_renderer_host.h"
#include <utility>
#include "base/run_loop.h"
#include "base/task/current_thread.h"
#include "base/task/single_thread_task_runner.h"
#include "base/test/task_environment.h"
#include "build/build_config.h"
#include "build/config/linux/dbus/buildflags.h"
#include "components/input/render_widget_host_input_event_router.h"
#include "content/browser/gpu/gpu_data_manager_impl.h"
#include "content/browser/renderer_host/frame_tree_node.h"
#include "content/browser/renderer_host/navigation_entry_impl.h"
#include "content/browser/renderer_host/navigation_request.h"
#include "content/browser/renderer_host/render_view_host_factory.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/browser/site_instance_impl.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_widget_host_iterator.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/mock_render_process_host.h"
#include "content/public/test/navigation_simulator.h"
#include "content/public/test/test_browser_context.h"
#include "content/public/test/test_image_transport_factory.h"
#include "content/public/test/test_utils.h"
#include "content/test/content_browser_consistency_checker.h"
#include "content/test/test_navigation_url_loader_factory.h"
#include "content/test/test_page_factory.h"
#include "content/test/test_render_frame_host.h"
#include "content/test/test_render_frame_host_factory.h"
#include "content/test/test_render_view_host.h"
#include "content/test/test_render_view_host_factory.h"
#include "content/test/test_render_widget_host_factory.h"
#include "content/test/test_web_contents.h"
#include "net/base/mock_network_change_notifier.h"
#include "third_party/blink/public/common/input/synthetic_web_input_event_builders.h"
#include "third_party/blink/public/common/input/web_input_event.h"
#if BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_ANDROID)
#include "ui/display/screen.h"
#endif
#if BUILDFLAG(IS_ANDROID)
#include "ui/android/dummy_screen_android.h"
#endif
#if BUILDFLAG(IS_WIN)
#include "ui/base/win/scoped_ole_initializer.h"
#endif
#if defined(USE_AURA)
#include "ui/aura/test/aura_test_helper.h"
#endif
#if BUILDFLAG(IS_MAC)
#include "ui/accelerated_widget_mac/window_resize_helper_mac.h"
#endif
#if BUILDFLAG(IS_LINUX) && BUILDFLAG(USE_DBUS)
#include "components/dbus/thread_linux/dbus_thread_linux.h"
#endif
namespace content {
// RenderFrameHostTester ------------------------------------------------------
// static
RenderFrameHostTester* RenderFrameHostTester::For(RenderFrameHost* host) {
return static_cast<TestRenderFrameHost*>(host);
}
// static
void RenderFrameHostTester::CommitPendingLoad(
NavigationController* controller) {
auto navigation = NavigationSimulator::CreateFromPending(*controller);
navigation->Commit();
}
// RenderViewHostTester -------------------------------------------------------
// static
RenderViewHostTester* RenderViewHostTester::For(RenderViewHost* host) {
return static_cast<TestRenderViewHost*>(host);
}
// static
std::unique_ptr<content::InputMsgWatcher>
RenderViewHostTester::CreateInputWatcher(RenderViewHost* rvh,
blink::WebInputEvent::Type type) {
RenderWidgetHostImpl* host_impl =
RenderWidgetHostImpl::From(rvh->GetWidget());
return std::make_unique<content::InputMsgWatcher>(host_impl, type);
}
// static
void RenderViewHostTester::SendTouchEvent(
RenderViewHost* rvh,
blink::SyntheticWebTouchEvent* touch_event) {
RenderWidgetHostImpl* host_impl =
RenderWidgetHostImpl::From(rvh->GetWidget());
auto* input_event_router = host_impl->delegate()->GetInputEventRouter();
input_event_router->RouteTouchEvent(host_impl->GetView(), touch_event,
ui::LatencyInfo());
}
// RenderViewHostTestEnabler --------------------------------------------------
RenderViewHostTestEnabler::RenderViewHostTestEnabler(
NavigationURLLoaderFactoryType url_loader_factory_type)
: rph_factory_(new MockRenderProcessHostFactory()),
asgh_factory_(new MockAgentSchedulingGroupHostFactory()),
page_factory_(new TestPageFactory()),
rvh_factory_(new TestRenderViewHostFactory(rph_factory_.get(),
asgh_factory_.get())),
rfh_factory_(new TestRenderFrameHostFactory()),
rwhi_factory_(new TestRenderWidgetHostFactory()),
loader_factory_(url_loader_factory_type ==
NavigationURLLoaderFactoryType::kTest
? new TestNavigationURLLoaderFactory()
: nullptr) {
// A TaskEnvironment is needed on the main thread for Mojo bindings to
// graphics services. Some tests have their own, so this only creates one
// (single-threaded) when none exists. This means tests must ensure any
// TaskEnvironment they make is created before the RenderViewHostTestEnabler.
if (!base::CurrentThread::Get()) {
task_environment_ =
std::make_unique<base::test::SingleThreadTaskEnvironment>();
}
#if !BUILDFLAG(IS_ANDROID)
ImageTransportFactory::SetFactory(
std::make_unique<TestImageTransportFactory>());
#else
if (!screen_)
screen_.reset(ui::CreateDummyScreenAndroid());
display::Screen::SetScreenInstance(screen_.get());
#endif
#if BUILDFLAG(IS_MAC)
if (base::SingleThreadTaskRunner::HasCurrentDefault())
ui::WindowResizeHelperMac::Get()->Init(
base::SingleThreadTaskRunner::GetCurrentDefault());
#endif // BUILDFLAG(IS_MAC)
}
RenderViewHostTestEnabler::~RenderViewHostTestEnabler() {
#if BUILDFLAG(IS_MAC)
ui::WindowResizeHelperMac::Get()->ShutdownForTests();
#endif // BUILDFLAG(IS_MAC)
#if !BUILDFLAG(IS_ANDROID)
// RenderWidgetHostView holds on to a reference to SurfaceManager, so it
// must be shut down before the ImageTransportFactory.
ImageTransportFactory::Terminate();
#else
display::Screen::SetScreenInstance(nullptr);
#endif
}
// RenderViewHostTestHarness --------------------------------------------------
RenderViewHostTestHarness::~RenderViewHostTestHarness() {
DCHECK(!task_environment_) << "TearDown() was not called.";
}
NavigationController& RenderViewHostTestHarness::controller() {
return web_contents()->GetController();
}
WebContents* RenderViewHostTestHarness::web_contents() const {
return contents_.get();
}
RenderViewHost* RenderViewHostTestHarness::rvh() {
return web_contents()->GetPrimaryMainFrame()->GetRenderViewHost();
}
RenderFrameHost* RenderViewHostTestHarness::main_rfh() {
return web_contents()->GetPrimaryMainFrame();
}
BrowserContext* RenderViewHostTestHarness::browser_context() {
return GetBrowserContext();
}
MockRenderProcessHost* RenderViewHostTestHarness::process() {
auto* contents = static_cast<TestWebContents*>(web_contents());
return contents->GetPrimaryMainFrame()->GetProcess();
}
void RenderViewHostTestHarness::DeleteContents() {
contents_.reset();
}
void RenderViewHostTestHarness::SetContents(
std::unique_ptr<WebContents> contents) {
contents_ = std::move(contents);
}
std::unique_ptr<WebContents>
RenderViewHostTestHarness::CreateTestWebContents() {
// Make sure we ran SetUp() already.
#if BUILDFLAG(IS_WIN)
DCHECK(ole_initializer_);
#endif
#if defined(USE_AURA)
DCHECK(aura_test_helper_);
#endif
scoped_refptr<SiteInstance> instance =
SiteInstance::Create(GetBrowserContext());
instance->GetOrCreateProcessForTesting()->Init();
return TestWebContents::Create(GetBrowserContext(), std::move(instance));
}
void RenderViewHostTestHarness::FocusWebContentsOnMainFrame() {
FocusWebContentsOnFrame(web_contents()->GetPrimaryMainFrame());
}
void RenderViewHostTestHarness::FocusWebContentsOnFrame(
content::RenderFrameHost* rfh) {
content::FocusWebContentsOnFrame(web_contents(), rfh);
}
void RenderViewHostTestHarness::NavigateAndCommit(
const GURL& url,
ui::PageTransition transition) {
static_cast<TestWebContents*>(web_contents())
->NavigateAndCommit(url, transition);
}
void RenderViewHostTestHarness::SetUp() {
rvh_test_enabler_ = std::make_unique<RenderViewHostTestEnabler>();
if (factory_)
rvh_test_enabler_->rvh_factory_->set_render_process_host_factory(factory_);
#if BUILDFLAG(IS_WIN)
ole_initializer_ = std::make_unique<ui::ScopedOleInitializer>();
#endif
#if BUILDFLAG(IS_APPLE)
screen_ = std::make_unique<display::ScopedNativeScreen>();
#endif
#if defined(USE_AURA)
aura_test_helper_ = std::make_unique<aura::test::AuraTestHelper>(
ImageTransportFactory::GetInstance()->GetContextFactory());
aura_test_helper_->SetUp();
#endif
consistency_checker_ = std::make_unique<ContentBrowserConsistencyChecker>();
network_change_notifier_ = net::test::MockNetworkChangeNotifier::Create();
DCHECK(!browser_context_);
browser_context_ = CreateBrowserContext();
SetContents(CreateTestWebContents());
// Create GpuDataManagerImpl here so it always runs on the main thread.
GpuDataManagerImpl::GetInstance();
}
void RenderViewHostTestHarness::TearDown() {
DeleteContents();
#if defined(USE_AURA)
aura_test_helper_->TearDown();
#endif
// Make sure that we flush any messages related to WebContentsImpl destruction
// before we destroy the browser context.
base::RunLoop().RunUntilIdle();
#if BUILDFLAG(IS_LINUX) && BUILDFLAG(USE_DBUS)
dbus_thread_linux::ShutdownOnDBusThreadAndBlock();
#endif
#if BUILDFLAG(IS_WIN)
ole_initializer_.reset();
#endif
// Delete any RenderProcessHosts before the BrowserContext goes away.
if (rvh_test_enabler_->rph_factory_) {
auto render_widget_hosts = RenderWidgetHost::GetRenderWidgetHosts();
ASSERT_EQ(nullptr, render_widget_hosts->GetNextHost()) <<
"Test is leaking at least one RenderWidgetHost.";
rvh_test_enabler_->rph_factory_.reset();
}
rvh_test_enabler_.reset();
// Release the browser context by posting itself on the end of the task
// queue. This is preferable to immediate deletion because it will behave
// properly if the |rph_factory_| reset above enqueued any tasks which
// depend on |browser_context_|.
GetUIThreadTaskRunner({})->DeleteSoon(FROM_HERE, browser_context_.release());
// Although this isn't required by many, some subclasses members require that
// the task environment is gone by the time that they are destroyed (akin to
// browser shutdown).
task_environment_.reset();
}
std::unique_ptr<BrowserContext>
RenderViewHostTestHarness::CreateBrowserContext() {
return std::make_unique<TestBrowserContext>();
}
BrowserContext* RenderViewHostTestHarness::GetBrowserContext() {
return browser_context_.get();
}
void RenderViewHostTestHarness::SetRenderProcessHostFactory(
RenderProcessHostFactory* factory) {
if (rvh_test_enabler_)
rvh_test_enabler_->rvh_factory_->set_render_process_host_factory(factory);
else
factory_ = factory;
}
RenderViewHostTestHarness::RenderViewHostTestHarness(
std::unique_ptr<BrowserTaskEnvironment> task_environment)
: task_environment_(std::move(task_environment)) {}
} // namespace content