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