• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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