OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "mojo/edk/embedder/embedder.h" | 5 #include "mojo/edk/embedder/embedder.h" |
6 | 6 |
7 #include <stddef.h> | 7 #include <stddef.h> |
8 #include <stdint.h> | 8 #include <stdint.h> |
9 | 9 |
10 #include <utility> | 10 #include <utility> |
11 | 11 |
12 #include "base/bind.h" | 12 #include "base/bind.h" |
13 #include "base/command_line.h" | 13 #include "base/command_line.h" |
14 #include "base/logging.h" | 14 #include "base/logging.h" |
15 #include "base/message_loop/message_loop.h" | 15 #include "base/message_loop/message_loop.h" |
16 #include "base/synchronization/waitable_event.h" | 16 #include "base/synchronization/waitable_event.h" |
17 #include "base/test/test_timeouts.h" | 17 #include "base/test/test_timeouts.h" |
18 #include "mojo/edk/embedder/embedder.h" | 18 #include "mojo/edk/embedder/embedder.h" |
19 #include "mojo/edk/embedder/platform_channel_pair.h" | 19 #include "mojo/edk/embedder/platform_channel_pair.h" |
20 #include "mojo/edk/embedder/simple_platform_support.h" | 20 #include "mojo/edk/embedder/simple_platform_support.h" |
21 #include "mojo/edk/embedder/test_embedder.h" | 21 #include "mojo/edk/embedder/test_embedder.h" |
22 #include "mojo/edk/system/test_utils.h" | 22 #include "mojo/edk/system/test_utils.h" |
23 #include "mojo/edk/test/multiprocess_test_helper.h" | 23 #include "mojo/edk/test/mojo_test_base.h" |
24 #include "mojo/message_pump/message_pump_mojo.h" | 24 #include "mojo/message_pump/message_pump_mojo.h" |
25 #include "mojo/public/c/system/core.h" | 25 #include "mojo/public/c/system/core.h" |
26 #include "mojo/public/cpp/system/handle.h" | 26 #include "mojo/public/cpp/system/handle.h" |
27 #include "mojo/public/cpp/system/macros.h" | 27 #include "mojo/public/cpp/system/macros.h" |
28 #include "mojo/public/cpp/system/message_pipe.h" | 28 #include "mojo/public/cpp/system/message_pipe.h" |
29 #include "testing/gtest/include/gtest/gtest.h" | 29 #include "testing/gtest/include/gtest/gtest.h" |
30 | 30 |
31 namespace mojo { | 31 namespace mojo { |
32 namespace edk { | 32 namespace edk { |
33 namespace { | 33 namespace { |
34 | 34 |
35 const MojoHandleSignals kSignalReadadableWritable = | 35 const MojoHandleSignals kSignalReadadableWritable = |
36 MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE; | 36 MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE; |
37 | 37 |
38 const MojoHandleSignals kSignalAll = MOJO_HANDLE_SIGNAL_READABLE | | 38 const MojoHandleSignals kSignalAll = MOJO_HANDLE_SIGNAL_READABLE | |
39 MOJO_HANDLE_SIGNAL_WRITABLE | | 39 MOJO_HANDLE_SIGNAL_WRITABLE | |
40 MOJO_HANDLE_SIGNAL_PEER_CLOSED; | 40 MOJO_HANDLE_SIGNAL_PEER_CLOSED; |
41 | 41 |
42 typedef testing::Test EmbedderTest; | 42 using EmbedderTest = test::MojoTestBase; |
43 | 43 |
44 TEST_F(EmbedderTest, ChannelBasic) { | 44 TEST_F(EmbedderTest, ChannelBasic) { |
45 MojoHandle server_mp, client_mp; | 45 MojoHandle server_mp, client_mp; |
46 ASSERT_EQ(MOJO_RESULT_OK, | 46 CreateMessagePipe(&server_mp, &client_mp); |
47 MojoCreateMessagePipe(nullptr, &server_mp, &client_mp)); | 47 |
| 48 const std::string kHello = "hello"; |
48 | 49 |
49 // We can write to a message pipe handle immediately. | 50 // We can write to a message pipe handle immediately. |
50 const char kHello[] = "hello"; | 51 WriteMessage(server_mp, kHello); |
51 | 52 EXPECT_EQ(kHello, ReadMessage(client_mp)); |
52 size_t write_size = sizeof(kHello); | |
53 const char* write_buffer = kHello; | |
54 ASSERT_EQ(MOJO_RESULT_OK, | |
55 MojoWriteMessage(server_mp, write_buffer, | |
56 static_cast<uint32_t>(write_size), nullptr, 0, | |
57 MOJO_WRITE_MESSAGE_FLAG_NONE)); | |
58 | |
59 // Now wait for the other side to become readable. | |
60 MojoHandleSignalsState state; | |
61 ASSERT_EQ(MOJO_RESULT_OK, MojoWait(client_mp, MOJO_HANDLE_SIGNAL_READABLE, | |
62 MOJO_DEADLINE_INDEFINITE, &state)); | |
63 ASSERT_EQ(kSignalReadadableWritable, state.satisfied_signals); | |
64 ASSERT_EQ(kSignalAll, state.satisfiable_signals); | |
65 | |
66 char read_buffer[1000] = {}; | |
67 uint32_t num_bytes = static_cast<uint32_t>(sizeof(read_buffer)); | |
68 ASSERT_EQ(MOJO_RESULT_OK, | |
69 MojoReadMessage(client_mp, read_buffer, &num_bytes, nullptr, | |
70 nullptr, MOJO_READ_MESSAGE_FLAG_NONE)); | |
71 ASSERT_EQ(write_size, num_bytes); | |
72 EXPECT_STREQ(kHello, read_buffer); | |
73 | 53 |
74 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(server_mp)); | 54 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(server_mp)); |
75 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(client_mp)); | 55 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(client_mp)); |
76 } | 56 } |
77 | 57 |
78 // Test sending a MP which has read messages out of the OS pipe but which have | 58 // Test sending a MP which has read messages out of the OS pipe but which have |
79 // not been consumed using MojoReadMessage yet. | 59 // not been consumed using MojoReadMessage yet. |
80 TEST_F(EmbedderTest, SendReadableMessagePipe) { | 60 TEST_F(EmbedderTest, SendReadableMessagePipe) { |
81 MojoHandle server_mp, client_mp; | 61 MojoHandle server_mp, client_mp; |
82 ASSERT_EQ(MOJO_RESULT_OK, | 62 CreateMessagePipe(&server_mp, &client_mp); |
83 MojoCreateMessagePipe(nullptr, &server_mp, &client_mp)); | |
84 | 63 |
85 MojoHandle server_mp2, client_mp2; | 64 MojoHandle server_mp2, client_mp2; |
86 MojoCreateMessagePipeOptions options; | 65 CreateMessagePipe(&server_mp2, &client_mp2); |
87 options.struct_size = sizeof(MojoCreateMessagePipeOptions); | |
88 options.flags = MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_TRANSFERABLE; | |
89 ASSERT_EQ(MOJO_RESULT_OK, | |
90 MojoCreateMessagePipe(&options, &server_mp2, &client_mp2)); | |
91 | 66 |
92 // Write to server2 and wait for client2 to be readable before sending it. | 67 // Write to server2 and wait for client2 to be readable before sending it. |
93 // client2's MessagePipeDispatcher will have the message below in its | 68 // client2's MessagePipeDispatcher will have the message below in its |
94 // message_queue_. For extra measures, also verify that this pending message | 69 // message_queue_. For extra measures, also verify that this pending message |
95 // can contain a message pipe. | 70 // can contain a message pipe. |
96 MojoHandle server_mp3, client_mp3; | 71 MojoHandle server_mp3, client_mp3; |
97 ASSERT_EQ(MOJO_RESULT_OK, | 72 CreateMessagePipe(&server_mp3, &client_mp3); |
98 MojoCreateMessagePipe(nullptr, &server_mp3, &client_mp3)); | 73 |
99 const char kHello[] = "hello"; | 74 const std::string kHello = "hello"; |
100 size_t write_size; | 75 WriteMessageWithHandles(server_mp2, kHello, &client_mp3, 1); |
101 const char* write_buffer; | |
102 write_buffer = kHello; | |
103 write_size = sizeof(kHello); | |
104 ASSERT_EQ(MOJO_RESULT_OK, | |
105 MojoWriteMessage(server_mp2, write_buffer, | |
106 static_cast<uint32_t>(write_size), &client_mp3, 1, | |
107 MOJO_WRITE_MESSAGE_FLAG_NONE)); | |
108 | 76 |
109 MojoHandleSignalsState state; | 77 MojoHandleSignalsState state; |
110 ASSERT_EQ(MOJO_RESULT_OK, MojoWait(client_mp2, MOJO_HANDLE_SIGNAL_READABLE, | 78 ASSERT_EQ(MOJO_RESULT_OK, MojoWait(client_mp2, MOJO_HANDLE_SIGNAL_READABLE, |
111 MOJO_DEADLINE_INDEFINITE, &state)); | 79 MOJO_DEADLINE_INDEFINITE, &state)); |
112 ASSERT_EQ(kSignalReadadableWritable, state.satisfied_signals); | 80 ASSERT_EQ(kSignalReadadableWritable, state.satisfied_signals); |
113 ASSERT_EQ(kSignalAll, state.satisfiable_signals); | 81 ASSERT_EQ(kSignalAll, state.satisfiable_signals); |
114 | 82 |
115 // Now send client2 | 83 // Now send client2 |
116 ASSERT_EQ(MOJO_RESULT_OK, | 84 WriteMessageWithHandles(server_mp, kHello, &client_mp2, 1); |
117 MojoWriteMessage(server_mp, write_buffer, | |
118 static_cast<uint32_t>(write_size), &client_mp2, 1, | |
119 MOJO_WRITE_MESSAGE_FLAG_NONE)); | |
120 | 85 |
| 86 MojoHandle port; |
| 87 std::string message = ReadMessageWithHandles(client_mp, &port, 1); |
| 88 EXPECT_EQ(kHello, message); |
121 | 89 |
122 ASSERT_EQ(MOJO_RESULT_OK, MojoWait(client_mp, MOJO_HANDLE_SIGNAL_READABLE, | 90 client_mp2 = port; |
123 MOJO_DEADLINE_INDEFINITE, &state)); | 91 message = ReadMessageWithHandles(client_mp2, &client_mp3, 1); |
124 ASSERT_EQ(kSignalReadadableWritable, state.satisfied_signals); | 92 EXPECT_EQ(kHello, message); |
125 ASSERT_EQ(kSignalAll, state.satisfiable_signals); | |
126 | |
127 char read_buffer[20000] = {}; | |
128 uint32_t num_bytes = static_cast<uint32_t>(sizeof(read_buffer)); | |
129 MojoHandle ports[10]; | |
130 uint32_t num_ports = arraysize(ports); | |
131 ASSERT_EQ(MOJO_RESULT_OK, | |
132 MojoReadMessage(client_mp, read_buffer, &num_bytes, &ports[0], | |
133 &num_ports, MOJO_READ_MESSAGE_FLAG_NONE)); | |
134 ASSERT_EQ(write_size, num_bytes); | |
135 EXPECT_STREQ(kHello, read_buffer); | |
136 ASSERT_EQ(1u, num_ports); | |
137 | |
138 | |
139 client_mp2 = ports[0]; | |
140 ASSERT_EQ(MOJO_RESULT_OK, MojoWait(client_mp2, MOJO_HANDLE_SIGNAL_READABLE, | |
141 MOJO_DEADLINE_INDEFINITE, &state)); | |
142 ASSERT_EQ(kSignalReadadableWritable, state.satisfied_signals); | |
143 ASSERT_EQ(kSignalAll, state.satisfiable_signals); | |
144 | |
145 | |
146 ASSERT_EQ(MOJO_RESULT_OK, | |
147 MojoReadMessage(client_mp2, read_buffer, &num_bytes, &client_mp3, | |
148 &num_ports, MOJO_READ_MESSAGE_FLAG_NONE)); | |
149 ASSERT_EQ(write_size, num_bytes); | |
150 EXPECT_STREQ(kHello, read_buffer); | |
151 ASSERT_EQ(1u, num_ports); | |
152 | |
153 | 93 |
154 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(server_mp3)); | 94 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(server_mp3)); |
155 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(client_mp3)); | 95 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(client_mp3)); |
156 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(server_mp2)); | 96 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(server_mp2)); |
157 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(client_mp2)); | 97 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(client_mp2)); |
158 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(server_mp)); | 98 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(server_mp)); |
159 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(client_mp)); | 99 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(client_mp)); |
160 } | 100 } |
161 | 101 |
162 // Verifies that a MP with pending messages to be written can be sent and the | 102 // Verifies that a MP with pending messages to be written can be sent and the |
163 // pending messages aren't dropped. | 103 // pending messages aren't dropped. |
164 TEST_F(EmbedderTest, SendMessagePipeWithWriteQueue) { | 104 TEST_F(EmbedderTest, SendMessagePipeWithWriteQueue) { |
165 MojoHandle server_mp, client_mp; | 105 MojoHandle server_mp, client_mp; |
166 ASSERT_EQ(MOJO_RESULT_OK, | 106 CreateMessagePipe(&server_mp, &client_mp); |
167 MojoCreateMessagePipe(nullptr, &server_mp, &client_mp)); | |
168 | 107 |
169 MojoCreateMessagePipeOptions options; | |
170 options.struct_size = sizeof(MojoCreateMessagePipeOptions); | |
171 options.flags = MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_TRANSFERABLE; | |
172 MojoHandle server_mp2, client_mp2; | 108 MojoHandle server_mp2, client_mp2; |
173 ASSERT_EQ(MOJO_RESULT_OK, | 109 CreateMessagePipe(&server_mp2, &client_mp2); |
174 MojoCreateMessagePipe(&options, &server_mp2, &client_mp2)); | |
175 | 110 |
176 static const size_t kNumMessages = 1001; | 111 static const size_t kNumMessages = 1001; |
177 for (size_t i = 0; i < kNumMessages; i++) { | 112 for (size_t i = 1; i <= kNumMessages; i++) |
178 std::string write_buffer(i, 'A' + (i % 26)); | 113 WriteMessage(client_mp2, std::string(i, 'A' + (i % 26))); |
179 ASSERT_EQ(MOJO_RESULT_OK, | |
180 MojoWriteMessage(client_mp2, write_buffer.data(), | |
181 static_cast<uint32_t>(write_buffer.size()), | |
182 nullptr, 0, MOJO_WRITE_MESSAGE_FLAG_NONE)); | |
183 } | |
184 | 114 |
185 // Now send client2. | 115 // Now send client2. |
186 ASSERT_EQ(MOJO_RESULT_OK, | 116 WriteMessageWithHandles(server_mp, "hey", &client_mp2, 1); |
187 MojoWriteMessage(server_mp, nullptr, 0, &client_mp2, 1, | |
188 MOJO_WRITE_MESSAGE_FLAG_NONE)); | |
189 client_mp2 = MOJO_HANDLE_INVALID; | 117 client_mp2 = MOJO_HANDLE_INVALID; |
190 | 118 |
191 // Read client2 just so we can close it later. | 119 // Read client2 just so we can close it later. |
192 MojoHandleSignalsState state; | 120 EXPECT_EQ("hey", ReadMessageWithHandles(client_mp, &client_mp2, 1)); |
193 ASSERT_EQ(MOJO_RESULT_OK, MojoWait(client_mp, MOJO_HANDLE_SIGNAL_READABLE, | 121 EXPECT_NE(MOJO_HANDLE_INVALID, client_mp2); |
194 MOJO_DEADLINE_INDEFINITE, &state)); | |
195 ASSERT_EQ(kSignalReadadableWritable, state.satisfied_signals); | |
196 ASSERT_EQ(kSignalAll, state.satisfiable_signals); | |
197 | |
198 uint32_t num_handles = 1; | |
199 ASSERT_EQ(MOJO_RESULT_OK, MojoReadMessage(client_mp, nullptr, 0, &client_mp2, | |
200 &num_handles, | |
201 MOJO_READ_MESSAGE_FLAG_NONE)); | |
202 ASSERT_EQ(1u, num_handles); | |
203 | 122 |
204 // Now verify that all the messages that were written were sent correctly. | 123 // Now verify that all the messages that were written were sent correctly. |
205 for (size_t i = 0; i < kNumMessages; i++) { | 124 for (size_t i = 1; i <= kNumMessages; i++) |
206 ASSERT_EQ(MOJO_RESULT_OK, MojoWait(server_mp2, MOJO_HANDLE_SIGNAL_READABLE, | 125 ASSERT_EQ(std::string(i, 'A' + (i % 26)), ReadMessage(server_mp2)); |
207 MOJO_DEADLINE_INDEFINITE, &state)); | |
208 ASSERT_EQ(kSignalReadadableWritable, state.satisfied_signals); | |
209 ASSERT_EQ(kSignalAll, state.satisfiable_signals); | |
210 | |
211 std::string read_buffer(kNumMessages * 2, '\0'); | |
212 uint32_t read_buffer_size = static_cast<uint32_t>(read_buffer.size()); | |
213 ASSERT_EQ(MOJO_RESULT_OK, MojoReadMessage(server_mp2, &read_buffer[0], | |
214 &read_buffer_size, nullptr, 0, | |
215 MOJO_READ_MESSAGE_FLAG_NONE)); | |
216 read_buffer.resize(read_buffer_size); | |
217 | |
218 ASSERT_EQ(std::string(i, 'A' + (i % 26)), read_buffer); | |
219 } | |
220 | 126 |
221 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(server_mp2)); | 127 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(server_mp2)); |
222 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(client_mp2)); | 128 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(client_mp2)); |
223 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(server_mp)); | 129 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(server_mp)); |
224 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(client_mp)); | 130 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(client_mp)); |
225 } | 131 } |
226 | 132 |
227 TEST_F(EmbedderTest, ChannelsHandlePassing) { | 133 TEST_F(EmbedderTest, ChannelsHandlePassing) { |
228 MojoHandle server_mp, client_mp; | 134 MojoHandle server_mp, client_mp; |
229 ASSERT_EQ(MOJO_RESULT_OK, | 135 CreateMessagePipe(&server_mp, &client_mp); |
230 MojoCreateMessagePipe(nullptr, &server_mp, &client_mp)); | |
231 EXPECT_NE(server_mp, MOJO_HANDLE_INVALID); | 136 EXPECT_NE(server_mp, MOJO_HANDLE_INVALID); |
232 EXPECT_NE(client_mp, MOJO_HANDLE_INVALID); | 137 EXPECT_NE(client_mp, MOJO_HANDLE_INVALID); |
233 | 138 |
234 MojoHandle h0, h1; | 139 MojoHandle h0, h1; |
235 ASSERT_EQ(MOJO_RESULT_OK, MojoCreateMessagePipe(nullptr, &h0, &h1)); | 140 CreateMessagePipe(&h0, &h1); |
236 | 141 |
237 // Write a message to |h0| (attaching nothing). | 142 // Write a message to |h0| (attaching nothing). |
238 const char kHello[] = "hello"; | 143 const std::string kHello = "hello"; |
239 ASSERT_EQ(MOJO_RESULT_OK, | 144 WriteMessage(h0, kHello); |
240 MojoWriteMessage(h0, kHello, static_cast<uint32_t>(sizeof(kHello)), | |
241 nullptr, 0, MOJO_WRITE_MESSAGE_FLAG_NONE)); | |
242 | 145 |
243 // Write one message to |server_mp|, attaching |h1|. | 146 // Write one message to |server_mp|, attaching |h1|. |
244 const char kWorld[] = "world!!!"; | 147 const std::string kWorld = "world!!!"; |
245 ASSERT_EQ( | 148 WriteMessageWithHandles(server_mp, kWorld, &h1, 1); |
246 MOJO_RESULT_OK, | |
247 MojoWriteMessage(server_mp, kWorld, static_cast<uint32_t>(sizeof(kWorld)), | |
248 &h1, 1, MOJO_WRITE_MESSAGE_FLAG_NONE)); | |
249 h1 = MOJO_HANDLE_INVALID; | 149 h1 = MOJO_HANDLE_INVALID; |
250 | 150 |
251 // Write another message to |h0|. | 151 // Write another message to |h0|. |
252 const char kFoo[] = "foo"; | 152 const std::string kFoo = "foo"; |
253 ASSERT_EQ(MOJO_RESULT_OK, | 153 WriteMessage(h0, kFoo); |
254 MojoWriteMessage(h0, kFoo, static_cast<uint32_t>(sizeof(kFoo)), | |
255 nullptr, 0, MOJO_WRITE_MESSAGE_FLAG_NONE)); | |
256 | 154 |
257 // Wait for |client_mp| to become readable. | 155 // Wait for |client_mp| to become readable and read a message from it. |
258 MojoHandleSignalsState state; | 156 EXPECT_EQ(kWorld, ReadMessageWithHandles(client_mp, &h1, 1)); |
259 ASSERT_EQ(MOJO_RESULT_OK, MojoWait(client_mp, MOJO_HANDLE_SIGNAL_READABLE, | 157 EXPECT_NE(h1, MOJO_HANDLE_INVALID); |
260 MOJO_DEADLINE_INDEFINITE, &state)); | |
261 ASSERT_EQ(kSignalReadadableWritable, state.satisfied_signals); | |
262 ASSERT_EQ(kSignalAll, state.satisfiable_signals); | |
263 | 158 |
264 // Read a message from |client_mp|. | 159 // Wait for |h1| to become readable and read a message from it. |
265 char buffer[1000] = {}; | 160 EXPECT_EQ(kHello, ReadMessage(h1)); |
266 uint32_t num_bytes = static_cast<uint32_t>(sizeof(buffer)); | |
267 MojoHandle handles[10] = {}; | |
268 uint32_t num_handles = MOJO_ARRAYSIZE(handles); | |
269 ASSERT_EQ(MOJO_RESULT_OK, | |
270 MojoReadMessage(client_mp, buffer, &num_bytes, handles, | |
271 &num_handles, MOJO_READ_MESSAGE_FLAG_NONE)); | |
272 ASSERT_EQ(sizeof(kWorld), num_bytes); | |
273 EXPECT_STREQ(kWorld, buffer); | |
274 ASSERT_EQ(1u, num_handles); | |
275 EXPECT_NE(handles[0], MOJO_HANDLE_INVALID); | |
276 h1 = handles[0]; | |
277 | 161 |
278 // Wait for |h1| to become readable. | 162 // Wait for |h1| to become readable (again) and read its second message. |
279 ASSERT_EQ(MOJO_RESULT_OK, MojoWait(h1, MOJO_HANDLE_SIGNAL_READABLE, | 163 EXPECT_EQ(kFoo, ReadMessage(h1)); |
280 MOJO_DEADLINE_INDEFINITE, &state)); | |
281 ASSERT_EQ(kSignalReadadableWritable, state.satisfied_signals); | |
282 ASSERT_EQ(kSignalAll, state.satisfiable_signals); | |
283 | |
284 // Read a message from |h1|. | |
285 memset(buffer, 0, sizeof(buffer)); | |
286 num_bytes = static_cast<uint32_t>(sizeof(buffer)); | |
287 memset(handles, 0, sizeof(handles)); | |
288 num_handles = MOJO_ARRAYSIZE(handles); | |
289 ASSERT_EQ(MOJO_RESULT_OK, | |
290 MojoReadMessage(h1, buffer, &num_bytes, handles, &num_handles, | |
291 MOJO_READ_MESSAGE_FLAG_NONE)); | |
292 ASSERT_EQ(sizeof(kHello), num_bytes); | |
293 EXPECT_STREQ(kHello, buffer); | |
294 ASSERT_EQ(0u, num_handles); | |
295 | |
296 // Wait for |h1| to become readable (again). | |
297 ASSERT_EQ(MOJO_RESULT_OK, MojoWait(h1, MOJO_HANDLE_SIGNAL_READABLE, | |
298 MOJO_DEADLINE_INDEFINITE, &state)); | |
299 ASSERT_EQ(kSignalReadadableWritable, state.satisfied_signals); | |
300 ASSERT_EQ(kSignalAll, state.satisfiable_signals); | |
301 | |
302 // Read the second message from |h1|. | |
303 memset(buffer, 0, sizeof(buffer)); | |
304 num_bytes = static_cast<uint32_t>(sizeof(buffer)); | |
305 ASSERT_EQ(MOJO_RESULT_OK, | |
306 MojoReadMessage(h1, buffer, &num_bytes, nullptr, nullptr, | |
307 MOJO_READ_MESSAGE_FLAG_NONE)); | |
308 ASSERT_EQ(sizeof(kFoo), num_bytes); | |
309 EXPECT_STREQ(kFoo, buffer); | |
310 | 164 |
311 // Write a message to |h1|. | 165 // Write a message to |h1|. |
312 const char kBarBaz[] = "barbaz"; | 166 const std::string kBarBaz = "barbaz"; |
313 ASSERT_EQ( | 167 WriteMessage(h1, kBarBaz); |
314 MOJO_RESULT_OK, | |
315 MojoWriteMessage(h1, kBarBaz, static_cast<uint32_t>(sizeof(kBarBaz)), | |
316 nullptr, 0, MOJO_WRITE_MESSAGE_FLAG_NONE)); | |
317 | 168 |
318 // Wait for |h0| to become readable. | 169 // Wait for |h0| to become readable and read a message from it. |
319 ASSERT_EQ(MOJO_RESULT_OK, MojoWait(h0, MOJO_HANDLE_SIGNAL_READABLE, | 170 EXPECT_EQ(kBarBaz, ReadMessage(h0)); |
320 MOJO_DEADLINE_INDEFINITE, &state)); | |
321 ASSERT_EQ(kSignalReadadableWritable, state.satisfied_signals); | |
322 ASSERT_EQ(kSignalAll, state.satisfiable_signals); | |
323 | |
324 // Read a message from |h0|. | |
325 memset(buffer, 0, sizeof(buffer)); | |
326 num_bytes = static_cast<uint32_t>(sizeof(buffer)); | |
327 ASSERT_EQ(MOJO_RESULT_OK, | |
328 MojoReadMessage(h0, buffer, &num_bytes, nullptr, nullptr, | |
329 MOJO_READ_MESSAGE_FLAG_NONE)); | |
330 ASSERT_EQ(sizeof(kBarBaz), num_bytes); | |
331 EXPECT_STREQ(kBarBaz, buffer); | |
332 | 171 |
333 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(server_mp)); | 172 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(server_mp)); |
334 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(client_mp)); | 173 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(client_mp)); |
335 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(h0)); | 174 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(h0)); |
336 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(h1)); | 175 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(h1)); |
337 } | 176 } |
338 | 177 |
339 // The sequence of messages sent is: | 178 // The sequence of messages sent is: |
340 // server_mp client_mp mp0 mp1 mp2 mp3 | 179 // server_mp client_mp mp0 mp1 mp2 mp3 |
341 // 1. "hello" | 180 // 1. "hello" |
342 // 2. "world!" | 181 // 2. "world!" |
343 // 3. "FOO" | 182 // 3. "FOO" |
344 // 4. "Bar"+mp1 | 183 // 4. "Bar"+mp1 |
345 // 5. (close) | 184 // 5. (close) |
346 // 6. (close) | 185 // 6. (close) |
347 // 7. "baz" | 186 // 7. "baz" |
348 // 8. (closed) | 187 // 8. (closed) |
349 // 9. "quux"+mp2 | 188 // 9. "quux"+mp2 |
350 // 10. (close) | 189 // 10. (close) |
351 // 11. (wait/cl.) | 190 // 11. (wait/cl.) |
352 // 12. (wait/cl.) | 191 // 12. (wait/cl.) |
353 | 192 |
354 #if defined(OS_ANDROID) | 193 #if defined(OS_ANDROID) |
355 // Android multi-process tests are not executing the new process. This is flaky. | 194 // Android multi-process tests are not executing the new process. This is flaky. |
356 #define MAYBE_MultiprocessChannels DISABLED_MultiprocessChannels | 195 #define MAYBE_MultiprocessChannels DISABLED_MultiprocessChannels |
357 #else | 196 #else |
358 #define MAYBE_MultiprocessChannels MultiprocessChannels | 197 #define MAYBE_MultiprocessChannels MultiprocessChannels |
359 #endif // defined(OS_ANDROID) | 198 #endif // defined(OS_ANDROID) |
360 TEST_F(EmbedderTest, MAYBE_MultiprocessChannels) { | 199 TEST_F(EmbedderTest, MAYBE_MultiprocessChannels) { |
361 test::MultiprocessTestHelper multiprocess_test_helper; | 200 RUN_CHILD_ON_PIPE(MultiprocessChannelsClient, server_mp) |
362 multiprocess_test_helper.StartChild("MultiprocessChannelsClient"); | |
363 | |
364 { | |
365 MojoHandle server_mp = | |
366 CreateMessagePipe( | |
367 std::move(multiprocess_test_helper.server_platform_handle)) | |
368 .release() | |
369 .value(); | |
370 | |
371 // 1. Write a message to |server_mp| (attaching nothing). | 201 // 1. Write a message to |server_mp| (attaching nothing). |
372 const char kHello[] = "hello"; | 202 WriteMessage(server_mp, "hello"); |
373 ASSERT_EQ(MOJO_RESULT_OK, | |
374 MojoWriteMessage(server_mp, kHello, | |
375 static_cast<uint32_t>(sizeof(kHello)), nullptr, | |
376 0, MOJO_WRITE_MESSAGE_FLAG_NONE)); | |
377 | |
378 // TODO(vtl): If the scope were ended immediately here (maybe after closing | |
379 // |server_mp|), we die with a fatal error in |Channel::HandleLocalError()|. | |
380 | 203 |
381 // 2. Read a message from |server_mp|. | 204 // 2. Read a message from |server_mp|. |
382 MojoHandleSignalsState state; | 205 EXPECT_EQ("world!", ReadMessage(server_mp)); |
383 ASSERT_EQ(MOJO_RESULT_OK, MojoWait(server_mp, MOJO_HANDLE_SIGNAL_READABLE, | |
384 MOJO_DEADLINE_INDEFINITE, &state)); | |
385 ASSERT_EQ(kSignalReadadableWritable, state.satisfied_signals); | |
386 ASSERT_EQ(kSignalAll, state.satisfiable_signals); | |
387 | 206 |
388 char buffer[1000] = {}; | 207 // 3. Create a new message pipe (endpoints |mp0| and |mp1|). |
389 uint32_t num_bytes = static_cast<uint32_t>(sizeof(buffer)); | 208 MojoHandle mp0, mp1; |
390 ASSERT_EQ(MOJO_RESULT_OK, | 209 CreateMessagePipe(&mp0, &mp1); |
391 MojoReadMessage(server_mp, buffer, &num_bytes, nullptr, nullptr, | |
392 MOJO_READ_MESSAGE_FLAG_NONE)); | |
393 const char kWorld[] = "world!"; | |
394 ASSERT_EQ(sizeof(kWorld), num_bytes); | |
395 EXPECT_STREQ(kWorld, buffer); | |
396 | 210 |
397 // Create a new message pipe (endpoints |mp0| and |mp1|). | 211 // 4. Write something to |mp0|. |
398 MojoHandle mp0, mp1; | 212 WriteMessage(mp0, "FOO"); |
399 ASSERT_EQ(MOJO_RESULT_OK, MojoCreateMessagePipe(nullptr, &mp0, &mp1)); | |
400 | 213 |
401 // 3. Write something to |mp0|. | 214 // 5. Write a message to |server_mp|, attaching |mp1|. |
402 const char kFoo[] = "FOO"; | 215 WriteMessageWithHandles(server_mp, "Bar", &mp1, 1); |
403 ASSERT_EQ(MOJO_RESULT_OK, | |
404 MojoWriteMessage(mp0, kFoo, static_cast<uint32_t>(sizeof(kFoo)), | |
405 nullptr, 0, MOJO_WRITE_MESSAGE_FLAG_NONE)); | |
406 | |
407 // 4. Write a message to |server_mp|, attaching |mp1|. | |
408 const char kBar[] = "Bar"; | |
409 ASSERT_EQ( | |
410 MOJO_RESULT_OK, | |
411 MojoWriteMessage(server_mp, kBar, static_cast<uint32_t>(sizeof(kBar)), | |
412 &mp1, 1, MOJO_WRITE_MESSAGE_FLAG_NONE)); | |
413 mp1 = MOJO_HANDLE_INVALID; | 216 mp1 = MOJO_HANDLE_INVALID; |
414 | 217 |
415 // 5. Close |server_mp|. | 218 // 6. Read a message from |mp0|, which should have |mp2| attached. |
416 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(server_mp)); | |
417 | |
418 // 9. Read a message from |mp0|, which should have |mp2| attached. | |
419 ASSERT_EQ(MOJO_RESULT_OK, MojoWait(mp0, MOJO_HANDLE_SIGNAL_READABLE, | |
420 MOJO_DEADLINE_INDEFINITE, &state)); | |
421 ASSERT_EQ(kSignalReadadableWritable, state.satisfied_signals); | |
422 ASSERT_EQ(kSignalAll, state.satisfiable_signals); | |
423 | |
424 memset(buffer, 0, sizeof(buffer)); | |
425 num_bytes = static_cast<uint32_t>(sizeof(buffer)); | |
426 MojoHandle mp2 = MOJO_HANDLE_INVALID; | 219 MojoHandle mp2 = MOJO_HANDLE_INVALID; |
427 uint32_t num_handles = 1; | 220 EXPECT_EQ("quux", ReadMessageWithHandles(mp0, &mp2, 1)); |
428 ASSERT_EQ(MOJO_RESULT_OK, | |
429 MojoReadMessage(mp0, buffer, &num_bytes, &mp2, &num_handles, | |
430 MOJO_READ_MESSAGE_FLAG_NONE)); | |
431 const char kQuux[] = "quux"; | |
432 ASSERT_EQ(sizeof(kQuux), num_bytes); | |
433 EXPECT_STREQ(kQuux, buffer); | |
434 ASSERT_EQ(1u, num_handles); | |
435 EXPECT_NE(mp2, MOJO_HANDLE_INVALID); | |
436 | 221 |
437 // 7. Read a message from |mp2|. | 222 // 7. Read a message from |mp2|. |
438 ASSERT_EQ(MOJO_RESULT_OK, MojoWait(mp2, MOJO_HANDLE_SIGNAL_PEER_CLOSED, | 223 EXPECT_EQ("baz", ReadMessage(mp2)); |
439 MOJO_DEADLINE_INDEFINITE, &state)); | |
440 ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, | |
441 state.satisfied_signals); | |
442 ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, | |
443 state.satisfiable_signals); | |
444 | 224 |
445 memset(buffer, 0, sizeof(buffer)); | 225 // 8. Close |mp0|. |
446 num_bytes = static_cast<uint32_t>(sizeof(buffer)); | |
447 ASSERT_EQ(MOJO_RESULT_OK, | |
448 MojoReadMessage(mp2, buffer, &num_bytes, nullptr, nullptr, | |
449 MOJO_READ_MESSAGE_FLAG_NONE)); | |
450 const char kBaz[] = "baz"; | |
451 ASSERT_EQ(sizeof(kBaz), num_bytes); | |
452 EXPECT_STREQ(kBaz, buffer); | |
453 | |
454 // 10. Close |mp0|. | |
455 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(mp0)); | 226 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(mp0)); |
456 | 227 |
457 // 12. Wait on |mp2| (which should eventually fail) and then close it. | 228 // 9. Tell the client to quit. |
458 // TODO(vtl): crbug.com/351768 | 229 WriteMessage(server_mp, "quit"); |
459 #if 0 | 230 |
| 231 // 10. Wait on |mp2| (which should eventually fail) and then close it. |
| 232 MojoHandleSignalsState state; |
460 ASSERT_EQ(MOJO_RESULT_FAILED_PRECONDITION, | 233 ASSERT_EQ(MOJO_RESULT_FAILED_PRECONDITION, |
461 MojoWait(mp2, MOJO_HANDLE_SIGNAL_READABLE, | 234 MojoWait(mp2, MOJO_HANDLE_SIGNAL_READABLE, |
462 MOJO_DEADLINE_INDEFINITE, | 235 MOJO_DEADLINE_INDEFINITE, |
463 &state)); | 236 &state)); |
464 ASSERT_EQ(MOJO_HANDLE_SIGNAL_NONE, state.satisfied_signals); | 237 ASSERT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, state.satisfied_signals); |
465 ASSERT_EQ(MOJO_HANDLE_SIGNAL_NONE, state.satisfiable_signals); | 238 ASSERT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, state.satisfiable_signals); |
466 #endif | 239 |
467 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(mp2)); | 240 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(mp2)); |
468 } | 241 END_CHILD() |
469 | |
470 EXPECT_TRUE(multiprocess_test_helper.WaitForChildTestShutdown()); | |
471 } | 242 } |
472 | 243 |
473 MOJO_MULTIPROCESS_TEST_CHILD_TEST(MultiprocessChannelsClient) { | 244 DEFINE_TEST_CLIENT_TEST_WITH_PIPE(MultiprocessChannelsClient, EmbedderTest, |
474 ScopedPlatformHandle client_platform_handle = | 245 client_mp) { |
475 std::move(test::MultiprocessTestHelper::client_platform_handle); | |
476 EXPECT_TRUE(client_platform_handle.is_valid()); | |
477 | |
478 MojoHandle client_mp = | |
479 CreateMessagePipe(std::move(client_platform_handle)).release().value(); | |
480 | |
481 // 1. Read the first message from |client_mp|. | 246 // 1. Read the first message from |client_mp|. |
482 MojoHandleSignalsState state; | 247 EXPECT_EQ("hello", ReadMessage(client_mp)); |
483 ASSERT_EQ(MOJO_RESULT_OK, MojoWait(client_mp, MOJO_HANDLE_SIGNAL_READABLE, | |
484 MOJO_DEADLINE_INDEFINITE, &state)); | |
485 ASSERT_EQ(kSignalReadadableWritable, state.satisfied_signals); | |
486 ASSERT_EQ(kSignalAll, state.satisfiable_signals); | |
487 | |
488 char buffer[1000] = {}; | |
489 uint32_t num_bytes = static_cast<uint32_t>(sizeof(buffer)); | |
490 ASSERT_EQ(MOJO_RESULT_OK, | |
491 MojoReadMessage(client_mp, buffer, &num_bytes, nullptr, nullptr, | |
492 MOJO_READ_MESSAGE_FLAG_NONE)); | |
493 const char kHello[] = "hello"; | |
494 ASSERT_EQ(sizeof(kHello), num_bytes); | |
495 EXPECT_STREQ(kHello, buffer); | |
496 | 248 |
497 // 2. Write a message to |client_mp| (attaching nothing). | 249 // 2. Write a message to |client_mp| (attaching nothing). |
498 const char kWorld[] = "world!"; | 250 WriteMessage(client_mp, "world!"); |
499 ASSERT_EQ(MOJO_RESULT_OK, | |
500 MojoWriteMessage(client_mp, kWorld, | |
501 static_cast<uint32_t>(sizeof(kWorld)), nullptr, | |
502 0, MOJO_WRITE_MESSAGE_FLAG_NONE)); | |
503 | 251 |
504 // 4. Read a message from |client_mp|, which should have |mp1| attached. | 252 // 4. Read a message from |client_mp|, which should have |mp1| attached. |
505 ASSERT_EQ(MOJO_RESULT_OK, MojoWait(client_mp, MOJO_HANDLE_SIGNAL_READABLE, | 253 MojoHandle mp1; |
506 MOJO_DEADLINE_INDEFINITE, &state)); | 254 EXPECT_EQ("Bar", ReadMessageWithHandles(client_mp, &mp1, 1)); |
507 // The other end of the handle may or may not be closed at this point, so we | |
508 // can't test MOJO_HANDLE_SIGNAL_WRITABLE or MOJO_HANDLE_SIGNAL_PEER_CLOSED. | |
509 ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE, | |
510 state.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE); | |
511 ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE, | |
512 state.satisfiable_signals & MOJO_HANDLE_SIGNAL_READABLE); | |
513 // TODO(vtl): If the scope were to end here (and |client_mp| closed), we'd | |
514 // die (again due to |Channel::HandleLocalError()|). | |
515 memset(buffer, 0, sizeof(buffer)); | |
516 num_bytes = static_cast<uint32_t>(sizeof(buffer)); | |
517 MojoHandle mp1 = MOJO_HANDLE_INVALID; | |
518 uint32_t num_handles = 1; | |
519 ASSERT_EQ(MOJO_RESULT_OK, | |
520 MojoReadMessage(client_mp, buffer, &num_bytes, &mp1, &num_handles, | |
521 MOJO_READ_MESSAGE_FLAG_NONE)); | |
522 const char kBar[] = "Bar"; | |
523 ASSERT_EQ(sizeof(kBar), num_bytes); | |
524 EXPECT_STREQ(kBar, buffer); | |
525 ASSERT_EQ(1u, num_handles); | |
526 EXPECT_NE(mp1, MOJO_HANDLE_INVALID); | |
527 // TODO(vtl): If the scope were to end here (and the two handles closed), | |
528 // we'd die due to |Channel::RunRemoteMessagePipeEndpoint()| not handling | |
529 // write errors (assuming the parent had closed the pipe). | |
530 | 255 |
531 // 6. Close |client_mp|. | 256 // 5. Create a new message pipe (endpoints |mp2| and |mp3|). |
532 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(client_mp)); | 257 MojoHandle mp2, mp3; |
| 258 CreateMessagePipe(&mp2, &mp3); |
533 | 259 |
534 // Create a new message pipe (endpoints |mp2| and |mp3|). | 260 // 6. Write a message to |mp3|. |
535 MojoHandle mp2, mp3; | 261 WriteMessage(mp3, "baz"); |
536 ASSERT_EQ(MOJO_RESULT_OK, MojoCreateMessagePipe(nullptr, &mp2, &mp3)); | |
537 | 262 |
538 // 7. Write a message to |mp3|. | 263 // 7. Close |mp3|. |
539 const char kBaz[] = "baz"; | |
540 ASSERT_EQ(MOJO_RESULT_OK, | |
541 MojoWriteMessage(mp3, kBaz, static_cast<uint32_t>(sizeof(kBaz)), | |
542 nullptr, 0, MOJO_WRITE_MESSAGE_FLAG_NONE)); | |
543 | |
544 // 8. Close |mp3|. | |
545 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(mp3)); | 264 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(mp3)); |
546 | 265 |
547 // 9. Write a message to |mp1|, attaching |mp2|. | 266 // 8. Write a message to |mp1|, attaching |mp2|. |
548 const char kQuux[] = "quux"; | 267 WriteMessageWithHandles(mp1, "quux", &mp2, 1); |
549 ASSERT_EQ(MOJO_RESULT_OK, | |
550 MojoWriteMessage(mp1, kQuux, static_cast<uint32_t>(sizeof(kQuux)), | |
551 &mp2, 1, MOJO_WRITE_MESSAGE_FLAG_NONE)); | |
552 mp2 = MOJO_HANDLE_INVALID; | 268 mp2 = MOJO_HANDLE_INVALID; |
553 | 269 |
554 // 3. Read a message from |mp1|. | 270 // 9. Read a message from |mp1|. |
555 ASSERT_EQ(MOJO_RESULT_OK, MojoWait(mp1, MOJO_HANDLE_SIGNAL_READABLE, | 271 EXPECT_EQ("FOO", ReadMessage(mp1)); |
556 MOJO_DEADLINE_INDEFINITE, &state)); | |
557 ASSERT_EQ(kSignalReadadableWritable, state.satisfied_signals); | |
558 ASSERT_EQ(kSignalAll, state.satisfiable_signals); | |
559 | 272 |
560 memset(buffer, 0, sizeof(buffer)); | 273 EXPECT_EQ("quit", ReadMessage(client_mp)); |
561 num_bytes = static_cast<uint32_t>(sizeof(buffer)); | |
562 ASSERT_EQ(MOJO_RESULT_OK, | |
563 MojoReadMessage(mp1, buffer, &num_bytes, nullptr, nullptr, | |
564 MOJO_READ_MESSAGE_FLAG_NONE)); | |
565 const char kFoo[] = "FOO"; | |
566 ASSERT_EQ(sizeof(kFoo), num_bytes); | |
567 EXPECT_STREQ(kFoo, buffer); | |
568 | 274 |
569 // 11. Wait on |mp1| (which should eventually fail) and then close it. | 275 // 10. Wait on |mp1| (which should eventually fail) and then close it. |
| 276 MojoHandleSignalsState state; |
570 ASSERT_EQ(MOJO_RESULT_FAILED_PRECONDITION, | 277 ASSERT_EQ(MOJO_RESULT_FAILED_PRECONDITION, |
571 MojoWait(mp1, MOJO_HANDLE_SIGNAL_READABLE, | 278 MojoWait(mp1, MOJO_HANDLE_SIGNAL_READABLE, |
572 MOJO_DEADLINE_INDEFINITE, &state)); | 279 MOJO_DEADLINE_INDEFINITE, &state)); |
573 ASSERT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, state.satisfied_signals); | 280 ASSERT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, state.satisfied_signals); |
574 ASSERT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, state.satisfiable_signals); | 281 ASSERT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, state.satisfiable_signals); |
575 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(mp1)); | 282 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(mp1)); |
576 } | 283 } |
577 | 284 |
578 // TODO(vtl): Test immediate write & close. | 285 // TODO(vtl): Test immediate write & close. |
579 // TODO(vtl): Test broken-connection cases. | 286 // TODO(vtl): Test broken-connection cases. |
580 | 287 |
581 } // namespace | 288 } // namespace |
582 } // namespace edk | 289 } // namespace edk |
583 } // namespace mojo | 290 } // namespace mojo |
OLD | NEW |