// Copyright (c) 2012 The Chromium 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 "ppapi/tests/test_message_loop.h" #include "ppapi/c/pp_macros.h" #include "ppapi/cpp/core.h" #include "ppapi/cpp/logging.h" #include "ppapi/cpp/message_loop.h" #include "ppapi/cpp/module.h" #include "ppapi/tests/testing_instance.h" #include "ppapi/utility/threading/simple_thread.h" REGISTER_TEST_CASE(MessageLoop); TestMessageLoop::TestMessageLoop(TestingInstance* instance) : TestCase(instance), param_(kInvalid), callback_factory_(this), main_loop_task_ran_(instance->pp_instance()) { } TestMessageLoop::~TestMessageLoop() { } void TestMessageLoop::RunTests(const std::string& filter) { RUN_TEST(Basics, filter); RUN_TEST(Post, filter); } std::string TestMessageLoop::TestBasics() { // The main thread message loop should be valid, and equal to the "current" // one. ASSERT_NE(0, pp::MessageLoop::GetForMainThread().pp_resource()); ASSERT_EQ(pp::MessageLoop::GetForMainThread().pp_resource(), pp::MessageLoop::GetCurrent().pp_resource()); // We shouldn't be able to attach a new loop to the main thread. pp::MessageLoop loop(instance_); ASSERT_EQ(PP_ERROR_INPROGRESS, loop.AttachToCurrentThread()); // Nested loops aren't allowed. ASSERT_EQ(PP_ERROR_INPROGRESS, pp::MessageLoop::GetForMainThread().Run()); // We can't run on a loop that isn't attached to a thread. ASSERT_EQ(PP_ERROR_WRONG_THREAD, loop.Run()); PASS(); } std::string TestMessageLoop::TestPost() { // Make sure we can post a task from the main thread back to the main thread. pp::MessageLoop::GetCurrent().PostWork(callback_factory_.NewCallback( &TestMessageLoop::SetParamAndQuitTask, kMainToMain)); main_loop_task_ran_.Wait(); ASSERT_EQ(param_, kMainToMain); main_loop_task_ran_.Reset(); pp::SimpleThread thread(instance_); // Post a task before the thread is started, to make sure it is run. // TODO(dmichael): CompletionCallbackFactory is not 100% thread safe for // posting tasks to a thread other than where the factory was created. It // should be OK for this test, since we know that the // CompletionCallbackFactory and its target object outlive all callbacks. But // developers are likely to misuse CompletionCallbackFactory. Maybe we should // make it safe to use a callback on another thread? thread.message_loop().PostWork(callback_factory_.NewCallback( &TestMessageLoop::EchoParamToMainTask, kBeforeStart)); ASSERT_TRUE(thread.Start()); main_loop_task_ran_.Wait(); ASSERT_EQ(param_, kBeforeStart); main_loop_task_ran_.Reset(); // Now post another one after start. This is the more normal case. // Nested loops aren't allowed. ASSERT_EQ(PP_ERROR_INPROGRESS, pp::MessageLoop::GetForMainThread().Run()); thread.message_loop().PostWork(callback_factory_.NewCallback( &TestMessageLoop::EchoParamToMainTask, kAfterStart)); main_loop_task_ran_.Wait(); ASSERT_EQ(param_, kAfterStart); main_loop_task_ran_.Reset(); // Quit and join the thread. ASSERT_TRUE(thread.Join()); PASS(); } void TestMessageLoop::SetParamAndQuitTask(int32_t result, TestParam param) { PP_DCHECK(result == PP_OK); param_ = param; main_loop_task_ran_.Signal(); } void TestMessageLoop::EchoParamToMainTask(int32_t result, TestParam param) { PP_DCHECK(result == PP_OK); pp::MessageLoop::GetForMainThread().PostWork( callback_factory_.NewCallback( &TestMessageLoop::SetParamAndQuitTask, param)); }