Home | History | Annotate | Download | only in tests
      1 // Copyright 2013 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 <stdlib.h>
      6 #include <string.h>
      7 
      8 #include "mojo/public/bindings/lib/bindings_support.h"
      9 #include "mojo/public/bindings/lib/connector.h"
     10 #include "mojo/public/bindings/lib/message_queue.h"
     11 #include "mojo/public/system/macros.h"
     12 #include "mojo/public/tests/simple_bindings_support.h"
     13 #include "testing/gtest/include/gtest/gtest.h"
     14 
     15 namespace mojo {
     16 namespace test {
     17 
     18 class MessageAccumulator : public MessageReceiver {
     19  public:
     20   MessageAccumulator() {
     21   }
     22 
     23   virtual bool Accept(Message* message) MOJO_OVERRIDE {
     24     queue_.Push(message);
     25     return true;
     26   }
     27 
     28   bool IsEmpty() const {
     29     return queue_.IsEmpty();
     30   }
     31 
     32   void Pop(Message* message) {
     33     queue_.Pop(message);
     34   }
     35 
     36  private:
     37   MessageQueue queue_;
     38 };
     39 
     40 class BindingsConnectorTest : public testing::Test {
     41  public:
     42   BindingsConnectorTest() {
     43   }
     44 
     45   virtual void SetUp() MOJO_OVERRIDE {
     46     CreateMessagePipe(&handle0_, &handle1_);
     47   }
     48 
     49   virtual void TearDown() MOJO_OVERRIDE {
     50   }
     51 
     52   void AllocMessage(const char* text, Message* message) {
     53     size_t payload_size = strlen(text) + 1;  // Plus null terminator.
     54     size_t num_bytes = sizeof(MessageHeader) + payload_size;
     55     message->data = static_cast<MessageData*>(malloc(num_bytes));
     56     message->data->header.num_bytes = static_cast<uint32_t>(num_bytes);
     57     message->data->header.name = 1;
     58     memcpy(message->data->payload, text, payload_size);
     59   }
     60 
     61   void PumpMessages() {
     62     bindings_support_.Process();
     63   }
     64 
     65  protected:
     66   ScopedMessagePipeHandle handle0_;
     67   ScopedMessagePipeHandle handle1_;
     68 
     69  private:
     70   SimpleBindingsSupport bindings_support_;
     71 };
     72 
     73 TEST_F(BindingsConnectorTest, Basic) {
     74   internal::Connector connector0(handle0_.Pass());
     75   internal::Connector connector1(handle1_.Pass());
     76 
     77   const char kText[] = "hello world";
     78 
     79   Message message;
     80   AllocMessage(kText, &message);
     81 
     82   connector0.Accept(&message);
     83 
     84   MessageAccumulator accumulator;
     85   connector1.SetIncomingReceiver(&accumulator);
     86 
     87   PumpMessages();
     88 
     89   ASSERT_FALSE(accumulator.IsEmpty());
     90 
     91   Message message_received;
     92   accumulator.Pop(&message_received);
     93 
     94   EXPECT_EQ(std::string(kText),
     95             std::string(
     96                 reinterpret_cast<char*>(message_received.data->payload)));
     97 }
     98 
     99 TEST_F(BindingsConnectorTest, Basic_EarlyIncomingReceiver) {
    100   internal::Connector connector0(handle0_.Pass());
    101   internal::Connector connector1(handle1_.Pass());
    102 
    103   MessageAccumulator accumulator;
    104   connector1.SetIncomingReceiver(&accumulator);
    105 
    106   const char kText[] = "hello world";
    107 
    108   Message message;
    109   AllocMessage(kText, &message);
    110 
    111   connector0.Accept(&message);
    112 
    113   PumpMessages();
    114 
    115   ASSERT_FALSE(accumulator.IsEmpty());
    116 
    117   Message message_received;
    118   accumulator.Pop(&message_received);
    119 
    120   EXPECT_EQ(std::string(kText),
    121             std::string(
    122                 reinterpret_cast<char*>(message_received.data->payload)));
    123 }
    124 
    125 TEST_F(BindingsConnectorTest, Basic_TwoMessages) {
    126   internal::Connector connector0(handle0_.Pass());
    127   internal::Connector connector1(handle1_.Pass());
    128 
    129   const char* kText[] = { "hello", "world" };
    130 
    131   for (size_t i = 0; i < MOJO_ARRAYSIZE(kText); ++i) {
    132     Message message;
    133     AllocMessage(kText[i], &message);
    134 
    135     connector0.Accept(&message);
    136   }
    137 
    138   MessageAccumulator accumulator;
    139   connector1.SetIncomingReceiver(&accumulator);
    140 
    141   PumpMessages();
    142 
    143   for (size_t i = 0; i < MOJO_ARRAYSIZE(kText); ++i) {
    144     ASSERT_FALSE(accumulator.IsEmpty());
    145 
    146     Message message_received;
    147     accumulator.Pop(&message_received);
    148 
    149     EXPECT_EQ(std::string(kText[i]),
    150               std::string(
    151                   reinterpret_cast<char*>(message_received.data->payload)));
    152   }
    153 }
    154 
    155 TEST_F(BindingsConnectorTest, WriteToClosedPipe) {
    156   // Leak this, so the closed handle isn't closed again.
    157   MojoHandle mojo_handle = handle0_.get().value();
    158   internal::Connector* connector0 = new internal::Connector(handle0_.Pass());
    159 
    160   const char kText[] = "hello world";
    161 
    162   Message message;
    163   AllocMessage(kText, &message);
    164 
    165   // Close handle out from under the connection
    166   MojoClose(mojo_handle);
    167 
    168   bool ok = connector0->Accept(&message);
    169   EXPECT_FALSE(ok);
    170 
    171   EXPECT_TRUE(connector0->encountered_error());
    172 }
    173 
    174 // Enable this test once MojoWriteMessage supports passing handles.
    175 TEST_F(BindingsConnectorTest, MessageWithHandles) {
    176   internal::Connector connector0(handle0_.Pass());
    177   internal::Connector connector1(handle1_.Pass());
    178 
    179   const char kText[] = "hello world";
    180 
    181   Message message;
    182   AllocMessage(kText, &message);
    183 
    184   ScopedMessagePipeHandle handles[2];
    185   CreateMessagePipe(&handles[0], &handles[1]);
    186   message.handles.push_back(handles[0].release());
    187 
    188   connector0.Accept(&message);
    189 
    190   // The message should have been transferred, releasing the handles.
    191   EXPECT_TRUE(message.handles.empty());
    192 
    193   MessageAccumulator accumulator;
    194   connector1.SetIncomingReceiver(&accumulator);
    195 
    196   PumpMessages();
    197 
    198   ASSERT_FALSE(accumulator.IsEmpty());
    199 
    200   Message message_received;
    201   accumulator.Pop(&message_received);
    202 
    203   EXPECT_EQ(std::string(kText),
    204             std::string(
    205                 reinterpret_cast<char*>(message_received.data->payload)));
    206   ASSERT_EQ(1U, message_received.handles.size());
    207 
    208   // Now send a message to the transferred handle and confirm it's sent through
    209   // to the orginal pipe.
    210   // TODO(vtl): Do we need a better way of "downcasting" the handle types?
    211   ScopedMessagePipeHandle smph;
    212   smph.reset(MessagePipeHandle(message_received.handles[0].value()));
    213   message_received.handles[0] = Handle();  // |smph| now owns this handle.
    214 
    215   internal::Connector connector_received(smph.Pass());
    216   internal::Connector connector_original(handles[1].Pass());
    217 
    218   AllocMessage(kText, &message);
    219 
    220   connector_received.Accept(&message);
    221   connector_original.SetIncomingReceiver(&accumulator);
    222   PumpMessages();
    223 
    224   ASSERT_FALSE(accumulator.IsEmpty());
    225 
    226   accumulator.Pop(&message_received);
    227 
    228   EXPECT_EQ(std::string(kText),
    229             std::string(
    230                 reinterpret_cast<char*>(message_received.data->payload)));
    231 }
    232 
    233 }  // namespace test
    234 }  // namespace mojo
    235