• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
MessageAccumulator()22   MessageAccumulator() {
23   }
24 
Accept(Message * message)25   virtual bool Accept(Message* message) MOJO_OVERRIDE {
26     queue_.Push(message);
27     return true;
28   }
29 
IsEmpty() const30   bool IsEmpty() const {
31     return queue_.IsEmpty();
32   }
33 
Pop(Message * message)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:
ConnectorTest()44   ConnectorTest() {
45   }
46 
SetUp()47   virtual void SetUp() MOJO_OVERRIDE {
48     CreateMessagePipe(NULL, &handle0_, &handle1_);
49   }
50 
TearDown()51   virtual void TearDown() MOJO_OVERRIDE {
52   }
53 
AllocMessage(const char * text,Message * message)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 
PumpMessages()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 
TEST_F(ConnectorTest,Basic)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 
TEST_F(ConnectorTest,Basic_EarlyIncomingReceiver)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 
TEST_F(ConnectorTest,Basic_TwoMessages)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 
TEST_F(ConnectorTest,WriteToClosedPipe)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 
TEST_F(ConnectorTest,MessageWithHandles)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