| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ppapi/tests/test_message_handler.h" | 5 #include "ppapi/tests/test_message_handler.h" |
| 6 | 6 |
| 7 #include <string.h> | 7 #include <string.h> |
| 8 #include <algorithm> | 8 #include <algorithm> |
| 9 #include <map> | 9 #include <map> |
| 10 #include <sstream> | 10 #include <sstream> |
| 11 #include <vector> |
| 11 | 12 |
| 12 #include "ppapi/c/pp_var.h" | 13 #include "ppapi/c/pp_var.h" |
| 13 #include "ppapi/c/ppb_file_io.h" | 14 #include "ppapi/c/ppb_file_io.h" |
| 14 #include "ppapi/c/ppb_messaging.h" | 15 #include "ppapi/c/ppb_messaging.h" |
| 15 #include "ppapi/c/ppp_message_handler.h" | 16 #include "ppapi/c/ppp_message_handler.h" |
| 16 #include "ppapi/cpp/completion_callback.h" | 17 #include "ppapi/cpp/completion_callback.h" |
| 17 #include "ppapi/cpp/file_io.h" | 18 #include "ppapi/cpp/file_io.h" |
| 18 #include "ppapi/cpp/file_ref.h" | 19 #include "ppapi/cpp/file_ref.h" |
| 19 #include "ppapi/cpp/file_system.h" | 20 #include "ppapi/cpp/file_system.h" |
| 20 #include "ppapi/cpp/instance.h" | 21 #include "ppapi/cpp/instance.h" |
| (...skipping 16 matching lines...) Expand all Loading... |
| 37 | 38 |
| 38 REGISTER_TEST_CASE(MessageHandler); | 39 REGISTER_TEST_CASE(MessageHandler); |
| 39 | 40 |
| 40 namespace { | 41 namespace { |
| 41 | 42 |
| 42 // Created and destroyed on the main thread. All public methods should be called | 43 // Created and destroyed on the main thread. All public methods should be called |
| 43 // on the main thread. Most data members are only accessed on the main thread. | 44 // on the main thread. Most data members are only accessed on the main thread. |
| 44 // (Though it handles messages on the background thread). | 45 // (Though it handles messages on the background thread). |
| 45 class MyMessageHandler : public pp::MessageHandler { | 46 class MyMessageHandler : public pp::MessageHandler { |
| 46 public: | 47 public: |
| 47 explicit MyMessageHandler(TestingInstance* instance, | 48 MyMessageHandler(TestingInstance* instance, const pp::MessageLoop& loop) |
| 48 const pp::MessageLoop& loop) | |
| 49 : testing_instance_(instance), | 49 : testing_instance_(instance), |
| 50 message_handler_loop_(loop), | 50 message_handler_loop_(loop), |
| 51 is_registered_(false), | 51 is_registered_(false), |
| 52 test_finished_event_(instance->pp_instance()), | 52 test_finished_event_(instance->pp_instance()), |
| 53 destroy_event_(instance->pp_instance()), | 53 destroy_event_(instance->pp_instance()), |
| 54 async_message_received_(instance->pp_instance()) { | 54 finished_message_received_(instance->pp_instance()) { |
| 55 AssertOnMainThread(); | 55 AssertOnMainThread(); |
| 56 } | 56 } |
| 57 void Register() { | 57 void Register() { |
| 58 AssertOnMainThread(); | 58 AssertOnMainThread(); |
| 59 assert(!is_registered_); | 59 assert(!is_registered_); |
| 60 int32_t result = | 60 int32_t result = |
| 61 testing_instance_->RegisterMessageHandler(this, message_handler_loop_); | 61 testing_instance_->RegisterMessageHandler(this, message_handler_loop_); |
| 62 if (result == PP_OK) { | 62 if (result == PP_OK) { |
| 63 is_registered_ = true; | 63 is_registered_ = true; |
| 64 } else { | 64 } else { |
| (...skipping 24 matching lines...) Expand all Loading... |
| 89 assert(!is_registered_); | 89 assert(!is_registered_); |
| 90 destroy_event_.Wait(); | 90 destroy_event_.Wait(); |
| 91 destroy_event_.Reset(); | 91 destroy_event_.Reset(); |
| 92 // Now that we know Destroy() has been called, we know errors_ isn't being | 92 // Now that we know Destroy() has been called, we know errors_ isn't being |
| 93 // written on the MessageHandler thread anymore. So we can safely read it | 93 // written on the MessageHandler thread anymore. So we can safely read it |
| 94 // here on the main thread (since destroy_event_ gave us a memory barrier). | 94 // here on the main thread (since destroy_event_ gave us a memory barrier). |
| 95 std::string temp_errors; | 95 std::string temp_errors; |
| 96 errors_.swap(temp_errors); | 96 errors_.swap(temp_errors); |
| 97 return temp_errors; | 97 return temp_errors; |
| 98 } | 98 } |
| 99 pp::Var WaitForAsyncMessage() { | 99 void WaitForAsyncMessages(std::vector<pp::Var>* out_vec) { |
| 100 async_message_received_.Wait(); | 100 finished_message_received_.Wait(); |
| 101 pp::Var var_to_return = last_async_message_received_; | 101 out_vec->swap(async_messages_received_); |
| 102 last_async_message_received_ = pp::Var(); | 102 finished_message_received_.Reset(); |
| 103 async_message_received_.Reset(); | |
| 104 return var_to_return; | |
| 105 } | 103 } |
| 106 private: | 104 private: |
| 107 static void AssertOnMainThread() { | 105 static void AssertOnMainThread() { |
| 108 assert(pp::MessageLoop::GetForMainThread() == | 106 assert(pp::MessageLoop::GetForMainThread() == |
| 109 pp::MessageLoop::GetCurrent()); | 107 pp::MessageLoop::GetCurrent()); |
| 110 } | 108 } |
| 111 void AddError(const std::string& error) { | 109 void AddError(const std::string& error) { |
| 112 if (!error.empty()) { | 110 if (!error.empty()) { |
| 113 if (!errors_.empty()) | 111 if (!errors_.empty()) |
| 114 errors_ += "<p>"; | 112 errors_ += "<p>"; |
| 115 errors_ += error; | 113 errors_ += error; |
| 116 } | 114 } |
| 117 } | 115 } |
| 118 virtual void HandleMessage(pp::InstanceHandle instance, const pp::Var& var) { | 116 virtual void HandleMessage(pp::InstanceHandle instance, const pp::Var& var) { |
| 119 if (pp::MessageLoop::GetCurrent() != message_handler_loop_) | 117 if (pp::MessageLoop::GetCurrent() != message_handler_loop_) |
| 120 AddError("HandleMessage was called on the wrong thread!"); | 118 AddError("HandleMessage was called on the wrong thread!"); |
| 121 if (instance.pp_instance() != testing_instance_->pp_instance()) | 119 if (instance.pp_instance() != testing_instance_->pp_instance()) |
| 122 AddError("HandleMessage was passed the wrong instance!"); | 120 AddError("HandleMessage was passed the wrong instance!"); |
| 123 if (var.is_string() && var.AsString() == "FINISHED_TEST") { | 121 if (var.is_string() && var.AsString() == "FINISHED_TEST") { |
| 124 test_finished_event_.Signal(); | 122 test_finished_event_.Signal(); |
| 123 } else if (var.is_string() && var.AsString() == "FINISHED_WAITING") { |
| 124 finished_message_received_.Signal(); |
| 125 } else { | 125 } else { |
| 126 // Any client causing a message to arrive must wait for the message | 126 async_messages_received_.push_back(var); |
| 127 // before continuing. See WaitForAsyncMessage(). | |
| 128 assert(last_async_message_received_.is_undefined()); | |
| 129 last_async_message_received_ = var; | |
| 130 async_message_received_.Signal(); | |
| 131 } | 127 } |
| 132 } | 128 } |
| 133 | 129 |
| 134 virtual pp::Var HandleBlockingMessage(pp::InstanceHandle instance, | 130 virtual pp::Var HandleBlockingMessage(pp::InstanceHandle instance, |
| 135 const pp::Var& var) { | 131 const pp::Var& var) { |
| 136 if (pp::MessageLoop::GetCurrent() != message_handler_loop_) | 132 if (pp::MessageLoop::GetCurrent() != message_handler_loop_) |
| 137 AddError("HandleBlockingMessage was called on the wrong thread!"); | 133 AddError("HandleBlockingMessage was called on the wrong thread!"); |
| 138 if (instance.pp_instance() != testing_instance_->pp_instance()) | 134 if (instance.pp_instance() != testing_instance_->pp_instance()) |
| 139 AddError("HandleBlockingMessage was passed the wrong instance!"); | 135 AddError("HandleBlockingMessage was passed the wrong instance!"); |
| 140 | 136 |
| (...skipping 30 matching lines...) Expand all Loading... |
| 171 // is_registered_ is only read/written on the main thread. | 167 // is_registered_ is only read/written on the main thread. |
| 172 bool is_registered_; | 168 bool is_registered_; |
| 173 | 169 |
| 174 // errors_ is written on the MessageHandler thread. When Destroy() is | 170 // errors_ is written on the MessageHandler thread. When Destroy() is |
| 175 // called, we stop writing to errors_ and signal destroy_event_. This causes | 171 // called, we stop writing to errors_ and signal destroy_event_. This causes |
| 176 // a memory barrier, so it's safe to read errors_ after that. | 172 // a memory barrier, so it's safe to read errors_ after that. |
| 177 std::string errors_; | 173 std::string errors_; |
| 178 NestedEvent test_finished_event_; | 174 NestedEvent test_finished_event_; |
| 179 NestedEvent destroy_event_; | 175 NestedEvent destroy_event_; |
| 180 | 176 |
| 181 pp::Var last_async_message_received_; | 177 std::vector<pp::Var> async_messages_received_; |
| 182 NestedEvent async_message_received_; | 178 NestedEvent finished_message_received_; |
| 183 | 179 |
| 184 // Undefined & private to disallow copy and assign. | 180 // Undefined & private to disallow copy and assign. |
| 185 MyMessageHandler(const MyMessageHandler&); | 181 MyMessageHandler(const MyMessageHandler&); |
| 186 MyMessageHandler& operator=(const MyMessageHandler&); | 182 MyMessageHandler& operator=(const MyMessageHandler&); |
| 187 }; | 183 }; |
| 188 | 184 |
| 189 void FakeHandleMessage(PP_Instance instance, | 185 void FakeHandleMessage(PP_Instance instance, |
| 190 void* user_data, | 186 void* user_data, |
| 191 const PP_Var* message_data) {} | 187 const PP_Var* message_data) {} |
| 192 void FakeHandleBlockingMessage(PP_Instance instance, | 188 void FakeHandleBlockingMessage(PP_Instance instance, |
| (...skipping 20 matching lines...) Expand all Loading... |
| 213 pp::Module::Get()->GetBrowserInterface(PPB_MESSAGING_INTERFACE_1_2)); | 209 pp::Module::Get()->GetBrowserInterface(PPB_MESSAGING_INTERFACE_1_2)); |
| 214 return ppb_messaging_if_ && | 210 return ppb_messaging_if_ && |
| 215 CheckTestingInterface() && | 211 CheckTestingInterface() && |
| 216 handler_thread_.Start(); | 212 handler_thread_.Start(); |
| 217 } | 213 } |
| 218 | 214 |
| 219 void TestMessageHandler::RunTests(const std::string& filter) { | 215 void TestMessageHandler::RunTests(const std::string& filter) { |
| 220 RUN_TEST(RegisterErrorConditions, filter); | 216 RUN_TEST(RegisterErrorConditions, filter); |
| 221 RUN_TEST(PostMessageAndAwaitResponse, filter); | 217 RUN_TEST(PostMessageAndAwaitResponse, filter); |
| 222 RUN_TEST(Exceptions, filter); | 218 RUN_TEST(Exceptions, filter); |
| 219 RUN_TEST(BrowserHostedResources, filter); |
| 223 } | 220 } |
| 224 | 221 |
| 225 void TestMessageHandler::HandleMessage(const pp::Var& message_data) { | 222 void TestMessageHandler::HandleMessage(const pp::Var& message_data) { |
| 226 if (instance()->current_test_name() == "Exceptions") { | 223 if (instance()->current_test_name() == "Exceptions") { |
| 227 // For TestPostMessageAndAwaitResponse(), all messages should go to the | 224 // For TestPostMessageAndAwaitResponse(), all messages should go to the |
| 228 // background thread message handler. | 225 // background thread message handler. |
| 229 assert(false); | 226 assert(false); |
| 230 } else { | 227 } else { |
| 231 // Any subtest causing a message to arrive here must wait for it before | 228 // Any subtest causing a message to arrive here must wait for it before |
| 232 // continuing. See WaitForMessage(). | 229 // continuing. See WaitForMessage(). |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 299 handler.Unregister(); | 296 handler.Unregister(); |
| 300 ASSERT_SUBTEST_SUCCESS(handler.WaitForDestroy()); | 297 ASSERT_SUBTEST_SUCCESS(handler.WaitForDestroy()); |
| 301 | 298 |
| 302 PASS(); | 299 PASS(); |
| 303 } | 300 } |
| 304 | 301 |
| 305 std::string TestMessageHandler::TestExceptions() { | 302 std::string TestMessageHandler::TestExceptions() { |
| 306 MyMessageHandler handler(instance(), | 303 MyMessageHandler handler(instance(), |
| 307 handler_thread_.message_loop()); | 304 handler_thread_.message_loop()); |
| 308 { | 305 { |
| 309 // First, try sending a blocking message when there is no handler | 306 // First try sending a blocking message when there is no handler |
| 310 // registered. It should throw an exception. | 307 // registered. It should throw an exception. |
| 311 std::string js_code( | 308 std::string js_code( |
| 312 "var plugin = document.getElementById('plugin');\n" | 309 "var plugin = document.getElementById('plugin');\n" |
| 313 "var caught_exception = false;\n" | 310 "var caught_exception = false;\n" |
| 314 "try {\n" | 311 "try {\n" |
| 315 " plugin.postMessageAndAwaitResponse('Hello!');\n" | 312 " plugin.postMessageAndAwaitResponse('Hello!');\n" |
| 316 "} catch (err) {\n" | 313 "} catch (err) {\n" |
| 317 " caught_exception = true;\n" | 314 " caught_exception = true;\n" |
| 318 "}\n" | 315 "}\n" |
| 319 "plugin.postMessage(caught_exception ? 'SUCCESS' : 'FAIL');\n"); | 316 "plugin.postMessage(caught_exception ? 'SUCCESS' : 'FAIL');\n"); |
| 320 instance_->EvalScript(js_code); | 317 instance_->EvalScript(js_code); |
| 321 // Note that we want to wait for the Instance to get the SUCCESS/FAIL | 318 // Note that we want to wait for the Instance to get the SUCCESS/FAIL |
| 322 // message here. |message_handler| is not yet registered, so the message | 319 // message here. |message_handler| is not yet registered, so the message |
| 323 // goes to the instance instead. | 320 // goes to the instance instead. |
| 324 pp::Var msg = WaitForMessage(); | 321 pp::Var msg = WaitForMessage(); |
| 325 ASSERT_TRUE(msg.is_string()); | 322 ASSERT_TRUE(msg.is_string()); |
| 326 ASSERT_EQ("SUCCESS", msg.AsString()); | 323 ASSERT_EQ("SUCCESS", msg.AsString()); |
| 327 } | 324 } |
| 328 handler.Register(); | 325 handler.Register(); |
| 329 { | 326 { |
| 330 // Now that a handler is registered, try requesting and sending a | 327 // Try passing different numbers of arguments; only 1 argument is allowed. |
| 331 // FileSystem. It should throw an exception. The file system is opened | 328 // Other numbers should throw an exception. |
| 332 // asynchronously. What *should* happen is that it opens successfully, then | 329 std::string js_code( |
| 333 // we try to send it via postMessageAndAwaitResponse, which fails with an | 330 "var plugin = document.getElementById('plugin');\n" |
| 334 // exception. The test could fail either because the filesystem doesn't | 331 "var caught_exception = false;\n" |
| 335 // open or because postMessageAndAwaitResponse doesn't throw an exception. | 332 "try {\n" |
| 333 " plugin.postMessageAndAwaitResponse();\n" |
| 334 "} catch (err) {\n" |
| 335 " caught_exception = true;\n" |
| 336 "}\n" |
| 337 "plugin.postMessage(caught_exception ? 'SUCCESS' : 'FAIL');\n" |
| 338 "try {\n" |
| 339 " plugin.postMessageAndAwaitResponse('hello', 5);\n" |
| 340 "} catch (err) {\n" |
| 341 " caught_exception = true;\n" |
| 342 "}\n" |
| 343 "plugin.postMessage(caught_exception ? 'SUCCESS' : 'FAIL');\n" |
| 344 "plugin.postMessage('FINISHED_WAITING');\n"); |
| 345 instance_->EvalScript(js_code); |
| 346 std::vector<pp::Var> messages; |
| 347 handler.WaitForAsyncMessages(&messages); |
| 348 ASSERT_EQ(2u, messages.size()); |
| 349 ASSERT_EQ("SUCCESS", messages[0].AsString()); |
| 350 ASSERT_EQ("SUCCESS", messages[1].AsString()); |
| 351 } |
| 352 handler.Unregister(); |
| 353 ASSERT_SUBTEST_SUCCESS(handler.WaitForDestroy()); |
| 354 |
| 355 PASS(); |
| 356 } |
| 357 |
| 358 std::string TestMessageHandler::TestBrowserHostedResources() { |
| 359 MyMessageHandler handler(instance(), |
| 360 handler_thread_.message_loop()); |
| 361 handler.Register(); |
| 362 { |
| 363 // Try requesting and sending a FileSystem. It should throw an exception. |
| 364 // The file system is opened asynchronously. Once it opens successfully, |
| 365 // then we send it via postMessage and postMessageAndAwaitResponse. We try |
| 366 // both to make sure that the ordering is correct. |
| 336 std::string js_code( | 367 std::string js_code( |
| 337 "var plugin = document.getElementById('plugin');\n" | 368 "var plugin = document.getElementById('plugin');\n" |
| 338 "function gotFileSystem(fs) {\n" | 369 "function gotFileSystem(fs) {\n" |
| 339 " var caught_exception = false;\n" | 370 " var caught_exception = false;\n" |
| 340 " try {\n" | 371 " try {\n" |
| 341 " plugin.postMessageAndAwaitResponse(fs);\n" | 372 " plugin.postMessage(fs);" |
| 373 " plugin.postMessage(fs);" |
| 374 " plugin.postMessage(fs);" |
| 375 " plugin.postMessage(fs);" |
| 376 " var result = plugin.postMessageAndAwaitResponse(fs);\n" |
| 342 " } catch (err) {\n" | 377 " } catch (err) {\n" |
| 343 " caught_exception = true;\n" | 378 " caught_exception = true;\n" |
| 344 " }\n" | 379 " }\n" //TODO(dmichael): Really test that the filesystem is right |
| 345 " plugin.postMessage(caught_exception ? 'SUCCESS' : 'FAIL');\n" | 380 // ...and FileRef? |
| 381 " plugin.postMessage(result.toString() == fs.toString() ?" |
| 382 " 'SUCCESS' : result.toString());\n" |
| 383 " plugin.postMessage('FINISHED_WAITING');\n" |
| 346 "}\n" | 384 "}\n" |
| 347 "function fileSystemError() {\n" | 385 "function fileSystemError() {\n" |
| 348 " plugin.postMessage('Failed to open filesystem');\n" | 386 " plugin.postMessage('Failed to open filesystem');\n" |
| 349 "}\n" | 387 "}\n" |
| 350 "window.webkitRequestFileSystem(\n" | 388 "window.webkitRequestFileSystem(\n" |
| 351 " window.Temporary, 1024, gotFileSystem, fileSystemError)\n"); | 389 " window.Temporary, 1024, gotFileSystem, fileSystemError)\n"); |
| 352 instance_->EvalScript(js_code); | 390 instance_->EvalScript(js_code); |
| 353 pp::Var msg = handler.WaitForAsyncMessage(); | 391 std::vector<pp::Var> messages; |
| 354 ASSERT_EQ(PP_VARTYPE_STRING, msg.pp_var().type); | 392 handler.WaitForAsyncMessages(&messages); |
| 355 ASSERT_EQ("SUCCESS", msg.AsString()); | 393 ASSERT_EQ(5u, messages.size()); |
| 394 ASSERT_EQ("SUCCESS", messages.back().AsString()); |
| 356 } | 395 } |
| 357 handler.Unregister(); | 396 handler.Unregister(); |
| 358 ASSERT_SUBTEST_SUCCESS(handler.WaitForDestroy()); | 397 ASSERT_SUBTEST_SUCCESS(handler.WaitForDestroy()); |
| 359 | 398 |
| 360 PASS(); | 399 PASS(); |
| 361 } | 400 } |
| 362 | 401 |
| 402 |
| 363 pp::Var TestMessageHandler::WaitForMessage() { | 403 pp::Var TestMessageHandler::WaitForMessage() { |
| 364 message_received_.Wait(); | 404 message_received_.Wait(); |
| 365 pp::Var var_to_return = last_message_; | 405 pp::Var var_to_return = last_message_; |
| 366 last_message_ = pp::Var(); | 406 last_message_ = pp::Var(); |
| 367 message_received_.Reset(); | 407 message_received_.Reset(); |
| 368 return var_to_return; | 408 return var_to_return; |
| 369 } | 409 } |
| 370 | 410 |
| OLD | NEW |