OLD | NEW |
| (Empty) |
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 bool Accept(Message* message) override { | |
25 queue_.Push(message); | |
26 return true; | |
27 } | |
28 | |
29 bool IsEmpty() const { return queue_.IsEmpty(); } | |
30 | |
31 void Pop(Message* message) { queue_.Pop(message); } | |
32 | |
33 private: | |
34 internal::MessageQueue queue_; | |
35 }; | |
36 | |
37 class ConnectorDeletingMessageAccumulator : public MessageAccumulator { | |
38 public: | |
39 ConnectorDeletingMessageAccumulator(internal::Connector** connector) | |
40 : connector_(connector) {} | |
41 | |
42 bool Accept(Message* message) override { | |
43 delete *connector_; | |
44 *connector_ = 0; | |
45 return MessageAccumulator::Accept(message); | |
46 } | |
47 | |
48 private: | |
49 internal::Connector** connector_; | |
50 }; | |
51 | |
52 class ReentrantMessageAccumulator : public MessageAccumulator { | |
53 public: | |
54 ReentrantMessageAccumulator(internal::Connector* connector) | |
55 : connector_(connector), number_of_calls_(0) {} | |
56 | |
57 bool Accept(Message* message) override { | |
58 if (!MessageAccumulator::Accept(message)) | |
59 return false; | |
60 number_of_calls_++; | |
61 if (number_of_calls_ == 1) { | |
62 return connector_->WaitForIncomingMessage(); | |
63 } | |
64 return true; | |
65 } | |
66 | |
67 int number_of_calls() { return number_of_calls_; } | |
68 | |
69 private: | |
70 internal::Connector* connector_; | |
71 int number_of_calls_; | |
72 }; | |
73 | |
74 class ConnectorTest : public testing::Test { | |
75 public: | |
76 ConnectorTest() {} | |
77 | |
78 void SetUp() override { | |
79 CreateMessagePipe(nullptr, &handle0_, &handle1_); | |
80 } | |
81 | |
82 void TearDown() override {} | |
83 | |
84 void AllocMessage(const char* text, Message* message) { | |
85 size_t payload_size = strlen(text) + 1; // Plus null terminator. | |
86 internal::MessageBuilder builder(1, payload_size); | |
87 memcpy(builder.buffer()->Allocate(payload_size), text, payload_size); | |
88 builder.Finish(message); | |
89 } | |
90 | |
91 void PumpMessages() { loop_.RunUntilIdle(); } | |
92 | |
93 protected: | |
94 ScopedMessagePipeHandle handle0_; | |
95 ScopedMessagePipeHandle handle1_; | |
96 | |
97 private: | |
98 Environment env_; | |
99 RunLoop loop_; | |
100 }; | |
101 | |
102 TEST_F(ConnectorTest, Basic) { | |
103 internal::Connector connector0(handle0_.Pass()); | |
104 internal::Connector connector1(handle1_.Pass()); | |
105 | |
106 const char kText[] = "hello world"; | |
107 | |
108 Message message; | |
109 AllocMessage(kText, &message); | |
110 | |
111 connector0.Accept(&message); | |
112 | |
113 MessageAccumulator accumulator; | |
114 connector1.set_incoming_receiver(&accumulator); | |
115 | |
116 PumpMessages(); | |
117 | |
118 ASSERT_FALSE(accumulator.IsEmpty()); | |
119 | |
120 Message message_received; | |
121 accumulator.Pop(&message_received); | |
122 | |
123 EXPECT_EQ( | |
124 std::string(kText), | |
125 std::string(reinterpret_cast<const char*>(message_received.payload()))); | |
126 } | |
127 | |
128 TEST_F(ConnectorTest, Basic_Synchronous) { | |
129 internal::Connector connector0(handle0_.Pass()); | |
130 internal::Connector connector1(handle1_.Pass()); | |
131 | |
132 const char kText[] = "hello world"; | |
133 | |
134 Message message; | |
135 AllocMessage(kText, &message); | |
136 | |
137 connector0.Accept(&message); | |
138 | |
139 MessageAccumulator accumulator; | |
140 connector1.set_incoming_receiver(&accumulator); | |
141 | |
142 connector1.WaitForIncomingMessage(); | |
143 | |
144 ASSERT_FALSE(accumulator.IsEmpty()); | |
145 | |
146 Message message_received; | |
147 accumulator.Pop(&message_received); | |
148 | |
149 EXPECT_EQ( | |
150 std::string(kText), | |
151 std::string(reinterpret_cast<const char*>(message_received.payload()))); | |
152 } | |
153 | |
154 TEST_F(ConnectorTest, Basic_EarlyIncomingReceiver) { | |
155 internal::Connector connector0(handle0_.Pass()); | |
156 internal::Connector connector1(handle1_.Pass()); | |
157 | |
158 MessageAccumulator accumulator; | |
159 connector1.set_incoming_receiver(&accumulator); | |
160 | |
161 const char kText[] = "hello world"; | |
162 | |
163 Message message; | |
164 AllocMessage(kText, &message); | |
165 | |
166 connector0.Accept(&message); | |
167 | |
168 PumpMessages(); | |
169 | |
170 ASSERT_FALSE(accumulator.IsEmpty()); | |
171 | |
172 Message message_received; | |
173 accumulator.Pop(&message_received); | |
174 | |
175 EXPECT_EQ( | |
176 std::string(kText), | |
177 std::string(reinterpret_cast<const char*>(message_received.payload()))); | |
178 } | |
179 | |
180 TEST_F(ConnectorTest, Basic_TwoMessages) { | |
181 internal::Connector connector0(handle0_.Pass()); | |
182 internal::Connector connector1(handle1_.Pass()); | |
183 | |
184 const char* kText[] = {"hello", "world"}; | |
185 | |
186 for (size_t i = 0; i < MOJO_ARRAYSIZE(kText); ++i) { | |
187 Message message; | |
188 AllocMessage(kText[i], &message); | |
189 | |
190 connector0.Accept(&message); | |
191 } | |
192 | |
193 MessageAccumulator accumulator; | |
194 connector1.set_incoming_receiver(&accumulator); | |
195 | |
196 PumpMessages(); | |
197 | |
198 for (size_t i = 0; i < MOJO_ARRAYSIZE(kText); ++i) { | |
199 ASSERT_FALSE(accumulator.IsEmpty()); | |
200 | |
201 Message message_received; | |
202 accumulator.Pop(&message_received); | |
203 | |
204 EXPECT_EQ( | |
205 std::string(kText[i]), | |
206 std::string(reinterpret_cast<const char*>(message_received.payload()))); | |
207 } | |
208 } | |
209 | |
210 TEST_F(ConnectorTest, Basic_TwoMessages_Synchronous) { | |
211 internal::Connector connector0(handle0_.Pass()); | |
212 internal::Connector connector1(handle1_.Pass()); | |
213 | |
214 const char* kText[] = {"hello", "world"}; | |
215 | |
216 for (size_t i = 0; i < MOJO_ARRAYSIZE(kText); ++i) { | |
217 Message message; | |
218 AllocMessage(kText[i], &message); | |
219 | |
220 connector0.Accept(&message); | |
221 } | |
222 | |
223 MessageAccumulator accumulator; | |
224 connector1.set_incoming_receiver(&accumulator); | |
225 | |
226 connector1.WaitForIncomingMessage(); | |
227 | |
228 ASSERT_FALSE(accumulator.IsEmpty()); | |
229 | |
230 Message message_received; | |
231 accumulator.Pop(&message_received); | |
232 | |
233 EXPECT_EQ( | |
234 std::string(kText[0]), | |
235 std::string(reinterpret_cast<const char*>(message_received.payload()))); | |
236 | |
237 ASSERT_TRUE(accumulator.IsEmpty()); | |
238 } | |
239 | |
240 TEST_F(ConnectorTest, WriteToClosedPipe) { | |
241 internal::Connector connector0(handle0_.Pass()); | |
242 | |
243 const char kText[] = "hello world"; | |
244 | |
245 Message message; | |
246 AllocMessage(kText, &message); | |
247 | |
248 // Close the other end of the pipe. | |
249 handle1_.reset(); | |
250 | |
251 // Not observed yet because we haven't spun the RunLoop yet. | |
252 EXPECT_FALSE(connector0.encountered_error()); | |
253 | |
254 // Write failures are not reported. | |
255 bool ok = connector0.Accept(&message); | |
256 EXPECT_TRUE(ok); | |
257 | |
258 // Still not observed. | |
259 EXPECT_FALSE(connector0.encountered_error()); | |
260 | |
261 // Spin the RunLoop, and then we should start observing the closed pipe. | |
262 PumpMessages(); | |
263 | |
264 EXPECT_TRUE(connector0.encountered_error()); | |
265 } | |
266 | |
267 TEST_F(ConnectorTest, MessageWithHandles) { | |
268 internal::Connector connector0(handle0_.Pass()); | |
269 internal::Connector connector1(handle1_.Pass()); | |
270 | |
271 const char kText[] = "hello world"; | |
272 | |
273 Message message1; | |
274 AllocMessage(kText, &message1); | |
275 | |
276 MessagePipe pipe; | |
277 message1.mutable_handles()->push_back(pipe.handle0.release()); | |
278 | |
279 connector0.Accept(&message1); | |
280 | |
281 // The message should have been transferred, releasing the handles. | |
282 EXPECT_TRUE(message1.handles()->empty()); | |
283 | |
284 MessageAccumulator accumulator; | |
285 connector1.set_incoming_receiver(&accumulator); | |
286 | |
287 PumpMessages(); | |
288 | |
289 ASSERT_FALSE(accumulator.IsEmpty()); | |
290 | |
291 Message message_received; | |
292 accumulator.Pop(&message_received); | |
293 | |
294 EXPECT_EQ( | |
295 std::string(kText), | |
296 std::string(reinterpret_cast<const char*>(message_received.payload()))); | |
297 ASSERT_EQ(1U, message_received.handles()->size()); | |
298 | |
299 // Now send a message to the transferred handle and confirm it's sent through | |
300 // to the orginal pipe. | |
301 // TODO(vtl): Do we need a better way of "downcasting" the handle types? | |
302 ScopedMessagePipeHandle smph; | |
303 smph.reset(MessagePipeHandle(message_received.handles()->front().value())); | |
304 message_received.mutable_handles()->front() = Handle(); | |
305 // |smph| now owns this handle. | |
306 | |
307 internal::Connector connector_received(smph.Pass()); | |
308 internal::Connector connector_original(pipe.handle1.Pass()); | |
309 | |
310 Message message2; | |
311 AllocMessage(kText, &message2); | |
312 | |
313 connector_received.Accept(&message2); | |
314 connector_original.set_incoming_receiver(&accumulator); | |
315 PumpMessages(); | |
316 | |
317 ASSERT_FALSE(accumulator.IsEmpty()); | |
318 | |
319 accumulator.Pop(&message_received); | |
320 | |
321 EXPECT_EQ( | |
322 std::string(kText), | |
323 std::string(reinterpret_cast<const char*>(message_received.payload()))); | |
324 } | |
325 | |
326 TEST_F(ConnectorTest, WaitForIncomingMessageWithError) { | |
327 internal::Connector connector0(handle0_.Pass()); | |
328 // Close the other end of the pipe. | |
329 handle1_.reset(); | |
330 ASSERT_FALSE(connector0.WaitForIncomingMessage()); | |
331 } | |
332 | |
333 TEST_F(ConnectorTest, WaitForIncomingMessageWithDeletion) { | |
334 internal::Connector connector0(handle0_.Pass()); | |
335 internal::Connector* connector1 = new internal::Connector(handle1_.Pass()); | |
336 | |
337 const char kText[] = "hello world"; | |
338 | |
339 Message message; | |
340 AllocMessage(kText, &message); | |
341 | |
342 connector0.Accept(&message); | |
343 | |
344 ConnectorDeletingMessageAccumulator accumulator(&connector1); | |
345 connector1->set_incoming_receiver(&accumulator); | |
346 | |
347 connector1->WaitForIncomingMessage(); | |
348 | |
349 ASSERT_FALSE(connector1); | |
350 ASSERT_FALSE(accumulator.IsEmpty()); | |
351 | |
352 Message message_received; | |
353 accumulator.Pop(&message_received); | |
354 | |
355 EXPECT_EQ( | |
356 std::string(kText), | |
357 std::string(reinterpret_cast<const char*>(message_received.payload()))); | |
358 } | |
359 | |
360 TEST_F(ConnectorTest, WaitForIncomingMessageWithReentrancy) { | |
361 internal::Connector connector0(handle0_.Pass()); | |
362 internal::Connector connector1(handle1_.Pass()); | |
363 | |
364 const char* kText[] = {"hello", "world"}; | |
365 | |
366 for (size_t i = 0; i < MOJO_ARRAYSIZE(kText); ++i) { | |
367 Message message; | |
368 AllocMessage(kText[i], &message); | |
369 | |
370 connector0.Accept(&message); | |
371 } | |
372 | |
373 ReentrantMessageAccumulator accumulator(&connector1); | |
374 connector1.set_incoming_receiver(&accumulator); | |
375 | |
376 PumpMessages(); | |
377 | |
378 for (size_t i = 0; i < MOJO_ARRAYSIZE(kText); ++i) { | |
379 ASSERT_FALSE(accumulator.IsEmpty()); | |
380 | |
381 Message message_received; | |
382 accumulator.Pop(&message_received); | |
383 | |
384 EXPECT_EQ( | |
385 std::string(kText[i]), | |
386 std::string(reinterpret_cast<const char*>(message_received.payload()))); | |
387 } | |
388 | |
389 ASSERT_EQ(2, accumulator.number_of_calls()); | |
390 } | |
391 | |
392 } // namespace | |
393 } // namespace test | |
394 } // namespace mojo | |
OLD | NEW |