OLD | NEW |
| (Empty) |
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/edk/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/edk/embedder/platform_channel_pair.h" | |
17 #include "mojo/edk/embedder/test_embedder.h" | |
18 #include "mojo/edk/system/test_utils.h" | |
19 #include "mojo/edk/test/multiprocess_test_helper.h" | |
20 #include "mojo/public/c/system/core.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 | |
OLD | NEW |