From 9260b8f0d823ba65403bd4924bf07e7ab67b9250 Mon Sep 17 00:00:00 2001
From: "dmichael@chromium.org"
 <dmichael@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>
Date: Tue, 6 Sep 2011 19:21:21 +0000
Subject: Reland http://codereview.chromium.org/7821001/

Add test for calling PostMessage during Init. Deflakify TestPostMessage.

BUG=93260,91768
TEST=This test
TBR=dmichael

Review URL: http://codereview.chromium.org/7834049

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@99785 0039d316-1c4b-4281-b951-d872f2087c98
---
 ppapi/tests/test_post_message.cc | 148 ++++++++++++++++++++++++++-------------
 ppapi/tests/test_post_message.h  |  12 +++-
 2 files changed, 111 insertions(+), 49 deletions(-)

(limited to 'ppapi/tests')

diff --git a/ppapi/tests/test_post_message.cc b/ppapi/tests/test_post_message.cc
index f19a3b1..9d6e569 100644
--- a/ppapi/tests/test_post_message.cc
+++ b/ppapi/tests/test_post_message.cc
@@ -28,8 +28,8 @@ const char kTestString[] = "Hello world!";
 const bool kTestBool = true;
 const int32_t kTestInt = 42;
 const double kTestDouble = 42.0;
-const int32_t kThreadsToRun = 10;
-const int32_t kMessagesToSendPerThread = 50;
+const int32_t kThreadsToRun = 4;
+const int32_t kMessagesToSendPerThread = 10;
 
 // The struct that invoke_post_message_thread_func expects for its argument.
 // It includes the instance on which to invoke PostMessage, and the value to
@@ -49,13 +49,67 @@ void InvokePostMessageThreadFunc(void* user_data) {
   delete arg;
 }
 
+#define FINISHED_WAITING_MESSAGE "TEST_POST_MESSAGE_FINISHED_WAITING"
+
 }  // namespace
 
