1 // Copyright 2014 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/web_test/browser/web_test_browser_main_runner.h"
6 
7 #include <iostream>
8 #include <memory>
9 
10 #include "base/bind.h"
11 #include "base/check_op.h"
12 #include "base/command_line.h"
13 #include "base/files/file_path.h"
14 #include "base/files/file_util.h"
15 #include "base/files/scoped_temp_dir.h"
16 #include "base/location.h"
17 #include "base/run_loop.h"
18 #include "base/single_thread_task_runner.h"
19 #include "base/strings/sys_string_conversions.h"
20 #include "base/strings/utf_string_conversions.h"
21 #include "base/threading/thread_restrictions.h"
22 #include "base/threading/thread_task_runner_handle.h"
23 #include "build/build_config.h"
24 #include "cc/base/switches.h"
25 #include "components/network_session_configurator/common/network_switches.h"
26 #include "components/viz/common/switches.h"
27 #include "content/browser/renderer_host/render_widget_host_impl.h"
28 #include "content/public/browser/browser_main_runner.h"
29 #include "content/public/common/content_switches.h"
30 #include "content/public/common/url_constants.h"
31 #include "content/public/test/ppapi_test_utils.h"
32 #include "content/shell/browser/shell.h"
33 #include "content/shell/common/shell_switches.h"
34 #include "content/test/gpu_browsertest_helpers.h"
35 #include "content/web_test/browser/test_info_extractor.h"
36 #include "content/web_test/browser/web_test_browser_main_platform_support.h"
37 #include "content/web_test/browser/web_test_control_host.h"
38 #include "content/web_test/common/web_test_switches.h"
39 #include "gpu/config/gpu_switches.h"
40 #include "gpu/ipc/client/gpu_channel_host.h"
41 #include "media/base/media_switches.h"
42 #include "net/base/filename_util.h"
43 #include "ppapi/buildflags/buildflags.h"
44 #include "services/network/public/cpp/network_switches.h"
45 #include "ui/base/ui_base_switches.h"
46 #include "ui/display/display_switches.h"
47 #include "ui/gl/gl_implementation.h"
48 #include "ui/gl/gl_switches.h"
49 
50 namespace content {
51 
52 namespace {
53 
RunOneTest(const content::TestInfo & test_info,content::WebTestControlHost * web_test_control_host,content::BrowserMainRunner * main_runner)54 bool RunOneTest(const content::TestInfo& test_info,
55                 content::WebTestControlHost* web_test_control_host,
56                 content::BrowserMainRunner* main_runner) {
57   TRACE_EVENT0("shell", "WebTestBrowserMainRunner::RunOneTest");
58   DCHECK(web_test_control_host);
59 
60   if (!web_test_control_host->PrepareForWebTest(test_info))
61     return false;
62 
63   main_runner->Run();
64 
65   return web_test_control_host->ResetBrowserAfterWebTest();
66 }
67 
RunTests(content::BrowserMainRunner * main_runner)68 void RunTests(content::BrowserMainRunner* main_runner) {
69   TRACE_EVENT0("shell", "WebTestBrowserMainRunner::RunTests");
70   content::WebTestControlHost test_controller;
71   {
72     // We're outside of the message loop here, and this is a test.
73     base::ScopedAllowBlockingForTesting allow_blocking;
74     base::FilePath temp_path;
75     base::GetTempDir(&temp_path);
76     test_controller.SetTempPath(temp_path);
77   }
78 
79   {
80     // Kick off the launch of the GPU process early, to minimize blocking
81     // startup of the first renderer process in PrepareForWebTest. (This avoids
82     // GPU process startup time from being counted in the first test's timeout,
83     // hopefully making it less likely to time out flakily.)
84     // https://crbug.com/953991
85     TRACE_EVENT0("shell",
86                  "WebTestBrowserMainRunner::RunTests::EstablishGpuChannelSync");
87     content::GpuBrowsertestEstablishGpuChannelSyncRunLoop();
88   }
89 
90   std::cout << "#READY\n";
91   std::cout.flush();
92 
93   content::TestInfoExtractor test_extractor(
94       *base::CommandLine::ForCurrentProcess());
95   bool ran_at_least_once = false;
96   std::unique_ptr<content::TestInfo> test_info;
97   while ((test_info = test_extractor.GetNextTest())) {
98     ran_at_least_once = true;
99     if (!RunOneTest(*test_info, &test_controller, main_runner))
100       break;
101   }
102   if (!ran_at_least_once) {
103     // CloseAllWindows will cause the |main_runner| loop to quit.
104     base::ThreadTaskRunnerHandle::Get()->PostTask(
105         FROM_HERE, base::BindOnce(&content::Shell::CloseAllWindows));
106     main_runner->Run();
107   }
108 }
109 
110 }  // namespace
111 
Initialize()112 void WebTestBrowserMainRunner::Initialize() {
113 #if defined(OS_WIN)
114   bool layout_system_deps_ok = content::WebTestBrowserCheckLayoutSystemDeps();
115   CHECK(layout_system_deps_ok);
116 #endif
117 
118   base::CommandLine& command_line = *base::CommandLine::ForCurrentProcess();
119 
120   CHECK(browser_context_path_for_web_tests_.CreateUniqueTempDir());
121   CHECK(!browser_context_path_for_web_tests_.GetPath().MaybeAsASCII().empty());
122   command_line.AppendSwitchASCII(
123       switches::kContentShellDataPath,
124       browser_context_path_for_web_tests_.GetPath().MaybeAsASCII());
125 
126   command_line.AppendSwitch(switches::kIgnoreCertificateErrors);
127 
128   // Disable occlusion tracking. In a headless shell WebContents would always
129   // behave as if they were occluded, i.e. would not render frames and would
130   // not receive input events. For non-headless mode we do not want tests
131   // running in parallel to trigger occlusion tracking.
132   command_line.AppendSwitch(
133       switches::kDisableBackgroundingOccludedWindowsForTesting);
134 
135   // Always disable the unsandbox GPU process for DX12 Info collection to avoid
136   // interference. This GPU process is launched 120 seconds after chrome starts.
137   command_line.AppendSwitch(switches::kDisableGpuProcessForDX12InfoCollection);
138 
139 #if BUILDFLAG(ENABLE_PLUGINS)
140   bool ppapi_ok = ppapi::RegisterBlinkTestPlugin(&command_line);
141   CHECK(ppapi_ok);
142 #endif
143 
144   command_line.AppendSwitch(cc::switches::kEnableGpuBenchmarking);
145   command_line.AppendSwitch(switches::kEnableLogging);
146   command_line.AppendSwitch(switches::kAllowFileAccessFromFiles);
147   // only default to a software GL if the flag isn't already specified.
148   if (!command_line.HasSwitch(switches::kUseGpuInTests) &&
149       !command_line.HasSwitch(switches::kUseGL)) {
150     command_line.AppendSwitchASCII(
151         switches::kUseGL,
152         gl::GetGLImplementationName(gl::GetSoftwareGLImplementation()));
153   }
154   command_line.AppendSwitchASCII(switches::kTouchEventFeatureDetection,
155                                  switches::kTouchEventFeatureDetectionEnabled);
156   if (!command_line.HasSwitch(switches::kForceDeviceScaleFactor))
157     command_line.AppendSwitchASCII(switches::kForceDeviceScaleFactor, "1.0");
158 
159   if (!command_line.HasSwitch(switches::kAutoplayPolicy)) {
160     command_line.AppendSwitchASCII(
161         switches::kAutoplayPolicy,
162         switches::autoplay::kNoUserGestureRequiredPolicy);
163   }
164 
165   if (!command_line.HasSwitch(switches::kStableReleaseMode)) {
166     command_line.AppendSwitch(switches::kEnableExperimentalWebPlatformFeatures);
167     command_line.AppendSwitch(switches::kEnableBlinkTestFeatures);
168   }
169 
170   if (!command_line.HasSwitch(switches::kEnableThreadedCompositing)) {
171     command_line.AppendSwitch(switches::kDisableThreadedCompositing);
172     command_line.AppendSwitch(cc::switches::kDisableThreadedAnimation);
173   }
174 
175   // With display compositor pixel dumps, we ensure that we complete all
176   // stages of compositing before draw. We also can't have checker imaging,
177   // since it's incompatible with single threaded compositor and display
178   // compositor pixel dumps.
179   //
180   // TODO(crbug.com/894613) Add kRunAllCompositorStagesBeforeDraw back here
181   // once you figure out why it causes so much web test flakiness.
182   // command_line.AppendSwitch(switches::kRunAllCompositorStagesBeforeDraw);
183   command_line.AppendSwitch(cc::switches::kDisableCheckerImaging);
184 
185   command_line.AppendSwitch(switches::kMuteAudio);
186 
187   command_line.AppendSwitch(switches::kEnablePreciseMemoryInfo);
188 
189   command_line.AppendSwitchASCII(network::switches::kHostResolverRules,
190                                  "MAP nonexistent.*.test ~NOTFOUND,"
191                                  "MAP *.test. 127.0.0.1,"
192                                  "MAP *.test 127.0.0.1");
193 
194   // We want to know determanistically from command line flags if the Gpu
195   // process will provide gpu raster in its capabilities or not.
196   //
197   // If kEnableGpuRasterization is specified, the Gpu process always reports
198   // that it can gpu raster, and the renderer will use it. Otherwise, we don't
199   // want to choose at runtime, and we ensure that gpu raster is disabled.
200   if (!command_line.HasSwitch(switches::kEnableGpuRasterization))
201     command_line.AppendSwitch(switches::kDisableGpuRasterization);
202 
203   // If the virtual test suite didn't specify a display color space, then
204   // force sRGB.
205   if (!command_line.HasSwitch(switches::kForceDisplayColorProfile))
206     command_line.AppendSwitchASCII(switches::kForceDisplayColorProfile, "srgb");
207 
208   // We want stable/baseline results when running web tests.
209   command_line.AppendSwitch(switches::kDisableSkiaRuntimeOpts);
210 
211   command_line.AppendSwitch(switches::kDisallowNonExactResourceReuse);
212 
213   // Always run with fake media devices.
214   command_line.AppendSwitch(switches::kUseFakeUIForMediaStream);
215   command_line.AppendSwitch(switches::kUseFakeDeviceForMediaStream);
216 
217   // Enable the deprecated WebAuthn Mojo Testing API.
218   command_line.AppendSwitch(switches::kEnableWebAuthDeprecatedMojoTestingApi);
219 
220   // Always disable the unsandbox GPU process for DX12 Info collection to avoid
221   // interference. This GPU process is launched 120 seconds after chrome starts.
222   command_line.AppendSwitch(switches::kDisableGpuProcessForDX12InfoCollection);
223 
224 #if defined(OS_WIN) || defined(OS_MAC) || defined(OS_LINUX) || \
225     defined(OS_CHROMEOS)
226   content::WebTestBrowserPlatformInitialize();
227 #endif
228 
229   RenderWidgetHostImpl::DisableResizeAckCheckForTesting();
230 }
231 
RunBrowserMain(const content::MainFunctionParams & parameters)232 void WebTestBrowserMainRunner::RunBrowserMain(
233     const content::MainFunctionParams& parameters) {
234   std::unique_ptr<content::BrowserMainRunner> main_runner =
235       content::BrowserMainRunner::Create();
236   int initialize_exit_code = main_runner->Initialize(parameters);
237   DCHECK_LT(initialize_exit_code, 0)
238       << "BrowserMainRunner::Initialize failed in WebTestBrowserMainRunner";
239 
240   RunTests(main_runner.get());
241   base::RunLoop().RunUntilIdle();
242 
243   content::Shell::CloseAllWindows();
244 
245   main_runner->Shutdown();
246 }
247 
248 }  // namespace content
249