]> git.sesse.net Git - casparcg/blobdiff - dependencies64/cef/linux/tests/ceftests/thread_unittest.cc
Upgrade CEF to 3.3029.1611.g44e39a8 / Chromium 58.0.3029.81.
[casparcg] / dependencies64 / cef / linux / tests / ceftests / thread_unittest.cc
diff --git a/dependencies64/cef/linux/tests/ceftests/thread_unittest.cc b/dependencies64/cef/linux/tests/ceftests/thread_unittest.cc
new file mode 100644 (file)
index 0000000..a0f9e91
--- /dev/null
@@ -0,0 +1,440 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "include/base/cef_bind.h"
+#include "include/cef_task.h"
+#include "include/cef_thread.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "tests/ceftests/test_handler.h"
+#include "tests/gtest/include/gtest/gtest.h"
+#include "tests/shared/browser/client_app_browser.h"
+#include "tests/shared/renderer/client_app_renderer.h"
+
+using client::ClientAppBrowser;
+using client::ClientAppRenderer;
+
+namespace {
+
+// Base class for creating and testing threads.
+class ThreadTest : public base::RefCountedThreadSafe<ThreadTest> {
+ public:
+  ThreadTest() {}
+  virtual ~ThreadTest() {}
+
+  // Create the test thread. Should only be called one time.
+  void CreateTestThread() {
+    EXPECT_TRUE(!thread_.get());
+
+    owner_task_runner_ = CefTaskRunner::GetForCurrentThread();
+    EXPECT_TRUE(owner_task_runner_.get());
+    EXPECT_TRUE(owner_task_runner_->BelongsToCurrentThread());
+
+    thread_ = CefThread::CreateThread("test_thread");
+    EXPECT_TRUE(thread_.get());
+    EXPECT_TRUE(thread_->IsRunning());
+
+    thread_id_ = thread_->GetPlatformThreadId();
+    EXPECT_NE(thread_id_, kInvalidPlatformThreadId);
+
+    thread_task_runner_ = thread_->GetTaskRunner();
+    EXPECT_TRUE(thread_task_runner_.get());
+
+    AssertOwnerThread();
+  }
+
+  // Destroy the test thread. Should only be called one time.
+  void DestroyTestThread() {
+    EXPECT_TRUE(thread_.get());
+    AssertOwnerThread();
+
+    EXPECT_TRUE(thread_->IsRunning());
+    thread_->Stop();
+    EXPECT_FALSE(thread_->IsRunning());
+
+    AssertOwnerThread();
+
+    thread_ = nullptr;
+  }
+
+  // Execute |test_task| on the test thread. After execution |callback| will be
+  // posted to |callback_task_runner|.
+  void PostOnTestThreadAndCallback(
+      const base::Closure& test_task,
+      CefRefPtr<CefTaskRunner> callback_task_runner,
+      const base::Closure& callback) {
+    EXPECT_TRUE(thread_.get());
+    thread_task_runner_->PostTask(CefCreateClosureTask(
+        base::Bind(&ThreadTest::ExecuteOnTestThread, this, test_task,
+                   callback_task_runner, callback)));
+  }
+
+  CefRefPtr<CefTaskRunner> owner_task_runner() const {
+    return owner_task_runner_;
+  }
+  CefRefPtr<CefTaskRunner> thread_task_runner() const {
+    return thread_task_runner_;
+  }
+
+  // Assert that we're running on the owner thread.
+  void AssertOwnerThread() {
+    EXPECT_TRUE(owner_task_runner_->BelongsToCurrentThread());
+    EXPECT_FALSE(thread_task_runner_->BelongsToCurrentThread());
+    EXPECT_TRUE(thread_task_runner_->IsSame(thread_->GetTaskRunner()));
+    EXPECT_EQ(thread_id_, thread_->GetPlatformThreadId());
+  }
+
+  // Assert that we're running on the test thread.
+  void AssertTestThread() {
+    EXPECT_FALSE(owner_task_runner_->BelongsToCurrentThread());
+    EXPECT_TRUE(thread_task_runner_->BelongsToCurrentThread());
+    EXPECT_TRUE(thread_task_runner_->IsSame(thread_->GetTaskRunner()));
+    EXPECT_EQ(thread_id_, thread_->GetPlatformThreadId());
+  }
+
+ private:
+  // Helper for PostOnTestThreadAndCallback().
+  void ExecuteOnTestThread(const base::Closure& test_task,
+                           CefRefPtr<CefTaskRunner> callback_task_runner,
+                           const base::Closure& callback) {
+    AssertTestThread();
+
+    test_task.Run();
+
+    callback_task_runner->PostTask(CefCreateClosureTask(callback));
+  }
+
+  CefRefPtr<CefTaskRunner> owner_task_runner_;
+
+  CefRefPtr<CefThread> thread_;
+  cef_platform_thread_id_t thread_id_;
+  CefRefPtr<CefTaskRunner> thread_task_runner_;
+
+  DISALLOW_COPY_AND_ASSIGN(ThreadTest);
+};
+
+}  // namespace
+
+// Test thread creation and destruction without any task execution.
+TEST(ThreadTest, Create) {
+  scoped_refptr<ThreadTest> thread_test = new ThreadTest();
+  thread_test->CreateTestThread();
+  thread_test->DestroyTestThread();
+  thread_test = nullptr;
+}
+
+
+namespace {
+
+// Simple implementation of ThreadTest that creates a thread, executes tasks
+// on the thread, then destroys the thread after all tasks have completed.
+class SimpleThreadTest : public ThreadTest {
+ public:
+  SimpleThreadTest(size_t expected_task_count,
+                   const base::Closure& task_callback,
+                   const base::Closure& done_callback)
+    : expected_task_count_(expected_task_count),
+      task_callback_(task_callback),
+      done_callback_(done_callback),
+      got_task_count_(0U),
+      got_done_count_(0U) {}
+
+  void RunTest() {
+    // Create the test thread.
+    CreateTestThread();
+
+    for (size_t i = 0U; i < expected_task_count_; ++i) {
+      // Execute Task() on the test thread and then call Done() on this thread.
+      PostOnTestThreadAndCallback(
+          base::Bind(&SimpleThreadTest::Task, this), owner_task_runner(),
+          base::Bind(&SimpleThreadTest::Done, this));
+    }
+  }
+
+  void DestroyTest() {
+    EXPECT_EQ(expected_task_count_, got_task_count_);
+    EXPECT_EQ(expected_task_count_, got_done_count_);
+
+    // Destroy the test thread.
+    DestroyTestThread();
+  }
+
+ private:
+  void Task() {
+    AssertTestThread();
+    got_task_count_++;
+    if (!task_callback_.is_null())
+      task_callback_.Run();
+  }
+
+  void Done() {
+    AssertOwnerThread();
+    if (++got_done_count_ == expected_task_count_ && !done_callback_.is_null())
+      done_callback_.Run();
+  }
+
+  const size_t expected_task_count_;
+  base::Closure task_callback_;
+  base::Closure done_callback_;
+
+  size_t got_task_count_;
+  size_t got_done_count_;
+
+  DISALLOW_COPY_AND_ASSIGN(SimpleThreadTest);
+};
+
+
+// Test creation/execution of threads in the browser process.
+
+const char kBrowserThreadTestHtml[] = "http://test.com/browserthread.html";
+
+// Browser side.
+class BrowserThreadTestHandler : public TestHandler {
+ public:
+  explicit BrowserThreadTestHandler(CefThreadId owner_thread_id)
+    : owner_thread_id_(owner_thread_id) {}
+
+  void RunTest() override {
+    AddResource(kBrowserThreadTestHtml, "<html><body>Test</body></html>",
+                "text/html");
+
+    CreateBrowser(kBrowserThreadTestHtml);
+
+    // Time out the test after a reasonable period of time.
+    SetTestTimeout();
+  }
+
+  void RunThreadTestOnOwnerThread() {
+    if (!CefCurrentlyOn(owner_thread_id_)) {
+      // Run the test on the desired owner thread.
+      CefPostTask(owner_thread_id_,
+          base::Bind(&BrowserThreadTestHandler::RunThreadTestOnOwnerThread,
+                     this));
+      return;
+    }
+
+    EXPECT_FALSE(thread_test_.get());
+    thread_test_ = new SimpleThreadTest(
+        3, base::Closure(),
+        base::Bind(&BrowserThreadTestHandler::DoneOnOwnerThread, this));
+    thread_test_->RunTest();
+  }
+
+  void DoneOnOwnerThread() {
+    // Let the call stack unwind before destroying |thread_test_|.
+    CefPostTask(owner_thread_id_,
+        base::Bind(&BrowserThreadTestHandler::DestroyTestOnOwnerThread, this));
+  }
+
+  void DestroyTestOnOwnerThread() {
+    EXPECT_TRUE(CefCurrentlyOn(owner_thread_id_));
+
+    EXPECT_TRUE(thread_test_.get());
+    if (thread_test_) {
+      thread_test_->DestroyTest();
+      thread_test_ = nullptr;
+    }
+
+    got_test_done_.yes();
+
+    // Call DestroyTest() on the UI thread.
+    CefPostTask(TID_UI,
+        base::Bind(&BrowserThreadTestHandler::DestroyTest, this));
+  }
+
+  void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
+                            bool isLoading,
+                            bool canGoBack,
+                            bool canGoForward) override {
+    if (!isLoading)
+      RunThreadTestOnOwnerThread();
+  }
+
+ private:
+  void DestroyTest() override {
+    EXPECT_FALSE(thread_test_.get());
+    EXPECT_TRUE(got_test_done_);
+
+    TestHandler::DestroyTest();
+  }
+
+  const CefThreadId owner_thread_id_;
+
+  scoped_refptr<SimpleThreadTest> thread_test_;
+  TrackCallback got_test_done_;
+
+  IMPLEMENT_REFCOUNTING(BrowserThreadTestHandler);
+  DISALLOW_COPY_AND_ASSIGN(BrowserThreadTestHandler);
+};
+
+}  // namespace
+
+// Test creation of new threads from the browser UI thread.
+TEST(ThreadTest, CreateFromBrowserUIThread) {
+  CefRefPtr<BrowserThreadTestHandler> handler =
+      new BrowserThreadTestHandler(TID_UI);
+  handler->ExecuteTest();
+  ReleaseAndWaitForDestructor(handler);
+}
+
+// Test creation of new threads from the browser IO thread.
+TEST(ThreadTest, CreateFromBrowserIOThread) {
+  CefRefPtr<BrowserThreadTestHandler> handler =
+      new BrowserThreadTestHandler(TID_IO);
+  handler->ExecuteTest();
+  ReleaseAndWaitForDestructor(handler);
+}
+
+// Test creation of new threads from the browser FILE thread.
+TEST(ThreadTest, CreateFromBrowserFILEThread) {
+  CefRefPtr<BrowserThreadTestHandler> handler =
+      new BrowserThreadTestHandler(TID_FILE);
+  handler->ExecuteTest();
+  ReleaseAndWaitForDestructor(handler);
+}
+
+
+namespace {
+
+// Test creation/execution of threads in the render process.
+
+const char kRenderThreadTestHtml[] = "http://test.com/renderthread.html";
+const char kRenderThreadTestMsg[] = "ThreadTest.RenderThreadTest";
+
+// Browser side.
+class RenderThreadTestHandler : public TestHandler {
+ public:
+  RenderThreadTestHandler() {}
+
+  void RunTest() override {
+    AddResource(kRenderThreadTestHtml, "<html><body>Test</body></html>",
+                "text/html");
+
+    CreateBrowser(kRenderThreadTestHtml);
+
+    // Time out the test after a reasonable period of time.
+    SetTestTimeout();
+  }
+
+  void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
+                            bool isLoading,
+                            bool canGoBack,
+                            bool canGoForward) override {
+    if (!isLoading) {
+      // Return the test in the render process.
+      CefRefPtr<CefProcessMessage> msg =
+          CefProcessMessage::Create(kRenderThreadTestMsg);
+      EXPECT_TRUE(browser->SendProcessMessage(PID_RENDERER, msg));
+    }
+  }
+
+  bool OnProcessMessageReceived(
+      CefRefPtr<CefBrowser> browser,
+      CefProcessId source_process,
+      CefRefPtr<CefProcessMessage> message) override {
+    EXPECT_TRUE(browser.get());
+    EXPECT_EQ(PID_RENDERER, source_process);
+    EXPECT_TRUE(message.get());
+    EXPECT_TRUE(message->IsReadOnly());
+
+    const std::string& message_name = message->GetName();
+    EXPECT_STREQ(kRenderThreadTestMsg, message_name.c_str());
+
+    got_message_.yes();
+
+    if (message->GetArgumentList()->GetBool(0))
+      got_success_.yes();
+
+    // Test is complete.
+    DestroyTest();
+
+    return true;
+  }
+
+ protected:
+  void DestroyTest() override {
+    EXPECT_TRUE(got_message_);
+    EXPECT_TRUE(got_success_);
+
+    TestHandler::DestroyTest();
+  }
+
+  TrackCallback got_message_;
+  TrackCallback got_success_;
+
+  IMPLEMENT_REFCOUNTING(RenderThreadTestHandler);
+  DISALLOW_COPY_AND_ASSIGN(RenderThreadTestHandler);
+};
+
+// Renderer side.
+class RenderThreadRendererTest : public ClientAppRenderer::Delegate {
+ public:
+  RenderThreadRendererTest() {}
+
+  bool OnProcessMessageReceived(
+      CefRefPtr<ClientAppRenderer> app,
+      CefRefPtr<CefBrowser> browser,
+      CefProcessId source_process,
+      CefRefPtr<CefProcessMessage> message) override {
+    if (message->GetName().ToString() == kRenderThreadTestMsg) {
+      browser_ = browser;
+      EXPECT_FALSE(thread_test_.get());
+      thread_test_ = new SimpleThreadTest(
+          3, base::Closure(),
+          base::Bind(&RenderThreadRendererTest::Done, this));
+      thread_test_->RunTest();
+      return true;
+    }
+
+    // Message not handled.
+    return false;
+  }
+
+ private:
+  void Done() {
+    // Let the call stack unwind before destroying |thread_test_|.
+    CefPostTask(TID_RENDERER,
+        base::Bind(&RenderThreadRendererTest::DestroyTest, this));
+  }
+
+  void DestroyTest() {
+    EXPECT_TRUE(thread_test_.get());
+    if (thread_test_) {
+      thread_test_->DestroyTest();
+      thread_test_ = nullptr;
+    }
+
+    // Check if the test has failed.
+    bool result = !TestFailed();
+
+    // Return the result to the browser process.
+    CefRefPtr<CefProcessMessage> return_msg =
+        CefProcessMessage::Create(kRenderThreadTestMsg);
+    EXPECT_TRUE(return_msg->GetArgumentList()->SetBool(0, result));
+    EXPECT_TRUE(browser_->SendProcessMessage(PID_BROWSER, return_msg));
+
+    browser_ = nullptr;
+  }
+
+  CefRefPtr<CefBrowser> browser_;
+  scoped_refptr<SimpleThreadTest> thread_test_;
+
+  IMPLEMENT_REFCOUNTING(RenderThreadRendererTest);
+  DISALLOW_COPY_AND_ASSIGN(RenderThreadRendererTest);
+};
+
+}  // namespace
+
+TEST(ThreadTest, CreateFromRenderThread) {
+  CefRefPtr<RenderThreadTestHandler> handler = new RenderThreadTestHandler();
+  handler->ExecuteTest();
+  ReleaseAndWaitForDestructor(handler);
+}
+
+
+// Entry point for creating request handler renderer test objects.
+// Called from client_app_delegates.cc.
+void CreateThreadRendererTests(
+    ClientAppRenderer::DelegateSet& delegates) {
+  delegates.insert(new RenderThreadRendererTest);
+}