| // Copyright (c) 2012, 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'; |
| |
| const SERVERSHUTDOWN = -1; |
| const ITERATIONS = 10; |
| |
| |
| class SocketClose { |
| |
| SocketClose.start(this._mode, this._donePort) |
| : _receivePort = new ReceivePort(), |
| _sendPort = null, |
| _readBytes = 0, |
| _dataEvents = 0, |
| _closeEvents = 0, |
| _errorEvents = 0, |
| _iterations = 0 { |
| _sendPort = spawnFunction(startSocketCloseServer); |
| initialize(); |
| } |
| |
| void proceed() { |
| if (_iterations < ITERATIONS) { |
| new Timer(0, sendData); |
| } else { |
| shutdown(); |
| } |
| } |
| |
| void sendData(Timer timer) { |
| |
| void dataHandler() { |
| switch (_mode) { |
| case 0: |
| case 1: |
| case 2: |
| Expect.fail("No data expected"); |
| break; |
| case 3: |
| case 4: |
| case 5: |
| case 6: |
| case 7: |
| case 8: |
| var read = _socket.inputStream.read(); |
| _readBytes += read.length; |
| if ((_readBytes % 5) == 0) { |
| _dataEvents++; |
| } |
| break; |
| default: |
| Expect.fail("Unknown test mode"); |
| } |
| } |
| |
| void closeHandler() { |
| _closeEvents++; |
| switch (_mode) { |
| case 0: |
| case 1: |
| break; |
| case 2: |
| case 3: |
| case 4: |
| _socket.outputStream.close(); |
| proceed(); |
| break; |
| case 5: |
| proceed(); |
| break; |
| case 6: |
| _socket.outputStream.close(); |
| proceed(); |
| break; |
| case 7: |
| case 8: |
| proceed(); |
| break; |
| default: |
| Expect.fail("Unknown test mode"); |
| } |
| } |
| |
| void errorHandler(Exception e) { |
| _errorEvents++; |
| _socket.close(); |
| } |
| |
| void connectHandler() { |
| _socket.inputStream.onData = dataHandler; |
| _socket.inputStream.onClosed = closeHandler; |
| _socket.onError = errorHandler; |
| |
| _iterations++; |
| switch (_mode) { |
| case 0: |
| _socket.inputStream.close(); |
| proceed(); |
| break; |
| case 1: |
| _socket.outputStream.write("Hello".charCodes); |
| _socket.outputStream.onNoPendingWrites = () { |
| _socket.inputStream.close(); |
| proceed(); |
| }; |
| break; |
| case 2: |
| case 3: |
| case 4: |
| _socket.outputStream.write("Hello".charCodes); |
| break; |
| case 5: |
| _socket.outputStream.write("Hello".charCodes); |
| _socket.outputStream.onNoPendingWrites = () { |
| _socket.outputStream.close(); |
| }; |
| break; |
| case 6: |
| _socket.outputStream.write("Hello".charCodes); |
| break; |
| case 7: |
| case 8: |
| _socket.outputStream.write("Hello".charCodes); |
| _socket.outputStream.onNoPendingWrites = () { |
| _socket.outputStream.close(); |
| }; |
| break; |
| default: |
| Expect.fail("Unknown test mode"); |
| } |
| } |
| |
| _socket = new Socket(SocketCloseServer.HOST, _port); |
| Expect.equals(true, _socket != null); |
| _socket.onConnect = connectHandler; |
| } |
| |
| void initialize() { |
| _receivePort.receive((var message, SendPort replyTo) { |
| _port = message; |
| proceed(); |
| }); |
| _sendPort.send(_mode, _receivePort.toSendPort()); |
| } |
| |
| void shutdown() { |
| _sendPort.send(SERVERSHUTDOWN, _receivePort.toSendPort()); |
| _receivePort.receive((message, ignore) { |
| _donePort.send(null); |
| _receivePort.close(); |
| }); |
| |
| switch (_mode) { |
| case 0: |
| case 1: |
| Expect.equals(0, _dataEvents); |
| Expect.equals(0, _closeEvents); |
| break; |
| case 2: |
| Expect.equals(0, _dataEvents); |
| Expect.equals(ITERATIONS, _closeEvents); |
| break; |
| case 3: |
| Expect.equals(ITERATIONS, _dataEvents); |
| Expect.equals(ITERATIONS, _closeEvents); |
| break; |
| case 4: |
| Expect.equals(ITERATIONS, _closeEvents); |
| break; |
| case 5: |
| case 6: |
| case 7: |
| case 8: |
| Expect.equals(ITERATIONS, _dataEvents); |
| Expect.equals(ITERATIONS, _closeEvents); |
| break; |
| default: |
| Expect.fail("Unknown test mode"); |
| } |
| Expect.equals(0, _errorEvents); |
| } |
| |
| int _port; |
| ReceivePort _receivePort; |
| SendPort _sendPort; |
| Socket _socket; |
| List<int> _buffer; |
| int _readBytes; |
| int _dataEvents; |
| int _closeEvents; |
| int _errorEvents; |
| int _iterations; |
| int _mode; |
| SendPort _donePort; |
| } |
| |
| |
| class ConnectionData { |
| ConnectionData(Socket this.connection) : readBytes = 0; |
| Socket connection; |
| int readBytes; |
| } |
| |
| |
| void startSocketCloseServer() { |
| var server = new SocketCloseServer(); |
| port.receive(server.dispatch); |
| } |
| |
| |
| class SocketCloseServer { |
| |
| static const HOST = "127.0.0.1"; |
| |
| SocketCloseServer() : super() {} |
| |
| void connectionHandler(ConnectionData data) { |
| var connection = data.connection; |
| |
| void readBytes(whenFiveBytes) { |
| var read = connection.inputStream.read(); |
| data.readBytes += read.length; |
| if (data.readBytes == 5) { |
| whenFiveBytes(); |
| } |
| } |
| |
| void dataHandler() { |
| switch (_mode) { |
| case 0: |
| Expect.fail("No data expected"); |
| break; |
| case 1: |
| readBytes(() { |
| _dataEvents++; |
| }); |
| break; |
| case 2: |
| readBytes(() { |
| _dataEvents++; |
| connection.inputStream.close(); |
| }); |
| break; |
| case 3: |
| readBytes(() { |
| _dataEvents++; |
| connection.outputStream.write("Hello".charCodes); |
| connection.outputStream.onNoPendingWrites = () { |
| connection.inputStream.close(); |
| }; |
| }); |
| break; |
| case 4: |
| readBytes(() { |
| _dataEvents++; |
| connection.outputStream.write("Hello".charCodes); |
| connection.inputStream.close(); |
| }); |
| break; |
| case 5: |
| readBytes(() { |
| _dataEvents++; |
| connection.outputStream.write("Hello".charCodes); |
| }); |
| break; |
| case 6: |
| case 7: |
| readBytes(() { |
| _dataEvents++; |
| connection.outputStream.write("Hello".charCodes); |
| connection.outputStream.onNoPendingWrites = () { |
| connection.outputStream.close(); |
| }; |
| }); |
| break; |
| case 8: |
| readBytes(() { |
| _dataEvents++; |
| connection.outputStream.write("Hello".charCodes); |
| connection.outputStream.close(); |
| }); |
| break; |
| default: |
| Expect.fail("Unknown test mode"); |
| } |
| } |
| |
| void closeHandler() { |
| _closeEvents++; |
| connection.outputStream.close(); |
| } |
| |
| void errorHandler(Exception e) { |
| Expect.fail("Socket error $e"); |
| } |
| |
| _iterations++; |
| |
| connection.inputStream.onData = dataHandler; |
| connection.inputStream.onClosed = closeHandler; |
| connection.onError = errorHandler; |
| } |
| |
| void errorHandlerServer(Exception e) { |
| Expect.fail("Server socket error"); |
| } |
| |
| waitForResult(Timer timer) { |
| // 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 || _mode == 4))) { |
| switch (_mode) { |
| case 0: |
| Expect.equals(0, _dataEvents); |
| Expect.equals(ITERATIONS, _closeEvents); |
| break; |
| case 1: |
| Expect.equals(ITERATIONS, _dataEvents); |
| Expect.equals(ITERATIONS, _closeEvents); |
| break; |
| case 2: |
| case 3: |
| case 4: |
| Expect.equals(ITERATIONS, _dataEvents); |
| Expect.equals(0, _closeEvents); |
| break; |
| case 5: |
| case 6: |
| case 7: |
| case 8: |
| Expect.equals(ITERATIONS, _dataEvents); |
| Expect.equals(ITERATIONS, _closeEvents); |
| break; |
| default: |
| Expect.fail("Unknown test mode"); |
| } |
| Expect.equals(0, _errorEvents); |
| _server.close(); |
| port.close(); |
| _donePort.send(null); |
| } else { |
| new Timer(100, waitForResult); |
| } |
| } |
| |
| void dispatch(message, replyTo) { |
| _donePort = replyTo; |
| if (message != SERVERSHUTDOWN) { |
| _readBytes = 0; |
| _errorEvents = 0; |
| _dataEvents = 0; |
| _closeEvents = 0; |
| _iterations = 0; |
| _mode = message; |
| _server = new ServerSocket(HOST, 0, 10); |
| Expect.equals(true, _server != null); |
| _server.onConnection = (connection) { |
| var data = new ConnectionData(connection); |
| connectionHandler(data); |
| }; |
| _server.onError = errorHandlerServer; |
| replyTo.send(_server.port, null); |
| } else { |
| new Timer(0, waitForResult); |
| } |
| } |
| |
| ServerSocket _server; |
| 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 closes. |
| // 2: Client sends. Server closes. |
| // 3: Client sends. Server responds and closes. |
| // 4: Client sends. Server responds and closes without waiting for everything |
| // being sent. |
| // 5: Client sends and half-closes. Server responds and closes. |
| // 6: Client sends. Server responds and half closes. |
| // 7: Client sends and half-closes. Server responds and half closes. |
| // 8: Client sends and half-closes. Server responds and half closes without |
| // explicitly waiting for everything being sent. |
| var tests = 9; |
| var port = new ReceivePort(); |
| var completed = 0; |
| port.receive((message, ignore) { |
| if (++completed == tests) port.close(); |
| }); |
| for (var i = 0; i < tests; i++) { |
| new SocketClose.start(i, port.toSendPort()); |
| } |
| } |