Upstream version 11.39.266.0
[platform/framework/web/crosswalk.git] / src / mojo / embedder / embedder_unittest.cc
1 // Copyright 2014 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 "mojo/embedder/embedder.h"
6
7 #include <string.h>
8
9 #include "base/bind.h"
10 #include "base/location.h"
11 #include "base/logging.h"
12 #include "base/macros.h"
13 #include "base/message_loop/message_loop.h"
14 #include "base/synchronization/waitable_event.h"
15 #include "base/test/test_io_thread.h"
16 #include "mojo/common/test/multiprocess_test_helper.h"
17 #include "mojo/embedder/platform_channel_pair.h"
18 #include "mojo/embedder/test_embedder.h"
19 #include "mojo/public/c/system/core.h"
20 #include "mojo/system/test_utils.h"
21 #include "testing/gtest/include/gtest/gtest.h"
22
23 namespace mojo {
24 namespace embedder {
25 namespace {
26
27 class ScopedTestChannel {
28  public:
29   // Creates a channel that lives on a given I/O thread (determined by the given
30   // |TaskRunner|) attached to the given |platform_handle|. After construction,
31   // |bootstrap_message_pipe()| gives the Mojo handle for the bootstrap message
32   // pipe on this channel; it is up to the caller to close this handle.
33   // Note: The I/O thread must outlive this object (and its message loop must
34   // continue pumping messages while this object is alive).
35   ScopedTestChannel(scoped_refptr<base::TaskRunner> io_thread_task_runner,
36                     ScopedPlatformHandle platform_handle)
37       : io_thread_task_runner_(io_thread_task_runner),
38         bootstrap_message_pipe_(MOJO_HANDLE_INVALID),
39         did_create_channel_event_(true, false),
40         channel_info_(nullptr) {
41     bootstrap_message_pipe_ =
42         CreateChannel(platform_handle.Pass(),
43                       io_thread_task_runner_,
44                       base::Bind(&ScopedTestChannel::DidCreateChannel,
45                                  base::Unretained(this)),
46                       nullptr)
47             .release()
48             .value();
49     CHECK_NE(bootstrap_message_pipe_, MOJO_HANDLE_INVALID);
50   }
51
52   // Destructor: Shuts down the channel. (As noted above, for this to happen,
53   // the I/O thread must be alive and pumping messages.)
54   ~ScopedTestChannel() {
55     system::test::PostTaskAndWait(
56         io_thread_task_runner_,
57         FROM_HERE,
58         base::Bind(&ScopedTestChannel::DestroyChannel, base::Unretained(this)));
59   }
60
61   // Waits for channel creation to be completed.
62   void WaitForChannelCreationCompletion() { did_create_channel_event_.Wait(); }
63
64   MojoHandle bootstrap_message_pipe() const { return bootstrap_message_pipe_; }
65
66   // Call only after |WaitForChannelCreationCompletion()|. Use only to check
67   // that it's not null.
68   const ChannelInfo* channel_info() const { return channel_info_; }
69
70  private:
71   void DidCreateChannel(ChannelInfo* channel_info) {
72     CHECK(channel_info);
73     CHECK(!channel_info_);
74     channel_info_ = channel_info;
75     did_create_channel_event_.Signal();
76   }
77
78   void DestroyChannel() {
79     CHECK(channel_info_);
80     DestroyChannelOnIOThread(channel_info_);
81     channel_info_ = nullptr;
82   }
83
84   scoped_refptr<base::TaskRunner> io_thread_task_runner_;
85
86   // Valid from creation until whenever it gets closed (by the "owner" of this
87   // object).
88   // Note: We don't want use the C++ wrappers here, since we want to test the
89   // API at the lowest level.
90   MojoHandle bootstrap_message_pipe_;
91
92   // Set after channel creation has been completed (i.e., the callback to
93   // |CreateChannel()| has been called).
94   base::WaitableEvent did_create_channel_event_;
95
96   // Valid after channel creation completion until destruction.
97   ChannelInfo* channel_info_;
98
99   DISALLOW_COPY_AND_ASSIGN(ScopedTestChannel);
100 };
101
102 class EmbedderTest : public testing::Test {
103  public:
104   EmbedderTest() : test_io_thread_(base::TestIOThread::kAutoStart) {}
105   virtual ~EmbedderTest() {}
106
107  protected:
108   base::TestIOThread* test_io_thread() { return &test_io_thread_; }
109
110  private:
111   base::TestIOThread test_io_thread_;
112
113   DISALLOW_COPY_AND_ASSIGN(EmbedderTest);
114 };
115
116 TEST_F(EmbedderTest, ChannelsBasic) {
117   mojo::embedder::test::InitWithSimplePlatformSupport();
118
119   {
120     PlatformChannelPair channel_pair;
121     ScopedTestChannel server_channel(test_io_thread()->task_runner(),
122                                      channel_pair.PassServerHandle());
123     MojoHandle server_mp = server_channel.bootstrap_message_pipe();
124     EXPECT_NE(server_mp, MOJO_HANDLE_INVALID);
125     ScopedTestChannel client_channel(test_io_thread()->task_runner(),
126                                      channel_pair.PassClientHandle());
127     MojoHandle client_mp = client_channel.bootstrap_message_pipe();
128     EXPECT_NE(client_mp, MOJO_HANDLE_INVALID);
129
130     // We can write to a message pipe handle immediately.
131     const char kHello[] = "hello";
132     EXPECT_EQ(MOJO_RESULT_OK,
133               MojoWriteMessage(server_mp,
134                                kHello,
135                                static_cast<uint32_t>(sizeof(kHello)),
136                                nullptr,
137                                0,
138                                MOJO_WRITE_MESSAGE_FLAG_NONE));
139
140     // Now wait for the other side to become readable.
141     EXPECT_EQ(
142         MOJO_RESULT_OK,
143         MojoWait(
144             client_mp, MOJO_HANDLE_SIGNAL_READABLE, MOJO_DEADLINE_INDEFINITE));
145
146     char buffer[1000] = {};
147     uint32_t num_bytes = static_cast<uint32_t>(sizeof(buffer));
148     EXPECT_EQ(MOJO_RESULT_OK,
149               MojoReadMessage(client_mp,
150                               buffer,
151                               &num_bytes,
152                               nullptr,
153                               nullptr,
154                               MOJO_READ_MESSAGE_FLAG_NONE));
155     EXPECT_EQ(sizeof(kHello), num_bytes);
156     EXPECT_STREQ(kHello, buffer);
157
158     EXPECT_EQ(MOJO_RESULT_OK, MojoClose(server_mp));
159     EXPECT_EQ(MOJO_RESULT_OK, MojoClose(client_mp));
160
161     // By this point, these waits should basically be no-ops (since we've waited
162     // for the client message pipe to become readable, which implies that both
163     // the server and client channels were completely created).
164     server_channel.WaitForChannelCreationCompletion();
165     client_channel.WaitForChannelCreationCompletion();
166     EXPECT_TRUE(server_channel.channel_info());
167     EXPECT_TRUE(client_channel.channel_info());
168   }
169
170   EXPECT_TRUE(test::Shutdown());
171 }
172
173 TEST_F(EmbedderTest, ChannelsHandlePassing) {
174   mojo::embedder::test::InitWithSimplePlatformSupport();
175
176   {
177     PlatformChannelPair channel_pair;
178     ScopedTestChannel server_channel(test_io_thread()->task_runner(),
179                                      channel_pair.PassServerHandle());
180     MojoHandle server_mp = server_channel.bootstrap_message_pipe();
181     EXPECT_NE(server_mp, MOJO_HANDLE_INVALID);
182     ScopedTestChannel client_channel(test_io_thread()->task_runner(),
183                                      channel_pair.PassClientHandle());
184     MojoHandle client_mp = client_channel.bootstrap_message_pipe();
185     EXPECT_NE(client_mp, MOJO_HANDLE_INVALID);
186
187     MojoHandle h0, h1;
188     EXPECT_EQ(MOJO_RESULT_OK, MojoCreateMessagePipe(nullptr, &h0, &h1));
189
190     // Write a message to |h0| (attaching nothing).
191     const char kHello[] = "hello";
192     EXPECT_EQ(MOJO_RESULT_OK,
193               MojoWriteMessage(h0,
194                                kHello,
195                                static_cast<uint32_t>(sizeof(kHello)),
196                                nullptr,
197                                0,
198                                MOJO_WRITE_MESSAGE_FLAG_NONE));
199
200     // Write one message to |server_mp|, attaching |h1|.
201     const char kWorld[] = "world!!!";
202     EXPECT_EQ(MOJO_RESULT_OK,
203               MojoWriteMessage(server_mp,
204                                kWorld,
205                                static_cast<uint32_t>(sizeof(kWorld)),
206                                &h1,
207                                1,
208                                MOJO_WRITE_MESSAGE_FLAG_NONE));
209     h1 = MOJO_HANDLE_INVALID;
210
211     // Write another message to |h0|.
212     const char kFoo[] = "foo";
213     EXPECT_EQ(MOJO_RESULT_OK,
214               MojoWriteMessage(h0,
215                                kFoo,
216                                static_cast<uint32_t>(sizeof(kFoo)),
217                                nullptr,
218                                0,
219                                MOJO_WRITE_MESSAGE_FLAG_NONE));
220
221     // Wait for |client_mp| to become readable.
222     EXPECT_EQ(
223         MOJO_RESULT_OK,
224         MojoWait(
225             client_mp, MOJO_HANDLE_SIGNAL_READABLE, MOJO_DEADLINE_INDEFINITE));
226
227     // Read a message from |client_mp|.
228     char buffer[1000] = {};
229     uint32_t num_bytes = static_cast<uint32_t>(sizeof(buffer));
230     MojoHandle handles[10] = {};
231     uint32_t num_handles = arraysize(handles);
232     EXPECT_EQ(MOJO_RESULT_OK,
233               MojoReadMessage(client_mp,
234                               buffer,
235                               &num_bytes,
236                               handles,
237                               &num_handles,
238                               MOJO_READ_MESSAGE_FLAG_NONE));
239     EXPECT_EQ(sizeof(kWorld), num_bytes);
240     EXPECT_STREQ(kWorld, buffer);
241     EXPECT_EQ(1u, num_handles);
242     EXPECT_NE(handles[0], MOJO_HANDLE_INVALID);
243     h1 = handles[0];
244
245     // Wait for |h1| to become readable.
246     EXPECT_EQ(
247         MOJO_RESULT_OK,
248         MojoWait(h1, MOJO_HANDLE_SIGNAL_READABLE, MOJO_DEADLINE_INDEFINITE));
249
250     // Read a message from |h1|.
251     memset(buffer, 0, sizeof(buffer));
252     num_bytes = static_cast<uint32_t>(sizeof(buffer));
253     memset(handles, 0, sizeof(handles));
254     num_handles = arraysize(handles);
255     EXPECT_EQ(MOJO_RESULT_OK,
256               MojoReadMessage(h1,
257                               buffer,
258                               &num_bytes,
259                               handles,
260                               &num_handles,
261                               MOJO_READ_MESSAGE_FLAG_NONE));
262     EXPECT_EQ(sizeof(kHello), num_bytes);
263     EXPECT_STREQ(kHello, buffer);
264     EXPECT_EQ(0u, num_handles);
265
266     // Wait for |h1| to become readable (again).
267     EXPECT_EQ(
268         MOJO_RESULT_OK,
269         MojoWait(h1, MOJO_HANDLE_SIGNAL_READABLE, MOJO_DEADLINE_INDEFINITE));
270
271     // Read the second message from |h1|.
272     memset(buffer, 0, sizeof(buffer));
273     num_bytes = static_cast<uint32_t>(sizeof(buffer));
274     EXPECT_EQ(MOJO_RESULT_OK,
275               MojoReadMessage(h1,
276                               buffer,
277                               &num_bytes,
278                               nullptr,
279                               nullptr,
280                               MOJO_READ_MESSAGE_FLAG_NONE));
281     EXPECT_EQ(sizeof(kFoo), num_bytes);
282     EXPECT_STREQ(kFoo, buffer);
283
284     // Write a message to |h1|.
285     const char kBarBaz[] = "barbaz";
286     EXPECT_EQ(MOJO_RESULT_OK,
287               MojoWriteMessage(h1,
288                                kBarBaz,
289                                static_cast<uint32_t>(sizeof(kBarBaz)),
290                                nullptr,
291                                0,
292                                MOJO_WRITE_MESSAGE_FLAG_NONE));
293
294     // Wait for |h0| to become readable.
295     EXPECT_EQ(
296         MOJO_RESULT_OK,
297         MojoWait(h0, MOJO_HANDLE_SIGNAL_READABLE, MOJO_DEADLINE_INDEFINITE));
298
299     // Read a message from |h0|.
300     memset(buffer, 0, sizeof(buffer));
301     num_bytes = static_cast<uint32_t>(sizeof(buffer));
302     EXPECT_EQ(MOJO_RESULT_OK,
303               MojoReadMessage(h0,
304                               buffer,
305                               &num_bytes,
306                               nullptr,
307                               nullptr,
308                               MOJO_READ_MESSAGE_FLAG_NONE));
309     EXPECT_EQ(sizeof(kBarBaz), num_bytes);
310     EXPECT_STREQ(kBarBaz, buffer);
311
312     EXPECT_EQ(MOJO_RESULT_OK, MojoClose(server_mp));
313     EXPECT_EQ(MOJO_RESULT_OK, MojoClose(client_mp));
314     EXPECT_EQ(MOJO_RESULT_OK, MojoClose(h0));
315     EXPECT_EQ(MOJO_RESULT_OK, MojoClose(h1));
316
317     server_channel.WaitForChannelCreationCompletion();
318     client_channel.WaitForChannelCreationCompletion();
319     EXPECT_TRUE(server_channel.channel_info());
320     EXPECT_TRUE(client_channel.channel_info());
321   }
322
323   EXPECT_TRUE(test::Shutdown());
324 }
325
326 // The sequence of messages sent is:
327 //       server_mp   client_mp   mp0         mp1         mp2         mp3
328 //   1.  "hello"
329 //   2.              "world!"
330 //   3.                          "FOO"
331 //   4.  "Bar"+mp1
332 //   5.  (close)
333 //   6.              (close)
334 //   7.                                                              "baz"
335 //   8.                                                              (closed)
336 //   9.                                      "quux"+mp2
337 //  10.                          (close)
338 //  11.                                      (wait/cl.)
339 //  12.                                                  (wait/cl.)
340 TEST_F(EmbedderTest, MultiprocessChannels) {
341   mojo::embedder::test::InitWithSimplePlatformSupport();
342   mojo::test::MultiprocessTestHelper multiprocess_test_helper;
343   multiprocess_test_helper.StartChild("MultiprocessChannelsClient");
344
345   {
346     ScopedTestChannel server_channel(
347         test_io_thread()->task_runner(),
348         multiprocess_test_helper.server_platform_handle.Pass());
349     MojoHandle server_mp = server_channel.bootstrap_message_pipe();
350     EXPECT_NE(server_mp, MOJO_HANDLE_INVALID);
351     server_channel.WaitForChannelCreationCompletion();
352     EXPECT_TRUE(server_channel.channel_info());
353
354     // 1. Write a message to |server_mp| (attaching nothing).
355     const char kHello[] = "hello";
356     EXPECT_EQ(MOJO_RESULT_OK,
357               MojoWriteMessage(server_mp,
358                                kHello,
359                                static_cast<uint32_t>(sizeof(kHello)),
360                                nullptr,
361                                0,
362                                MOJO_WRITE_MESSAGE_FLAG_NONE));
363
364     // TODO(vtl): If the scope were ended immediately here (maybe after closing
365     // |server_mp|), we die with a fatal error in |Channel::HandleLocalError()|.
366
367     // 2. Read a message from |server_mp|.
368     EXPECT_EQ(
369         MOJO_RESULT_OK,
370         MojoWait(
371             server_mp, MOJO_HANDLE_SIGNAL_READABLE, MOJO_DEADLINE_INDEFINITE));
372     char buffer[1000] = {};
373     uint32_t num_bytes = static_cast<uint32_t>(sizeof(buffer));
374     EXPECT_EQ(MOJO_RESULT_OK,
375               MojoReadMessage(server_mp,
376                               buffer,
377                               &num_bytes,
378                               nullptr,
379                               nullptr,
380                               MOJO_READ_MESSAGE_FLAG_NONE));
381     const char kWorld[] = "world!";
382     EXPECT_EQ(sizeof(kWorld), num_bytes);
383     EXPECT_STREQ(kWorld, buffer);
384
385     // Create a new message pipe (endpoints |mp0| and |mp1|).
386     MojoHandle mp0, mp1;
387     EXPECT_EQ(MOJO_RESULT_OK, MojoCreateMessagePipe(nullptr, &mp0, &mp1));
388
389     // 3. Write something to |mp0|.
390     const char kFoo[] = "FOO";
391     EXPECT_EQ(MOJO_RESULT_OK,
392               MojoWriteMessage(mp0,
393                                kFoo,
394                                static_cast<uint32_t>(sizeof(kFoo)),
395                                nullptr,
396                                0,
397                                MOJO_WRITE_MESSAGE_FLAG_NONE));
398
399     // 4. Write a message to |server_mp|, attaching |mp1|.
400     const char kBar[] = "Bar";
401     EXPECT_EQ(MOJO_RESULT_OK,
402               MojoWriteMessage(server_mp,
403                                kBar,
404                                static_cast<uint32_t>(sizeof(kBar)),
405                                &mp1,
406                                1,
407                                MOJO_WRITE_MESSAGE_FLAG_NONE));
408     mp1 = MOJO_HANDLE_INVALID;
409
410     // 5. Close |server_mp|.
411     EXPECT_EQ(MOJO_RESULT_OK, MojoClose(server_mp));
412
413     // 9. Read a message from |mp0|, which should have |mp2| attached.
414     EXPECT_EQ(
415         MOJO_RESULT_OK,
416         MojoWait(mp0, MOJO_HANDLE_SIGNAL_READABLE, MOJO_DEADLINE_INDEFINITE));
417     memset(buffer, 0, sizeof(buffer));
418     num_bytes = static_cast<uint32_t>(sizeof(buffer));
419     MojoHandle mp2 = MOJO_HANDLE_INVALID;
420     uint32_t num_handles = 1;
421     EXPECT_EQ(MOJO_RESULT_OK,
422               MojoReadMessage(mp0,
423                               buffer,
424                               &num_bytes,
425                               &mp2,
426                               &num_handles,
427                               MOJO_READ_MESSAGE_FLAG_NONE));
428     const char kQuux[] = "quux";
429     EXPECT_EQ(sizeof(kQuux), num_bytes);
430     EXPECT_STREQ(kQuux, buffer);
431     EXPECT_EQ(1u, num_handles);
432     EXPECT_NE(mp2, MOJO_HANDLE_INVALID);
433
434     // 7. Read a message from |mp2|.
435     EXPECT_EQ(
436         MOJO_RESULT_OK,
437         MojoWait(mp2, MOJO_HANDLE_SIGNAL_READABLE, MOJO_DEADLINE_INDEFINITE));
438     memset(buffer, 0, sizeof(buffer));
439     num_bytes = static_cast<uint32_t>(sizeof(buffer));
440     EXPECT_EQ(MOJO_RESULT_OK,
441               MojoReadMessage(mp2,
442                               buffer,
443                               &num_bytes,
444                               nullptr,
445                               nullptr,
446                               MOJO_READ_MESSAGE_FLAG_NONE));
447     const char kBaz[] = "baz";
448     EXPECT_EQ(sizeof(kBaz), num_bytes);
449     EXPECT_STREQ(kBaz, buffer);
450
451     // 10. Close |mp0|.
452     EXPECT_EQ(MOJO_RESULT_OK, MojoClose(mp0));
453
454 // 12. Wait on |mp2| (which should eventually fail) and then close it.
455 // TODO(vtl): crbug.com/351768
456 #if 0
457     EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
458               MojoWait(mp2, MOJO_HANDLE_SIGNAL_READABLE,
459                        MOJO_DEADLINE_INDEFINITE));
460 #endif
461     EXPECT_EQ(MOJO_RESULT_OK, MojoClose(mp2));
462   }
463
464   EXPECT_TRUE(multiprocess_test_helper.WaitForChildTestShutdown());
465   EXPECT_TRUE(test::Shutdown());
466 }
467
468 MOJO_MULTIPROCESS_TEST_CHILD_TEST(MultiprocessChannelsClient) {
469   ScopedPlatformHandle client_platform_handle =
470       mojo::test::MultiprocessTestHelper::client_platform_handle.Pass();
471   EXPECT_TRUE(client_platform_handle.is_valid());
472
473   base::TestIOThread test_io_thread(base::TestIOThread::kAutoStart);
474   mojo::embedder::test::InitWithSimplePlatformSupport();
475
476   {
477     ScopedTestChannel client_channel(test_io_thread.task_runner(),
478                                      client_platform_handle.Pass());
479     MojoHandle client_mp = client_channel.bootstrap_message_pipe();
480     EXPECT_NE(client_mp, MOJO_HANDLE_INVALID);
481     client_channel.WaitForChannelCreationCompletion();
482     CHECK(client_channel.channel_info() != nullptr);
483
484     // 1. Read the first message from |client_mp|.
485     EXPECT_EQ(
486         MOJO_RESULT_OK,
487         MojoWait(
488             client_mp, MOJO_HANDLE_SIGNAL_READABLE, MOJO_DEADLINE_INDEFINITE));
489     char buffer[1000] = {};
490     uint32_t num_bytes = static_cast<uint32_t>(sizeof(buffer));
491     EXPECT_EQ(MOJO_RESULT_OK,
492               MojoReadMessage(client_mp,
493                               buffer,
494                               &num_bytes,
495                               nullptr,
496                               nullptr,
497                               MOJO_READ_MESSAGE_FLAG_NONE));
498     const char kHello[] = "hello";
499     EXPECT_EQ(sizeof(kHello), num_bytes);
500     EXPECT_STREQ(kHello, buffer);
501
502     // 2. Write a message to |client_mp| (attaching nothing).
503     const char kWorld[] = "world!";
504     EXPECT_EQ(MOJO_RESULT_OK,
505               MojoWriteMessage(client_mp,
506                                kWorld,
507                                static_cast<uint32_t>(sizeof(kWorld)),
508                                nullptr,
509                                0,
510                                MOJO_WRITE_MESSAGE_FLAG_NONE));
511
512     // 4. Read a message from |client_mp|, which should have |mp1| attached.
513     EXPECT_EQ(
514         MOJO_RESULT_OK,
515         MojoWait(
516             client_mp, MOJO_HANDLE_SIGNAL_READABLE, MOJO_DEADLINE_INDEFINITE));
517     // TODO(vtl): If the scope were to end here (and |client_mp| closed), we'd
518     // die (again due to |Channel::HandleLocalError()|).
519     memset(buffer, 0, sizeof(buffer));
520     num_bytes = static_cast<uint32_t>(sizeof(buffer));
521     MojoHandle mp1 = MOJO_HANDLE_INVALID;
522     uint32_t num_handles = 1;
523     EXPECT_EQ(MOJO_RESULT_OK,
524               MojoReadMessage(client_mp,
525                               buffer,
526                               &num_bytes,
527                               &mp1,
528                               &num_handles,
529                               MOJO_READ_MESSAGE_FLAG_NONE));
530     const char kBar[] = "Bar";
531     EXPECT_EQ(sizeof(kBar), num_bytes);
532     EXPECT_STREQ(kBar, buffer);
533     EXPECT_EQ(1u, num_handles);
534     EXPECT_NE(mp1, MOJO_HANDLE_INVALID);
535     // TODO(vtl): If the scope were to end here (and the two handles closed),
536     // we'd die due to |Channel::RunRemoteMessagePipeEndpoint()| not handling
537     // write errors (assuming the parent had closed the pipe).
538
539     // 6. Close |client_mp|.
540     EXPECT_EQ(MOJO_RESULT_OK, MojoClose(client_mp));
541
542     // Create a new message pipe (endpoints |mp2| and |mp3|).
543     MojoHandle mp2, mp3;
544     EXPECT_EQ(MOJO_RESULT_OK, MojoCreateMessagePipe(nullptr, &mp2, &mp3));
545
546     // 7. Write a message to |mp3|.
547     const char kBaz[] = "baz";
548     EXPECT_EQ(MOJO_RESULT_OK,
549               MojoWriteMessage(mp3,
550                                kBaz,
551                                static_cast<uint32_t>(sizeof(kBaz)),
552                                nullptr,
553                                0,
554                                MOJO_WRITE_MESSAGE_FLAG_NONE));
555
556     // 8. Close |mp3|.
557     EXPECT_EQ(MOJO_RESULT_OK, MojoClose(mp3));
558
559     // 9. Write a message to |mp1|, attaching |mp2|.
560     const char kQuux[] = "quux";
561     EXPECT_EQ(MOJO_RESULT_OK,
562               MojoWriteMessage(mp1,
563                                kQuux,
564                                static_cast<uint32_t>(sizeof(kQuux)),
565                                &mp2,
566                                1,
567                                MOJO_WRITE_MESSAGE_FLAG_NONE));
568     mp2 = MOJO_HANDLE_INVALID;
569
570     // 3. Read a message from |mp1|.
571     EXPECT_EQ(
572         MOJO_RESULT_OK,
573         MojoWait(mp1, MOJO_HANDLE_SIGNAL_READABLE, MOJO_DEADLINE_INDEFINITE));
574     memset(buffer, 0, sizeof(buffer));
575     num_bytes = static_cast<uint32_t>(sizeof(buffer));
576     EXPECT_EQ(MOJO_RESULT_OK,
577               MojoReadMessage(mp1,
578                               buffer,
579                               &num_bytes,
580                               nullptr,
581                               nullptr,
582                               MOJO_READ_MESSAGE_FLAG_NONE));
583     const char kFoo[] = "FOO";
584     EXPECT_EQ(sizeof(kFoo), num_bytes);
585     EXPECT_STREQ(kFoo, buffer);
586
587     // 11. Wait on |mp1| (which should eventually fail) and then close it.
588     EXPECT_EQ(
589         MOJO_RESULT_FAILED_PRECONDITION,
590         MojoWait(mp1, MOJO_HANDLE_SIGNAL_READABLE, MOJO_DEADLINE_INDEFINITE));
591     EXPECT_EQ(MOJO_RESULT_OK, MojoClose(mp1));
592   }
593
594   EXPECT_TRUE(test::Shutdown());
595 }
596
597 // TODO(vtl): Test immediate write & close.
598 // TODO(vtl): Test broken-connection cases.
599
600 }  // namespace
601 }  // namespace embedder
602 }  // namespace mojo