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.
5 #include "ppapi/tests/test_post_message.h"
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"
26 // Windows defines 'PostMessage', so we have to undef it.
31 REGISTER_TEST_CASE(PostMessage
);
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;
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.
44 const int32_t kThreadsToRun
= 2;
45 const int32_t kMessagesToSendPerThread
= 5;
47 const int32_t kThreadsToRun
= 4;
48 const int32_t kMessagesToSendPerThread
= 10;
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
;
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
);
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())
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
)
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
;
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())
102 for (uint32_t i
= 0; i
< expected_array
.GetLength(); ++i
) {
103 if (!VarsEqual(expected_array
.Get(i
), actual_array
.Get(i
), visited_ids
))
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()) {
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
))
118 if (!VarsEqual(expected_dict
.Get(key
), actual_dict
.Get(key
), visited_ids
))
123 return expected
== actual
;
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
);
133 class ScopedArrayBufferSizeSetter
{
135 ScopedArrayBufferSizeSetter(const PPB_Testing_Private
* interface
,
136 PP_Instance instance
,
138 : interface_(interface
),
139 instance_(instance
) {
140 interface_
->SetMinimumArrayBufferSizeForShmem(instance_
, threshold
);
142 ~ScopedArrayBufferSizeSetter() {
143 interface_
->SetMinimumArrayBufferSizeForShmem(instance_
, 0);
146 const PPB_Testing_Private
* interface_
;
147 PP_Instance instance_
;
150 #define FINISHED_WAITING_MESSAGE "TEST_POST_MESSAGE_FINISHED_WAITING"
154 TestPostMessage::TestPostMessage(TestingInstance
* instance
)
155 : TestCase(instance
) {
158 TestPostMessage::~TestPostMessage() {
159 instance_
->PostMessage(pp::Var("This isn't guaranteed to be received, but "
160 "shouldn't cause a crash."));
162 // Remove the special listener that only responds to a FINISHED_WAITING
163 // string. See Init for where it gets added.
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
);
172 bool TestPostMessage::Init() {
173 bool success
= CheckTestingInterface();
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");
183 // Set up a special listener that only responds to a FINISHED_WAITING string.
184 // This is for use by WaitForMessages.
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
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
"');"
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
);
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
210 instance_
->PostMessage(pp::Var(kTestString
));
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
);
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());
238 message_data_
.push_back(message_data
);
241 bool TestPostMessage::AddEchoingListener(const std::string
& expression
) {
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
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
;
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
);
267 bool TestPostMessage::PostMessageFromJavaScript(const std::string
& func
) {
269 js_code
+= "var plugin = document.getElementById('plugin');"
270 "plugin.postMessage(";
271 js_code
+= func
+ "()";
273 instance_
->EvalScript(js_code
);
277 bool TestPostMessage::ClearListeners() {
279 js_code
+= "var plugin = document.getElementById('plugin');"
280 "while (plugin.eventListeners.length) {"
281 " plugin.removeEventListener('message',"
282 " plugin.eventListeners.pop());"
284 instance_
->EvalScript(js_code
);
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 static_cast<int>(message_data_
.size() - message_size_before
);
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();
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());
321 std::string
TestPostMessage::TestSendInInit() {
322 // Wait for the messages from Init() to be guaranteed to be sent.
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();
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.
337 ASSERT_TRUE(ClearListeners());
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"));
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
);
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());
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
);
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());
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());
379 message_data_
.clear();
380 ASSERT_TRUE(ClearListeners());
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.
390 ASSERT_TRUE(ClearListeners());
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
));
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
);
409 message_data_
.clear();
410 ASSERT_TRUE(ClearListeners());
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.
420 ASSERT_TRUE(ClearListeners());
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(),
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());
433 // Create an appropriately sized array buffer with test_data[i] == i.
434 pp::VarArrayBuffer
test_data(sizes
[i
]);
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
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);
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
);
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
);
463 ASSERT_SUBTEST_SUCCESS(CheckMessageProperties(test_data
,
464 properties_to_check
));
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.
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
]);
487 message_data_
.clear();
488 ASSERT_TRUE(ClearListeners());
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.
499 ASSERT_TRUE(ClearListeners());
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
));
508 std::stringstream ss
;
509 ss
<< array
.GetLength();
510 std::string
length_as_string(ss
.str());
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
));
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()));
534 message_data_
.clear();
535 ASSERT_TRUE(ClearListeners());
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.
545 ASSERT_TRUE(ClearListeners());
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());
553 std::stringstream ss
;
554 ss
<< dictionary
.GetKeys().GetLength();
555 std::string
length_as_string(ss
.str());
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 === ") +
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
));
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()));
581 message_data_
.clear();
582 ASSERT_TRUE(ClearListeners());
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.
592 message_data_
.clear();
593 ASSERT_TRUE(ClearListeners());
595 std::string
file_path("/");
596 file_path
+= kTestFilename
;
597 int content_length
= static_cast<int>(strlen(kTestString
));
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();
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("
632 " message_event.data.name.length - ':Temporary'.length) !== -1");
633 ASSERT_SUBTEST_SUCCESS(CheckMessageProperties(file_system_var
,
634 properties_to_check
));
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());
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
));
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());
657 // Ensure that the file can be queried.
658 TestCompletionCallbackWithOutput
<PP_FileInfo
> cc(instance_
->pp_instance(),
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
);
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());
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
));
683 message_data_
.clear();
684 ASSERT_TRUE(ClearListeners());
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.
694 message_data_
.clear();
695 ASSERT_TRUE(ClearListeners());
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());
704 // Reference to 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
));
712 dictionary
.Set(pp::Var("array-ref1"), array
);
713 dictionary
.Set(pp::Var("array-ref2"), array
);
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()));
727 message_data_
.clear();
728 ASSERT_TRUE(ClearListeners());
730 // Set up a (dictionary -> array -> dictionary) cycle. Cycles shouldn't be
733 array2
.Set(0, dictionary
);
734 dictionary
.Set(pp::Var("array2"), array2
);
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);
743 dictionary
.Delete(pp::Var("array2"));
746 message_data_
.clear();
747 ASSERT_TRUE(ClearListeners());
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);
756 message_data_
.clear();
757 ASSERT_TRUE(ClearListeners());
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.
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());
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)"
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());
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"));
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.)
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());
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);
822 message_data_
.clear();
823 ASSERT_TRUE(ClearListeners());
828 std::string
TestPostMessage::TestNoHandler() {
829 // Delete any lingering messages and event listeners.
831 ASSERT_TRUE(ClearListeners());
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());
842 std::string
TestPostMessage::TestExtraParam() {
843 // Delete any lingering messages and event listeners.
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, []"));
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());
856 ASSERT_TRUE(ClearListeners());
861 std::string
TestPostMessage::TestNonMainThread() {
863 ASSERT_TRUE(ClearListeners());
864 ASSERT_TRUE(AddEchoingListener("message_event.data"));
865 message_data_
.clear();
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
);
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
));
882 // Now join all threads.
883 for (int32_t i
= 0; i
< kThreadsToRun
; ++i
)
884 PP_JoinThread(threads
[i
]);
886 // PostMessage is asynchronous, so we should not receive a response yet.
887 ASSERT_EQ(0, message_data_
.size());
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);
908 ASSERT_TRUE(received_value
>= 0);
909 ASSERT_TRUE(received_value
<= kThreadsToRun
);
910 ++received_counts
[received_value
];
912 ASSERT_EQ(expected_counts
, received_counts
);
914 message_data_
.clear();
915 ASSERT_TRUE(ClearListeners());