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/cpp/bindings/lib/connector.h"
      9 #include "mojo/public/cpp/bindings/lib/message_builder.h"
     10 #include "mojo/public/cpp/bindings/lib/message_queue.h"
     11 #include "mojo/public/cpp/environment/environment.h"
     12 #include "mojo/public/cpp/system/macros.h"
     13 #include "mojo/public/cpp/utility/run_loop.h"
     14 #include "testing/gtest/include/gtest/gtest.h"
     15 
     16 namespace mojo {
     17 namespace test {
     18 namespace {
     19 
     20 class MessageAccumulator : public MessageReceiver {
     21  public:
     22   MessageAccumulator() {
     23   }
     24 
     25   virtual bool Accept(Message* message) MOJO_OVERRIDE {
     26     queue_.Push(message);
     27     return true;
     28   }
     29 
     30   bool IsEmpty() const {
     31     return queue_.IsEmpty();
     32   }
     33 
     34   void Pop(Message* message) {
     35     queue_.Pop(message);
     36   }
     37 
     38  private:
     39   internal::MessageQueue queue_;
     40 };
     41 
     42 class ConnectorTest : public testing::Test {
     43  public:
     44   ConnectorTest() {
     45   }
     46 
     47   virtual void SetUp() MOJO_OVERRIDE {
     48     CreateMessagePipe(NULL, &handle0_, &handle1_);
     49   }
     50 
     51   virtual void TearDown() MOJO_OVERRIDE {
     52   }
     53 
     54   void AllocMessage(const char* text, Message* message) {
     55     size_t payload_size = strlen(text) + 1;  // Plus null terminator.
     56     internal::MessageBuilder builder(1, payload_size);
     57     memcpy(builder.buffer()->Allocate(payload_size), text, payload_size);
     58     builder.Finish(message);
     59   }
     60 
     61   void PumpMessages() {
     62     loop_.RunUntilIdle();
     63   }
     64 
     65  protected:
     66   ScopedMessagePipeHandle handle0_;
     67   ScopedMessagePipeHandle handle1_;
     68 
     69  private:
     70   Environment env_;
     71   RunLoop loop_;
     72 };
     73 
     74 TEST_F(ConnectorTest, Basic) {
     75   internal::Connector connector0(handle0_.Pass());
     76   internal::Connector connector1(handle1_.Pass());
     77 
     78   const char kText[] = "hello world";
     79 
     80   Message message;
     81   AllocMessage(kText, &message);
     82 
     83   connector0.Accept(&message);
     84 
     85   MessageAccumulator accumulator;
     86   connector1.set_incoming_receiver(&accumulator);
     87 
     88   PumpMessages();
     89 
     90   ASSERT_FALSE(accumulator.IsEmpty());
     91 
     92   Message message_received;
     93   accumulator.Pop(&message_received);
     94 
     95   EXPECT_EQ(
     96       std::string(kText),
     97       std::string(reinterpret_cast<const char*>(message_received.payload())));
     98 }
     99 
    100 TEST_F(ConnectorTest, Basic_EarlyIncomingReceiver) {
    101   internal::Connector connector0(handle0_.Pass());
    102   internal::Connector connector1(handle1_.Pass());
    103 
    104   MessageAccumulator accumulator;
    105   connector1.set_incoming_receiver(&accumulator);
    106 
    107   const char kText[] = "hello world";
    108 
    109   Message message;
    110   AllocMessage(kText, &message);
    111 
    112   connector0.Accept(&message);
    113 
    114   PumpMessages();
    115 
    116   ASSERT_FALSE(accumulator.IsEmpty());
    117 
    118   Message message_received;
    119   accumulator.Pop(&message_received);
    120 
    121   EXPECT_EQ(
    122       std::string(kText),
    123       std::string(reinterpret_cast<const char*>(message_received.payload())));
    124 }
    125 
    126 TEST_F(ConnectorTest, Basic_TwoMessages) {
    127   internal::Connector connector0(handle0_.Pass());
    128   internal::Connector connector1(handle1_.Pass());
    129 
    130   const char* kText[] = { "hello", "world" };
    131 
    132   for (size_t i = 0; i < MOJO_ARRAYSIZE(kText); ++i) {
    133     Message message;
    134     AllocMessage(kText[i], &message);
    135 
    136     connector0.Accept(&message);
    137   }
    138 
    139   MessageAccumulator accumulator;
    140   connector1.set_incoming_receiver(&accumulator);
    141 
    142   PumpMessages();
    143 
    144   for (size_t i = 0; i < MOJO_ARRAYSIZE(kText); ++i) {
    145     ASSERT_FALSE(accumulator.IsEmpty());
    146 
    147     Message message_received;
    148     accumulator.Pop(&message_received);
    149 
    150     EXPECT_EQ(
    151         std::string(kText[i]),
    152         std::string(reinterpret_cast<const char*>(message_received.payload())));
    153   }
    154 }
    155 
    156 TEST_F(ConnectorTest, WriteToClosedPipe) {
    157   internal::Connector connector0(handle0_.Pass());
    158 
    159   const char kText[] = "hello world";
    160 
    161   Message message;
    162   AllocMessage(kText, &message);
    163 
    164   // Close the other end of the pipe.
    165   handle1_.reset();
    166 
    167   // Not observed yet because we haven't spun the RunLoop yet.
    168   EXPECT_FALSE(connector0.encountered_error());
    169 
    170   // Write failures are not reported.
    171   bool ok = connector0.Accept(&message);
    172   EXPECT_TRUE(ok);
    173 
    174   // Still not observed.
    175   EXPECT_FALSE(connector0.encountered_error());
    176 
    177   // Spin the RunLoop, and then we should start observing the closed pipe.
    178   PumpMessages();
    179 
    180   EXPECT_TRUE(connector0.encountered_error());
    181 }
    182 
    183 TEST_F(ConnectorTest, MessageWithHandles) {
    184   internal::Connector connector0(handle0_.Pass());
    185   internal::Connector connector1(handle1_.Pass());
    186 
    187   const char kText[] = "hello world";
    188 
    189   Message message1;
    190   AllocMessage(kText, &message1);
    191 
    192   MessagePipe pipe;
    193   message1.mutable_handles()->push_back(pipe.handle0.release());
    194 
    195   connector0.Accept(&message1);
    196 
    197   // The message should have been transferred, releasing the handles.
    198   EXPECT_TRUE(message1.handles()->empty());
    199 
    200   MessageAccumulator accumulator;
    201   connector1.set_incoming_receiver(&accumulator);
    202 
    203   PumpMessages();
    204 
    205   ASSERT_FALSE(accumulator.IsEmpty());
    206 
    207   Message message_received;
    208   accumulator.Pop(&message_received);
    209 
    210   EXPECT_EQ(
    211       std::string(kText),
    212       std::string(reinterpret_cast<const char*>(message_received.payload())));
    213   ASSERT_EQ(1U, message_received.handles()->size());
    214 
    215   // Now send a message to the transferred handle and confirm it's sent through
    216   // to the orginal pipe.
    217   // TODO(vtl): Do we need a better way of "downcasting" the handle types?
    218   ScopedMessagePipeHandle smph;
    219   smph.reset(MessagePipeHandle(message_received.handles()->front().value()));
    220   message_received.mutable_handles()->front() = Handle();
    221   // |smph| now owns this handle.
    222 
    223   internal::Connector connector_received(smph.Pass());
    224   internal::Connector connector_original(pipe.handle1.Pass());
    225 
    226   Message message2;
    227   AllocMessage(kText, &message2);
    228 
    229   connector_received.Accept(&message2);
    230   connector_original.set_incoming_receiver(&accumulator);
    231   PumpMessages();
    232 
    233   ASSERT_FALSE(accumulator.IsEmpty());
    234 
    235   accumulator.Pop(&message_received);
    236 
    237   EXPECT_EQ(
    238       std::string(kText),
    239       std::string(reinterpret_cast<const char*>(message_received.payload())));
    240 }
    241 
    242 }  // namespace
    243 }  // namespace test
    244 }  // namespace mojo
    245