1 // Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
2 // reserved. Use of this source code is governed by a BSD-style license that
3 // can be found in the LICENSE file.
4
5 #include "include/base/cef_build.h"
6 #include "include/cef_config.h"
7
8 #if defined(OS_LINUX) && defined(CEF_X11)
9 #include <X11/Xlib.h>
10 // Definitions conflict with gtest.
11 #undef None
12 #undef Bool
13 #endif
14
15 #if defined(OS_POSIX)
16 #include <unistd.h>
17 #endif
18
19 #include "include/base/cef_callback.h"
20 #include "include/cef_app.h"
21 #include "include/cef_task.h"
22 #include "include/cef_thread.h"
23 #include "include/cef_waitable_event.h"
24 #include "include/wrapper/cef_closure_task.h"
25 #include "include/wrapper/cef_helpers.h"
26 #include "tests/ceftests/test_handler.h"
27 #include "tests/ceftests/test_server.h"
28 #include "tests/ceftests/test_suite.h"
29 #include "tests/shared/browser/client_app_browser.h"
30 #include "tests/shared/browser/main_message_loop_external_pump.h"
31 #include "tests/shared/browser/main_message_loop_std.h"
32 #include "tests/shared/common/client_app_other.h"
33 #include "tests/shared/renderer/client_app_renderer.h"
34
35 #if defined(OS_MAC)
36 #include "include/wrapper/cef_library_loader.h"
37 #endif
38
39 // When generating projects with CMake the CEF_USE_SANDBOX value will be defined
40 // automatically if using the required compiler version. Pass -DUSE_SANDBOX=OFF
41 // to the CMake command-line to disable use of the sandbox.
42 #if defined(OS_WIN) && defined(CEF_USE_SANDBOX)
43 #include "include/cef_sandbox_win.h"
44
45 // The cef_sandbox.lib static library may not link successfully with all VS
46 // versions.
47 #pragma comment(lib, "cef_sandbox.lib")
48 #endif
49
50 namespace {
51
QuitMessageLoop()52 void QuitMessageLoop() {
53 CEF_REQUIRE_UI_THREAD();
54 client::MainMessageLoop* message_loop = client::MainMessageLoop::Get();
55 if (message_loop)
56 message_loop->Quit();
57 else
58 CefQuitMessageLoop();
59 }
60
sleep(int64 ms)61 void sleep(int64 ms) {
62 #if defined(OS_WIN)
63 Sleep(ms);
64 #elif defined(OS_POSIX)
65 usleep(ms * 1000);
66 #else
67 #error Unsupported platform
68 #endif
69 }
70
71 // Called on the test thread.
RunTestsOnTestThread()72 void RunTestsOnTestThread() {
73 // Run the test suite.
74 CefTestSuite::GetInstance()->Run();
75
76 // Wait for all browsers to exit.
77 while (TestHandler::HasBrowser())
78 sleep(100);
79
80 // Wait for the test server to stop, and then quit the CEF message loop.
81 test_server::Stop(base::BindOnce(QuitMessageLoop));
82 }
83
84 // Called on the UI thread.
ContinueOnUIThread(CefRefPtr<CefTaskRunner> test_task_runner)85 void ContinueOnUIThread(CefRefPtr<CefTaskRunner> test_task_runner) {
86 // Run the test suite on the test thread.
87 test_task_runner->PostTask(
88 CefCreateClosureTask(base::BindOnce(&RunTestsOnTestThread)));
89 }
90
91 #if defined(OS_LINUX) && defined(CEF_X11)
XErrorHandlerImpl(Display * display,XErrorEvent * event)92 int XErrorHandlerImpl(Display* display, XErrorEvent* event) {
93 LOG(WARNING) << "X error received: "
94 << "type " << event->type << ", "
95 << "serial " << event->serial << ", "
96 << "error_code " << static_cast<int>(event->error_code) << ", "
97 << "request_code " << static_cast<int>(event->request_code)
98 << ", "
99 << "minor_code " << static_cast<int>(event->minor_code);
100 return 0;
101 }
102
XIOErrorHandlerImpl(Display * display)103 int XIOErrorHandlerImpl(Display* display) {
104 return 0;
105 }
106 #endif // defined(OS_LINUX) && defined(CEF_X11)
107
108 } // namespace
109
main(int argc,char * argv[])110 int main(int argc, char* argv[]) {
111 #if defined(OS_MAC)
112 // Load the CEF framework library at runtime instead of linking directly
113 // as required by the macOS sandbox implementation.
114 CefScopedLibraryLoader library_loader;
115 if (!library_loader.LoadInMain())
116 return 1;
117 #endif
118
119 // Create the singleton test suite object.
120 CefTestSuite test_suite(argc, argv);
121
122 #if defined(OS_WIN)
123 if (test_suite.command_line()->HasSwitch("enable-high-dpi-support")) {
124 // Enable High-DPI support on Windows 7 and newer.
125 CefEnableHighDPISupport();
126 }
127
128 CefMainArgs main_args(::GetModuleHandle(nullptr));
129 #else
130 CefMainArgs main_args(argc, argv);
131 #endif
132
133 void* windows_sandbox_info = nullptr;
134
135 #if defined(OS_WIN) && defined(CEF_USE_SANDBOX)
136 // Manages the life span of the sandbox information object.
137 CefScopedSandboxInfo scoped_sandbox;
138 windows_sandbox_info = scoped_sandbox.sandbox_info();
139 #endif
140
141 // Create a ClientApp of the correct type.
142 CefRefPtr<CefApp> app;
143 client::ClientApp::ProcessType process_type =
144 client::ClientApp::GetProcessType(test_suite.command_line());
145 if (process_type == client::ClientApp::BrowserProcess) {
146 app = new client::ClientAppBrowser();
147 #if !defined(OS_MAC)
148 } else if (process_type == client::ClientApp::RendererProcess ||
149 process_type == client::ClientApp::ZygoteProcess) {
150 app = new client::ClientAppRenderer();
151 } else if (process_type == client::ClientApp::OtherProcess) {
152 app = new client::ClientAppOther();
153 }
154
155 // Execute the secondary process, if any.
156 int exit_code = CefExecuteProcess(main_args, app, windows_sandbox_info);
157 if (exit_code >= 0)
158 return exit_code;
159 #else
160 } else {
161 // On OS X this executable is only used for the main process.
162 NOTREACHED();
163 }
164 #endif
165
166 CefSettings settings;
167
168 #if !defined(CEF_USE_SANDBOX)
169 settings.no_sandbox = true;
170 #endif
171
172 client::ClientAppBrowser::PopulateSettings(test_suite.command_line(),
173 settings);
174 test_suite.GetSettings(settings);
175
176 #if defined(OS_MAC)
177 // Platform-specific initialization.
178 extern void PlatformInit();
179 PlatformInit();
180 #endif
181
182 #if defined(OS_LINUX) && defined(CEF_X11)
183 // Install xlib error handlers so that the application won't be terminated
184 // on non-fatal errors.
185 XSetErrorHandler(XErrorHandlerImpl);
186 XSetIOErrorHandler(XIOErrorHandlerImpl);
187 #endif
188
189 // Create the MessageLoop.
190 std::unique_ptr<client::MainMessageLoop> message_loop;
191 if (!settings.multi_threaded_message_loop) {
192 if (settings.external_message_pump)
193 message_loop = client::MainMessageLoopExternalPump::Create();
194 else
195 message_loop.reset(new client::MainMessageLoopStd);
196 }
197
198 // Initialize CEF.
199 CefInitialize(main_args, settings, app, windows_sandbox_info);
200
201 // Initialize the testing framework.
202 test_suite.InitMainProcess();
203
204 int retval;
205
206 if (settings.multi_threaded_message_loop) {
207 // Run the test suite on the main thread.
208 retval = test_suite.Run();
209
210 // Wait for the test server to stop.
211 CefRefPtr<CefWaitableEvent> event =
212 CefWaitableEvent::CreateWaitableEvent(true, false);
213 test_server::Stop(base::BindOnce(&CefWaitableEvent::Signal, event));
214 event->Wait();
215 } else {
216 // Create and start the test thread.
217 CefRefPtr<CefThread> thread = CefThread::CreateThread("test_thread");
218 if (!thread)
219 return 1;
220
221 // Start the tests from the UI thread so that any pending UI tasks get a
222 // chance to execute first.
223 CefPostTask(TID_UI,
224 base::BindOnce(&ContinueOnUIThread, thread->GetTaskRunner()));
225
226 // Run the CEF message loop.
227 message_loop->Run();
228
229 // The test suite has completed.
230 retval = test_suite.retval();
231
232 // Terminate the test thread.
233 thread->Stop();
234 thread = nullptr;
235 }
236
237 // Shut down CEF.
238 CefShutdown();
239
240 test_suite.DeleteTempDirectories();
241
242 // Destroy the MessageLoop.
243 message_loop.reset(nullptr);
244
245 #if defined(OS_MAC)
246 // Platform-specific cleanup.
247 extern void PlatformCleanup();
248 PlatformCleanup();
249 #endif
250
251 return retval;
252 }
253