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
23namespace mojo {
24namespace embedder {
25namespace {
26
27class 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
102class 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
116TEST_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
173TEST_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.)
340TEST_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
468MOJO_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
603