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