6b3abe0a98
Issue b/177800357. TEST=existing test suite Change-Id: Id6b113932ab7014b8fa6c105845c5c490b60f5e8 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/181320 Commit-Queue: Alexander Aprelev <aam@google.com> Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
391 lines
9.2 KiB
Dart
391 lines
9.2 KiB
Dart
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
|
|
// VMOptions=--enable-isolate-groups --experimental-enable-isolate-groups-jit
|
|
// VMOptions=--no-enable-isolate-groups
|
|
//
|
|
// VMOptions=
|
|
// VMOptions=--short_socket_read
|
|
// VMOptions=--short_socket_write
|
|
// VMOptions=--short_socket_read --short_socket_write
|
|
//
|
|
// Test socket close events.
|
|
|
|
import 'dart:async';
|
|
import 'dart:io';
|
|
import 'dart:isolate';
|
|
|
|
import "package:async_helper/async_helper.dart";
|
|
import "package:expect/expect.dart";
|
|
|
|
const SERVERSHUTDOWN = -1;
|
|
const ITERATIONS = 10;
|
|
|
|
Future sendReceive(SendPort port, message) {
|
|
ReceivePort receivePort = new ReceivePort();
|
|
port.send([message, receivePort.sendPort]);
|
|
return receivePort.first;
|
|
}
|
|
|
|
class SocketClose {
|
|
SocketClose.start(this._mode, this._done)
|
|
: _sendPort = null,
|
|
_readBytes = 0,
|
|
_dataEvents = 0,
|
|
_closeEvents = 0,
|
|
_errorEvents = 0,
|
|
_iterations = 0 {
|
|
initialize();
|
|
}
|
|
|
|
void proceed() {
|
|
if (_iterations < ITERATIONS) {
|
|
Timer.run(sendData);
|
|
} else {
|
|
shutdown();
|
|
}
|
|
}
|
|
|
|
void sendData() {
|
|
void dataHandler(bytes) {
|
|
switch (_mode) {
|
|
case 0:
|
|
case 1:
|
|
case 2:
|
|
Expect.fail("No data expected");
|
|
break;
|
|
case 3:
|
|
case 4:
|
|
case 5:
|
|
case 6:
|
|
_readBytes += bytes.length;
|
|
if ((_readBytes % 5) == 0) {
|
|
_dataEvents++;
|
|
}
|
|
break;
|
|
default:
|
|
Expect.fail("Unknown test mode");
|
|
}
|
|
}
|
|
|
|
void closeHandler(socket) {
|
|
_closeEvents++;
|
|
switch (_mode) {
|
|
case 0:
|
|
case 1:
|
|
socket.close();
|
|
break;
|
|
case 2:
|
|
case 3:
|
|
socket.close();
|
|
proceed();
|
|
break;
|
|
case 4:
|
|
proceed();
|
|
break;
|
|
case 5:
|
|
socket.close();
|
|
proceed();
|
|
break;
|
|
case 6:
|
|
proceed();
|
|
break;
|
|
default:
|
|
Expect.fail("Unknown test mode");
|
|
}
|
|
}
|
|
|
|
void errorHandler(Socket socket) {
|
|
_errorEvents++;
|
|
socket.close();
|
|
}
|
|
|
|
void connectHandler(socket) {
|
|
socket.listen(dataHandler,
|
|
onDone: () => closeHandler(socket),
|
|
onError: (error) => errorHandler(socket));
|
|
|
|
void writeHello() {
|
|
socket.write("Hello");
|
|
}
|
|
|
|
_iterations++;
|
|
switch (_mode) {
|
|
case 0:
|
|
socket.destroy();
|
|
proceed();
|
|
break;
|
|
case 1:
|
|
writeHello();
|
|
socket.destroy();
|
|
proceed();
|
|
break;
|
|
case 2:
|
|
case 3:
|
|
writeHello();
|
|
break;
|
|
case 4:
|
|
writeHello();
|
|
socket.close(); // Half close.
|
|
break;
|
|
case 5:
|
|
writeHello();
|
|
break;
|
|
case 6:
|
|
writeHello();
|
|
socket.close(); // Half close.
|
|
break;
|
|
default:
|
|
Expect.fail("Unknown test mode");
|
|
}
|
|
}
|
|
|
|
Socket.connect(SocketCloseServer.HOST, _port).then(connectHandler);
|
|
}
|
|
|
|
void initialize() {
|
|
ReceivePort receivePort = new ReceivePort();
|
|
var remote = Isolate.spawn(startSocketCloseServer, receivePort.sendPort);
|
|
|
|
receivePort.first.then((message) {
|
|
this._sendPort = message;
|
|
sendReceive(_sendPort, _mode).then((port) {
|
|
this._port = port;
|
|
proceed();
|
|
});
|
|
});
|
|
}
|
|
|
|
void shutdown() {
|
|
sendReceive(_sendPort, SERVERSHUTDOWN).then((_) {
|
|
_done();
|
|
});
|
|
|
|
switch (_mode) {
|
|
case 0:
|
|
case 1:
|
|
Expect.equals(0, _dataEvents);
|
|
Expect.equals(ITERATIONS, _closeEvents);
|
|
break;
|
|
case 2:
|
|
Expect.equals(0, _dataEvents);
|
|
Expect.equals(ITERATIONS, _closeEvents);
|
|
break;
|
|
case 3:
|
|
case 4:
|
|
Expect.isTrue(_dataEvents <= ITERATIONS);
|
|
Expect.isTrue(_dataEvents >= 0);
|
|
Expect.equals(ITERATIONS, _closeEvents);
|
|
break;
|
|
case 5:
|
|
case 6:
|
|
Expect.equals(ITERATIONS, _dataEvents);
|
|
Expect.equals(ITERATIONS, _closeEvents);
|
|
break;
|
|
default:
|
|
Expect.fail("Unknown test mode");
|
|
}
|
|
Expect.equals(0, _errorEvents);
|
|
}
|
|
|
|
int _port;
|
|
SendPort _sendPort;
|
|
List<int> _buffer;
|
|
int _readBytes;
|
|
int _dataEvents;
|
|
int _closeEvents;
|
|
int _errorEvents;
|
|
int _iterations;
|
|
int _mode;
|
|
Function _done;
|
|
}
|
|
|
|
class ConnectionData {
|
|
ConnectionData(Socket this.connection) : readBytes = 0;
|
|
Socket connection;
|
|
int readBytes;
|
|
}
|
|
|
|
void startSocketCloseServer(Object replyToObj) {
|
|
SendPort replyTo = replyToObj;
|
|
var server = new SocketCloseServer();
|
|
replyTo.send(server.dispatchSendPort);
|
|
}
|
|
|
|
class SocketCloseServer {
|
|
static const HOST = "127.0.0.1";
|
|
|
|
SocketCloseServer() : _dispatchPort = new ReceivePort() {
|
|
_dispatchPort.listen(dispatch);
|
|
}
|
|
|
|
void connectionHandler(ConnectionData data) {
|
|
var connection = data.connection;
|
|
|
|
void readBytes(bytes, whenFiveBytes) {
|
|
data.readBytes += bytes.length;
|
|
Expect.isTrue(data.readBytes <= 5);
|
|
if (data.readBytes == 5) {
|
|
whenFiveBytes();
|
|
}
|
|
}
|
|
|
|
void writeHello() {
|
|
connection.write("Hello");
|
|
}
|
|
|
|
void dataHandler(bytes) {
|
|
switch (_mode) {
|
|
case 0:
|
|
Expect.fail("No data expected");
|
|
break;
|
|
case 1:
|
|
readBytes(bytes, () {
|
|
_dataEvents++;
|
|
});
|
|
break;
|
|
case 2:
|
|
readBytes(bytes, () {
|
|
_dataEvents++;
|
|
connection.destroy();
|
|
});
|
|
break;
|
|
case 3:
|
|
readBytes(bytes, () {
|
|
_dataEvents++;
|
|
writeHello();
|
|
connection.destroy();
|
|
});
|
|
break;
|
|
case 4:
|
|
readBytes(bytes, () {
|
|
_dataEvents++;
|
|
writeHello();
|
|
});
|
|
break;
|
|
case 5:
|
|
case 6:
|
|
readBytes(bytes, () {
|
|
_dataEvents++;
|
|
writeHello();
|
|
connection.close(); // Half close.
|
|
});
|
|
break;
|
|
default:
|
|
Expect.fail("Unknown test mode");
|
|
}
|
|
}
|
|
|
|
void closeHandler() {
|
|
_closeEvents++;
|
|
connection.close();
|
|
}
|
|
|
|
void errorHandler(e) {
|
|
Expect.fail("Socket error $e");
|
|
}
|
|
|
|
_iterations++;
|
|
|
|
connection.listen(dataHandler, onDone: closeHandler, onError: errorHandler);
|
|
}
|
|
|
|
void errorHandlerServer(e) {
|
|
Expect.fail("Server socket error");
|
|
}
|
|
|
|
waitForResult() {
|
|
// Make sure all iterations have been run. In multiple of these
|
|
// scenarios it is possible to get the SERVERSHUTDOWN message
|
|
// before we have received the last close event on the
|
|
// server. In these cases we wait for the correct number of
|
|
// close events.
|
|
if (_iterations == ITERATIONS &&
|
|
(_closeEvents == ITERATIONS || (_mode == 2 || _mode == 3))) {
|
|
switch (_mode) {
|
|
case 0:
|
|
Expect.equals(0, _dataEvents);
|
|
Expect.equals(ITERATIONS, _closeEvents);
|
|
break;
|
|
case 1:
|
|
Expect.isTrue(_dataEvents <= ITERATIONS);
|
|
Expect.isTrue(_dataEvents >= 0);
|
|
Expect.equals(ITERATIONS, _closeEvents);
|
|
break;
|
|
case 2:
|
|
case 3:
|
|
Expect.equals(ITERATIONS, _dataEvents);
|
|
Expect.equals(ITERATIONS, _closeEvents);
|
|
break;
|
|
case 4:
|
|
case 5:
|
|
case 6:
|
|
Expect.equals(ITERATIONS, _dataEvents);
|
|
Expect.equals(ITERATIONS, _closeEvents);
|
|
break;
|
|
default:
|
|
Expect.fail("Unknown test mode");
|
|
}
|
|
Expect.equals(0, _errorEvents);
|
|
_server.close();
|
|
_dispatchPort.close();
|
|
_donePort.send(null);
|
|
} else {
|
|
new Timer(new Duration(milliseconds: 100), waitForResult);
|
|
}
|
|
}
|
|
|
|
SendPort get dispatchSendPort => _dispatchPort.sendPort;
|
|
|
|
void dispatch(message) {
|
|
var command = message[0];
|
|
SendPort replyTo = message[1];
|
|
_donePort = replyTo;
|
|
if (command != SERVERSHUTDOWN) {
|
|
_readBytes = 0;
|
|
_errorEvents = 0;
|
|
_dataEvents = 0;
|
|
_closeEvents = 0;
|
|
_iterations = 0;
|
|
_mode = command;
|
|
ServerSocket.bind("127.0.0.1", 0).then((server) {
|
|
_server = server;
|
|
_server.listen((socket) {
|
|
var data = new ConnectionData(socket);
|
|
connectionHandler(data);
|
|
}, onError: errorHandlerServer);
|
|
replyTo.send(_server.port);
|
|
});
|
|
} else {
|
|
Timer.run(waitForResult);
|
|
}
|
|
}
|
|
|
|
ServerSocket _server;
|
|
final ReceivePort _dispatchPort;
|
|
SendPort _donePort;
|
|
int _readBytes;
|
|
int _errorEvents;
|
|
int _dataEvents;
|
|
int _closeEvents;
|
|
int _iterations;
|
|
int _mode;
|
|
}
|
|
|
|
main() {
|
|
// Run the close test in these different "modes".
|
|
// 0: Client closes without sending at all.
|
|
// 1: Client sends and destroys.
|
|
// 2: Client sends. Server destroys.
|
|
// 3: Client sends. Server responds and destroys.
|
|
// 4: Client sends and half-closes. Server responds and destroys.
|
|
// 5: Client sends. Server responds and half closes.
|
|
// 6: Client sends and half-closes. Server responds and half closes.
|
|
var tests = 7;
|
|
for (var i = 0; i < tests; i++) {
|
|
asyncStart();
|
|
new SocketClose.start(i, asyncEnd);
|
|
}
|
|
}
|