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