| 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> |
| (...skipping 24 matching lines...) Expand all Loading... |
| 35 #undef PostMessage | 35 #undef PostMessage |
| 36 #endif | 36 #endif |
| 37 | 37 |
| 38 REGISTER_TEST_CASE(MessageHandler); | 38 REGISTER_TEST_CASE(MessageHandler); |
| 39 | 39 |
| 40 namespace { | 40 namespace { |
| 41 | 41 |
| 42 // Created and destroyed on the main thread. All public methods should be called | 42 // 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. | 43 // on the main thread. Most data members are only accessed on the main thread. |
| 44 // (Though it handles messages on the background thread). | 44 // (Though it handles messages on the background thread). |
| 45 class EchoingMessageHandler : public pp::MessageHandler { | 45 class MyMessageHandler : public pp::MessageHandler { |
| 46 public: | 46 public: |
| 47 explicit EchoingMessageHandler(TestingInstance* instance, | 47 explicit MyMessageHandler(TestingInstance* instance, |
| 48 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 AssertOnMainThread(); | 55 AssertOnMainThread(); |
| 55 } | 56 } |
| 56 void Register() { | 57 void Register() { |
| 57 AssertOnMainThread(); | 58 AssertOnMainThread(); |
| 58 assert(!is_registered_); | 59 assert(!is_registered_); |
| 59 int32_t result = | 60 int32_t result = |
| 60 testing_instance_->RegisterMessageHandler(this, message_handler_loop_); | 61 testing_instance_->RegisterMessageHandler(this, message_handler_loop_); |
| 61 if (result == PP_OK) { | 62 if (result == PP_OK) { |
| 62 is_registered_ = true; | 63 is_registered_ = true; |
| 63 } else { | 64 } else { |
| (...skipping 24 matching lines...) Expand all Loading... |
| 88 assert(!is_registered_); | 89 assert(!is_registered_); |
| 89 destroy_event_.Wait(); | 90 destroy_event_.Wait(); |
| 90 destroy_event_.Reset(); | 91 destroy_event_.Reset(); |
| 91 // 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 |
| 92 // 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 |
| 93 // 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). |
| 94 std::string temp_errors; | 95 std::string temp_errors; |
| 95 errors_.swap(temp_errors); | 96 errors_.swap(temp_errors); |
| 96 return temp_errors; | 97 return temp_errors; |
| 97 } | 98 } |
| 99 pp::Var WaitForAsyncMessage() { |
| 100 async_message_received_.Wait(); |
| 101 pp::Var var_to_return = last_async_message_received_; |
| 102 last_async_message_received_ = pp::Var(); |
| 103 async_message_received_.Reset(); |
| 104 return var_to_return; |
| 105 } |
| 98 private: | 106 private: |
| 99 static void AssertOnMainThread() { | 107 static void AssertOnMainThread() { |
| 100 assert(pp::MessageLoop::GetForMainThread() == | 108 assert(pp::MessageLoop::GetForMainThread() == |
| 101 pp::MessageLoop::GetCurrent()); | 109 pp::MessageLoop::GetCurrent()); |
| 102 } | 110 } |
| 103 void AddError(const std::string& error) { | 111 void AddError(const std::string& error) { |
| 104 if (!error.empty()) { | 112 if (!error.empty()) { |
| 105 if (!errors_.empty()) | 113 if (!errors_.empty()) |
| 106 errors_ += "<p>"; | 114 errors_ += "<p>"; |
| 107 errors_ += error; | 115 errors_ += error; |
| 108 } | 116 } |
| 109 } | 117 } |
| 110 virtual void HandleMessage(pp::InstanceHandle instance, const pp::Var& var) { | 118 virtual void HandleMessage(pp::InstanceHandle instance, const pp::Var& var) { |
| 111 if (pp::MessageLoop::GetCurrent() != message_handler_loop_) | 119 if (pp::MessageLoop::GetCurrent() != message_handler_loop_) |
| 112 AddError("HandleMessage was called on the wrong thread!"); | 120 AddError("HandleMessage was called on the wrong thread!"); |
| 113 if (instance.pp_instance() != testing_instance_->pp_instance()) | 121 if (instance.pp_instance() != testing_instance_->pp_instance()) |
| 114 AddError("HandleMessage was passed the wrong instance!"); | 122 AddError("HandleMessage was passed the wrong instance!"); |
| 115 if (var.is_string() && var.AsString() == "FINISHED_TEST") | 123 if (var.is_string() && var.AsString() == "FINISHED_TEST") { |
| 116 test_finished_event_.Signal(); | 124 test_finished_event_.Signal(); |
| 117 else | 125 } else { |
| 118 testing_instance_->PostMessage(var); | 126 // Any client causing a message to arrive must wait for the message |
| 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 } |
| 119 } | 132 } |
| 120 | 133 |
| 121 virtual pp::Var HandleBlockingMessage(pp::InstanceHandle instance, | 134 virtual pp::Var HandleBlockingMessage(pp::InstanceHandle instance, |
| 122 const pp::Var& var) { | 135 const pp::Var& var) { |
| 123 if (pp::MessageLoop::GetCurrent() != message_handler_loop_) | 136 if (pp::MessageLoop::GetCurrent() != message_handler_loop_) |
| 124 AddError("HandleBlockingMessage was called on the wrong thread!"); | 137 AddError("HandleBlockingMessage was called on the wrong thread!"); |
| 125 if (instance.pp_instance() != testing_instance_->pp_instance()) | 138 if (instance.pp_instance() != testing_instance_->pp_instance()) |
| 126 AddError("HandleBlockingMessage was passed the wrong instance!"); | 139 AddError("HandleBlockingMessage was passed the wrong instance!"); |
| 127 | 140 |
| 128 // Attempt a blocking operation; make sure it's disallowed. | 141 // Attempt a blocking operation; make sure it's disallowed. |
| (...skipping 29 matching lines...) Expand all Loading... |
| 158 // is_registered_ is only read/written on the main thread. | 171 // is_registered_ is only read/written on the main thread. |
| 159 bool is_registered_; | 172 bool is_registered_; |
| 160 | 173 |
| 161 // errors_ is written on the MessageHandler thread. When Destroy() is | 174 // errors_ is written on the MessageHandler thread. When Destroy() is |
| 162 // called, we stop writing to errors_ and signal destroy_event_. This causes | 175 // called, we stop writing to errors_ and signal destroy_event_. This causes |
| 163 // a memory barrier, so it's safe to read errors_ after that. | 176 // a memory barrier, so it's safe to read errors_ after that. |
| 164 std::string errors_; | 177 std::string errors_; |
| 165 NestedEvent test_finished_event_; | 178 NestedEvent test_finished_event_; |
| 166 NestedEvent destroy_event_; | 179 NestedEvent destroy_event_; |
| 167 | 180 |
| 181 pp::Var last_async_message_received_; |
| 182 NestedEvent async_message_received_; |
| 183 |
| 168 // Undefined & private to disallow copy and assign. | 184 // Undefined & private to disallow copy and assign. |
| 169 EchoingMessageHandler(const EchoingMessageHandler&); | 185 MyMessageHandler(const MyMessageHandler&); |
| 170 EchoingMessageHandler& operator=(const EchoingMessageHandler&); | 186 MyMessageHandler& operator=(const MyMessageHandler&); |
| 171 }; | 187 }; |
| 172 | 188 |
| 173 void FakeHandleMessage(PP_Instance instance, | 189 void FakeHandleMessage(PP_Instance instance, |
| 174 void* user_data, | 190 void* user_data, |
| 175 const PP_Var* message_data) {} | 191 const PP_Var* message_data) {} |
| 176 void FakeHandleBlockingMessage(PP_Instance instance, | 192 void FakeHandleBlockingMessage(PP_Instance instance, |
| 177 void* user_data, | 193 void* user_data, |
| 178 const PP_Var* message_data, | 194 const PP_Var* message_data, |
| 179 PP_Var* result) {} | 195 PP_Var* result) {} |
| 180 void FakeDestroy(PP_Instance instance, void* user_data) {} | 196 void FakeDestroy(PP_Instance instance, void* user_data) {} |
| 181 | 197 |
| 182 } // namespace | 198 } // namespace |
| 183 | 199 |
| 184 TestMessageHandler::TestMessageHandler(TestingInstance* instance) | 200 TestMessageHandler::TestMessageHandler(TestingInstance* instance) |
| 185 : TestCase(instance), | 201 : TestCase(instance), |
| 202 message_received_(instance->pp_instance()), |
| 186 ppb_messaging_if_(NULL), | 203 ppb_messaging_if_(NULL), |
| 187 handler_thread_(instance), | 204 handler_thread_(instance) { |
| 188 message_received_(instance->pp_instance()) { | |
| 189 } | 205 } |
| 190 | 206 |
| 191 TestMessageHandler::~TestMessageHandler() { | 207 TestMessageHandler::~TestMessageHandler() { |
| 192 handler_thread_.Join(); | 208 handler_thread_.Join(); |
| 193 } | 209 } |
| 194 | 210 |
| 195 bool TestMessageHandler::Init() { | 211 bool TestMessageHandler::Init() { |
| 196 ppb_messaging_if_ = static_cast<const PPB_Messaging_1_2*>( | 212 ppb_messaging_if_ = static_cast<const PPB_Messaging_1_2*>( |
| 197 pp::Module::Get()->GetBrowserInterface(PPB_MESSAGING_INTERFACE_1_2)); | 213 pp::Module::Get()->GetBrowserInterface(PPB_MESSAGING_INTERFACE_1_2)); |
| 198 return ppb_messaging_if_ && | 214 return ppb_messaging_if_ && |
| 199 CheckTestingInterface() && | 215 CheckTestingInterface() && |
| 200 handler_thread_.Start(); | 216 handler_thread_.Start(); |
| 201 } | 217 } |
| 202 | 218 |
| 203 void TestMessageHandler::RunTests(const std::string& filter) { | 219 void TestMessageHandler::RunTests(const std::string& filter) { |
| 204 RUN_TEST(RegisterErrorConditions, filter); | 220 RUN_TEST(RegisterErrorConditions, filter); |
| 205 RUN_TEST(PostMessageAndAwaitResponse, filter); | 221 RUN_TEST(PostMessageAndAwaitResponse, filter); |
| 206 RUN_TEST(Exceptions, filter); | 222 RUN_TEST(Exceptions, filter); |
| 207 } | 223 } |
| 208 | 224 |
| 209 void TestMessageHandler::HandleMessage(const pp::Var& message_data) { | 225 void TestMessageHandler::HandleMessage(const pp::Var& message_data) { |
| 210 if (instance()->current_test_name() == "Exceptions") { | 226 if (instance()->current_test_name() == "Exceptions") { |
| 211 // For TestPostMessageAndAwaitResponse(), all messages should go to the | 227 // For TestPostMessageAndAwaitResponse(), all messages should go to the |
| 212 // background thread message handler. | 228 // background thread message handler. |
| 213 assert(false); | 229 assert(false); |
| 214 } else { | 230 } else { |
| 215 if (message_data.is_string()) { | 231 // Any subtest causing a message to arrive here must wait for it before |
| 216 last_message_ = message_data.AsString(); | 232 // continuing. See WaitForMessage(). |
| 217 } else { | 233 assert(last_message_.is_undefined()); |
| 218 last_message_ = "message_data was not a string!"; | 234 last_message_ = message_data; |
| 219 } | |
| 220 message_received_.Signal(); | 235 message_received_.Signal(); |
| 221 } | 236 } |
| 222 } | 237 } |
| 223 | 238 |
| 224 std::string TestMessageHandler::TestRegisterErrorConditions() { | 239 std::string TestMessageHandler::TestRegisterErrorConditions() { |
| 225 { | 240 { |
| 226 // Test registering with the main thread as the message loop. | 241 // Test registering with the main thread as the message loop. |
| 227 PPP_MessageHandler_0_2 fake_ppp_message_handler = { | 242 PPP_MessageHandler_0_2 fake_ppp_message_handler = { |
| 228 &FakeHandleMessage, &FakeHandleBlockingMessage, &FakeDestroy | 243 &FakeHandleMessage, &FakeHandleBlockingMessage, &FakeDestroy |
| 229 }; | 244 }; |
| (...skipping 17 matching lines...) Expand all Loading... |
| 247 reinterpret_cast<void*>(0xdeadbeef), | 262 reinterpret_cast<void*>(0xdeadbeef), |
| 248 &bad_ppp_ifs[i], | 263 &bad_ppp_ifs[i], |
| 249 handler_thread_.message_loop().pp_resource()); | 264 handler_thread_.message_loop().pp_resource()); |
| 250 ASSERT_EQ(PP_ERROR_BADARGUMENT, result); | 265 ASSERT_EQ(PP_ERROR_BADARGUMENT, result); |
| 251 } | 266 } |
| 252 } | 267 } |
| 253 PASS(); | 268 PASS(); |
| 254 } | 269 } |
| 255 | 270 |
| 256 std::string TestMessageHandler::TestPostMessageAndAwaitResponse() { | 271 std::string TestMessageHandler::TestPostMessageAndAwaitResponse() { |
| 257 EchoingMessageHandler handler(instance(), | 272 MyMessageHandler handler(instance(), |
| 258 handler_thread_.message_loop()); | 273 handler_thread_.message_loop()); |
| 259 // Test doing a sync call before the handler is registered. | |
| 260 handler.Register(); | 274 handler.Register(); |
| 261 std::string js_code("var plugin = document.getElementById('plugin');\n"); | 275 std::string js_code("var plugin = document.getElementById('plugin');\n"); |
| 262 js_code += "var result = undefined;\n"; | 276 js_code += "var result = undefined;\n"; |
| 263 const char* const values_to_test[] = { | 277 const char* const values_to_test[] = { |
| 264 "5", | 278 "5", |
| 265 "undefined", | 279 "undefined", |
| 266 "1.5", | 280 "1.5", |
| 267 "'hello'", | 281 "'hello'", |
| 268 "{'key': 'value', 'array_key': [1, 2, 3, 4, 5]}", | 282 "{'key': 'value', 'array_key': [1, 2, 3, 4, 5]}", |
| 269 NULL | 283 NULL |
| (...skipping 12 matching lines...) Expand all Loading... |
| 282 instance_->EvalScript(js_code); | 296 instance_->EvalScript(js_code); |
| 283 instance_->EvalScript("plugin.postMessage('FINISHED_TEST');\n"); | 297 instance_->EvalScript("plugin.postMessage('FINISHED_TEST');\n"); |
| 284 handler.WaitForTestFinishedMessage(); | 298 handler.WaitForTestFinishedMessage(); |
| 285 handler.Unregister(); | 299 handler.Unregister(); |
| 286 ASSERT_SUBTEST_SUCCESS(handler.WaitForDestroy()); | 300 ASSERT_SUBTEST_SUCCESS(handler.WaitForDestroy()); |
| 287 | 301 |
| 288 PASS(); | 302 PASS(); |
| 289 } | 303 } |
| 290 | 304 |
| 291 std::string TestMessageHandler::TestExceptions() { | 305 std::string TestMessageHandler::TestExceptions() { |
| 292 EchoingMessageHandler handler(instance(), | 306 MyMessageHandler handler(instance(), |
| 293 handler_thread_.message_loop()); | 307 handler_thread_.message_loop()); |
| 294 { | 308 { |
| 295 // First, try sending a blocking message when there is no handler | 309 // First, try sending a blocking message when there is no handler |
| 296 // registered. It should throw an exception. | 310 // registered. It should throw an exception. |
| 297 std::string js_code( | 311 std::string js_code( |
| 298 "var plugin = document.getElementById('plugin');\n" | 312 "var plugin = document.getElementById('plugin');\n" |
| 299 "var caught_exception = false;\n" | 313 "var caught_exception = false;\n" |
| 300 "try {\n" | 314 "try {\n" |
| 301 " plugin.postMessageAndAwaitResponse('Hello!');\n" | 315 " plugin.postMessageAndAwaitResponse('Hello!');\n" |
| 302 "} catch (err) {\n" | 316 "} catch (err) {\n" |
| 303 " caught_exception = true;\n" | 317 " caught_exception = true;\n" |
| 304 "}\n" | 318 "}\n" |
| 305 "plugin.postMessage(caught_exception ? 'SUCCESS' : 'FAIL');\n"); | 319 "plugin.postMessage(caught_exception ? 'SUCCESS' : 'FAIL');\n"); |
| 306 instance_->EvalScript(js_code); | 320 instance_->EvalScript(js_code); |
| 307 message_received_.Wait(); | 321 // Note that we want to wait for the Instance to get the SUCCESS/FAIL |
| 308 ASSERT_EQ("SUCCESS", last_message_); | 322 // message here. |message_handler| is not yet registered, so the message |
| 323 // goes to the instance instead. |
| 324 pp::Var msg = WaitForMessage(); |
| 325 ASSERT_TRUE(msg.is_string()); |
| 326 ASSERT_EQ("SUCCESS", msg.AsString()); |
| 309 } | 327 } |
| 310 handler.Register(); | 328 handler.Register(); |
| 311 { | 329 { |
| 312 // Now that a handler is registered, try requesting and sending a | 330 // Now that a handler is registered, try requesting and sending a |
| 313 // FileSystem. It should throw an exception. The file system is opened | 331 // FileSystem. It should throw an exception. The file system is opened |
| 314 // asynchronously. What *should* happen is that it opens successfully, then | 332 // asynchronously. What *should* happen is that it opens successfully, then |
| 315 // we try to send it via postMessageAndAwaitResponse, which fails with an | 333 // we try to send it via postMessageAndAwaitResponse, which fails with an |
| 316 // exception. The test could fail either because the filesystem doesn't | 334 // exception. The test could fail either because the filesystem doesn't |
| 317 // open or because postMessageAndAwaitResponse doesn't throw an exception. | 335 // open or because postMessageAndAwaitResponse doesn't throw an exception. |
| 318 std::string js_code( | 336 std::string js_code( |
| 319 "var plugin = document.getElementById('plugin');\n" | 337 "var plugin = document.getElementById('plugin');\n" |
| 320 "function gotFileSystem(fs) {\n" | 338 "function gotFileSystem(fs) {\n" |
| 321 " var caught_exception = false;\n" | 339 " var caught_exception = false;\n" |
| 322 " try {\n" | 340 " try {\n" |
| 323 " plugin.postMessageAndAwaitResponse(fs);\n" | 341 " plugin.postMessageAndAwaitResponse(fs);\n" |
| 324 " } catch (err) {\n" | 342 " } catch (err) {\n" |
| 325 " caught_exception = true;\n" | 343 " caught_exception = true;\n" |
| 326 " }\n" | 344 " }\n" |
| 327 " plugin.postMessage(caught_exception ? 'SUCCESS' : 'FAIL');\n" | 345 " plugin.postMessage(caught_exception ? 'SUCCESS' : 'FAIL');\n" |
| 328 "}\n" | 346 "}\n" |
| 329 "function fileSystemError() {\n" | 347 "function fileSystemError() {\n" |
| 330 " plugin.postMessage('Failed to open filesystem');\n" | 348 " plugin.postMessage('Failed to open filesystem');\n" |
| 331 "}\n" | 349 "}\n" |
| 332 "window.webkitRequestFileSystem(\n" | 350 "window.webkitRequestFileSystem(\n" |
| 333 " window.Temporary, 1024, gotFileSystem, fileSystemError)\n"); | 351 " window.Temporary, 1024, gotFileSystem, fileSystemError)\n"); |
| 334 instance_->EvalScript(js_code); | 352 instance_->EvalScript(js_code); |
| 335 message_received_.Wait(); | 353 pp::Var msg = handler.WaitForAsyncMessage(); |
| 336 ASSERT_EQ("SUCCESS", last_message_); | 354 ASSERT_EQ(PP_VARTYPE_STRING, msg.pp_var().type); |
| 355 ASSERT_EQ("SUCCESS", msg.AsString()); |
| 337 } | 356 } |
| 338 handler.Unregister(); | 357 handler.Unregister(); |
| 339 ASSERT_SUBTEST_SUCCESS(handler.WaitForDestroy()); | 358 ASSERT_SUBTEST_SUCCESS(handler.WaitForDestroy()); |
| 340 | 359 |
| 341 PASS(); | 360 PASS(); |
| 342 } | 361 } |
| 343 | 362 |
| 363 pp::Var TestMessageHandler::WaitForMessage() { |
| 364 message_received_.Wait(); |
| 365 pp::Var var_to_return = last_message_; |
| 366 last_message_ = pp::Var(); |
| 367 message_received_.Reset(); |
| 368 return var_to_return; |
| 369 } |
| 370 |
| OLD | NEW |