Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / mojo / public / bindings / tests / connector_unittest.cc
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/connector.h"
9 #include "mojo/public/bindings/lib/message_queue.h"
10 #include "mojo/public/environment/environment.h"
11 #include "mojo/public/system/macros.h"
12 #include "mojo/public/utility/run_loop.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   internal::MessageQueue queue_;
38 };
39
40 class ConnectorTest : public testing::Test {
41  public:
42   ConnectorTest() {
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     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(std::string(kText),
96             std::string(
97                 reinterpret_cast<char*>(message_received.data->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(std::string(kText),
122             std::string(
123                 reinterpret_cast<char*>(message_received.data->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(std::string(kText[i]),
151               std::string(
152                   reinterpret_cast<char*>(message_received.data->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 // Enable this test once MojoWriteMessage supports passing handles.
184 TEST_F(ConnectorTest, MessageWithHandles) {
185   internal::Connector connector0(handle0_.Pass());
186   internal::Connector connector1(handle1_.Pass());
187
188   const char kText[] = "hello world";
189
190   Message message;
191   AllocMessage(kText, &message);
192
193   ScopedMessagePipeHandle handles[2];
194   CreateMessagePipe(&handles[0], &handles[1]);
195   message.handles.push_back(handles[0].release());
196
197   connector0.Accept(&message);
198
199   // The message should have been transferred, releasing the handles.
200   EXPECT_TRUE(message.handles.empty());
201
202   MessageAccumulator accumulator;
203   connector1.set_incoming_receiver(&accumulator);
204
205   PumpMessages();
206
207   ASSERT_FALSE(accumulator.IsEmpty());
208
209   Message message_received;
210   accumulator.Pop(&message_received);
211
212   EXPECT_EQ(std::string(kText),
213             std::string(
214                 reinterpret_cast<char*>(message_received.data->payload)));
215   ASSERT_EQ(1U, message_received.handles.size());
216
217   // Now send a message to the transferred handle and confirm it's sent through
218   // to the orginal pipe.
219   // TODO(vtl): Do we need a better way of "downcasting" the handle types?
220   ScopedMessagePipeHandle smph;
221   smph.reset(MessagePipeHandle(message_received.handles[0].value()));
222   message_received.handles[0] = Handle();  // |smph| now owns this handle.
223
224   internal::Connector connector_received(smph.Pass());
225   internal::Connector connector_original(handles[1].Pass());
226
227   AllocMessage(kText, &message);
228
229   connector_received.Accept(&message);
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(std::string(kText),
238             std::string(
239                 reinterpret_cast<char*>(message_received.data->payload)));
240 }
241
242 }  // namespace test
243 }  // namespace mojo