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 603