1 // Copyright 2016 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_callback.h"
6 #include "include/base/cef_callback_helpers.h"
7 #include "include/cef_task.h"
8 #include "include/cef_thread.h"
9 #include "include/wrapper/cef_closure_task.h"
10 #include "tests/ceftests/test_handler.h"
11 #include "tests/gtest/include/gtest/gtest.h"
12 #include "tests/shared/browser/client_app_browser.h"
13 #include "tests/shared/renderer/client_app_renderer.h"
14
15 using client::ClientAppBrowser;
16 using client::ClientAppRenderer;
17
18 namespace {
19
20 // Base class for creating and testing threads.
21 class ThreadTest : public base::RefCountedThreadSafe<ThreadTest> {
22 public:
ThreadTest()23 ThreadTest() {}
~ThreadTest()24 virtual ~ThreadTest() {}
25
26 // Create the test thread. Should only be called one time.
CreateTestThread()27 void CreateTestThread() {
28 EXPECT_TRUE(!thread_.get());
29
30 owner_task_runner_ = CefTaskRunner::GetForCurrentThread();
31 EXPECT_TRUE(owner_task_runner_.get());
32 EXPECT_TRUE(owner_task_runner_->BelongsToCurrentThread());
33
34 thread_ = CefThread::CreateThread("test_thread");
35 EXPECT_TRUE(thread_.get());
36 EXPECT_TRUE(thread_->IsRunning());
37
38 thread_id_ = thread_->GetPlatformThreadId();
39 EXPECT_NE(thread_id_, kInvalidPlatformThreadId);
40
41 thread_task_runner_ = thread_->GetTaskRunner();
42 EXPECT_TRUE(thread_task_runner_.get());
43
44 AssertOwnerThread();
45 }
46
47 // Destroy the test thread. Should only be called one time.
DestroyTestThread()48 void DestroyTestThread() {
49 EXPECT_TRUE(thread_.get());
50 AssertOwnerThread();
51
52 EXPECT_TRUE(thread_->IsRunning());
53 thread_->Stop();
54 EXPECT_FALSE(thread_->IsRunning());
55
56 AssertOwnerThread();
57
58 thread_ = nullptr;
59 }
60
61 // Execute |test_task| on the test thread. After execution |callback| will be
62 // posted to |callback_task_runner|.
PostOnTestThreadAndCallback(base::OnceClosure test_task,CefRefPtr<CefTaskRunner> callback_task_runner,base::OnceClosure callback)63 void PostOnTestThreadAndCallback(
64 base::OnceClosure test_task,
65 CefRefPtr<CefTaskRunner> callback_task_runner,
66 base::OnceClosure callback) {
67 EXPECT_TRUE(thread_.get());
68 thread_task_runner_->PostTask(CefCreateClosureTask(base::BindOnce(
69 &ThreadTest::ExecuteOnTestThread, this, std::move(test_task),
70 callback_task_runner, std::move(callback))));
71 }
72
owner_task_runner() const73 CefRefPtr<CefTaskRunner> owner_task_runner() const {
74 return owner_task_runner_;
75 }
thread_task_runner() const76 CefRefPtr<CefTaskRunner> thread_task_runner() const {
77 return thread_task_runner_;
78 }
79
80 // Assert that we're running on the owner thread.
AssertOwnerThread()81 void AssertOwnerThread() {
82 EXPECT_TRUE(owner_task_runner_->BelongsToCurrentThread());
83 EXPECT_FALSE(thread_task_runner_->BelongsToCurrentThread());
84 EXPECT_TRUE(thread_task_runner_->IsSame(thread_->GetTaskRunner()));
85 EXPECT_EQ(thread_id_, thread_->GetPlatformThreadId());
86 }
87
88 // Assert that we're running on the test thread.
AssertTestThread()89 void AssertTestThread() {
90 EXPECT_FALSE(owner_task_runner_->BelongsToCurrentThread());
91 EXPECT_TRUE(thread_task_runner_->BelongsToCurrentThread());
92 EXPECT_TRUE(thread_task_runner_->IsSame(thread_->GetTaskRunner()));
93 EXPECT_EQ(thread_id_, thread_->GetPlatformThreadId());
94 }
95
96 private:
97 // Helper for PostOnTestThreadAndCallback().
ExecuteOnTestThread(base::OnceClosure test_task,CefRefPtr<CefTaskRunner> callback_task_runner,base::OnceClosure callback)98 void ExecuteOnTestThread(base::OnceClosure test_task,
99 CefRefPtr<CefTaskRunner> callback_task_runner,
100 base::OnceClosure callback) {
101 AssertTestThread();
102
103 std::move(test_task).Run();
104
105 callback_task_runner->PostTask(CefCreateClosureTask(std::move(callback)));
106 }
107
108 CefRefPtr<CefTaskRunner> owner_task_runner_;
109
110 CefRefPtr<CefThread> thread_;
111 cef_platform_thread_id_t thread_id_;
112 CefRefPtr<CefTaskRunner> thread_task_runner_;
113
114 DISALLOW_COPY_AND_ASSIGN(ThreadTest);
115 };
116
117 } // namespace
118
119 // Test thread creation and destruction without any task execution.
TEST(ThreadTest,Create)120 TEST(ThreadTest, Create) {
121 scoped_refptr<ThreadTest> thread_test = new ThreadTest();
122 thread_test->CreateTestThread();
123 thread_test->DestroyTestThread();
124 thread_test = nullptr;
125 }
126
127 namespace {
128
129 // Simple implementation of ThreadTest that creates a thread, executes tasks
130 // on the thread, then destroys the thread after all tasks have completed.
131 class SimpleThreadTest : public ThreadTest {
132 public:
SimpleThreadTest(size_t expected_task_count,base::OnceClosure task_callback,base::OnceClosure done_callback)133 SimpleThreadTest(size_t expected_task_count,
134 base::OnceClosure task_callback,
135 base::OnceClosure done_callback)
136 : expected_task_count_(expected_task_count),
137 task_callback_(std::move(task_callback)),
138 done_callback_(std::move(done_callback)),
139 got_task_count_(0U),
140 got_done_count_(0U) {}
141
RunTest()142 void RunTest() {
143 // Create the test thread.
144 CreateTestThread();
145
146 for (size_t i = 0U; i < expected_task_count_; ++i) {
147 // Execute Task() on the test thread and then call Done() on this thread.
148 PostOnTestThreadAndCallback(
149 base::BindOnce(&SimpleThreadTest::Task, this), owner_task_runner(),
150 base::BindOnce(&SimpleThreadTest::Done, this));
151 }
152 }
153
DestroyTest()154 void DestroyTest() {
155 EXPECT_EQ(expected_task_count_, got_task_count_);
156 EXPECT_EQ(expected_task_count_, got_done_count_);
157
158 // Destroy the test thread.
159 DestroyTestThread();
160 }
161
162 private:
Task()163 void Task() {
164 AssertTestThread();
165 got_task_count_++;
166 if (!task_callback_.is_null())
167 std::move(task_callback_).Run();
168 }
169
Done()170 void Done() {
171 AssertOwnerThread();
172 if (++got_done_count_ == expected_task_count_ && !done_callback_.is_null())
173 std::move(done_callback_).Run();
174 }
175
176 const size_t expected_task_count_;
177 base::OnceClosure task_callback_;
178 base::OnceClosure done_callback_;
179
180 size_t got_task_count_;
181 size_t got_done_count_;
182
183 DISALLOW_COPY_AND_ASSIGN(SimpleThreadTest);
184 };
185
186 // Test creation/execution of threads in the browser process.
187
188 const char kBrowserThreadTestHtml[] = "http://test.com/browserthread.html";
189
190 // Browser side.
191 class BrowserThreadTestHandler : public TestHandler {
192 public:
BrowserThreadTestHandler(CefThreadId owner_thread_id)193 explicit BrowserThreadTestHandler(CefThreadId owner_thread_id)
194 : owner_thread_id_(owner_thread_id) {}
195
RunTest()196 void RunTest() override {
197 AddResource(kBrowserThreadTestHtml, "<html><body>Test</body></html>",
198 "text/html");
199
200 CreateBrowser(kBrowserThreadTestHtml);
201
202 // Time out the test after a reasonable period of time.
203 SetTestTimeout();
204 }
205
RunThreadTestOnOwnerThread()206 void RunThreadTestOnOwnerThread() {
207 if (!CefCurrentlyOn(owner_thread_id_)) {
208 // Run the test on the desired owner thread.
209 CefPostTask(
210 owner_thread_id_,
211 base::BindOnce(&BrowserThreadTestHandler::RunThreadTestOnOwnerThread,
212 this));
213 return;
214 }
215
216 EXPECT_FALSE(thread_test_.get());
217 thread_test_ = new SimpleThreadTest(
218 3, base::DoNothing(),
219 base::BindOnce(&BrowserThreadTestHandler::DoneOnOwnerThread, this));
220 thread_test_->RunTest();
221 }
222
DoneOnOwnerThread()223 void DoneOnOwnerThread() {
224 // Let the call stack unwind before destroying |thread_test_|.
225 CefPostTask(owner_thread_id_,
226 base::BindOnce(
227 &BrowserThreadTestHandler::DestroyTestOnOwnerThread, this));
228 }
229
DestroyTestOnOwnerThread()230 void DestroyTestOnOwnerThread() {
231 EXPECT_TRUE(CefCurrentlyOn(owner_thread_id_));
232
233 EXPECT_TRUE(thread_test_.get());
234 if (thread_test_) {
235 thread_test_->DestroyTest();
236 thread_test_ = nullptr;
237 }
238
239 got_test_done_.yes();
240
241 // Call DestroyTest() on the UI thread.
242 CefPostTask(TID_UI,
243 base::BindOnce(&BrowserThreadTestHandler::DestroyTest, this));
244 }
245
OnLoadingStateChange(CefRefPtr<CefBrowser> browser,bool isLoading,bool canGoBack,bool canGoForward)246 void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
247 bool isLoading,
248 bool canGoBack,
249 bool canGoForward) override {
250 if (!isLoading)
251 RunThreadTestOnOwnerThread();
252 }
253
254 private:
DestroyTest()255 void DestroyTest() override {
256 EXPECT_FALSE(thread_test_.get());
257 EXPECT_TRUE(got_test_done_);
258
259 TestHandler::DestroyTest();
260 }
261
262 const CefThreadId owner_thread_id_;
263
264 scoped_refptr<SimpleThreadTest> thread_test_;
265 TrackCallback got_test_done_;
266
267 IMPLEMENT_REFCOUNTING(BrowserThreadTestHandler);
268 DISALLOW_COPY_AND_ASSIGN(BrowserThreadTestHandler);
269 };
270
271 } // namespace
272
273 // Test creation of new threads from the browser UI thread.
TEST(ThreadTest,CreateFromBrowserUIThread)274 TEST(ThreadTest, CreateFromBrowserUIThread) {
275 CefRefPtr<BrowserThreadTestHandler> handler =
276 new BrowserThreadTestHandler(TID_UI);
277 handler->ExecuteTest();
278 ReleaseAndWaitForDestructor(handler);
279 }
280
281 // Test creation of new threads from the browser IO thread.
TEST(ThreadTest,CreateFromBrowserIOThread)282 TEST(ThreadTest, CreateFromBrowserIOThread) {
283 CefRefPtr<BrowserThreadTestHandler> handler =
284 new BrowserThreadTestHandler(TID_IO);
285 handler->ExecuteTest();
286 ReleaseAndWaitForDestructor(handler);
287 }
288
289 // Test creation of new threads from the browser FILE thread.
TEST(ThreadTest,CreateFromBrowserFILEThread)290 TEST(ThreadTest, CreateFromBrowserFILEThread) {
291 // Use a FILE thread that will run tasks relatively quickly.
292 CefRefPtr<BrowserThreadTestHandler> handler =
293 new BrowserThreadTestHandler(TID_FILE_USER_VISIBLE);
294 handler->ExecuteTest();
295 ReleaseAndWaitForDestructor(handler);
296 }
297
298 namespace {
299
300 // Test creation/execution of threads in the render process.
301
302 const char kRenderThreadTestHtml[] = "http://test.com/renderthread.html";
303 const char kRenderThreadTestMsg[] = "ThreadTest.RenderThreadTest";
304
305 // Browser side.
306 class RenderThreadTestHandler : public TestHandler {
307 public:
RenderThreadTestHandler()308 RenderThreadTestHandler() {}
309
RunTest()310 void RunTest() override {
311 AddResource(kRenderThreadTestHtml, "<html><body>Test</body></html>",
312 "text/html");
313
314 CreateBrowser(kRenderThreadTestHtml);
315
316 // Time out the test after a reasonable period of time.
317 SetTestTimeout();
318 }
319
OnLoadingStateChange(CefRefPtr<CefBrowser> browser,bool isLoading,bool canGoBack,bool canGoForward)320 void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
321 bool isLoading,
322 bool canGoBack,
323 bool canGoForward) override {
324 if (!isLoading) {
325 // Return the test in the render process.
326 CefRefPtr<CefProcessMessage> msg =
327 CefProcessMessage::Create(kRenderThreadTestMsg);
328 browser->GetMainFrame()->SendProcessMessage(PID_RENDERER, msg);
329 }
330 }
331
OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefProcessId source_process,CefRefPtr<CefProcessMessage> message)332 bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
333 CefRefPtr<CefFrame> frame,
334 CefProcessId source_process,
335 CefRefPtr<CefProcessMessage> message) override {
336 EXPECT_TRUE(browser.get());
337 EXPECT_TRUE(frame.get());
338 EXPECT_EQ(PID_RENDERER, source_process);
339 EXPECT_TRUE(message.get());
340 EXPECT_TRUE(message->IsReadOnly());
341
342 const std::string& message_name = message->GetName();
343 EXPECT_STREQ(kRenderThreadTestMsg, message_name.c_str());
344
345 got_message_.yes();
346
347 if (message->GetArgumentList()->GetBool(0))
348 got_success_.yes();
349
350 // Test is complete.
351 DestroyTest();
352
353 return true;
354 }
355
356 protected:
DestroyTest()357 void DestroyTest() override {
358 EXPECT_TRUE(got_message_);
359 EXPECT_TRUE(got_success_);
360
361 TestHandler::DestroyTest();
362 }
363
364 TrackCallback got_message_;
365 TrackCallback got_success_;
366
367 IMPLEMENT_REFCOUNTING(RenderThreadTestHandler);
368 DISALLOW_COPY_AND_ASSIGN(RenderThreadTestHandler);
369 };
370
371 // Renderer side.
372 class RenderThreadRendererTest : public ClientAppRenderer::Delegate {
373 public:
RenderThreadRendererTest()374 RenderThreadRendererTest() {}
375
OnProcessMessageReceived(CefRefPtr<ClientAppRenderer> app,CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefProcessId source_process,CefRefPtr<CefProcessMessage> message)376 bool OnProcessMessageReceived(CefRefPtr<ClientAppRenderer> app,
377 CefRefPtr<CefBrowser> browser,
378 CefRefPtr<CefFrame> frame,
379 CefProcessId source_process,
380 CefRefPtr<CefProcessMessage> message) override {
381 if (message->GetName().ToString() == kRenderThreadTestMsg) {
382 browser_ = browser;
383 EXPECT_FALSE(thread_test_.get());
384 thread_test_ = new SimpleThreadTest(
385 3, base::DoNothing(),
386 base::BindOnce(&RenderThreadRendererTest::Done, this));
387 thread_test_->RunTest();
388 return true;
389 }
390
391 // Message not handled.
392 return false;
393 }
394
395 private:
Done()396 void Done() {
397 // Let the call stack unwind before destroying |thread_test_|.
398 CefPostTask(TID_RENDERER,
399 base::BindOnce(&RenderThreadRendererTest::DestroyTest, this));
400 }
401
DestroyTest()402 void DestroyTest() {
403 EXPECT_TRUE(thread_test_.get());
404 if (thread_test_) {
405 thread_test_->DestroyTest();
406 thread_test_ = nullptr;
407 }
408
409 // Check if the test has failed.
410 bool result = !TestFailed();
411
412 // Return the result to the browser process.
413 CefRefPtr<CefProcessMessage> return_msg =
414 CefProcessMessage::Create(kRenderThreadTestMsg);
415 EXPECT_TRUE(return_msg->GetArgumentList()->SetBool(0, result));
416 browser_->GetMainFrame()->SendProcessMessage(PID_BROWSER, return_msg);
417
418 browser_ = nullptr;
419 }
420
421 CefRefPtr<CefBrowser> browser_;
422 scoped_refptr<SimpleThreadTest> thread_test_;
423
424 IMPLEMENT_REFCOUNTING(RenderThreadRendererTest);
425 DISALLOW_COPY_AND_ASSIGN(RenderThreadRendererTest);
426 };
427
428 } // namespace
429
TEST(ThreadTest,CreateFromRenderThread)430 TEST(ThreadTest, CreateFromRenderThread) {
431 CefRefPtr<RenderThreadTestHandler> handler = new RenderThreadTestHandler();
432 handler->ExecuteTest();
433 ReleaseAndWaitForDestructor(handler);
434 }
435
436 // Entry point for creating request handler renderer test objects.
437 // Called from client_app_delegates.cc.
CreateThreadRendererTests(ClientAppRenderer::DelegateSet & delegates)438 void CreateThreadRendererTests(ClientAppRenderer::DelegateSet& delegates) {
439 delegates.insert(new RenderThreadRendererTest);
440 }
441