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
3 // found in the LICENSE file.
4 
5 #include "content/public/test/test_renderer_host.h"
6 
7 #include <utility>
8 
9 #include "base/run_loop.h"
10 #include "base/task/current_thread.h"
11 #include "base/test/task_environment.h"
12 #include "base/threading/thread_task_runner_handle.h"
13 #include "build/build_config.h"
14 #include "content/browser/compositor/test/test_image_transport_factory.h"
15 #include "content/browser/gpu/gpu_data_manager_impl.h"
16 #include "content/browser/renderer_host/frame_tree_node.h"
17 #include "content/browser/renderer_host/navigation_entry_impl.h"
18 #include "content/browser/renderer_host/navigation_request.h"
19 #include "content/browser/renderer_host/render_view_host_factory.h"
20 #include "content/browser/renderer_host/render_widget_host_impl.h"
21 #include "content/browser/renderer_host/render_widget_host_input_event_router.h"
22 #include "content/browser/site_instance_impl.h"
23 #include "content/public/browser/browser_task_traits.h"
24 #include "content/public/browser/browser_thread.h"
25 #include "content/public/browser/render_widget_host_iterator.h"
26 #include "content/public/browser/web_contents.h"
27 #include "content/public/common/navigation_policy.h"
28 #include "content/public/test/browser_test_utils.h"
29 #include "content/public/test/mock_render_process_host.h"
30 #include "content/public/test/navigation_simulator.h"
31 #include "content/public/test/test_browser_context.h"
32 #include "content/test/content_browser_consistency_checker.h"
33 #include "content/test/test_navigation_url_loader_factory.h"
34 #include "content/test/test_render_frame_host.h"
35 #include "content/test/test_render_frame_host_factory.h"
36 #include "content/test/test_render_view_host.h"
37 #include "content/test/test_render_view_host_factory.h"
38 #include "content/test/test_render_widget_host_factory.h"
39 #include "content/test/test_web_contents.h"
40 #include "net/base/mock_network_change_notifier.h"
41 #include "third_party/blink/public/common/input/synthetic_web_input_event_builders.h"
42 #include "third_party/blink/public/common/input/web_input_event.h"
43 
44 #if defined(OS_ANDROID)
45 #include "ui/android/dummy_screen_android.h"
46 #include "ui/display/screen.h"
47 #endif
48 
49 #if defined(OS_WIN)
50 #include "ui/base/win/scoped_ole_initializer.h"
51 #endif
52 
53 #if defined(USE_AURA)
54 #include "ui/aura/test/aura_test_helper.h"
55 #endif
56 
57 #if defined(OS_MAC)
58 #include "ui/accelerated_widget_mac/window_resize_helper_mac.h"
59 #endif
60 
61 namespace content {
62 
63 // RenderFrameHostTester ------------------------------------------------------
64 
65 // static
For(RenderFrameHost * host)66 RenderFrameHostTester* RenderFrameHostTester::For(RenderFrameHost* host) {
67   return static_cast<TestRenderFrameHost*>(host);
68 }
69 
70 // static
TestOnMessageReceived(RenderFrameHost * rfh,const IPC::Message & msg)71 bool RenderFrameHostTester::TestOnMessageReceived(RenderFrameHost* rfh,
72                                                   const IPC::Message& msg) {
73   return static_cast<RenderFrameHostImpl*>(rfh)->OnMessageReceived(msg);
74 }
75 
76 // static
CommitPendingLoad(NavigationController * controller)77 void RenderFrameHostTester::CommitPendingLoad(
78     NavigationController* controller) {
79   // This function is currently used by BrowserWithTestWindowTest. It would be
80   // ideal to instead make the users of that class create TestWebContents
81   // (rather than WebContentsImpl directly). It is not trivial to make
82   // that change, so for now we have this extra function for
83   // non-TestWebContents.
84   auto navigation =
85       NavigationSimulator::CreateFromPending(controller->GetWebContents());
86   navigation->Commit();
87 }
88 
89 // RenderViewHostTester -------------------------------------------------------
90 
91 // static
For(RenderViewHost * host)92 RenderViewHostTester* RenderViewHostTester::For(RenderViewHost* host) {
93   return static_cast<TestRenderViewHost*>(host);
94 }
95 
96 // static
SimulateFirstPaint(RenderViewHost * rvh)97 void RenderViewHostTester::SimulateFirstPaint(RenderViewHost* rvh) {
98   static_cast<RenderViewHostImpl*>(rvh)
99       ->GetWidget()
100       ->DidFirstVisuallyNonEmptyPaint();
101 }
102 
103 // static
104 std::unique_ptr<content::InputMsgWatcher>
CreateInputWatcher(RenderViewHost * rvh,blink::WebInputEvent::Type type)105 RenderViewHostTester::CreateInputWatcher(RenderViewHost* rvh,
106                                          blink::WebInputEvent::Type type) {
107   RenderWidgetHostImpl* host_impl =
108       RenderWidgetHostImpl::From(rvh->GetWidget());
109   return std::make_unique<content::InputMsgWatcher>(host_impl, type);
110 }
111 
112 // static
SendTouchEvent(RenderViewHost * rvh,blink::SyntheticWebTouchEvent * touch_event)113 void RenderViewHostTester::SendTouchEvent(
114     RenderViewHost* rvh,
115     blink::SyntheticWebTouchEvent* touch_event) {
116   RenderWidgetHostImpl* host_impl =
117       RenderWidgetHostImpl::From(rvh->GetWidget());
118   auto* input_event_router = host_impl->delegate()->GetInputEventRouter();
119   input_event_router->RouteTouchEvent(host_impl->GetView(), touch_event,
120                                       ui::LatencyInfo());
121 }
122 
123 // RenderViewHostTestEnabler --------------------------------------------------
124 
RenderViewHostTestEnabler()125 RenderViewHostTestEnabler::RenderViewHostTestEnabler()
126     : rph_factory_(new MockRenderProcessHostFactory()),
127       rvh_factory_(new TestRenderViewHostFactory(rph_factory_.get())),
128       rfh_factory_(new TestRenderFrameHostFactory()),
129       rwhi_factory_(new TestRenderWidgetHostFactory()),
130       loader_factory_(new TestNavigationURLLoaderFactory()) {
131   // A TaskEnvironment is needed on the main thread for Mojo bindings to
132   // graphics services. Some tests have their own, so this only creates one
133   // (single-threaded) when none exists. This means tests must ensure any
134   // TaskEnvironment they make is created before the RenderViewHostTestEnabler.
135   if (!base::CurrentThread::Get()) {
136     task_environment_ =
137         std::make_unique<base::test::SingleThreadTaskEnvironment>();
138   }
139 #if !defined(OS_ANDROID)
140   ImageTransportFactory::SetFactory(
141       std::make_unique<TestImageTransportFactory>());
142 #else
143   if (!screen_)
144     screen_.reset(ui::CreateDummyScreenAndroid());
145   display::Screen::SetScreenInstance(screen_.get());
146 #endif
147 #if defined(OS_MAC)
148   if (base::ThreadTaskRunnerHandle::IsSet())
149     ui::WindowResizeHelperMac::Get()->Init(base::ThreadTaskRunnerHandle::Get());
150 #endif  // OS_MAC
151 }
152 
~RenderViewHostTestEnabler()153 RenderViewHostTestEnabler::~RenderViewHostTestEnabler() {
154 #if defined(OS_MAC)
155   ui::WindowResizeHelperMac::Get()->ShutdownForTests();
156 #endif  // OS_MAC
157 #if !defined(OS_ANDROID)
158   // RenderWidgetHostView holds on to a reference to SurfaceManager, so it
159   // must be shut down before the ImageTransportFactory.
160   ImageTransportFactory::Terminate();
161 #else
162   display::Screen::SetScreenInstance(nullptr);
163 #endif
164 }
165 
166 
167 // RenderViewHostTestHarness --------------------------------------------------
168 
~RenderViewHostTestHarness()169 RenderViewHostTestHarness::~RenderViewHostTestHarness() {
170 }
171 
controller()172 NavigationController& RenderViewHostTestHarness::controller() {
173   return web_contents()->GetController();
174 }
175 
web_contents()176 WebContents* RenderViewHostTestHarness::web_contents() {
177   return contents_.get();
178 }
179 
rvh()180 RenderViewHost* RenderViewHostTestHarness::rvh() {
181   RenderViewHost* result = web_contents()->GetMainFrame()->GetRenderViewHost();
182   CHECK_EQ(result, web_contents()->GetMainFrame()->GetRenderViewHost());
183   return result;
184 }
185 
pending_rvh()186 RenderViewHost* RenderViewHostTestHarness::pending_rvh() {
187   return pending_main_rfh() ? pending_main_rfh()->GetRenderViewHost() : nullptr;
188 }
189 
active_rvh()190 RenderViewHost* RenderViewHostTestHarness::active_rvh() {
191   return pending_rvh() ? pending_rvh() : rvh();
192 }
193 
main_rfh()194 RenderFrameHost* RenderViewHostTestHarness::main_rfh() {
195   return web_contents()->GetMainFrame();
196 }
197 
pending_main_rfh()198 RenderFrameHost* RenderViewHostTestHarness::pending_main_rfh() {
199   return static_cast<TestWebContents*>(web_contents())->GetPendingMainFrame();
200 }
201 
browser_context()202 BrowserContext* RenderViewHostTestHarness::browser_context() {
203   return GetBrowserContext();
204 }
205 
process()206 MockRenderProcessHost* RenderViewHostTestHarness::process() {
207   return static_cast<MockRenderProcessHost*>(active_rvh()->GetProcess());
208 }
209 
DeleteContents()210 void RenderViewHostTestHarness::DeleteContents() {
211   contents_.reset();
212 }
213 
SetContents(std::unique_ptr<WebContents> contents)214 void RenderViewHostTestHarness::SetContents(
215     std::unique_ptr<WebContents> contents) {
216   contents_ = std::move(contents);
217 }
218 
219 std::unique_ptr<WebContents>
CreateTestWebContents()220 RenderViewHostTestHarness::CreateTestWebContents() {
221 // Make sure we ran SetUp() already.
222 #if defined(OS_WIN)
223   DCHECK(ole_initializer_);
224 #endif
225 #if defined(USE_AURA)
226   DCHECK(aura_test_helper_);
227 #endif
228 
229   scoped_refptr<SiteInstance> instance =
230       SiteInstance::Create(GetBrowserContext());
231   instance->GetProcess()->Init();
232 
233   return TestWebContents::Create(GetBrowserContext(), std::move(instance));
234 }
FocusWebContentsOnMainFrame()235 void RenderViewHostTestHarness::FocusWebContentsOnMainFrame() {
236   TestWebContents* contents = static_cast<TestWebContents*>(web_contents());
237   auto* root = contents->GetFrameTree()->root();
238   contents->GetFrameTree()->SetFocusedFrame(
239       root, root->current_frame_host()->GetSiteInstance());
240 }
241 
NavigateAndCommit(const GURL & url,ui::PageTransition transition)242 void RenderViewHostTestHarness::NavigateAndCommit(
243     const GURL& url,
244     ui::PageTransition transition) {
245   static_cast<TestWebContents*>(web_contents())
246       ->NavigateAndCommit(url, transition);
247 }
248 
SetUp()249 void RenderViewHostTestHarness::SetUp() {
250   rvh_test_enabler_ = std::make_unique<RenderViewHostTestEnabler>();
251   if (factory_)
252     rvh_test_enabler_->rvh_factory_->set_render_process_host_factory(factory_);
253 
254 #if defined(OS_WIN)
255   ole_initializer_ = std::make_unique<ui::ScopedOleInitializer>();
256 #endif
257 #if defined(USE_AURA)
258   aura_test_helper_ = std::make_unique<aura::test::AuraTestHelper>(
259       ImageTransportFactory::GetInstance()->GetContextFactory());
260   aura_test_helper_->SetUp();
261 #endif
262 
263   consistency_checker_ = std::make_unique<ContentBrowserConsistencyChecker>();
264 
265 #if !defined(OS_ANDROID)
266   network_change_notifier_ = net::test::MockNetworkChangeNotifier::Create();
267 #endif
268 
269   DCHECK(!browser_context_);
270   browser_context_ = CreateBrowserContext();
271 
272   SetContents(CreateTestWebContents());
273 
274   // Create GpuDataManagerImpl here so it always runs on the main thread.
275   GpuDataManagerImpl::GetInstance();
276 }
277 
TearDown()278 void RenderViewHostTestHarness::TearDown() {
279   DeleteContents();
280 #if defined(USE_AURA)
281   aura_test_helper_->TearDown();
282 #endif
283   // Make sure that we flush any messages related to WebContentsImpl destruction
284   // before we destroy the browser context.
285   base::RunLoop().RunUntilIdle();
286 
287 #if defined(OS_WIN)
288   ole_initializer_.reset();
289 #endif
290 
291   // Delete any RenderProcessHosts before the BrowserContext goes away.
292   if (rvh_test_enabler_->rph_factory_) {
293     auto render_widget_hosts = RenderWidgetHost::GetRenderWidgetHosts();
294     ASSERT_EQ(nullptr, render_widget_hosts->GetNextHost()) <<
295         "Test is leaking at least one RenderWidgetHost.";
296     rvh_test_enabler_->rph_factory_.reset();
297   }
298 
299   rvh_test_enabler_.reset();
300 
301   // Release the browser context by posting itself on the end of the task
302   // queue. This is preferable to immediate deletion because it will behave
303   // properly if the |rph_factory_| reset above enqueued any tasks which
304   // depend on |browser_context_|.
305   content::GetUIThreadTaskRunner({})->DeleteSoon(FROM_HERE,
306                                                  browser_context_.release());
307 
308   // Although this isn't required by many, some subclasses members require that
309   // the task environment is gone by the time that they are destroyed (akin to
310   // browser shutdown).
311   task_environment_.reset();
312 }
313 
314 std::unique_ptr<BrowserContext>
CreateBrowserContext()315 RenderViewHostTestHarness::CreateBrowserContext() {
316   return std::make_unique<TestBrowserContext>();
317 }
318 
GetBrowserContext()319 BrowserContext* RenderViewHostTestHarness::GetBrowserContext() {
320   return browser_context_.get();
321 }
322 
SetRenderProcessHostFactory(RenderProcessHostFactory * factory)323 void RenderViewHostTestHarness::SetRenderProcessHostFactory(
324     RenderProcessHostFactory* factory) {
325   if (rvh_test_enabler_)
326     rvh_test_enabler_->rvh_factory_->set_render_process_host_factory(factory);
327   else
328     factory_ = factory;
329 }
330 
RenderViewHostTestHarness(std::unique_ptr<BrowserTaskEnvironment> task_environment)331 RenderViewHostTestHarness::RenderViewHostTestHarness(
332     std::unique_ptr<BrowserTaskEnvironment> task_environment)
333     : task_environment_(std::move(task_environment)) {}
334 
335 }  // namespace content
336