import 'dart:async'; import 'dart:convert'; import 'dart:io'; import 'package:proto_socket/proto_socket.dart'; const _host = '127.0.0.1'; const _wsPort = 29098; const _wssPort = 29099; const _heartbeatIntervalSeconds = 30; const _heartbeatWaitSeconds = 10; const _serverObservationWindow = Duration(milliseconds: 500); const _processTimeout = Duration(seconds: 60); const _streamTimeout = Duration(seconds: 5); final _repoRoot = File.fromUri(Platform.script).parent.parent.parent.path; final _dartDir = Directory('$_repoRoot/dart').path; final _certFile = '$_repoRoot/dart/test/certs/server.crt'; final _keyFile = '$_repoRoot/dart/test/certs/server.key'; class _ServerWsClient extends WsProtobufClient { _ServerWsClient(WebSocket ws) : super(ws, _heartbeatIntervalSeconds, _heartbeatWaitSeconds, { TestData.getDefault().info_.qualifiedMessageName: TestData.fromBuffer, }); } class _DartWebWsServer extends WsProtobufServer { final void Function(WsProtobufClient) onConnected; _DartWebWsServer(int port, this.onConnected) : super(_host, port, (ws) => _ServerWsClient(ws)); _DartWebWsServer.secure( int port, SecurityContext securityContext, this.onConnected) : super.secure(_host, port, securityContext, (ws) => _ServerWsClient(ws)); @override void onClientConnected(WsProtobufClient client) => onConnected(client); } Future main() async { print( 'INFO typeName dart=${TestData.getDefault().info_.qualifiedMessageName}'); try { await _runWebSuites(); print('PASS scenario=ws-send-push'); print('PASS scenario=ws-request-response'); print('PASS scenario=wss-send-push'); print('PASS scenario=wss-request-response'); print('PASS all dart-server/dart-web-client crosstests passed'); } catch (error) { stderr.writeln('FAIL crosstest error=$error'); exitCode = 1; } } Future _runWebSuites() async { final wsReceived = Completer(); final wssReceived = Completer(); final securityContext = SecurityContext() ..useCertificateChain(_certFile) ..usePrivateKey(_keyFile); final wsServer = _DartWebWsServer(_wsPort, (client) { _configureWebClient(client, wsReceived); }); final wssServer = _DartWebWsServer.secure(_wssPort, securityContext, (client) { _configureWebClient(client, wssReceived); }); await wsServer.start(); await wssServer.start(); try { await _runDartBrowserTest('test/browser_ws_dart_io_test.dart'); await _expectReceived('WS', wsReceived); await _expectReceived('WSS', wssReceived); } finally { await Future.wait([ wssServer.stop(), wsServer.stop(), ]); } } void _configureWebClient(WsProtobufClient client, Completer received) { client.addRequestListener((req) async { print('SERVER_RECEIVED index=${req.index} message=${req.message}'); if (req.index == 101 && req.message == 'fire from dart web client') { if (!received.isCompleted) { received.complete(true); } unawaited(client.send(TestData() ..index = 200 ..message = 'push from dart server')); } return TestData() ..index = req.index * 2 ..message = 'echo: ${req.message}'; }); } Future _expectReceived(String transport, Completer received) async { final ok = await received.future .timeout(_serverObservationWindow, onTimeout: () => false); if (!ok) { throw StateError( '$transport web send-push server did not receive expected data'); } } Future _runDartBrowserTest(String testPath) async { final process = await Process.start( 'dart', ['test', '-p', 'chrome', testPath], workingDirectory: _dartDir, ); final stdoutDone = process.stdout .transform(utf8.decoder) .transform(const LineSplitter()) .listen(print) .asFuture(); final stderrDone = process.stderr .transform(utf8.decoder) .transform(const LineSplitter()) .listen(stderr.writeln) .asFuture(); final code = await process.exitCode.timeout(_processTimeout, onTimeout: () { process.kill(ProcessSignal.sigkill); return -1; }); await Future.wait([stdoutDone, stderrDone]).timeout(_streamTimeout, onTimeout: () { throw StateError('dart browser test streams did not finish'); }); if (code != 0) { throw StateError('dart browser test failed exitCode=$code'); } }