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 <stdint.h>
6 #include <string.h>
7
8 #include <algorithm>
9 #include <memory>
10 #include <string>
11 #include <vector>
12
13 #include "base/memory/ptr_util.h"
14 #include "base/memory/ref_counted.h"
15 #include "build/build_config.h"
16 #include "mojo/core/test/mojo_test_base.h"
17 #include "mojo/core/test_utils.h"
18 #include "mojo/public/c/system/core.h"
19 #include "mojo/public/c/system/types.h"
20 #include "mojo/public/cpp/system/message_pipe.h"
21
22 namespace mojo {
23 namespace core {
24 namespace {
25
26 const MojoHandleSignals kAllSignals =
27 MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE |
28 MOJO_HANDLE_SIGNAL_PEER_CLOSED | MOJO_HANDLE_SIGNAL_PEER_REMOTE |
29 MOJO_HANDLE_SIGNAL_QUOTA_EXCEEDED;
30
31 static const char kHelloWorld[] = "hello world";
32
33 class MessagePipeTest : public test::MojoTestBase {
34 public:
MessagePipeTest()35 MessagePipeTest() {
36 CHECK_EQ(MOJO_RESULT_OK, MojoCreateMessagePipe(nullptr, &pipe0_, &pipe1_));
37 }
38
~MessagePipeTest()39 ~MessagePipeTest() override {
40 if (pipe0_ != MOJO_HANDLE_INVALID)
41 CHECK_EQ(MOJO_RESULT_OK, MojoClose(pipe0_));
42 if (pipe1_ != MOJO_HANDLE_INVALID)
43 CHECK_EQ(MOJO_RESULT_OK, MojoClose(pipe1_));
44 }
45
WriteMessage(MojoHandle message_pipe_handle,const void * bytes,uint32_t num_bytes)46 MojoResult WriteMessage(MojoHandle message_pipe_handle,
47 const void* bytes,
48 uint32_t num_bytes) {
49 return mojo::WriteMessageRaw(MessagePipeHandle(message_pipe_handle), bytes,
50 num_bytes, nullptr, 0,
51 MOJO_WRITE_MESSAGE_FLAG_NONE);
52 }
53
ReadMessage(MojoHandle message_pipe_handle,void * bytes,uint32_t * num_bytes,bool may_discard=false)54 MojoResult ReadMessage(MojoHandle message_pipe_handle,
55 void* bytes,
56 uint32_t* num_bytes,
57 bool may_discard = false) {
58 MojoMessageHandle message_handle;
59 MojoResult rv =
60 MojoReadMessage(message_pipe_handle, nullptr, &message_handle);
61 if (rv != MOJO_RESULT_OK)
62 return rv;
63
64 const uint32_t expected_num_bytes = *num_bytes;
65 void* buffer;
66 rv = MojoGetMessageData(message_handle, nullptr, &buffer, num_bytes,
67 nullptr, nullptr);
68
69 if (rv == MOJO_RESULT_RESOURCE_EXHAUSTED) {
70 CHECK(may_discard);
71 } else if (*num_bytes) {
72 CHECK_EQ(MOJO_RESULT_OK, rv);
73 CHECK_GE(expected_num_bytes, *num_bytes);
74 CHECK(bytes);
75 memcpy(bytes, buffer, *num_bytes);
76 }
77 CHECK_EQ(MOJO_RESULT_OK, MojoDestroyMessage(message_handle));
78 return rv;
79 }
80
81 MojoHandle pipe0_, pipe1_;
82
83 private:
84 DISALLOW_COPY_AND_ASSIGN(MessagePipeTest);
85 };
86
87 using FuseMessagePipeTest = test::MojoTestBase;
88
TEST_F(MessagePipeTest,WriteData)89 TEST_F(MessagePipeTest, WriteData) {
90 ASSERT_EQ(MOJO_RESULT_OK,
91 WriteMessage(pipe0_, kHelloWorld, sizeof(kHelloWorld)));
92 }
93
94 // Tests:
95 // - only default flags
96 // - reading messages from a port
97 // - when there are no/one/two messages available for that port
98 // - with buffer size 0 (and null buffer) -- should get size
99 // - with too-small buffer -- should get size
100 // - also verify that buffers aren't modified when/where they shouldn't be
101 // - writing messages to a port
102 // - in the obvious scenarios (as above)
103 // - to a port that's been closed
104 // - writing a message to a port, closing the other (would be the source) port,
105 // and reading it
TEST_F(MessagePipeTest,Basic)106 TEST_F(MessagePipeTest, Basic) {
107 int32_t buffer[2];
108 const uint32_t kBufferSize = static_cast<uint32_t>(sizeof(buffer));
109 uint32_t buffer_size;
110
111 // Nothing to read yet on port 0.
112 buffer[0] = 123;
113 buffer[1] = 456;
114 buffer_size = kBufferSize;
115 ASSERT_EQ(MOJO_RESULT_SHOULD_WAIT, ReadMessage(pipe0_, buffer, &buffer_size));
116 ASSERT_EQ(kBufferSize, buffer_size);
117 ASSERT_EQ(123, buffer[0]);
118 ASSERT_EQ(456, buffer[1]);
119
120 // Ditto for port 1.
121 buffer[0] = 123;
122 buffer[1] = 456;
123 buffer_size = kBufferSize;
124 ASSERT_EQ(MOJO_RESULT_SHOULD_WAIT, ReadMessage(pipe1_, buffer, &buffer_size));
125
126 // Write from port 1 (to port 0).
127 buffer[0] = 789012345;
128 buffer[1] = 0;
129 ASSERT_EQ(MOJO_RESULT_OK, WriteMessage(pipe1_, buffer, sizeof(buffer[0])));
130
131 MojoHandleSignalsState state;
132 ASSERT_EQ(MOJO_RESULT_OK,
133 WaitForSignals(pipe0_, MOJO_HANDLE_SIGNAL_READABLE, &state));
134
135 // Read from port 0.
136 buffer[0] = 123;
137 buffer[1] = 456;
138 buffer_size = kBufferSize;
139 ASSERT_EQ(MOJO_RESULT_OK, ReadMessage(pipe0_, buffer, &buffer_size));
140 ASSERT_EQ(static_cast<uint32_t>(sizeof(buffer[0])), buffer_size);
141 ASSERT_EQ(789012345, buffer[0]);
142 ASSERT_EQ(456, buffer[1]);
143
144 // Read again from port 0 -- it should be empty.
145 buffer_size = kBufferSize;
146 ASSERT_EQ(MOJO_RESULT_SHOULD_WAIT, ReadMessage(pipe0_, buffer, &buffer_size));
147
148 // Write two messages from port 0 (to port 1).
149 buffer[0] = 123456789;
150 buffer[1] = 0;
151 ASSERT_EQ(MOJO_RESULT_OK, WriteMessage(pipe0_, buffer, sizeof(buffer[0])));
152 buffer[0] = 234567890;
153 buffer[1] = 0;
154 ASSERT_EQ(MOJO_RESULT_OK, WriteMessage(pipe0_, buffer, sizeof(buffer[0])));
155
156 ASSERT_EQ(MOJO_RESULT_OK,
157 WaitForSignals(pipe1_, MOJO_HANDLE_SIGNAL_READABLE, &state));
158
159 // Read from port 1.
160 buffer[0] = 123;
161 buffer[1] = 456;
162 buffer_size = kBufferSize;
163 ASSERT_EQ(MOJO_RESULT_OK, ReadMessage(pipe1_, buffer, &buffer_size));
164 ASSERT_EQ(static_cast<uint32_t>(sizeof(buffer[0])), buffer_size);
165 ASSERT_EQ(123456789, buffer[0]);
166 ASSERT_EQ(456, buffer[1]);
167
168 ASSERT_EQ(MOJO_RESULT_OK,
169 WaitForSignals(pipe1_, MOJO_HANDLE_SIGNAL_READABLE, &state));
170
171 // Read again from port 1.
172 buffer[0] = 123;
173 buffer[1] = 456;
174 buffer_size = kBufferSize;
175 ASSERT_EQ(MOJO_RESULT_OK, ReadMessage(pipe1_, buffer, &buffer_size));
176 ASSERT_EQ(static_cast<uint32_t>(sizeof(buffer[0])), buffer_size);
177 ASSERT_EQ(234567890, buffer[0]);
178 ASSERT_EQ(456, buffer[1]);
179
180 // Read again from port 1 -- it should be empty.
181 buffer_size = kBufferSize;
182 ASSERT_EQ(MOJO_RESULT_SHOULD_WAIT, ReadMessage(pipe1_, buffer, &buffer_size));
183
184 // Write from port 0 (to port 1).
185 buffer[0] = 345678901;
186 buffer[1] = 0;
187 ASSERT_EQ(MOJO_RESULT_OK, WriteMessage(pipe0_, buffer, sizeof(buffer[0])));
188
189 // Close port 0.
190 MojoClose(pipe0_);
191 pipe0_ = MOJO_HANDLE_INVALID;
192
193 ASSERT_EQ(MOJO_RESULT_OK,
194 WaitForSignals(pipe1_, MOJO_HANDLE_SIGNAL_PEER_CLOSED, &state));
195
196 // Try to write from port 1 (to port 0).
197 buffer[0] = 456789012;
198 buffer[1] = 0;
199 ASSERT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
200 WriteMessage(pipe1_, buffer, sizeof(buffer[0])));
201
202 // Read from port 1; should still get message (even though port 0 was closed).
203 buffer[0] = 123;
204 buffer[1] = 456;
205 buffer_size = kBufferSize;
206 ASSERT_EQ(MOJO_RESULT_OK, ReadMessage(pipe1_, buffer, &buffer_size));
207 ASSERT_EQ(static_cast<uint32_t>(sizeof(buffer[0])), buffer_size);
208 ASSERT_EQ(345678901, buffer[0]);
209 ASSERT_EQ(456, buffer[1]);
210
211 // Read again from port 1 -- it should be empty (and port 0 is closed).
212 buffer_size = kBufferSize;
213 ASSERT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
214 ReadMessage(pipe1_, buffer, &buffer_size));
215 }
216
TEST_F(MessagePipeTest,CloseWithQueuedIncomingMessages)217 TEST_F(MessagePipeTest, CloseWithQueuedIncomingMessages) {
218 int32_t buffer[1];
219 const uint32_t kBufferSize = static_cast<uint32_t>(sizeof(buffer));
220 uint32_t buffer_size;
221
222 // Write some messages from port 1 (to port 0).
223 for (int32_t i = 0; i < 5; i++) {
224 buffer[0] = i;
225 ASSERT_EQ(MOJO_RESULT_OK, WriteMessage(pipe1_, buffer, kBufferSize));
226 }
227
228 MojoHandleSignalsState state;
229 ASSERT_EQ(MOJO_RESULT_OK,
230 WaitForSignals(pipe0_, MOJO_HANDLE_SIGNAL_READABLE, &state));
231
232 // Port 0 shouldn't be empty.
233 buffer_size = kBufferSize;
234 ASSERT_EQ(MOJO_RESULT_OK, ReadMessage(pipe0_, buffer, &buffer_size));
235 ASSERT_EQ(kBufferSize, buffer_size);
236
237 // Close port 0 first, which should have outstanding (incoming) messages.
238 MojoClose(pipe0_);
239 MojoClose(pipe1_);
240 pipe0_ = pipe1_ = MOJO_HANDLE_INVALID;
241 }
242
TEST_F(MessagePipeTest,BasicWaiting)243 TEST_F(MessagePipeTest, BasicWaiting) {
244 MojoHandleSignalsState hss;
245
246 int32_t buffer[1];
247 const uint32_t kBufferSize = static_cast<uint32_t>(sizeof(buffer));
248 uint32_t buffer_size;
249
250 // Always writable (until the other port is closed). Not yet readable. Peer
251 // not closed.
252 hss = GetSignalsState(pipe0_);
253 ASSERT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals);
254 ASSERT_EQ(kAllSignals, hss.satisfiable_signals);
255 hss = MojoHandleSignalsState();
256
257 // Write from port 0 (to port 1), to make port 1 readable.
258 buffer[0] = 123456789;
259 ASSERT_EQ(MOJO_RESULT_OK, WriteMessage(pipe0_, buffer, kBufferSize));
260
261 // Port 1 should already be readable now.
262 ASSERT_EQ(MOJO_RESULT_OK,
263 WaitForSignals(pipe1_, MOJO_HANDLE_SIGNAL_READABLE, &hss));
264 ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE,
265 hss.satisfied_signals);
266 ASSERT_EQ(kAllSignals, hss.satisfiable_signals);
267 // ... and still writable.
268 hss = MojoHandleSignalsState();
269 ASSERT_EQ(MOJO_RESULT_OK,
270 WaitForSignals(pipe1_, MOJO_HANDLE_SIGNAL_WRITABLE, &hss));
271 ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE,
272 hss.satisfied_signals);
273 ASSERT_EQ(kAllSignals, hss.satisfiable_signals);
274
275 // Close port 0.
276 MojoClose(pipe0_);
277 pipe0_ = MOJO_HANDLE_INVALID;
278
279 // Port 1 should be signaled with peer closed.
280 hss = MojoHandleSignalsState();
281 ASSERT_EQ(MOJO_RESULT_OK,
282 WaitForSignals(pipe1_, MOJO_HANDLE_SIGNAL_PEER_CLOSED, &hss));
283 ASSERT_TRUE(hss.satisfied_signals & MOJO_HANDLE_SIGNAL_PEER_CLOSED);
284 ASSERT_TRUE(hss.satisfiable_signals & MOJO_HANDLE_SIGNAL_PEER_CLOSED);
285
286 // Port 1 should not be writable now or ever again.
287 hss = MojoHandleSignalsState();
288
289 ASSERT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
290 WaitForSignals(pipe1_, MOJO_HANDLE_SIGNAL_WRITABLE, &hss));
291 ASSERT_FALSE(hss.satisfied_signals & MOJO_HANDLE_SIGNAL_WRITABLE);
292 ASSERT_FALSE(hss.satisfiable_signals & MOJO_HANDLE_SIGNAL_WRITABLE);
293
294 // But it should still be readable.
295 hss = MojoHandleSignalsState();
296 ASSERT_EQ(MOJO_RESULT_OK,
297 WaitForSignals(pipe1_, MOJO_HANDLE_SIGNAL_READABLE, &hss));
298 ASSERT_TRUE(hss.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE);
299 ASSERT_TRUE(hss.satisfiable_signals & MOJO_HANDLE_SIGNAL_READABLE);
300
301 // Read from port 1.
302 buffer[0] = 0;
303 buffer_size = kBufferSize;
304 ASSERT_EQ(MOJO_RESULT_OK, ReadMessage(pipe1_, buffer, &buffer_size));
305 ASSERT_EQ(123456789, buffer[0]);
306
307 // Now port 1 should no longer be readable.
308 hss = MojoHandleSignalsState();
309 ASSERT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
310 WaitForSignals(pipe1_, MOJO_HANDLE_SIGNAL_READABLE, &hss));
311 ASSERT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals);
312 ASSERT_FALSE(hss.satisfiable_signals & MOJO_HANDLE_SIGNAL_READABLE);
313 ASSERT_FALSE(hss.satisfiable_signals & MOJO_HANDLE_SIGNAL_WRITABLE);
314 }
315
316 #if !defined(OS_IOS)
317
318 const size_t kPingPongHandlesPerIteration = 30;
319 const size_t kPingPongIterations = 500;
320
DEFINE_TEST_CLIENT_TEST_WITH_PIPE(HandlePingPong,MessagePipeTest,h)321 DEFINE_TEST_CLIENT_TEST_WITH_PIPE(HandlePingPong, MessagePipeTest, h) {
322 // Waits for a handle to become readable and writes it back to the sender.
323 for (size_t i = 0; i < kPingPongIterations; i++) {
324 MojoHandle handles[kPingPongHandlesPerIteration];
325 ReadMessageWithHandles(h, handles, kPingPongHandlesPerIteration);
326 WriteMessageWithHandles(h, "", handles, kPingPongHandlesPerIteration);
327 }
328
329 EXPECT_EQ(MOJO_RESULT_OK, WaitForSignals(h, MOJO_HANDLE_SIGNAL_READABLE));
330 char msg[4];
331 uint32_t num_bytes = 4;
332 EXPECT_EQ(MOJO_RESULT_OK, ReadMessage(h, msg, &num_bytes));
333 }
334
335 // This test is flaky: http://crbug.com/585784
TEST_F(MessagePipeTest,DISABLED_DataPipeConsumerHandlePingPong)336 TEST_F(MessagePipeTest, DISABLED_DataPipeConsumerHandlePingPong) {
337 MojoHandle p, c[kPingPongHandlesPerIteration];
338 for (size_t i = 0; i < kPingPongHandlesPerIteration; ++i) {
339 EXPECT_EQ(MOJO_RESULT_OK, MojoCreateDataPipe(nullptr, &p, &c[i]));
340 MojoClose(p);
341 }
342
343 RunTestClient("HandlePingPong", [&](MojoHandle h) {
344 for (size_t i = 0; i < kPingPongIterations; i++) {
345 WriteMessageWithHandles(h, "", c, kPingPongHandlesPerIteration);
346 ReadMessageWithHandles(h, c, kPingPongHandlesPerIteration);
347 }
348 WriteMessage(h, "quit", 4);
349 });
350 for (size_t i = 0; i < kPingPongHandlesPerIteration; ++i)
351 MojoClose(c[i]);
352 }
353
354 // This test is flaky: http://crbug.com/585784
TEST_F(MessagePipeTest,DISABLED_DataPipeProducerHandlePingPong)355 TEST_F(MessagePipeTest, DISABLED_DataPipeProducerHandlePingPong) {
356 MojoHandle p[kPingPongHandlesPerIteration], c;
357 for (size_t i = 0; i < kPingPongHandlesPerIteration; ++i) {
358 EXPECT_EQ(MOJO_RESULT_OK, MojoCreateDataPipe(nullptr, &p[i], &c));
359 MojoClose(c);
360 }
361
362 RunTestClient("HandlePingPong", [&](MojoHandle h) {
363 for (size_t i = 0; i < kPingPongIterations; i++) {
364 WriteMessageWithHandles(h, "", p, kPingPongHandlesPerIteration);
365 ReadMessageWithHandles(h, p, kPingPongHandlesPerIteration);
366 }
367 WriteMessage(h, "quit", 4);
368 });
369 for (size_t i = 0; i < kPingPongHandlesPerIteration; ++i)
370 MojoClose(p[i]);
371 }
372
TEST_F(MessagePipeTest,SharedBufferHandlePingPong)373 TEST_F(MessagePipeTest, SharedBufferHandlePingPong) {
374 MojoHandle buffers[kPingPongHandlesPerIteration];
375 for (size_t i = 0; i < kPingPongHandlesPerIteration; ++i)
376 EXPECT_EQ(MOJO_RESULT_OK, MojoCreateSharedBuffer(1, nullptr, &buffers[i]));
377
378 RunTestClient("HandlePingPong", [&](MojoHandle h) {
379 for (size_t i = 0; i < kPingPongIterations; i++) {
380 WriteMessageWithHandles(h, "", buffers, kPingPongHandlesPerIteration);
381 ReadMessageWithHandles(h, buffers, kPingPongHandlesPerIteration);
382 }
383 WriteMessage(h, "quit", 4);
384 });
385 for (size_t i = 0; i < kPingPongHandlesPerIteration; ++i)
386 MojoClose(buffers[i]);
387 }
388
389 #endif // !defined(OS_IOS)
390
TEST_F(FuseMessagePipeTest,Basic)391 TEST_F(FuseMessagePipeTest, Basic) {
392 // Test that we can fuse pipes and they still work.
393
394 MojoHandle a, b, c, d;
395 CreateMessagePipe(&a, &b);
396 CreateMessagePipe(&c, &d);
397
398 EXPECT_EQ(MOJO_RESULT_OK, MojoFuseMessagePipes(b, c, nullptr));
399
400 // Handles b and c should be closed.
401 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(b));
402 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(c));
403
404 const std::string kTestMessage1 = "Hello, world!";
405 const std::string kTestMessage2 = "Goodbye, world!";
406
407 WriteMessage(a, kTestMessage1);
408 EXPECT_EQ(kTestMessage1, ReadMessage(d));
409
410 WriteMessage(d, kTestMessage2);
411 EXPECT_EQ(kTestMessage2, ReadMessage(a));
412
413 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a));
414 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(d));
415 }
416
TEST_F(FuseMessagePipeTest,FuseAfterPeerWrite)417 TEST_F(FuseMessagePipeTest, FuseAfterPeerWrite) {
418 // Test that messages written before fusion are eventually delivered.
419
420 MojoHandle a, b, c, d;
421 CreateMessagePipe(&a, &b);
422 CreateMessagePipe(&c, &d);
423
424 const std::string kTestMessage1 = "Hello, world!";
425 const std::string kTestMessage2 = "Goodbye, world!";
426 WriteMessage(a, kTestMessage1);
427 WriteMessage(d, kTestMessage2);
428
429 EXPECT_EQ(MOJO_RESULT_OK, MojoFuseMessagePipes(b, c, nullptr));
430
431 // Handles b and c should be closed.
432 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(b));
433 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(c));
434
435 EXPECT_EQ(kTestMessage1, ReadMessage(d));
436 EXPECT_EQ(kTestMessage2, ReadMessage(a));
437
438 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a));
439 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(d));
440 }
441
TEST_F(FuseMessagePipeTest,NoFuseAfterWrite)442 TEST_F(FuseMessagePipeTest, NoFuseAfterWrite) {
443 // Test that a pipe endpoint which has been written to cannot be fused.
444
445 MojoHandle a, b, c, d;
446 CreateMessagePipe(&a, &b);
447 CreateMessagePipe(&c, &d);
448
449 WriteMessage(b, "shouldn't have done that!");
450 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
451 MojoFuseMessagePipes(b, c, nullptr));
452
453 // Handles b and c should be closed.
454 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(b));
455 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(c));
456
457 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a));
458 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(d));
459 }
460
TEST_F(FuseMessagePipeTest,NoFuseSelf)461 TEST_F(FuseMessagePipeTest, NoFuseSelf) {
462 // Test that a pipe's own endpoints can't be fused together.
463
464 MojoHandle a, b;
465 CreateMessagePipe(&a, &b);
466
467 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
468 MojoFuseMessagePipes(a, b, nullptr));
469
470 // Handles a and b should be closed.
471 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(a));
472 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(b));
473 }
474
TEST_F(FuseMessagePipeTest,FuseInvalidArguments)475 TEST_F(FuseMessagePipeTest, FuseInvalidArguments) {
476 MojoHandle a, b, c, d;
477 CreateMessagePipe(&a, &b);
478 CreateMessagePipe(&c, &d);
479
480 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b));
481
482 // Can't fuse an invalid handle.
483 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoFuseMessagePipes(b, c, nullptr));
484
485 // Handle c should be closed.
486 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(c));
487
488 // Can't fuse a non-message pipe handle.
489 MojoHandle e, f;
490 CreateDataPipe(&e, &f, 16);
491
492 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoFuseMessagePipes(e, d, nullptr));
493
494 // Handles d and e should be closed.
495 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(d));
496 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(e));
497
498 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a));
499 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(f));
500 }
501
TEST_F(FuseMessagePipeTest,FuseAfterPeerClosure)502 TEST_F(FuseMessagePipeTest, FuseAfterPeerClosure) {
503 // Test that peer closure prior to fusion can still be detected after fusion.
504
505 MojoHandle a, b, c, d;
506 CreateMessagePipe(&a, &b);
507 CreateMessagePipe(&c, &d);
508
509 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a));
510 EXPECT_EQ(MOJO_RESULT_OK, MojoFuseMessagePipes(b, c, nullptr));
511
512 // Handles b and c should be closed.
513 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(b));
514 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(c));
515
516 EXPECT_EQ(MOJO_RESULT_OK, WaitForSignals(d, MOJO_HANDLE_SIGNAL_PEER_CLOSED));
517 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(d));
518 }
519
TEST_F(FuseMessagePipeTest,FuseAfterPeerWriteAndClosure)520 TEST_F(FuseMessagePipeTest, FuseAfterPeerWriteAndClosure) {
521 // Test that peer write and closure prior to fusion still results in the
522 // both message arrival and awareness of peer closure.
523
524 MojoHandle a, b, c, d;
525 CreateMessagePipe(&a, &b);
526 CreateMessagePipe(&c, &d);
527
528 const std::string kTestMessage = "ayyy lmao";
529 WriteMessage(a, kTestMessage);
530 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a));
531
532 EXPECT_EQ(MOJO_RESULT_OK, MojoFuseMessagePipes(b, c, nullptr));
533
534 // Handles b and c should be closed.
535 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(b));
536 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(c));
537
538 EXPECT_EQ(kTestMessage, ReadMessage(d));
539 EXPECT_EQ(MOJO_RESULT_OK, WaitForSignals(d, MOJO_HANDLE_SIGNAL_PEER_CLOSED));
540 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(d));
541 }
542
TEST_F(MessagePipeTest,ClosePipesStressTest)543 TEST_F(MessagePipeTest, ClosePipesStressTest) {
544 // Stress test to exercise https://crbug.com/665869.
545 const size_t kNumPipes = 100000;
546 for (size_t i = 0; i < kNumPipes; ++i) {
547 MojoHandle a, b;
548 CreateMessagePipe(&a, &b);
549 MojoClose(a);
550 MojoClose(b);
551 }
552 }
553
554 } // namespace
555 } // namespace core
556 } // namespace mojo
557