Commit fab5194c authored by dmichael@chromium.org's avatar dmichael@chromium.org

Add means for running some tests only o-o-p. Add messaging non-main thread test.

BUG=92909
TEST=included

Review URL: http://codereview.chromium.org/7648033

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@98826 0039d316-1c4b-4281-b951-d872f2087c98
parent 42f5c7ef
/* Copyright (c) 2010 The Chromium Authors. All rights reserved. /* Copyright (c) 2011 The Chromium Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be * Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file. * found in the LICENSE file.
*/ */
...@@ -12,8 +12,10 @@ ...@@ -12,8 +12,10 @@
struct PP_Point; struct PP_Point;
// TODO(dmichael): Delete support for 0.6.
#define PPB_TESTING_DEV_INTERFACE_0_6 "PPB_Testing(Dev);0.6" #define PPB_TESTING_DEV_INTERFACE_0_6 "PPB_Testing(Dev);0.6"
#define PPB_TESTING_DEV_INTERFACE PPB_TESTING_DEV_INTERFACE_0_6 #define PPB_TESTING_DEV_INTERFACE_0_7 "PPB_Testing(Dev);0.7"
#define PPB_TESTING_DEV_INTERFACE PPB_TESTING_DEV_INTERFACE_0_7
// This interface contains functions used for unit testing. Do not use in // This interface contains functions used for unit testing. Do not use in
// production code. They are not guaranteed to be available in normal plugin // production code. They are not guaranteed to be available in normal plugin
...@@ -68,6 +70,10 @@ struct PPB_Testing_Dev { ...@@ -68,6 +70,10 @@ struct PPB_Testing_Dev {
// associated with this plugin instance. Used for detecting leaks. Returns // associated with this plugin instance. Used for detecting leaks. Returns
// (uint32_t)-1 on failure. // (uint32_t)-1 on failure.
uint32_t (*GetLiveObjectsForInstance)(PP_Instance instance); uint32_t (*GetLiveObjectsForInstance)(PP_Instance instance);
// Returns PP_TRUE if the plugin is running out-of-process, PP_FALSE
// otherwise.
PP_Bool (*IsOutOfProcess)();
}; };
#endif /* PPAPI_C_DEV_PPB_TESTING_DEV_H_ */ #endif /* PPAPI_C_DEV_PPB_TESTING_DEV_H_ */
......
...@@ -72,6 +72,7 @@ ...@@ -72,6 +72,7 @@
'tests/all_cpp_includes.h', 'tests/all_cpp_includes.h',
'tests/arch_dependent_sizes_32.h', 'tests/arch_dependent_sizes_32.h',
'tests/arch_dependent_sizes_64.h', 'tests/arch_dependent_sizes_64.h',
'tests/pp_thread.h',
'tests/test_broker.cc', 'tests/test_broker.cc',
'tests/test_broker.h', 'tests/test_broker.h',
'tests/test_buffer.cc', 'tests/test_buffer.cc',
......
...@@ -109,7 +109,6 @@ bool PluginDispatcher::IsPlugin() const { ...@@ -109,7 +109,6 @@ bool PluginDispatcher::IsPlugin() const {
} }
bool PluginDispatcher::Send(IPC::Message* msg) { bool PluginDispatcher::Send(IPC::Message* msg) {
DCHECK(MessageLoop::current());
TRACE_EVENT2("ppapi proxy", "PluginDispatcher::Send", TRACE_EVENT2("ppapi proxy", "PluginDispatcher::Send",
"Class", IPC_MESSAGE_ID_CLASS(msg->type()), "Class", IPC_MESSAGE_ID_CLASS(msg->type()),
"Line", IPC_MESSAGE_ID_LINE(msg->type())); "Line", IPC_MESSAGE_ID_LINE(msg->type()));
......
...@@ -63,11 +63,16 @@ uint32_t GetLiveObjectsForInstance(PP_Instance instance_id) { ...@@ -63,11 +63,16 @@ uint32_t GetLiveObjectsForInstance(PP_Instance instance_id) {
return result; return result;
} }
PP_Bool IsOutOfProcess() {
return PP_TRUE;
}
const PPB_Testing_Dev testing_interface = { const PPB_Testing_Dev testing_interface = {
&ReadImageData, &ReadImageData,
&RunMessageLoop, &RunMessageLoop,
&QuitMessageLoop, &QuitMessageLoop,
&GetLiveObjectsForInstance &GetLiveObjectsForInstance,
&IsOutOfProcess
}; };
InterfaceProxy* CreateTestingProxy(Dispatcher* dispatcher, InterfaceProxy* CreateTestingProxy(Dispatcher* dispatcher,
......
/* Copyright (c) 2011 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.
*/
#ifndef PPAPI_TESTS_PP_THREAD_H_
#define PPAPI_TESTS_PP_THREAD_H_
#include "ppapi/c/pp_macros.h"
/* These precompiler names were copied from chromium's build_config.h. */
#if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \
defined(__OpenBSD__) || defined(__sun) || defined(__native_client__)
#define PPAPI_HAS_POSIX_THREADS 1
#elif defined (_MSC_VER)
#define PPAPI_HAS_WINDOWS_THREADS 1
#endif
#if defined(PPAPI_HAS_POSIX_THREADS)
#include <pthread.h>
#elif defined(PPAPI_HAS_WINDOWS_THREADS)
#include <process.h>
#include <windows.h>
#endif
/**
* @file
* This file provides platform-independent wrappers around threads. This is for
* use by PPAPI wrappers and tests which need to run on multiple platforms to
* support both trusted platforms (Windows, Mac, Linux) and untrusted (Native
* Client). Apps that use PPAPI only with Native Client should generally use the
* Native Client POSIX implementation instead.
*
* TODO(dmichael): Move this file to ppapi/c and delete this comment, if we end
* up needing platform independent threads in PPAPI C or C++. This file was
* written using inline functions and PPAPI naming conventions with the intent
* of making it possible to put it in to ppapi/c. Currently, however, it's only
* used in ppapi/tests, so is not part of the published API.
*/
#if defined(PPAPI_HAS_POSIX_THREADS)
typedef pthread_t PP_ThreadType;
#elif defined(PPAPI_HAS_WINDOWS_THREADS)
typedef uintptr_t PP_ThreadType;
#endif
typedef void (PP_ThreadFunction)(void* data);
PP_INLINE bool PP_CreateThread(PP_ThreadType* thread,
PP_ThreadFunction function,
void* thread_arg);
PP_INLINE void PP_JoinThread(PP_ThreadType thread);
#if defined(PPAPI_HAS_POSIX_THREADS)
/* Because POSIX thread functions return void* and Windows thread functions do
* not, we make PPAPI thread functions have the least capability (no returns).
* This struct wraps the user data & function so that we can use the correct
* function type on POSIX platforms.
*/
struct PP_ThreadFunctionArgWrapper {
void* user_data;
PP_ThreadFunction* user_function;
};
PP_INLINE void* PP_POSIXThreadFunctionThunk(void* posix_thread_arg) {
PP_ThreadFunctionArgWrapper* arg_wrapper =
(PP_ThreadFunctionArgWrapper*)posix_thread_arg;
arg_wrapper->user_function(arg_wrapper->user_data);
free(posix_thread_arg);
return NULL;
}
PP_INLINE bool PP_CreateThread(PP_ThreadType* thread,
PP_ThreadFunction function,
void* thread_arg) {
PP_ThreadFunctionArgWrapper* arg_wrapper =
(PP_ThreadFunctionArgWrapper*)malloc(sizeof(PP_ThreadFunctionArgWrapper));
arg_wrapper->user_function = function;
arg_wrapper->user_data = thread_arg;
return (pthread_create(thread,
NULL,
PP_POSIXThreadFunctionThunk,
arg_wrapper) == 0);
}
PP_INLINE void PP_JoinThread(PP_ThreadType thread) {
void* exit_status;
pthread_join(thread, &exit_status);
}
#elif defined(PPAPI_HAS_WINDOWS_THREADS)
typedef DWORD (PP_WindowsThreadFunction)(void* data);
PP_INLINE bool PP_CreateThread(PP_ThreadType* thread,
PP_ThreadFunction function,
void* thread_arg) {
if (!thread)
return false;
*thread = ::_beginthread(function,
0, /* Use default stack size. */
thread_arg);
return (*thread != NULL);
}
PP_INLINE void PP_JoinThread(PP_ThreadType thread) {
::WaitForSingleObject((HANDLE)thread, INFINITE);
}
#endif
/**
* @}
*/
#endif /* PPAPI_TESTS_PP_THREAD_H_ */
...@@ -130,18 +130,24 @@ class TestCaseFactory { ...@@ -130,18 +130,24 @@ class TestCaseFactory {
// RunTest function. This assumes the function name is TestFoo where Foo is the // RunTest function. This assumes the function name is TestFoo where Foo is the
// test |name|. // test |name|.
#define RUN_TEST(name) \ #define RUN_TEST(name) \
force_async_ = false; \ do { \
instance_->LogTest(#name, Test##name()); force_async_ = false; \
instance_->LogTest(#name, Test##name()); \
} while (false)
// Like RUN_TEST above but forces functions taking callbacks to complete // Like RUN_TEST above but forces functions taking callbacks to complete
// asynchronously on success or error. // asynchronously on success or error.
#define RUN_TEST_FORCEASYNC(name) \ #define RUN_TEST_FORCEASYNC(name) \
force_async_ = true; \ do { \
instance_->LogTest(#name"ForceAsync", Test##name()); force_async_ = true; \
instance_->LogTest(#name"ForceAsync", Test##name()); \
} while (false)
#define RUN_TEST_FORCEASYNC_AND_NOT(name) \ #define RUN_TEST_FORCEASYNC_AND_NOT(name) \
RUN_TEST_FORCEASYNC(name); \ do { \
RUN_TEST(name); RUN_TEST_FORCEASYNC(name); \
RUN_TEST(name); \
} while (false)
// Helper macros for checking values in tests, and returning a location // Helper macros for checking values in tests, and returning a location
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "ppapi/cpp/dev/scriptable_object_deprecated.h" #include "ppapi/cpp/dev/scriptable_object_deprecated.h"
#include "ppapi/cpp/instance.h" #include "ppapi/cpp/instance.h"
#include "ppapi/cpp/var.h" #include "ppapi/cpp/var.h"
#include "ppapi/tests/pp_thread.h"
#include "ppapi/tests/test_utils.h" #include "ppapi/tests/test_utils.h"
#include "ppapi/tests/testing_instance.h" #include "ppapi/tests/testing_instance.h"
...@@ -28,6 +29,25 @@ const bool kTestBool = true; ...@@ -28,6 +29,25 @@ const bool kTestBool = true;
const int32_t kTestInt = 42; const int32_t kTestInt = 42;
const double kTestDouble = 42.0; const double kTestDouble = 42.0;
const int32_t kThreadsToRun = 10; const int32_t kThreadsToRun = 10;
const int32_t kMessagesToSendPerThread = 50;
// The struct that invoke_post_message_thread_func expects for its argument.
// It includes the instance on which to invoke PostMessage, and the value to
// pass to PostMessage.
struct InvokePostMessageThreadArg {
InvokePostMessageThreadArg(pp::Instance* i, const pp::Var& v)
: instance(i), value_to_send(v) {}
pp::Instance* instance;
pp::Var value_to_send;
};
void InvokePostMessageThreadFunc(void* user_data) {
InvokePostMessageThreadArg* arg =
static_cast<InvokePostMessageThreadArg*>(user_data);
for (int32_t i = 0; i < kMessagesToSendPerThread; ++i)
arg->instance->PostMessage(arg->value_to_send);
delete arg;
}
} // namespace } // namespace
...@@ -40,6 +60,8 @@ void TestPostMessage::RunTest() { ...@@ -40,6 +60,8 @@ void TestPostMessage::RunTest() {
RUN_TEST(MessageEvent); RUN_TEST(MessageEvent);
RUN_TEST(NoHandler); RUN_TEST(NoHandler);
RUN_TEST(ExtraParam); RUN_TEST(ExtraParam);
if (testing_interface_->IsOutOfProcess())
RUN_TEST(NonMainThread);
} }
void TestPostMessage::HandleMessage(const pp::Var& message_data) { void TestPostMessage::HandleMessage(const pp::Var& message_data) {
...@@ -254,3 +276,63 @@ std::string TestPostMessage::TestExtraParam() { ...@@ -254,3 +276,63 @@ std::string TestPostMessage::TestExtraParam() {
PASS(); PASS();
} }
std::string TestPostMessage::TestNonMainThread() {
ASSERT_TRUE(ClearListeners());
ASSERT_TRUE(AddEchoingListener("message_event.data"));
message_data_.clear();
// Set up a thread for each integer from 0 to (kThreadsToRun - 1). Make each
// thread send the number that matches its index kMessagesToSendPerThread
// times. For good measure, call postMessage from the main thread
// kMessagesToSendPerThread times. At the end, we make sure we got all the
// values we expected.
PP_ThreadType threads[kThreadsToRun];
for (int32_t i = 0; i < kThreadsToRun; ++i) {
// Set up a thread to send a value of i.
void* arg = new InvokePostMessageThreadArg(instance_, pp::Var(i));
PP_CreateThread(&threads[i], &InvokePostMessageThreadFunc, arg);
}
// Invoke PostMessage right now to send a value of (kThreadsToRun).
for (int32_t i = 0; i < kMessagesToSendPerThread; ++i)
instance_->PostMessage(pp::Var(kThreadsToRun));
// Now join all threads.
for (int32_t i = 0; i < kThreadsToRun; ++i)
PP_JoinThread(threads[i]);
// PostMessage is asynchronous, so we should not receive a response yet.
ASSERT_EQ(message_data_.size(), 0);
// Make sure we got all values that we expected. Note that because it's legal
// for the JavaScript engine to treat our integers as floating points, we
// can't just use std::find or equality comparison. So we instead, we convert
// each incoming value to an integer, and count them in received_counts.
int32_t expected_num = (kThreadsToRun + 1) * kMessagesToSendPerThread;
// Count how many we receive per-index.
std::vector<int32_t> expected_counts(kThreadsToRun + 1,
kMessagesToSendPerThread);
std::vector<int32_t> received_counts(kThreadsToRun + 1, 0);
for (int32_t i = 0; i < expected_num; ++i) {
// Run the message loop to get the next expected message.
testing_interface_->RunMessageLoop(instance_->pp_instance());
// Make sure we got another message in.
ASSERT_EQ(message_data_.size(), 1);
pp::Var latest_var(message_data_.back());
message_data_.clear();
ASSERT_TRUE(latest_var.is_int() || latest_var.is_double());
int32_t received_value = -1;
if (latest_var.is_int()) {
received_value = latest_var.AsInt();
} else if (latest_var.is_double()) {
received_value = static_cast<int32_t>(latest_var.AsDouble() + 0.5);
}
ASSERT_TRUE(received_value >= 0);
ASSERT_TRUE(received_value <= kThreadsToRun);
++received_counts[received_value];
}
ASSERT_EQ(received_counts, expected_counts);
PASS();
}
...@@ -53,6 +53,9 @@ class TestPostMessage : public TestCase { ...@@ -53,6 +53,9 @@ class TestPostMessage : public TestCase {
// nothing happens. // nothing happens.
std::string TestExtraParam(); std::string TestExtraParam();
// Test sending messages off of the main thread.
std::string TestNonMainThread();
typedef std::vector<pp::Var> VarVector; typedef std::vector<pp::Var> VarVector;
// This is used to store pp::Var objects we receive via a call to // This is used to store pp::Var objects we receive via a call to
......
...@@ -200,11 +200,16 @@ uint32_t GetLiveObjectsForInstance(PP_Instance instance_id) { ...@@ -200,11 +200,16 @@ uint32_t GetLiveObjectsForInstance(PP_Instance instance_id) {
return ResourceTracker::Get()->GetLiveObjectsForInstance(instance_id); return ResourceTracker::Get()->GetLiveObjectsForInstance(instance_id);
} }
PP_Bool IsOutOfProcess() {
return PP_FALSE;
}
const PPB_Testing_Dev testing_interface = { const PPB_Testing_Dev testing_interface = {
&ReadImageData, &ReadImageData,
&RunMessageLoop, &RunMessageLoop,
&QuitMessageLoop, &QuitMessageLoop,
&GetLiveObjectsForInstance &GetLiveObjectsForInstance,
&IsOutOfProcess
}; };
// GetInterface ---------------------------------------------------------------- // GetInterface ----------------------------------------------------------------
...@@ -364,7 +369,11 @@ const void* GetInterface(const char* name) { ...@@ -364,7 +369,11 @@ const void* GetInterface(const char* name) {
// Only support the testing interface when the command line switch is // Only support the testing interface when the command line switch is
// specified. This allows us to prevent people from (ab)using this interface // specified. This allows us to prevent people from (ab)using this interface
// in production code. // in production code.
if (strcmp(name, PPB_TESTING_DEV_INTERFACE) == 0) { // TODO(dmichael): Remove support for 0.6. Note that 0.7 only adds a function
// to the end, so returning an 0.7 struct for use by clients of 0.6 just
// works in practice.
if (strcmp(name, PPB_TESTING_DEV_INTERFACE) == 0 ||
strcmp(name, PPB_TESTING_DEV_INTERFACE_0_6) == 0) {
if (CommandLine::ForCurrentProcess()->HasSwitch("enable-pepper-testing")) if (CommandLine::ForCurrentProcess()->HasSwitch("enable-pepper-testing"))
return &testing_interface; return &testing_interface;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment