a323c55162
Change-Id: I4d492a63a41880ef8cd69321372a4853825b9efd Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/426321 Reviewed-by: Liam Appelbe <liama@google.com> Auto-Submit: Bob Nystrom <rnystrom@google.com> Commit-Queue: Liam Appelbe <liama@google.com>
389 lines
9.1 KiB
Dart
389 lines
9.1 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=
|
|
// 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 'dart:typed_data';
|
|
|
|
import "package:expect/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)
|
|
: _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(Uint8List 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);
|
|
}
|
|
|
|
late int _port;
|
|
late SendPort _sendPort;
|
|
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 as SendPort;
|
|
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(Uint8List bytes, whenFiveBytes) {
|
|
data.readBytes += bytes.length;
|
|
Expect.isTrue(data.readBytes <= 5);
|
|
if (data.readBytes == 5) {
|
|
whenFiveBytes();
|
|
}
|
|
}
|
|
|
|
void writeHello() {
|
|
connection.write("Hello");
|
|
}
|
|
|
|
void dataHandler(Uint8List 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);
|
|
}
|
|
}
|
|
|
|
late ServerSocket _server;
|
|
final ReceivePort _dispatchPort;
|
|
late SendPort _donePort;
|
|
int _readBytes = 0;
|
|
int _errorEvents = 0;
|
|
int _dataEvents = 0;
|
|
int _closeEvents = 0;
|
|
int _iterations = 0;
|
|
int _mode = 0;
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|