Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(115)

Side by Side Diff: tests/standalone/io/raw_synchronous_socket_test.dart

Issue 2803543006: Added synchronous socket implementation to dart:io. (Closed)
Patch Set: Changed signature for GetSocketIdNativeField Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « sdk/lib/io/sync_socket.dart ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 import "dart:async";
6 import "dart:io";
7 import "dart:isolate";
8 import "dart:math";
9
10 import "package:async_helper/async_helper.dart";
11 import "package:expect/expect.dart";
12
13 const String LOOPBACK_IP_V4_STRING = "127.0.0.1";
14
15 void testArguments() {
16 Expect.throws(() => RawSynchronousSocket.connectSync(null, 0));
17 Expect.throws(
18 () => RawSynchronousSocket.connectSync(LOOPBACK_IP_V4_STRING, null));
19 Expect.throws(
20 () => RawSynchronousSocket.connectSync(LOOPBACK_IP_V4_STRING, 65536));
21 Expect.throws(
22 () => RawSynchronousSocket.connectSync(LOOPBACK_IP_V4_STRING, -1));
23 Expect.throws(() =>
24 RawSynchronousSocket.connectSync(LOOPBACK_IP_V4_STRING, 0, backlog: -1));
25 }
26
27 void testInvalidConnect() {
28 // Connect to an unknown DNS name.
29 try {
30 var socket = RawSynchronousSocket.connectSync("ko.faar.__hest__", 0);
31 Expect.fail("Failure expected");
32 } catch (e) {
33 Expect.isTrue(e is SocketException);
34 }
35
36 // Connect to an unavaliable IP-address.
37 try {
38 var socket = RawSynchronousSocket.connectSync("1.2.3.4", 0);
39 Expect.fail("Failure expected");
40 } catch (e) {
41 Expect.isTrue(e is SocketException);
42 }
43 ;
44 }
45
46 void testSimpleConnect() {
47 asyncStart();
48 RawServerSocket.bind(InternetAddress.LOOPBACK_IP_V4, 0).then((server) {
49 var socket =
50 RawSynchronousSocket.connectSync(LOOPBACK_IP_V4_STRING, server.port);
51 server.listen((serverSocket) {
52 Expect.equals(socket.address, serverSocket.remoteAddress);
53 Expect.equals(socket.port, serverSocket.remotePort);
54 Expect.equals(socket.remoteAddress, server.address);
55 Expect.equals(socket.remotePort, server.port);
56 socket.closeSync();
57 server.close();
58 asyncEnd();
59 });
60 });
61 }
62
63 void testServerListenAfterConnect() {
64 asyncStart();
65 RawServerSocket.bind(InternetAddress.LOOPBACK_IP_V4, 0).then((server) {
66 Expect.isTrue(server.port > 0);
67 var client =
68 RawSynchronousSocket.connectSync(LOOPBACK_IP_V4_STRING, server.port);
69 server.listen((socket) {
70 client.closeSync();
71 server.close();
72 socket.close();
73 asyncEnd();
74 });
75 });
76 }
77
78 const messageSize = 1000;
79 // Configuration fields for the EchoServer.
80 enum EchoServerTypes {
81 // Max accumulated connections to server before close. Defaults to 1.
82 CONNECTION_COUNT,
83 // Sets the range of the fields to check in the list generated by
84 // createTestData().
85 OFFSET_END,
86 OFFSET_START,
87 // The port used to communicate with an isolate.
88 ISOLATE_SEND_PORT,
89 // The port of the newly created echo server.
90 SERVER_PORT
91 }
92
93 List<int> createTestData() {
94 return new List<int>.generate(messageSize, (index) => index & 0xff);
95 }
96
97 // Consumes data generated by a test and compares it against the original test
98 // data. The optional fields, start and end, are used to compare against
99 // segments of the original test data list. In other words, data.length == (end
100 // - start).
101 void verifyTestData(List<int> data, [int start = 0, int end]) {
102 assert(data != null);
103 List<int> expected = createTestData();
104 if (end == null) {
105 end = data.length;
106 }
107 end = min(messageSize, end);
108 Expect.equals(end - start, data.length);
109 for (int i = 0; i < (end - start); i++) {
110 Expect.equals(expected[start + i], data[i]);
111 }
112 }
113
114 // The echo server is spawned in a new isolate and is used to test various
115 // synchronous read/write operations by echoing any data received back to the
116 // sender. The server should shutdown automatically after a specified number of
117 // socket disconnections (default: 1).
118 Future echoServer(var sendPort) async {
119 RawServerSocket.bind(InternetAddress.LOOPBACK_IP_V4, 0).then((server) async {
120 ReceivePort receivePort = new ReceivePort();
121 Map response = {
122 EchoServerTypes.ISOLATE_SEND_PORT: receivePort.sendPort,
123 EchoServerTypes.SERVER_PORT: server.port
124 };
125 sendPort.send(response);
126 Map limits = await receivePort.first;
127 int start = limits[EchoServerTypes.OFFSET_START];
128 int end = limits[EchoServerTypes.OFFSET_END];
129 int length = end - start;
130 int connection_count = limits[EchoServerTypes.CONNECTION_COUNT] ?? 1;
131 int connections = 0;
132 sendPort = limits[EchoServerTypes.ISOLATE_SEND_PORT];
133 server.listen((client) {
134 int bytesRead = 0;
135 int bytesWritten = 0;
136 bool closedEventReceived = false;
137 List<int> data = new List<int>(length);
138 client.writeEventsEnabled = false;
139 client.listen((event) {
140 switch (event) {
141 case RawSocketEvent.READ:
142 Expect.isTrue(bytesWritten == 0);
143 Expect.isTrue(client.available() > 0);
144 var buffer = client.read(client.available());
145 data.setRange(bytesRead, bytesRead + buffer.length, buffer);
146 bytesRead += buffer.length;
147 // Once we've read all the data, we can echo it back. Otherwise,
148 // keep waiting for more bytes.
149 if (bytesRead >= length) {
150 verifyTestData(data, start, end);
151 client.writeEventsEnabled = true;
152 }
153 break;
154 case RawSocketEvent.WRITE:
155 Expect.isFalse(client.writeEventsEnabled);
156 bytesWritten +=
157 client.write(data, bytesWritten, data.length - bytesWritten);
158 if (bytesWritten < length) {
159 client.writeEventsEnabled = true;
160 } else if (bytesWritten == length) {
161 // Close the socket for writing from the server since we're done
162 // writing to this socket. The connection is closed completely
163 // after the client closes the socket for reading from the server.
164 client.shutdown(SocketDirection.SEND);
165 }
166 break;
167 case RawSocketEvent.READ_CLOSED:
168 client.close();
169 break;
170 case RawSocketEvent.CLOSED:
171 Expect.isFalse(closedEventReceived);
172 closedEventReceived = true;
173 break;
174 default:
175 throw "Unexpected event $event";
176 }
177 }, onDone: () {
178 Expect.isTrue(closedEventReceived);
179 connections++;
180 if (connections >= connection_count) {
181 server.close();
182 }
183 });
184 }, onDone: () {
185 // Let the client know we're shutting down then kill the isolate.
186 sendPort.send(null);
187 kill();
188 });
189 });
190 }
191
192 Future testSimpleReadWrite({bool dropReads}) async {
193 asyncStart();
194 // This test creates a server and a client connects. The client writes data
195 // to the socket and the server echos it back. The client confirms the data it
196 // reads is the same as the data sent, then closes the socket, resulting in
197 // the closing of the server, which responds on receivePort with null to
198 // specify the echo server isolate is about to be killed. If an error occurs
199 // in the echo server, the exception and stack trace are sent to receivePort,
200 // which prints the exception and stack trace before eventually throwing an
201 // error.
202 ReceivePort receivePort = new ReceivePort();
203 Isolate echo = await Isolate.spawn(echoServer, receivePort.sendPort);
204
205 Map response = await receivePort.first;
206 SendPort sendPort = response[EchoServerTypes.ISOLATE_SEND_PORT];
207 int serverInternetPort = response[EchoServerTypes.SERVER_PORT];
208
209 receivePort = new ReceivePort();
210 echo.addErrorListener(receivePort.sendPort);
211
212 Map limits = {
213 EchoServerTypes.OFFSET_START: 0,
214 EchoServerTypes.OFFSET_END: messageSize,
215 EchoServerTypes.ISOLATE_SEND_PORT: receivePort.sendPort
216 };
217 sendPort.send(limits);
218
219 try {
220 var socket = RawSynchronousSocket.connectSync(
221 LOOPBACK_IP_V4_STRING, serverInternetPort);
222 List<int> data = createTestData();
223 socket.writeFromSync(data);
224 List<int> result = socket.readSync(data.length);
225 verifyTestData(result);
226 socket.shutdown(SocketDirection.SEND);
227 socket.closeSync();
228 } catch (e, stack) {
229 print("Echo test failed in the client");
230 rethrow;
231 }
232 // Wait for the server to shutdown before finishing the test.
233 var result = await receivePort.first;
234 if (result != null) {
235 throw "Echo test failed in server!\nError: ${result[0]}\nStack trace:" +
236 " ${result[1]}";
237 }
238 asyncEnd();
239 }
240
241 Future testPartialRead() async {
242 asyncStart();
243 // This test is based on testSimpleReadWrite, but instead of reading the
244 // entire echoed message at once, it reads it in two calls to readIntoSync.
245 ReceivePort receivePort = new ReceivePort();
246 Isolate echo = await Isolate.spawn(echoServer, receivePort.sendPort);
247
248 Map response = await receivePort.first;
249 SendPort sendPort = response[EchoServerTypes.ISOLATE_SEND_PORT];
250 int serverInternetPort = response[EchoServerTypes.SERVER_PORT];
251 List<int> data = createTestData();
252
253 receivePort = new ReceivePort();
254 echo.addErrorListener(receivePort.sendPort);
255
256 Map limits = {
257 EchoServerTypes.OFFSET_START: 0,
258 EchoServerTypes.OFFSET_END: 1000,
259 EchoServerTypes.ISOLATE_SEND_PORT: receivePort.sendPort
260 };
261 sendPort.send(limits);
262
263 try {
264 var socket = RawSynchronousSocket.connectSync(
265 LOOPBACK_IP_V4_STRING, serverInternetPort);
266 int half_length = (data.length / 2).toInt();
267
268 // Send the full data list to the server.
269 socket.writeFromSync(data);
270 List<int> result = new List<int>(data.length);
271
272 // Read half at a time and check that there's still more bytes available.
273 socket.readIntoSync(result, 0, half_length);
274 verifyTestData(result.sublist(0, half_length), 0, half_length);
275 Expect.isTrue(socket.available() == (data.length - half_length));
276
277 // Read the second half and verify again.
278 socket.readIntoSync(result, half_length);
279 verifyTestData(result);
280 Expect.isTrue(socket.available() == 0);
281
282 socket.closeSync();
283 } catch (e, stack) {
284 print("Echo test failed in the client.");
285 rethrow;
286 }
287 // Wait for the server to shutdown before finishing the test.
288 var result = await receivePort.first;
289 if (result != null) {
290 throw "Echo test failed in server!\nError: ${result[0]}\nStack trace:" +
291 " ${result[1]}";
292 }
293 asyncEnd();
294 }
295
296 Future testPartialWrite() async {
297 asyncStart();
298 // This test is based on testSimpleReadWrite, but instead of writing the
299 // entire data buffer at once, it writes different parts of the buffer over
300 // multiple calls to writeFromSync.
301 ReceivePort receivePort = new ReceivePort();
302 Isolate echo = await Isolate.spawn(echoServer, receivePort.sendPort);
303
304 Map response = await receivePort.first;
305 List<int> data = createTestData();
306 SendPort sendPort = response[EchoServerTypes.ISOLATE_SEND_PORT];
307 int startOffset = 32;
308 int endOffset = (data.length / 2).toInt();
309 int serverInternetPort = response[EchoServerTypes.SERVER_PORT];
310
311 receivePort = new ReceivePort();
312 echo.addErrorListener(receivePort.sendPort);
313
314 Map limits = {
315 EchoServerTypes.OFFSET_START: startOffset,
316 EchoServerTypes.OFFSET_END: endOffset,
317 EchoServerTypes.ISOLATE_SEND_PORT: receivePort.sendPort
318 };
319 sendPort.send(limits);
320 try {
321 var socket = RawSynchronousSocket.connectSync(
322 LOOPBACK_IP_V4_STRING, serverInternetPort);
323 List<int> data = createTestData();
324
325 // Write a subset of data to the server.
326 socket.writeFromSync(data, startOffset, endOffset);
327
328 // Grab the response and verify it's correct.
329 List<int> result = new List<int>(endOffset - startOffset);
330 socket.readIntoSync(result);
331
332 Expect.equals(result.length, endOffset - startOffset);
333 verifyTestData(result, startOffset, endOffset);
334 socket.closeSync();
335 } catch (e, stack) {
336 print("Echo test failed in the client.");
337 rethrow;
338 }
339
340 // Wait for the server to shutdown before finishing the test.
341 var result = await receivePort.first;
342 if (result != null) {
343 throw "Echo test failed in server!\nError: ${result[0]}\nStack trace:" +
344 " ${result[1]}";
345 }
346 asyncEnd();
347 }
348
349 Future testShutdown() async {
350 asyncStart();
351 // This test creates a server and a client connects. The client then tries to
352 // perform various operations after being shutdown in a specific direction, to
353 // ensure reads or writes cannot be performed if the socket has been shutdown
354 // for reading or writing.
355 ReceivePort receivePort = new ReceivePort();
356 Isolate echo = await Isolate.spawn(echoServer, receivePort.sendPort);
357
358 Map response = await receivePort.first;
359 SendPort sendPort = response[EchoServerTypes.ISOLATE_SEND_PORT];
360 int serverInternetPort = response[EchoServerTypes.SERVER_PORT];
361 List<int> data = createTestData();
362
363 receivePort = new ReceivePort();
364 echo.addErrorListener(receivePort.sendPort);
365
366 Map limits = {
367 EchoServerTypes.OFFSET_START: 0,
368 EchoServerTypes.OFFSET_END: data.length,
369 EchoServerTypes.ISOLATE_SEND_PORT: receivePort.sendPort,
370 // Tell the server to shutdown after 3 sockets disconnect.
371 EchoServerTypes.CONNECTION_COUNT: 3
372 };
373 sendPort.send(limits);
374
375 try {
376 var socket = RawSynchronousSocket.connectSync(
377 LOOPBACK_IP_V4_STRING, serverInternetPort);
378
379 // Close from both directions. Shouldn't be able to read/write to the
380 // socket.
381 socket.shutdown(SocketDirection.BOTH);
382 Expect.throws(
383 () => socket.writeFromSync(data), (e) => e is SocketException);
384 Expect.throws(
385 () => socket.readSync(data.length), (e) => e is SocketException);
386 socket.closeSync();
387
388 // Close the socket for reading, do a write, and see if we can get any
389 // response from the server (we shouldn't be able to).
390 socket = RawSynchronousSocket.connectSync(
391 LOOPBACK_IP_V4_STRING, serverInternetPort);
392 socket.shutdown(SocketDirection.RECEIVE);
393 socket.writeFromSync(data);
394 // Throws exception when the socket is closed for RECEIVE.
395 Expect.throws(
396 () => socket.readSync(data.length), (e) => e is SocketException);
397 Expect.isTrue(socket.available() == 0);
398 socket.closeSync();
399
400 // Close the socket for writing and try to do a write. This should cause an
401 // OSError to be throw as the pipe is closed for writing.
402 socket = RawSynchronousSocket.connectSync(
403 LOOPBACK_IP_V4_STRING, serverInternetPort);
404 socket.shutdown(SocketDirection.SEND);
405 Expect.throws(
406 () => socket.writeFromSync(data), (e) => e is SocketException);
407 socket.closeSync();
408 } catch (e, stack) {
409 print("Echo test failed in client.");
410 rethrow;
411 }
412 // Wait for the server to shutdown before finishing the test.
413 var result = await receivePort.first;
414 if (result != null) {
415 throw "Echo test failed in server!\nError: ${result[0]}\nStack trace:" +
416 " ${result[1]}";
417 }
418 asyncEnd();
419 }
420
421 Future testInvalidReadWriteOperations() {
422 asyncStart();
423 RawServerSocket.bind(InternetAddress.LOOPBACK_IP_V4, 0).then((server) {
424 server.listen((socket) {});
425 List<int> data = createTestData();
426 var socket =
427 RawSynchronousSocket.connectSync(LOOPBACK_IP_V4_STRING, server.port);
428
429 // Invalid writeFromSync invocations
430 Expect.throws(() => socket.writeFromSync(data, data.length + 1),
431 (e) => e is RangeError);
432 Expect.throws(() => socket.writeFromSync(data, 0, data.length + 1),
433 (e) => e is RangeError);
434 Expect.throws(
435 () => socket.writeFromSync(data, 1, 0), (e) => e is RangeError);
436 Expect.throws(
437 () => socket.writeFromSync(data, null), (e) => e is ArgumentError);
438
439 // Invalid readIntoSync invocations
440 List<int> buffer = new List<int>(10);
441 Expect.throws(() => socket.readIntoSync(buffer, buffer.length + 1),
442 (e) => e is RangeError);
443 Expect.throws(() => socket.readIntoSync(buffer, 0, buffer.length + 1),
444 (e) => e is RangeError);
445 Expect.throws(
446 () => socket.readIntoSync(buffer, 1, 0), (e) => e is RangeError);
447 Expect.throws(
448 () => socket.readIntoSync(buffer, null), (e) => e is ArgumentError);
449
450 // Invalid readSync invocation
451 Expect.throws(() => socket.readSync(-1), (e) => e is ArgumentError);
452
453 server.close();
454 socket.closeSync();
455 asyncEnd();
456 });
457 }
458
459 void testClosedError() {
460 asyncStart();
461 RawServerSocket.bind(InternetAddress.LOOPBACK_IP_V4, 0).then((server) {
462 server.listen((socket) {
463 socket.close();
464 });
465 var socket =
466 RawSynchronousSocket.connectSync(LOOPBACK_IP_V4_STRING, server.port);
467 server.close();
468 socket.closeSync();
469 Expect.throws(() => socket.remotePort, (e) => e is SocketException);
470 Expect.throws(() => socket.remoteAddress, (e) => e is SocketException);
471 asyncEnd();
472 });
473 }
474
475 main() async {
476 asyncStart();
477 testArguments();
478 testInvalidConnect();
479 await testShutdown();
480 testSimpleConnect();
481 testServerListenAfterConnect();
482 await testSimpleReadWrite();
483 await testPartialRead();
484 await testPartialWrite();
485 testInvalidReadWriteOperations();
486 testClosedError();
487 asyncEnd();
488 }
OLDNEW
« no previous file with comments | « sdk/lib/io/sync_socket.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698