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