| 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 | 
|---|