1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "ppapi/tests/test_post_message.h" 6 7 #include <string.h> 8 #include <algorithm> 9 #include <map> 10 #include <sstream> 11 12 #include "ppapi/c/pp_var.h" 13 #include "ppapi/c/ppb_file_io.h" 14 #include "ppapi/cpp/file_io.h" 15 #include "ppapi/cpp/file_ref.h" 16 #include "ppapi/cpp/file_system.h" 17 #include "ppapi/cpp/instance.h" 18 #include "ppapi/cpp/var.h" 19 #include "ppapi/cpp/var_array.h" 20 #include "ppapi/cpp/var_array_buffer.h" 21 #include "ppapi/cpp/var_dictionary.h" 22 #include "ppapi/tests/pp_thread.h" 23 #include "ppapi/tests/test_utils.h" 24 #include "ppapi/tests/testing_instance.h" 25 26 // Windows defines 'PostMessage', so we have to undef it. 27 #ifdef PostMessage 28 #undef PostMessage 29 #endif 30 31 REGISTER_TEST_CASE(PostMessage); 32 33 namespace { 34 35 const char kTestFilename[] = "testfile.txt"; 36 const char kTestString[] = "Hello world!"; 37 const bool kTestBool = true; 38 const int32_t kTestInt = 42; 39 const double kTestDouble = 42.0; 40 41 // On Windows XP bots, the NonMainThread test can run very slowly. So we dial 42 // back the number of threads & messages when running on Windows. 43 #ifdef PPAPI_OS_WIN 44 const int32_t kThreadsToRun = 2; 45 const int32_t kMessagesToSendPerThread = 5; 46 #else 47 const int32_t kThreadsToRun = 4; 48 const int32_t kMessagesToSendPerThread = 10; 49 #endif 50 51 // The struct that invoke_post_message_thread_func expects for its argument. 52 // It includes the instance on which to invoke PostMessage, and the value to 53 // pass to PostMessage. 54 struct InvokePostMessageThreadArg { 55 InvokePostMessageThreadArg(pp::Instance* i, const pp::Var& v) 56 : instance(i), value_to_send(v) {} 57 pp::Instance* instance; 58 pp::Var value_to_send; 59 }; 60 61 void InvokePostMessageThreadFunc(void* user_data) { 62 InvokePostMessageThreadArg* arg = 63 static_cast<InvokePostMessageThreadArg*>(user_data); 64 for (int32_t i = 0; i < kMessagesToSendPerThread; ++i) 65 arg->instance->PostMessage(arg->value_to_send); 66 delete arg; 67 } 68 69 // TODO(raymes): Consider putting something like this into pp::Var. 70 bool VarsEqual(const pp::Var& expected, 71 const pp::Var& actual, 72 std::map<int64_t, int64_t>* visited_ids) { 73 if (expected.pp_var().type != actual.pp_var().type) { 74 if (!expected.is_number() && !actual.is_number()) 75 return false; 76 } 77 // TODO(raymes): Implement a pp::Var::IsRefCounted() function. 78 if (expected.pp_var().type > PP_VARTYPE_DOUBLE) { 79 std::map<int64_t, int64_t>::const_iterator it = 80 visited_ids->find(expected.pp_var().value.as_id); 81 if (it != visited_ids->end()) { 82 if (it->second == actual.pp_var().value.as_id) 83 return true; 84 return false; 85 } 86 // Round-tripping reference graphs with strings will not necessarily 87 // result in isomorphic graphs. This is because string vars are converted 88 // to string primitives in JS which cannot be referenced. 89 if (!expected.is_string()) { 90 (*visited_ids)[expected.pp_var().value.as_id] = 91 actual.pp_var().value.as_id; 92 } 93 } 94 95 if (expected.is_number()) { 96 return fabs(expected.AsDouble() - actual.AsDouble()) < 1.0e-4; 97 } else if (expected.is_array()) { 98 pp::VarArray expected_array(expected); 99 pp::VarArray actual_array(actual); 100 if (expected_array.GetLength() != actual_array.GetLength()) 101 return false; 102 for (uint32_t i = 0; i < expected_array.GetLength(); ++i) { 103 if (!VarsEqual(expected_array.Get(i), actual_array.Get(i), visited_ids)) 104 return false; 105 } 106 return true; 107 } else if (expected.is_dictionary()) { 108 pp::VarDictionary expected_dict(expected); 109 pp::VarDictionary actual_dict(actual); 110 if (expected_dict.GetKeys().GetLength() != 111 actual_dict.GetKeys().GetLength()) { 112 return false; 113 } 114 for (uint32_t i = 0; i < expected_dict.GetKeys().GetLength(); ++i) { 115 pp::Var key = expected_dict.GetKeys().Get(i); 116 if (!actual_dict.HasKey(key)) 117 return false; 118 if (!VarsEqual(expected_dict.Get(key), actual_dict.Get(key), visited_ids)) 119 return false; 120 } 121 return true; 122 } else { 123 return expected == actual; 124 } 125 } 126 127 bool VarsEqual(const pp::Var& expected, 128 const pp::Var& actual) { 129 std::map<int64_t, int64_t> visited_ids; 130 return VarsEqual(expected, actual, &visited_ids); 131 } 132 133 class ScopedArrayBufferSizeSetter { 134 public: 135 ScopedArrayBufferSizeSetter(const PPB_Testing_Private* interface, 136 PP_Instance instance, 137 uint32_t threshold) 138 : interface_(interface), 139 instance_(instance) { 140 interface_->SetMinimumArrayBufferSizeForShmem(instance_, threshold); 141 } 142 ~ScopedArrayBufferSizeSetter() { 143 interface_->SetMinimumArrayBufferSizeForShmem(instance_, 0); 144 } 145 private: 146 const PPB_Testing_Private* interface_; 147 PP_Instance instance_; 148 }; 149 150 #define FINISHED_WAITING_MESSAGE "TEST_POST_MESSAGE_FINISHED_WAITING" 151 152 } // namespace 153 154 TestPostMessage::TestPostMessage(TestingInstance* instance) 155 : TestCase(instance) { 156 } 157 158 TestPostMessage::~TestPostMessage() { 159 instance_->PostMessage(pp::Var("This isn't guaranteed to be received, but " 160 "shouldn't cause a crash.")); 161 162 // Remove the special listener that only responds to a FINISHED_WAITING 163 // string. See Init for where it gets added. 164 std::string js_code; 165 js_code += "var plugin = document.getElementById('plugin');" 166 "plugin.removeEventListener('message'," 167 " plugin.wait_for_messages_handler);" 168 "delete plugin.wait_for_messages_handler;"; 169 instance_->EvalScript(js_code); 170 } 171 172 bool TestPostMessage::Init() { 173 bool success = CheckTestingInterface(); 174 175 // Add a post condition to tests which caches the postMessage function and 176 // then calls it after the instance is destroyed. The ensures that no UAF 177 // occurs because the MessageChannel may still be alive after the plugin 178 // instance is destroyed (it will get garbage collected eventually). 179 instance_->EvalScript("window.pluginPostMessage = " 180 "document.getElementById('plugin').postMessage"); 181 instance_->AddPostCondition("window.pluginPostMessage('') === undefined"); 182 183 // Set up a special listener that only responds to a FINISHED_WAITING string. 184 // This is for use by WaitForMessages. 185 std::string js_code; 186 // Note the following code is dependent on some features of test_case.html. 187 // E.g., it is assumed that the DOM element where the plugin is embedded has 188 // an id of 'plugin', and there is a function 'IsTestingMessage' that allows 189 // us to ignore the messages that are intended for use by the testing 190 // framework itself. 191 js_code += "var plugin = document.getElementById('plugin');" 192 "var wait_for_messages_handler = function(message_event) {" 193 " if (!IsTestingMessage(message_event.data) &&" 194 " message_event.data === '" FINISHED_WAITING_MESSAGE "') {" 195 " plugin.postMessage('" FINISHED_WAITING_MESSAGE "');" 196 " }" 197 "};" 198 "plugin.addEventListener('message', wait_for_messages_handler);" 199 // Stash it on the plugin so we can remove it in the destructor. 200 "plugin.wait_for_messages_handler = wait_for_messages_handler;"; 201 instance_->EvalScript(js_code); 202 203 // Set up the JavaScript message event listener to echo the data part of the 204 // message event back to us. 205 success = success && AddEchoingListener("message_event.data"); 206 message_data_.clear(); 207 // Send a message that the first test will expect to receive. This is to 208 // verify that we can send messages when the 'Instance::Init' function is on 209 // the stack. 210 instance_->PostMessage(pp::Var(kTestString)); 211 212 return success; 213 } 214 215 void TestPostMessage::RunTests(const std::string& filter) { 216 // Note: SendInInit must be first, because it expects to receive a message 217 // that was sent in Init above. 218 RUN_TEST(SendInInit, filter); 219 RUN_TEST(SendingData, filter); 220 RUN_TEST(SendingString, filter); 221 RUN_TEST(SendingArrayBuffer, filter); 222 RUN_TEST(SendingArray, filter); 223 RUN_TEST(SendingDictionary, filter); 224 RUN_TEST(SendingResource, filter); 225 RUN_TEST(SendingComplexVar, filter); 226 RUN_TEST(MessageEvent, filter); 227 RUN_TEST(NoHandler, filter); 228 RUN_TEST(ExtraParam, filter); 229 if (testing_interface_->IsOutOfProcess()) 230 RUN_TEST(NonMainThread, filter); 231 } 232 233 void TestPostMessage::HandleMessage(const pp::Var& message_data) { 234 if (message_data.is_string() && 235 (message_data.AsString() == FINISHED_WAITING_MESSAGE)) 236 testing_interface_->QuitMessageLoop(instance_->pp_instance()); 237 else 238 message_data_.push_back(message_data); 239 } 240 241 bool TestPostMessage::AddEchoingListener(const std::string& expression) { 242 std::string js_code; 243 // Note the following code is dependent on some features of test_case.html. 244 // E.g., it is assumed that the DOM element where the plugin is embedded has 245 // an id of 'plugin', and there is a function 'IsTestingMessage' that allows 246 // us to ignore the messages that are intended for use by the testing 247 // framework itself. 248 js_code += "var plugin = document.getElementById('plugin');" 249 "var message_handler = function(message_event) {" 250 " if (!IsTestingMessage(message_event.data) &&" 251 " !(message_event.data === '" FINISHED_WAITING_MESSAGE "')) {" 252 " plugin.postMessage("; 253 js_code += expression; 254 js_code += " );" 255 " }" 256 "};" 257 "plugin.addEventListener('message', message_handler);" 258 // Maintain an array of all event listeners, attached to the 259 // plugin. This is so that we can easily remove them later (see 260 // ClearListeners()). 261 "if (!plugin.eventListeners) plugin.eventListeners = [];" 262 "plugin.eventListeners.push(message_handler);"; 263 instance_->EvalScript(js_code); 264 return true; 265 } 266 267 bool TestPostMessage::PostMessageFromJavaScript(const std::string& func) { 268 std::string js_code; 269 js_code += "var plugin = document.getElementById('plugin');" 270 "plugin.postMessage("; 271 js_code += func + "()"; 272 js_code += " );"; 273 instance_->EvalScript(js_code); 274 return true; 275 } 276 277 bool TestPostMessage::ClearListeners() { 278 std::string js_code; 279 js_code += "var plugin = document.getElementById('plugin');" 280 "while (plugin.eventListeners.length) {" 281 " plugin.removeEventListener('message'," 282 " plugin.eventListeners.pop());" 283 "}"; 284 instance_->EvalScript(js_code); 285 return true; 286 } 287 288 int TestPostMessage::WaitForMessages() { 289 size_t message_size_before = message_data_.size(); 290 // We first post a FINISHED_WAITING_MESSAGE. This should be guaranteed to 291 // come back _after_ any other incoming messages that were already pending. 292 instance_->PostMessage(pp::Var(FINISHED_WAITING_MESSAGE)); 293 testing_interface_->RunMessageLoop(instance_->pp_instance()); 294 // Now that the FINISHED_WAITING_MESSAGE has been echoed back to us, we know 295 // that all pending messages have been slurped up. Return the number we 296 // received (which may be zero). 297 return message_data_.size() - message_size_before; 298 } 299 300 std::string TestPostMessage::CheckMessageProperties( 301 const pp::Var& test_data, 302 const std::vector<std::string>& properties_to_check) { 303 typedef std::vector<std::string>::const_iterator Iterator; 304 for (Iterator iter = properties_to_check.begin(); 305 iter != properties_to_check.end(); 306 ++iter) { 307 ASSERT_TRUE(AddEchoingListener(*iter)); 308 message_data_.clear(); 309 instance_->PostMessage(test_data); 310 ASSERT_EQ(0, message_data_.size()); 311 ASSERT_EQ(1, WaitForMessages()); 312 ASSERT_TRUE(message_data_.back().is_bool()); 313 if (!message_data_.back().AsBool()) 314 return std::string("Failed: ") + *iter; 315 ASSERT_TRUE(message_data_.back().AsBool()); 316 ASSERT_TRUE(ClearListeners()); 317 } 318 PASS(); 319 } 320 321 std::string TestPostMessage::TestSendInInit() { 322 // Wait for the messages from Init() to be guaranteed to be sent. 323 WaitForMessages(); 324 // This test assumes Init already sent a message. 325 ASSERT_EQ(1, message_data_.size()); 326 ASSERT_TRUE(message_data_.back().is_string()); 327 ASSERT_EQ(kTestString, message_data_.back().AsString()); 328 message_data_.clear(); 329 PASS(); 330 } 331 332 std::string TestPostMessage::TestSendingData() { 333 // Clean up after previous tests. This also swallows the message sent by Init 334 // if we didn't run the 'SendInInit' test. All tests other than 'SendInInit' 335 // should start with these. 336 WaitForMessages(); 337 ASSERT_TRUE(ClearListeners()); 338 339 // Set up the JavaScript message event listener to echo the data part of the 340 // message event back to us. 341 ASSERT_TRUE(AddEchoingListener("message_event.data")); 342 343 // Test sending a message to JavaScript for each supported type. The JS sends 344 // the data back to us, and we check that they match. 345 message_data_.clear(); 346 instance_->PostMessage(pp::Var(kTestBool)); 347 ASSERT_EQ(0, message_data_.size()); 348 ASSERT_EQ(1, WaitForMessages()); 349 ASSERT_TRUE(message_data_.back().is_bool()); 350 ASSERT_EQ(message_data_.back().AsBool(), kTestBool); 351 352 message_data_.clear(); 353 instance_->PostMessage(pp::Var(kTestInt)); 354 ASSERT_EQ(0, message_data_.size()); 355 ASSERT_EQ(1, WaitForMessages()); 356 ASSERT_TRUE(message_data_.back().is_number()); 357 ASSERT_DOUBLE_EQ(static_cast<double>(kTestInt), 358 message_data_.back().AsDouble()); 359 360 message_data_.clear(); 361 instance_->PostMessage(pp::Var(kTestDouble)); 362 ASSERT_EQ(0, message_data_.size()); 363 ASSERT_EQ(1, WaitForMessages()); 364 ASSERT_TRUE(message_data_.back().is_number()); 365 ASSERT_DOUBLE_EQ(message_data_.back().AsDouble(), kTestDouble); 366 367 message_data_.clear(); 368 instance_->PostMessage(pp::Var()); 369 ASSERT_EQ(0, message_data_.size()); 370 ASSERT_EQ(1, WaitForMessages()); 371 ASSERT_TRUE(message_data_.back().is_undefined()); 372 373 message_data_.clear(); 374 instance_->PostMessage(pp::Var(pp::Var::Null())); 375 ASSERT_EQ(0, message_data_.size()); 376 ASSERT_EQ(1, WaitForMessages()); 377 ASSERT_TRUE(message_data_.back().is_null()); 378 379 message_data_.clear(); 380 ASSERT_TRUE(ClearListeners()); 381 382 PASS(); 383 } 384 385 std::string TestPostMessage::TestSendingString() { 386 // Clean up after previous tests. This also swallows the message sent by Init 387 // if we didn't run the 'SendInInit' test. All tests other than 'SendInInit' 388 // should start with these. 389 WaitForMessages(); 390 ASSERT_TRUE(ClearListeners()); 391 392 // Test that a string var is converted to a primitive JS string. 393 message_data_.clear(); 394 std::vector<std::string> properties_to_check; 395 properties_to_check.push_back( 396 "typeof message_event.data === 'string'"); 397 ASSERT_SUBTEST_SUCCESS(CheckMessageProperties(kTestString, 398 properties_to_check)); 399 400 ASSERT_TRUE(AddEchoingListener("message_event.data")); 401 message_data_.clear(); 402 instance_->PostMessage(pp::Var(kTestString)); 403 // PostMessage is asynchronous, so we should not receive a response yet. 404 ASSERT_EQ(0, message_data_.size()); 405 ASSERT_EQ(1, WaitForMessages()); 406 ASSERT_TRUE(message_data_.back().is_string()); 407 ASSERT_EQ(message_data_.back().AsString(), kTestString); 408 409 message_data_.clear(); 410 ASSERT_TRUE(ClearListeners()); 411 412 PASS(); 413 } 414 415 std::string TestPostMessage::TestSendingArrayBuffer() { 416 // Clean up after previous tests. This also swallows the message sent by Init 417 // if we didn't run the 'SendInInit' test. All tests other than 'SendInInit' 418 // should start with these. 419 WaitForMessages(); 420 ASSERT_TRUE(ClearListeners()); 421 422 // TODO(sehr,dmichael): Add testing of longer array buffers when 423 // crbug.com/110086 is fixed. 424 ScopedArrayBufferSizeSetter setter(testing_interface_, 425 instance_->pp_instance(), 426 200); 427 uint32_t sizes[] = { 0, 100, 1000, 10000 }; 428 for (size_t i = 0; i < sizeof(sizes)/sizeof(sizes[i]); ++i) { 429 std::ostringstream size_stream; 430 size_stream << sizes[i]; 431 const std::string kSizeAsString(size_stream.str()); 432 433 // Create an appropriately sized array buffer with test_data[i] == i. 434 pp::VarArrayBuffer test_data(sizes[i]); 435 if (sizes[i] > 0) 436 ASSERT_NE(NULL, test_data.Map()); 437 // Make sure we can Unmap/Map successfully (there's not really any way to 438 // detect if it's unmapped, so we just re-map before getting the pointer to 439 // the buffer). 440 test_data.Unmap(); 441 test_data.Map(); 442 ASSERT_EQ(sizes[i], test_data.ByteLength()); 443 unsigned char* buff = static_cast<unsigned char*>(test_data.Map()); 444 const uint32_t kByteLength = test_data.ByteLength(); 445 for (size_t j = 0; j < kByteLength; ++j) 446 buff[j] = static_cast<uint8_t>(j % 256u); 447 448 // Have the listener test some properties of the ArrayBuffer. 449 std::vector<std::string> properties_to_check; 450 properties_to_check.push_back( 451 "message_event.data.constructor.name === 'ArrayBuffer'"); 452 properties_to_check.push_back( 453 std::string("message_event.data.byteLength === ") + kSizeAsString); 454 if (sizes[i] > 0) { 455 properties_to_check.push_back( 456 "(new DataView(message_event.data)).getUint8(0) == 0"); 457 // Checks that the last element has the right value: (byteLength-1)%256. 458 std::string received_byte("(new DataView(message_event.data)).getUint8(" 459 " message_event.data.byteLength-1)"); 460 std::string expected_byte("(message_event.data.byteLength-1)%256"); 461 properties_to_check.push_back(received_byte + " == " + expected_byte); 462 } 463 ASSERT_SUBTEST_SUCCESS(CheckMessageProperties(test_data, 464 properties_to_check)); 465 466 // Set up the JavaScript message event listener to echo the data part of the 467 // message event back to us. 468 ASSERT_TRUE(AddEchoingListener("message_event.data")); 469 message_data_.clear(); 470 instance_->PostMessage(test_data); 471 // PostMessage is asynchronous, so we should not receive a response yet. 472 ASSERT_EQ(0, message_data_.size()); 473 ASSERT_EQ(1, WaitForMessages()); 474 ASSERT_TRUE(message_data_.back().is_array_buffer()); 475 pp::VarArrayBuffer received(message_data_.back()); 476 message_data_.clear(); 477 ASSERT_EQ(test_data.ByteLength(), received.ByteLength()); 478 unsigned char* received_buff = static_cast<unsigned char*>(received.Map()); 479 // The buffer should be copied, so this should be a distinct buffer. When 480 // 'transferrables' are implemented for PPAPI, we'll also want to test that 481 // we get the _same_ buffer back when it's transferred. 482 if (sizes[i] > 0) 483 ASSERT_NE(buff, received_buff); 484 for (size_t i = 0; i < test_data.ByteLength(); ++i) 485 ASSERT_EQ(buff[i], received_buff[i]); 486 487 message_data_.clear(); 488 ASSERT_TRUE(ClearListeners()); 489 } 490 491 PASS(); 492 } 493 494 std::string TestPostMessage::TestSendingArray() { 495 // Clean up after previous tests. This also swallows the message sent by Init 496 // if we didn't run the 'SendInInit' test. All tests other than 'SendInInit' 497 // should start with these. 498 WaitForMessages(); 499 ASSERT_TRUE(ClearListeners()); 500 501 pp::VarArray array; 502 array.Set(0, pp::Var(kTestBool)); 503 array.Set(1, pp::Var(kTestString)); 504 // Purposely leave index 2 empty. 505 array.Set(3, pp::Var(kTestInt)); 506 array.Set(4, pp::Var(kTestDouble)); 507 508 std::stringstream ss; 509 ss << array.GetLength(); 510 std::string length_as_string(ss.str()); 511 512 // Have the listener test some properties of the Array. 513 std::vector<std::string> properties_to_check; 514 properties_to_check.push_back( 515 "message_event.data.constructor.name === 'Array'"); 516 properties_to_check.push_back( 517 std::string("message_event.data.length === ") + length_as_string); 518 // Check that the string is converted to a primitive JS string. 519 properties_to_check.push_back( 520 std::string("typeof message_event.data[1] === 'string'")); 521 ASSERT_SUBTEST_SUCCESS(CheckMessageProperties(array, properties_to_check)); 522 523 // Set up the JavaScript message event listener to echo the data part of the 524 // message event back to us. 525 ASSERT_TRUE(AddEchoingListener("message_event.data")); 526 message_data_.clear(); 527 instance_->PostMessage(array); 528 // PostMessage is asynchronous, so we should not receive a response yet. 529 ASSERT_EQ(0, message_data_.size()); 530 ASSERT_EQ(1, WaitForMessages()); 531 ASSERT_TRUE(message_data_.back().is_array()); 532 ASSERT_TRUE(VarsEqual(array, message_data_.back())); 533 534 message_data_.clear(); 535 ASSERT_TRUE(ClearListeners()); 536 537 PASS(); 538 } 539 540 std::string TestPostMessage::TestSendingDictionary() { 541 // Clean up after previous tests. This also swallows the message sent by Init 542 // if we didn't run the 'SendInInit' test. All tests other than 'SendInInit' 543 // should start with these. 544 WaitForMessages(); 545 ASSERT_TRUE(ClearListeners()); 546 547 pp::VarDictionary dictionary; 548 dictionary.Set(pp::Var("foo"), pp::Var(kTestBool)); 549 dictionary.Set(pp::Var("bar"), pp::Var(kTestString)); 550 dictionary.Set(pp::Var("abc"), pp::Var(kTestInt)); 551 dictionary.Set(pp::Var("def"), pp::Var()); 552 553 std::stringstream ss; 554 ss << dictionary.GetKeys().GetLength(); 555 std::string length_as_string(ss.str()); 556 557 // Have the listener test some properties of the Dictionary. 558 std::vector<std::string> properties_to_check; 559 properties_to_check.push_back( 560 "message_event.data.constructor.name === 'Object'"); 561 properties_to_check.push_back( 562 std::string("Object.keys(message_event.data).length === ") + 563 length_as_string); 564 // Check that the string is converted to a primitive JS string. 565 properties_to_check.push_back( 566 std::string("typeof message_event.data['bar'] === 'string'")); 567 ASSERT_SUBTEST_SUCCESS(CheckMessageProperties(dictionary, 568 properties_to_check)); 569 570 // Set up the JavaScript message event listener to echo the data part of the 571 // message event back to us. 572 ASSERT_TRUE(AddEchoingListener("message_event.data")); 573 message_data_.clear(); 574 instance_->PostMessage(dictionary); 575 // PostMessage is asynchronous, so we should not receive a response yet. 576 ASSERT_EQ(0, message_data_.size()); 577 ASSERT_EQ(1, WaitForMessages()); 578 ASSERT_TRUE(message_data_.back().is_dictionary()); 579 ASSERT_TRUE(VarsEqual(dictionary, message_data_.back())); 580 581 message_data_.clear(); 582 ASSERT_TRUE(ClearListeners()); 583 584 PASS(); 585 } 586 587 std::string TestPostMessage::TestSendingResource() { 588 // Clean up after previous tests. This also swallows the message sent by Init 589 // if we didn't run the 'SendInInit' test. All tests other than 'SendInInit' 590 // should start with these. 591 WaitForMessages(); 592 message_data_.clear(); 593 ASSERT_TRUE(ClearListeners()); 594 595 std::string file_path("/"); 596 file_path += kTestFilename; 597 int content_length = strlen(kTestString); 598 599 // Create a file in the HTML5 temporary file system, in the Pepper plugin. 600 TestCompletionCallback callback(instance_->pp_instance(), callback_type()); 601 pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY); 602 callback.WaitForResult(file_system.Open(1024, callback.GetCallback())); 603 CHECK_CALLBACK_BEHAVIOR(callback); 604 ASSERT_EQ(PP_OK, callback.result()); 605 pp::FileRef write_file_ref(file_system, file_path.c_str()); 606 // Write to the file. 607 pp::FileIO write_file_io(instance_); 608 ASSERT_NE(0, write_file_io.pp_resource()); 609 callback.WaitForResult( 610 write_file_io.Open(write_file_ref, 611 PP_FILEOPENFLAG_WRITE | PP_FILEOPENFLAG_CREATE, 612 callback.GetCallback())); 613 CHECK_CALLBACK_BEHAVIOR(callback); 614 ASSERT_EQ(PP_OK, callback.result()); 615 callback.WaitForResult(write_file_io.Write( 616 0, kTestString, content_length, callback.GetCallback())); 617 CHECK_CALLBACK_BEHAVIOR(callback); 618 ASSERT_EQ(callback.result(), content_length); 619 write_file_io.Close(); 620 621 // Pass the file system to JavaScript and have the listener test some 622 // properties of the file system. 623 pp::Var file_system_var(file_system); 624 std::vector<std::string> properties_to_check; 625 properties_to_check.push_back( 626 "message_event.data.constructor.name === 'DOMFileSystem'"); 627 properties_to_check.push_back( 628 "message_event.data.root.constructor.name === 'DirectoryEntry'"); 629 properties_to_check.push_back( 630 "message_event.data.name.indexOf(" 631 " ':Temporary'," 632 " message_event.data.name.length - ':Temporary'.length) !== -1"); 633 ASSERT_SUBTEST_SUCCESS(CheckMessageProperties(file_system_var, 634 properties_to_check)); 635 636 // Set up the JavaScript message event listener to echo the data part of the 637 // message event back to us. 638 ASSERT_TRUE(AddEchoingListener("message_event.data")); 639 // Send the file system in a message from the Pepper plugin to JavaScript. 640 message_data_.clear(); 641 instance_->PostMessage(file_system_var); 642 // PostMessage is asynchronous, so we should not receive a response yet. 643 ASSERT_EQ(0, message_data_.size()); 644 ASSERT_EQ(1, WaitForMessages()); 645 646 // The JavaScript should have posted the file system back to us. Verify that 647 // it is a file system and read the file contents that we wrote earlier. 648 pp::Var var = message_data_.back(); 649 ASSERT_TRUE(var.is_resource()); 650 pp::Resource result = var.AsResource(); 651 ASSERT_TRUE(pp::FileSystem::IsFileSystem(result)); 652 { 653 pp::FileSystem received_file_system(result); 654 pp::FileRef file_ref(received_file_system, file_path.c_str()); 655 ASSERT_NE(0, file_ref.pp_resource()); 656 657 // Ensure that the file can be queried. 658 TestCompletionCallbackWithOutput<PP_FileInfo> cc(instance_->pp_instance(), 659 callback_type()); 660 cc.WaitForResult(file_ref.Query(cc.GetCallback())); 661 CHECK_CALLBACK_BEHAVIOR(cc); 662 ASSERT_EQ(PP_OK, cc.result()); 663 ASSERT_EQ(cc.output().size, content_length); 664 665 // Read the file and test that its contents match. 666 pp::FileIO file_io(instance_); 667 ASSERT_NE(0, file_io.pp_resource()); 668 callback.WaitForResult( 669 file_io.Open(file_ref, PP_FILEOPENFLAG_READ, callback.GetCallback())); 670 CHECK_CALLBACK_BEHAVIOR(callback); 671 ASSERT_EQ(PP_OK, callback.result()); 672 673 std::vector<char> buffer_vector(content_length); 674 char* buffer = &buffer_vector[0]; // Note: Not null-terminated! 675 callback.WaitForResult( 676 file_io.Read(0, buffer, content_length, callback.GetCallback())); 677 CHECK_CALLBACK_BEHAVIOR(callback); 678 ASSERT_EQ(callback.result(), content_length); 679 ASSERT_EQ(0, memcmp(buffer, kTestString, content_length)); 680 } 681 682 WaitForMessages(); 683 message_data_.clear(); 684 ASSERT_TRUE(ClearListeners()); 685 686 PASS(); 687 } 688 689 std::string TestPostMessage::TestSendingComplexVar() { 690 // Clean up after previous tests. This also swallows the message sent by Init 691 // if we didn't run the 'SendInInit' test. All tests other than 'SendInInit' 692 // should start with these. 693 WaitForMessages(); 694 message_data_.clear(); 695 ASSERT_TRUE(ClearListeners()); 696 697 pp::Var string(kTestString); 698 pp::VarDictionary dictionary; 699 dictionary.Set(pp::Var("foo"), pp::Var(kTestBool)); 700 dictionary.Set(pp::Var("bar"), string); 701 dictionary.Set(pp::Var("abc"), pp::Var(kTestInt)); 702 dictionary.Set(pp::Var("def"), pp::Var()); 703 704 // Reference to array. 705 pp::VarArray array; 706 array.Set(0, pp::Var(kTestBool)); 707 array.Set(1, string); 708 // Purposely leave index 2 empty (which will place an undefined var there). 709 array.Set(3, pp::Var(kTestInt)); 710 array.Set(4, pp::Var(kTestDouble)); 711 712 dictionary.Set(pp::Var("array-ref1"), array); 713 dictionary.Set(pp::Var("array-ref2"), array); 714 715 // Set up the JavaScript message event listener to echo the data part of the 716 // message event back to us. 717 ASSERT_TRUE(AddEchoingListener("message_event.data")); 718 instance_->PostMessage(dictionary); 719 // PostMessage is asynchronous, so we should not receive a response yet. 720 ASSERT_EQ(0, message_data_.size()); 721 ASSERT_EQ(1, WaitForMessages()); 722 ASSERT_TRUE(message_data_.back().is_dictionary()); 723 pp::VarDictionary result(message_data_.back()); 724 ASSERT_TRUE(VarsEqual(dictionary, message_data_.back())); 725 726 WaitForMessages(); 727 message_data_.clear(); 728 ASSERT_TRUE(ClearListeners()); 729 730 // Set up a (dictionary -> array -> dictionary) cycle. Cycles shouldn't be 731 // transmitted. 732 pp::VarArray array2; 733 array2.Set(0, dictionary); 734 dictionary.Set(pp::Var("array2"), array2); 735 736 ASSERT_TRUE(AddEchoingListener("message_event.data")); 737 instance_->PostMessage(dictionary); 738 // PostMessage is asynchronous, so we should not receive a response yet. 739 ASSERT_EQ(0, message_data_.size()); 740 ASSERT_EQ(WaitForMessages(), 0); 741 742 // Break the cycles. 743 dictionary.Delete(pp::Var("array2")); 744 745 WaitForMessages(); 746 message_data_.clear(); 747 ASSERT_TRUE(ClearListeners()); 748 749 // Test sending a cycle from JavaScript to the plugin. 750 ASSERT_TRUE(AddEchoingListener("message_event.data")); 751 PostMessageFromJavaScript("function() { var x = []; x[0] = x; return x; }"); 752 ASSERT_EQ(0, message_data_.size()); 753 ASSERT_EQ(WaitForMessages(), 0); 754 755 WaitForMessages(); 756 message_data_.clear(); 757 ASSERT_TRUE(ClearListeners()); 758 759 PASS(); 760 } 761 762 std::string TestPostMessage::TestMessageEvent() { 763 // Set up the JavaScript message event listener to pass us some values from 764 // the MessageEvent and make sure they match our expectations. 765 766 WaitForMessages(); 767 ASSERT_TRUE(ClearListeners()); 768 // Have the listener pass back the class name of message_event and make sure 769 // it's "MessageEvent". 770 ASSERT_TRUE(AddEchoingListener("message_event.constructor.name")); 771 message_data_.clear(); 772 instance_->PostMessage(pp::Var(kTestInt)); 773 ASSERT_EQ(0, message_data_.size()); 774 ASSERT_EQ(1, WaitForMessages()); 775 ASSERT_TRUE(message_data_.back().is_string()); 776 ASSERT_EQ(message_data_.back().AsString(), "MessageEvent"); 777 ASSERT_TRUE(ClearListeners()); 778 779 // Make sure all the non-data properties have the expected values. 780 bool success = AddEchoingListener("((message_event.origin === '')" 781 " && (message_event.lastEventId === '')" 782 " && (message_event.source === null)" 783 " && (message_event.ports.length === 0)" 784 " && (message_event.bubbles === false)" 785 " && (message_event.cancelable === false)" 786 ")"); 787 ASSERT_TRUE(success); 788 message_data_.clear(); 789 instance_->PostMessage(pp::Var(kTestInt)); 790 ASSERT_EQ(0, message_data_.size()); 791 ASSERT_EQ(1, WaitForMessages()); 792 ASSERT_TRUE(message_data_.back().is_bool()); 793 ASSERT_TRUE(message_data_.back().AsBool()); 794 ASSERT_TRUE(ClearListeners()); 795 796 // Add some event handlers to make sure they receive messages. 797 ASSERT_TRUE(AddEchoingListener("1")); 798 ASSERT_TRUE(AddEchoingListener("2")); 799 ASSERT_TRUE(AddEchoingListener("3")); 800 801 message_data_.clear(); 802 instance_->PostMessage(pp::Var(kTestInt)); 803 // Make sure we don't get a response in a re-entrant fashion. 804 ASSERT_EQ(0, message_data_.size()); 805 // We should get 3 messages. 806 ASSERT_EQ(WaitForMessages(), 3); 807 // Copy to a vector of doubles and sort; w3c does not specify the order for 808 // event listeners. (Copying is easier than writing an operator< for pp::Var.) 809 // 810 // See http://www.w3.org/TR/2000/REC-DOM-Level-2-Events-20001113/events.html. 811 VarVector::iterator iter(message_data_.begin()), the_end(message_data_.end()); 812 std::vector<double> double_vec; 813 for (; iter != the_end; ++iter) { 814 ASSERT_TRUE(iter->is_number()); 815 double_vec.push_back(iter->AsDouble()); 816 } 817 std::sort(double_vec.begin(), double_vec.end()); 818 ASSERT_DOUBLE_EQ(double_vec[0], 1.0); 819 ASSERT_DOUBLE_EQ(double_vec[1], 2.0); 820 ASSERT_DOUBLE_EQ(double_vec[2], 3.0); 821 822 message_data_.clear(); 823 ASSERT_TRUE(ClearListeners()); 824 825 PASS(); 826 } 827 828 std::string TestPostMessage::TestNoHandler() { 829 // Delete any lingering messages and event listeners. 830 WaitForMessages(); 831 ASSERT_TRUE(ClearListeners()); 832 833 // Now send a message. We shouldn't get a response. 834 message_data_.clear(); 835 instance_->PostMessage(pp::Var()); 836 ASSERT_EQ(WaitForMessages(), 0); 837 ASSERT_TRUE(message_data_.empty()); 838 839 PASS(); 840 } 841 842 std::string TestPostMessage::TestExtraParam() { 843 // Delete any lingering messages and event listeners. 844 WaitForMessages(); 845 ASSERT_TRUE(ClearListeners()); 846 // Add a listener that will respond with 1 and an empty array (where the 847 // message port array would appear if it was Worker postMessage). 848 ASSERT_TRUE(AddEchoingListener("1, []")); 849 850 // Now send a message. We shouldn't get a response. 851 message_data_.clear(); 852 instance_->PostMessage(pp::Var()); 853 ASSERT_EQ(WaitForMessages(), 0); 854 ASSERT_TRUE(message_data_.empty()); 855 856 ASSERT_TRUE(ClearListeners()); 857 858 PASS(); 859 } 860 861 std::string TestPostMessage::TestNonMainThread() { 862 WaitForMessages(); 863 ASSERT_TRUE(ClearListeners()); 864 ASSERT_TRUE(AddEchoingListener("message_event.data")); 865 message_data_.clear(); 866 867 // Set up a thread for each integer from 0 to (kThreadsToRun - 1). Make each 868 // thread send the number that matches its index kMessagesToSendPerThread 869 // times. For good measure, call postMessage from the main thread 870 // kMessagesToSendPerThread times. At the end, we make sure we got all the 871 // values we expected. 872 PP_Thread threads[kThreadsToRun]; 873 for (int32_t i = 0; i < kThreadsToRun; ++i) { 874 // Set up a thread to send a value of i. 875 void* arg = new InvokePostMessageThreadArg(instance_, pp::Var(i)); 876 PP_CreateThread(&threads[i], &InvokePostMessageThreadFunc, arg); 877 } 878 // Invoke PostMessage right now to send a value of (kThreadsToRun). 879 for (int32_t i = 0; i < kMessagesToSendPerThread; ++i) 880 instance_->PostMessage(pp::Var(kThreadsToRun)); 881 882 // Now join all threads. 883 for (int32_t i = 0; i < kThreadsToRun; ++i) 884 PP_JoinThread(threads[i]); 885 886 // PostMessage is asynchronous, so we should not receive a response yet. 887 ASSERT_EQ(0, message_data_.size()); 888 889 // Make sure we got all values that we expected. Note that because it's legal 890 // for the JavaScript engine to treat our integers as floating points, we 891 // can't just use std::find or equality comparison. So we instead, we convert 892 // each incoming value to an integer, and count them in received_counts. 893 int32_t expected_num = (kThreadsToRun + 1) * kMessagesToSendPerThread; 894 // Count how many we receive per-index. 895 std::vector<int32_t> expected_counts(kThreadsToRun + 1, 896 kMessagesToSendPerThread); 897 std::vector<int32_t> received_counts(kThreadsToRun + 1, 0); 898 ASSERT_EQ(expected_num, WaitForMessages()); 899 for (int32_t i = 0; i < expected_num; ++i) { 900 const pp::Var& latest_var(message_data_[i]); 901 ASSERT_TRUE(latest_var.is_int() || latest_var.is_double()); 902 int32_t received_value = -1; 903 if (latest_var.is_int()) { 904 received_value = latest_var.AsInt(); 905 } else if (latest_var.is_double()) { 906 received_value = static_cast<int32_t>(latest_var.AsDouble() + 0.5); 907 } 908 ASSERT_TRUE(received_value >= 0); 909 ASSERT_TRUE(received_value <= kThreadsToRun); 910 ++received_counts[received_value]; 911 } 912 ASSERT_EQ(expected_counts, received_counts); 913 914 message_data_.clear(); 915 ASSERT_TRUE(ClearListeners()); 916 917 PASS(); 918 } 919