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