Chromium Code Reviews| Index: ppapi/tests/test_broker.cc |
| diff --git a/ppapi/tests/test_broker.cc b/ppapi/tests/test_broker.cc |
| index b1d5b028c58cf2adedbc4f45237335461277dfb4..4547d13ceba85307ee387b20ebcc3dfff8a4ed4a 100644 |
| --- a/ppapi/tests/test_broker.cc |
| +++ b/ppapi/tests/test_broker.cc |
| @@ -4,13 +4,198 @@ |
| #include "ppapi/tests/test_broker.h" |
| +#include <cstdio> |
| +#include <cstring> |
| +#include <fstream> |
| +#include <limits> |
| + |
| +#include "base/eintr_wrapper.h" |
| +#include "base/memory/scoped_ptr.h" |
| #include "ppapi/c/pp_errors.h" |
| +#include "ppapi/c/trusted/ppp_broker.h" |
| #include "ppapi/c/trusted/ppb_broker_trusted.h" |
| -#include "ppapi/cpp/module.h" |
| +#include "ppapi/tests/test_utils.h" |
| #include "ppapi/tests/testing_instance.h" |
| +#if defined(OS_WIN) |
| +#include "windows.h" |
| +#elif !defined(OS_POSIX) |
| +#error Not implemented. Don't remove as it's only checked here in this file. |
| +#endif |
| + |
| REGISTER_TEST_CASE(Broker); |
| +namespace { |
| + |
| +const char kHelloMessage[] = "Hello Plugin! This is Broker!"; |
| +// Message sent from broker to plugin if the broker is unsandboxed. |
| +const char kBrokerUnsandboxed[] = "Broker is Unsandboxed!"; |
| +// Message sent from broker to plugin if the broker is sandboxed. This message |
| +// needs to be longer than |kBrokerUnsandboxed| because the plugin is expecting |
| +// |kBrokerUnsandboxed|. If it's shorter and the broker doesn't close its handle |
| +// properly the plugin will hang waiting for all data of |kBrokerUnsandboxed| to |
| +// be read. |
| +const char kBrokerSandboxed[] = "Broker is Sandboxed! Verification failed!"; |
| + |
| +#if defined(OS_WIN) |
| +typedef HANDLE PlatformFile; |
| +const PlatformFile kInvalidPlatformFileValue = INVALID_HANDLE_VALUE; |
| +const int32_t kInvalidHandle = static_cast<int32_t>( |
| + reinterpret_cast<intptr_t>(INVALID_HANDLE_VALUE)); |
| +#elif defined(OS_POSIX) |
| +typedef int PlatformFile; |
| +const PlatformFile kInvalidPlatformFileValue = -1; |
| +const int32_t kInvalidHandle = -1; |
| +#endif |
| + |
| +PlatformFile IntToPlatformFile(int32_t handle) { |
| +#if defined(OS_WIN) |
| + return reinterpret_cast<HANDLE>(static_cast<intptr_t>(handle)); |
| +#elif defined(OS_POSIX) |
| + return handle; |
| +#endif |
| +} |
| + |
| +bool ReadMessage(PlatformFile file, size_t message_len, char* message) { |
| +#if defined(OS_WIN) |
| + assert(message_len < std::numeric_limits<DWORD>::max()); |
| + DWORD read = 0; |
| + const DWORD size = static_cast<DWORD>(message_len); |
| + return ::ReadFile(file, message, size, &read, NULL) && read == size; |
| +#elif defined(OS_POSIX) |
| + assert(message_len < |
| + static_cast<size_t>(std::numeric_limits<ssize_t>::max())); |
| + size_t total_read = 0; |
| + while (total_read < message_len) { |
| + ssize_t read = HANDLE_EINTR(::read(file, message + total_read, |
| + message_len - total_read)); |
| + if (read <= 0) |
| + break; |
| + total_read += read; |
| + } |
| + return total_read == message_len; |
| +#endif |
| +} |
| + |
| +bool WriteMessage(PlatformFile file, size_t message_len, const char* message) { |
| +#if defined(OS_WIN) |
| + assert(message_len < std::numeric_limits<DWORD>::max()); |
| + DWORD written = 0; |
| + const DWORD size = static_cast<DWORD>(message_len); |
| + return ::WriteFile(file, message, size, &written, NULL) && written == size; |
| +#elif defined(OS_POSIX) |
| + assert(message_len < |
| + static_cast<size_t>(std::numeric_limits<ssize_t>::max())); |
| + size_t total_written = 0; |
| + while (total_written < message_len) { |
| + ssize_t written = HANDLE_EINTR(::write(file, message + total_written, |
| + message_len - total_written)); |
| + if (written <= 0) |
| + break; |
| + total_written += written; |
| + } |
| + return total_written == message_len; |
| +#endif |
| +} |
| + |
| +bool VerifyMessage(PlatformFile file, size_t message_len, const char* message) { |
| + scoped_array<char> message_received(new char[message_len]); |
| + return ReadMessage(file, message_len, message_received.get()) && |
| + !::strcmp(message_received.get(), message); |
| +} |
| + |
| +bool ClosePlatformFile(PlatformFile file) { |
| +#if defined(OS_WIN) |
| + return !!::CloseHandle(file); |
| +#elif defined(OS_POSIX) |
| + return !::close(file); |
| +#endif |
| +} |
| + |
| +bool VerifyIsUnsandboxed() { |
| + FILE* file = NULL; |
| + |
| +#if defined(OS_WIN) |
| + wchar_t temp_path[MAX_PATH] = {'\0'}; |
| + wchar_t file_name[MAX_PATH] = {'\0'}; |
| + if (!::GetTempPath(MAX_PATH, temp_path) || |
| + !::GetTempFileName(temp_path, L"test_pepper_broker", 0, file_name) || |
| + ::_wfopen_s(&file, file_name, L"w")) |
| + return false; |
| + |
| + if (::fclose(file)) { |
| + ::DeleteFile(file_name); |
| + return false; |
| + } |
| + |
| + if (!::DeleteFile(file_name)) |
| + return false; |
| +#elif defined(OS_POSIX) |
| + char file_name[] = "/tmp/test_pepper_broker_XXXXXX"; |
| + int fd = ::mkstemp(file_name); |
| + if (-1 == fd) |
| + return false; |
| + |
| + file = ::fdopen(fd, "w"); |
|
piman
2011/11/15 01:58:14
I'd simplify it even further: fdopen doesn't do an
xhwang
2011/11/15 04:23:28
Done. Thanks!
|
| + if (!file) { |
| + ::remove(file_name); |
| + ::close(fd); |
| + return false; |
| + } |
| + |
| + if (::fclose(file)) { // Will also close |fd|. |
| + ::remove(file_name); |
| + return false; |
| + } |
| + |
| + if (::remove(file_name)) |
| + return false; |
| +#endif |
| + |
| + return true; |
| +} |
| + |
| +// Callback in the broker when a new broker connection occurs. |
| +int32_t OnInstanceConnected(PP_Instance instance, int32_t handle) { |
| + PlatformFile file = IntToPlatformFile(handle); |
| + if (file == kInvalidPlatformFileValue) |
| + return PP_ERROR_FAILED; |
| + |
| + // Send hello message. |
| + if (!WriteMessage(file, sizeof(kHelloMessage), kHelloMessage)) { |
| + ClosePlatformFile(file); |
| + return PP_ERROR_FAILED; |
| + } |
| + |
| + // Verify broker is not sandboxed and send result to plugin over the pipe. |
| + if (VerifyIsUnsandboxed()) { |
| + if (!WriteMessage(file, sizeof(kBrokerUnsandboxed), kBrokerUnsandboxed)) { |
| + ClosePlatformFile(file); |
| + return PP_ERROR_FAILED; |
| + } |
| + } else { |
| + if (!WriteMessage(file, sizeof(kBrokerSandboxed), kBrokerSandboxed)) { |
| + ClosePlatformFile(file); |
| + return PP_ERROR_FAILED; |
| + } |
| + } |
| + |
| + if (!ClosePlatformFile(file)) |
| + return PP_ERROR_FAILED; |
| + |
| + return PP_OK; |
| +} |
| + |
| +} // namespace |
| + |
| +PP_EXPORT int32_t PPP_InitializeBroker( |
| + PP_ConnectInstance_Func* connect_instance_func) { |
| + *connect_instance_func = &OnInstanceConnected; |
| + return PP_OK; |
| +} |
| + |
| +PP_EXPORT void PPP_ShutdownBroker() {} |
| + |
| TestBroker::TestBroker(TestingInstance* instance) |
| : TestCase(instance), |
| broker_interface_(NULL) { |
| @@ -24,6 +209,11 @@ bool TestBroker::Init() { |
| void TestBroker::RunTest() { |
| RUN_TEST(Create); |
| + RUN_TEST(GetHandleFailure); |
| + RUN_TEST(ConnectFailure); |
| +#if !defined(OS_WIN) // This is broken on Windows. See http://crbug.com/103975. |
| + RUN_TEST(ConnectAndPipe); |
| +#endif |
| } |
| std::string TestBroker::TestCreate() { |
| @@ -35,12 +225,65 @@ std::string TestBroker::TestCreate() { |
| ASSERT_FALSE(broker_interface_->IsBrokerTrusted(0)); |
| ASSERT_TRUE(broker_interface_->IsBrokerTrusted(broker)); |
| + PASS(); |
| +} |
| + |
| +// Test connection on invalid resource. |
| +std::string TestBroker::TestConnectFailure() { |
| + // Callback NOT force async. Connect should fail. The callback will not be |
| + // posted so there's no need to wait for the callback to complete. |
| + TestCompletionCallback cb_1(instance_->pp_instance(), false); |
| + ASSERT_EQ(PP_ERROR_BADRESOURCE, |
| + broker_interface_->Connect( |
| + 0, pp::CompletionCallback(cb_1).pp_completion_callback())); |
| + |
| + // Callback force async. Connect will return PP_OK_COMPLETIONPENDING and the |
| + // callback will be posted. However, the callback should fail. |
| + TestCompletionCallback cb_2(instance_->pp_instance(), true); |
| + ASSERT_EQ(PP_OK_COMPLETIONPENDING, |
| + broker_interface_->Connect( |
| + 0, pp::CompletionCallback(cb_2).pp_completion_callback())); |
| + ASSERT_EQ(PP_ERROR_BADRESOURCE, cb_2.WaitForResult()); |
| + |
| + PASS(); |
| +} |
| + |
| +std::string TestBroker::TestGetHandleFailure() { |
| + int32_t handle = kInvalidHandle; |
| + |
| // Test getting the handle for an invalid resource. |
| - int32_t handle; |
| - ASSERT_TRUE(broker_interface_->GetHandle(0, &handle) == PP_ERROR_BADRESOURCE); |
| + ASSERT_EQ(PP_ERROR_BADRESOURCE, broker_interface_->GetHandle(0, &handle)); |
| // Connect hasn't been called so this should fail. |
| - ASSERT_TRUE(broker_interface_->GetHandle(broker, &handle) == PP_ERROR_FAILED); |
| + PP_Resource broker = broker_interface_->CreateTrusted( |
| + instance_->pp_instance()); |
| + ASSERT_TRUE(broker); |
| + ASSERT_EQ(PP_ERROR_FAILED, broker_interface_->GetHandle(broker, &handle)); |
| + |
| + PASS(); |
| +} |
| + |
| +std::string TestBroker::TestConnectAndPipe() { |
| + PP_Resource broker = broker_interface_->CreateTrusted( |
| + instance_->pp_instance()); |
| + ASSERT_TRUE(broker); |
| + |
| + TestCompletionCallback cb_3(instance_->pp_instance()); |
| + ASSERT_EQ(PP_OK_COMPLETIONPENDING, |
| + broker_interface_->Connect( |
| + broker, pp::CompletionCallback(cb_3).pp_completion_callback())); |
| + ASSERT_EQ(PP_OK, cb_3.WaitForResult()); |
| + |
| + int32_t handle = kInvalidHandle; |
| + ASSERT_EQ(PP_OK, broker_interface_->GetHandle(broker, &handle)); |
| + ASSERT_NE(kInvalidHandle, handle); |
| + |
| + PlatformFile file = IntToPlatformFile(handle); |
| + ASSERT_TRUE(VerifyMessage(file, sizeof(kHelloMessage), kHelloMessage)); |
| + ASSERT_TRUE(VerifyMessage(file, sizeof(kBrokerUnsandboxed), |
| + kBrokerUnsandboxed)); |
| + |
| + ASSERT_TRUE(ClosePlatformFile(file)); |
| PASS(); |
| } |