+TestPostMessage::TestPostMessage(TestingInstance* instance)
+    : TestCase(instance) {
+}
+
+TestPostMessage::~TestPostMessage() {
+  // Remove the special listener that only responds to a FINISHED_WAITING
+  // string. See Init for where it gets added.
+  std::string js_code;
+  js_code += "var plugin = document.getElementById('plugin');"
+             "plugin.removeEventListener('message',"
+             "                           plugin.wait_for_messages_handler);"
+             "delete plugin.wait_for_messages_handler;";
+  pp::Var exception;
+  instance_->ExecuteScript(js_code, &exception);
+}
+
 bool TestPostMessage::Init() {
-  return InitTestingInterface();
+  bool success = InitTestingInterface();
+
+  // Set up a special listener that only responds to a FINISHED_WAITING string.
+  // This is for use by WaitForMessages.
+  std::string js_code;
+  // Note the following code is dependent on some features of test_case.html.
+  // E.g., it is assumed that the DOM element where the plugin is embedded has
+  // an id of 'plugin', and there is a function 'IsTestingMessage' that allows
+  // us to ignore the messages that are intended for use by the testing
+  // framework itself.
+  js_code += "var plugin = document.getElementById('plugin');"
+             "var wait_for_messages_handler = function(message_event) {"
+             "  if (!IsTestingMessage(message_event.data) &&"
+             "      message_event.data === '" FINISHED_WAITING_MESSAGE "') {"
+             "    plugin.postMessage('" FINISHED_WAITING_MESSAGE "');"
+             "  }"
+             "};"
+             "plugin.addEventListener('message', wait_for_messages_handler);"
+             // Stash it on the plugin so we can remove it in the destructor.
+             "plugin.wait_for_messages_handler = wait_for_messages_handler;";
+  pp::Var exception;
+  instance_->ExecuteScript(js_code, &exception);
+  success = success && exception.is_undefined();
+
+  // Set up the JavaScript message event listener to echo the data part of the
+  // message event back to us.
+  success = success && AddEchoingListener("message_event.data");
+  message_data_.clear();
+  // Send a message that the first test will expect to receive. This is to
+  // verify that we can send messages when the 'Instance::Init' function is on
+  // the stack.
+  instance_->PostMessage(pp::Var(kTestString));
+
+  return success;
 }
 
 void TestPostMessage::RunTest() {
+  // Note: SendInInit must be first, because it expects to receive a message
+  // that was sent in Init above.
+  RUN_TEST(SendInInit);
   RUN_TEST(SendingData);
   RUN_TEST(MessageEvent);
   RUN_TEST(NoHandler);
@@ -65,8 +119,11 @@ void TestPostMessage::RunTest() {
 }
 
 void TestPostMessage::HandleMessage(const pp::Var& message_data) {
-  message_data_.push_back(message_data);
-  testing_interface_->QuitMessageLoop(instance_->pp_instance());
+  if (message_data.is_string() &&
+      (message_data.AsString() == FINISHED_WAITING_MESSAGE))
+    testing_interface_->QuitMessageLoop(instance_->pp_instance());
+  else
+    message_data_.push_back(message_data);
 }
 
 bool TestPostMessage::AddEchoingListener(const std::string& expression) {
@@ -78,7 +135,8 @@ bool TestPostMessage::AddEchoingListener(const std::string& expression) {
   // framework itself.
   js_code += "var plugin = document.getElementById('plugin');"
              "var message_handler = function(message_event) {"
-             "  if (!IsTestingMessage(message_event.data)) {"
+             "  if (!IsTestingMessage(message_event.data) &&"
+             "      !(message_event.data === '" FINISHED_WAITING_MESSAGE "')) {"
              "    plugin.postMessage(";
   js_code += expression;
   js_code += "                      );"
@@ -106,9 +164,31 @@ bool TestPostMessage::ClearListeners() {
   return(exception.is_undefined());
 }
 
+int TestPostMessage::WaitForMessages() {
+  size_t message_size_before = message_data_.size();
+  // We first post a FINISHED_WAITING_MESSAGE. This should be guaranteed to
+  // come back _after_ any other incoming messages that were already pending.
+  instance_->PostMessage(pp::Var(FINISHED_WAITING_MESSAGE));
+  testing_interface_->RunMessageLoop(instance_->pp_instance());
+  // Now that the FINISHED_WAITING_MESSAGE has been echoed back to us, we know
+  // that all pending messages have been slurped up. Return the number we
+  // received (which may be zero).
+  return message_data_.size() - message_size_before;
+}
+
+std::string TestPostMessage::TestSendInInit() {
+  ASSERT_EQ(WaitForMessages(), 1);
+  // This test assumes Init already sent a message.
+  ASSERT_EQ(message_data_.size(), 1);
+  ASSERT_TRUE(message_data_.back().is_string());
+  ASSERT_EQ(message_data_.back().AsString(), kTestString);
+  PASS();
+}
+
 std::string TestPostMessage::TestSendingData() {
   // Set up the JavaScript message event listener to echo the data part of the
   // message event back to us.
+  ASSERT_TRUE(ClearListeners());
   ASSERT_TRUE(AddEchoingListener("message_event.data"));
 
   // Test sending a message to JavaScript for each supported type.  The JS sends
@@ -117,25 +197,21 @@ std::string TestPostMessage::TestSendingData() {
   instance_->PostMessage(pp::Var(kTestString));
   // PostMessage is asynchronous, so we should not receive a response yet.
   ASSERT_EQ(message_data_.size(), 0);
-
-  testing_interface_->RunMessageLoop(instance_->pp_instance());
-  ASSERT_EQ(message_data_.size(), 1);
+  ASSERT_EQ(WaitForMessages(), 1);
   ASSERT_TRUE(message_data_.back().is_string());
   ASSERT_EQ(message_data_.back().AsString(), kTestString);
 
   message_data_.clear();
   instance_->PostMessage(pp::Var(kTestBool));
   ASSERT_EQ(message_data_.size(), 0);
-  testing_interface_->RunMessageLoop(instance_->pp_instance());
-  ASSERT_EQ(message_data_.size(), 1);
+  ASSERT_EQ(WaitForMessages(), 1);
   ASSERT_TRUE(message_data_.back().is_bool());
   ASSERT_EQ(message_data_.back().AsBool(), kTestBool);
 
   message_data_.clear();
   instance_->PostMessage(pp::Var(kTestInt));
   ASSERT_EQ(message_data_.size(), 0);
-  testing_interface_->RunMessageLoop(instance_->pp_instance());
-  ASSERT_EQ(message_data_.size(), 1);
+  ASSERT_EQ(WaitForMessages(), 1);
   ASSERT_TRUE(message_data_.back().is_number());
   ASSERT_DOUBLE_EQ(message_data_.back().AsDouble(),
                    static_cast<double>(kTestInt));
@@ -143,23 +219,20 @@ std::string TestPostMessage::TestSendingData() {
   message_data_.clear();
   instance_->PostMessage(pp::Var(kTestDouble));
   ASSERT_EQ(message_data_.size(), 0);
-  testing_interface_->RunMessageLoop(instance_->pp_instance());
-  ASSERT_EQ(message_data_.size(), 1);
+  ASSERT_EQ(WaitForMessages(), 1);
   ASSERT_TRUE(message_data_.back().is_number());
   ASSERT_DOUBLE_EQ(message_data_.back().AsDouble(), kTestDouble);
 
   message_data_.clear();
   instance_->PostMessage(pp::Var());
   ASSERT_EQ(message_data_.size(), 0);
-  testing_interface_->RunMessageLoop(instance_->pp_instance());
-  ASSERT_EQ(message_data_.size(), 1);
+  ASSERT_EQ(WaitForMessages(), 1);
   ASSERT_TRUE(message_data_.back().is_undefined());
 
   message_data_.clear();
   instance_->PostMessage(pp::Var(pp::Var::Null()));
   ASSERT_EQ(message_data_.size(), 0);
-  testing_interface_->RunMessageLoop(instance_->pp_instance());
-  ASSERT_EQ(message_data_.size(), 1);
+  ASSERT_EQ(WaitForMessages(), 1);
   ASSERT_TRUE(message_data_.back().is_null());
 
   ASSERT_TRUE(ClearListeners());
@@ -173,12 +246,12 @@ std::string TestPostMessage::TestMessageEvent() {
 
   // Have the listener pass back the type of message_event and make sure it's
   // "object".
+  ASSERT_TRUE(ClearListeners());
   ASSERT_TRUE(AddEchoingListener("typeof(message_event)"));
   message_data_.clear();
   instance_->PostMessage(pp::Var(kTestInt));
   ASSERT_EQ(message_data_.size(), 0);
-  testing_interface_->RunMessageLoop(instance_->pp_instance());
-  ASSERT_EQ(message_data_.size(), 1);
+  ASSERT_EQ(WaitForMessages(), 1);
   ASSERT_TRUE(message_data_.back().is_string());
   ASSERT_EQ(message_data_.back().AsString(), "object");
   ASSERT_TRUE(ClearListeners());
@@ -195,8 +268,7 @@ std::string TestPostMessage::TestMessageEvent() {
   message_data_.clear();
   instance_->PostMessage(pp::Var(kTestInt));
   ASSERT_EQ(message_data_.size(), 0);
-  testing_interface_->RunMessageLoop(instance_->pp_instance());
-  ASSERT_EQ(message_data_.size(), 1);
+  ASSERT_EQ(WaitForMessages(), 1);
   ASSERT_TRUE(message_data_.back().is_bool());
   ASSERT_TRUE(message_data_.back().AsBool());
   ASSERT_TRUE(ClearListeners());
@@ -211,10 +283,7 @@ std::string TestPostMessage::TestMessageEvent() {
   // Make sure we don't get a response in a re-entrant fashion.
   ASSERT_EQ(message_data_.size(), 0);
   // We should get 3 messages.
-  testing_interface_->RunMessageLoop(instance_->pp_instance());
-  testing_interface_->RunMessageLoop(instance_->pp_instance());
-  testing_interface_->RunMessageLoop(instance_->pp_instance());
-  ASSERT_EQ(message_data_.size(), 3);
+  ASSERT_EQ(WaitForMessages(), 3);
   // Copy to a vector of doubles and sort; w3c does not specify the order for
   // event listeners. (Copying is easier than writing an operator< for pp::Var.)
   //
@@ -242,13 +311,7 @@ std::string TestPostMessage::TestNoHandler() {
   // Now send a message.  We shouldn't get a response.
   message_data_.clear();
   instance_->PostMessage(pp::Var());
-  // Note that at this point, if we call RunMessageLoop, we should hang, because
-  // there should be no call to our HandleMessage function to quit the loop.
-  // Therefore, we will do CallOnMainThread to yield control.  That event should
-  // fire, but we should see no messages when we return.
-  TestCompletionCallback callback(instance_->pp_instance());
-  pp::Module::Get()->core()->CallOnMainThread(0, callback);
-  callback.WaitForResult();
+  ASSERT_EQ(WaitForMessages(), 0);
   ASSERT_TRUE(message_data_.empty());
 
   PASS();
@@ -264,13 +327,7 @@ std::string TestPostMessage::TestExtraParam() {
   // Now send a message.  We shouldn't get a response.
   message_data_.clear();
   instance_->PostMessage(pp::Var());
-  // Note that at this point, if we call RunMessageLoop, we should hang, because
-  // there should be no call to our HandleMessage function to quit the loop.
-  // Therefore, we will do CallOnMainThread to yield control.  That event should
-  // fire, but we should see no messages when we return.
-  TestCompletionCallback callback(instance_->pp_instance());
-  pp::Module::Get()->core()->CallOnMainThread(0, callback);
-  callback.WaitForResult();
+  ASSERT_EQ(WaitForMessages(), 0);
   ASSERT_TRUE(message_data_.empty());
 
   PASS();
@@ -312,14 +369,9 @@ std::string TestPostMessage::TestNonMainThread() {
   std::vector<int32_t> expected_counts(kThreadsToRun + 1,
                                        kMessagesToSendPerThread);
   std::vector<int32_t> received_counts(kThreadsToRun + 1, 0);
+  ASSERT_EQ(WaitForMessages(), expected_num);
   for (int32_t i = 0; i < expected_num; ++i) {
-    // Run the message loop to get the next expected message.
-    testing_interface_->RunMessageLoop(instance_->pp_instance());
-    // Make sure we got another message in.
-    ASSERT_EQ(message_data_.size(), 1);
-    pp::Var latest_var(message_data_.back());
-    message_data_.clear();
-
+    const pp::Var& latest_var(message_data_[i]);
     ASSERT_TRUE(latest_var.is_int() || latest_var.is_double());
     int32_t received_value = -1;
     if (latest_var.is_int()) {
diff --git a/ppapi/tests/test_post_message.h b/ppapi/tests/test_post_message.h
index f081880..af1dc36 100644
--- a/ppapi/tests/test_post_message.h
+++ b/ppapi/tests/test_post_message.h
@@ -12,7 +12,8 @@
 
 class TestPostMessage : public TestCase {
  public:
-  explicit TestPostMessage(TestingInstance* instance) : TestCase(instance) {}
+  explicit TestPostMessage(TestingInstance* instance);
+  virtual ~TestPostMessage();
 
  private:
   // TestCase implementation.
@@ -38,6 +39,15 @@ class TestPostMessage : public TestCase {
   // Returns true on success, false on failure.
   bool ClearListeners();
 
+  // Wait for pending messages; return the number of messages that were pending
+  // at the time of invocation.
+  int WaitForMessages();
+
+  // Test that we can send a message from Instance::Init. Note the actual
+  // message is sent in TestPostMessage::Init, and this test simply makes sure
+  // we got it.
+  std::string TestSendInInit();
+
   // Test some basic functionality;  make sure we can send data successfully
   // in both directions.
   std::string TestSendingData();
-- 
cgit v1.1