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

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

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

Powered by Google App Engine
This is Rietveld 408576698