[dds] Support using port=0 for DAP and print the bound host/port in JSON to stdout

Change-Id: Ib1e99f1004b59cba6fa6970dbddbf5cbe87a8b32
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/205160
Reviewed-by: Ben Konyi <bkonyi@google.com>
Commit-Queue: Ben Konyi <bkonyi@google.com>
This commit is contained in:
Danny Tuppeny 2021-06-28 19:58:32 +00:00 committed by commit-bot@chromium.org
parent 0b35f89bf8
commit c84c21e741
3 changed files with 31 additions and 23 deletions

View file

@ -15,8 +15,6 @@ import 'protocol_stream_transformers.dart';
/// A DAP server that binds to a port and runs in multi-session mode.
class DapServer {
static const defaultPort = 9200;
final ServerSocket _socket;
final bool enableDds;
final bool enableAuthCodes;

View file

@ -6,15 +6,12 @@ import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'dart:isolate';
import 'dart:math' show Random;
import 'package:dds/src/dap/logging.dart';
import 'package:dds/src/dap/server.dart';
import 'package:path/path.dart' as path;
import 'package:pedantic/pedantic.dart';
final _random = Random();
abstract class DapTestServer {
List<String> get errorLogs;
String get host;
@ -53,14 +50,6 @@ class InProcessDapTestServer extends DapTestServer {
/// but will be a little more difficult to debug tests as the debugger will not
/// be attached to the process.
class OutOfProcessDapTestServer extends DapTestServer {
/// To avoid issues with port bindings if multiple test libraries are run
/// concurrently (in their own processes), start from a random port between
/// [DapServer.defaultPort] and [DapServer.defaultPort] + 5000.
///
/// This number will then be increased should multiple libraries run within
/// this same process.
static var _nextPort = DapServer.defaultPort + _random.nextInt(5000);
var _isShuttingDown = false;
final Process _process;
final int port;
@ -75,10 +64,7 @@ class OutOfProcessDapTestServer extends DapTestServer {
this.port,
Logger? logger,
) {
// The DAP server should generally not write to stdout/stderr (unless -v is
// passed), but it may do if it fails to start or crashes. If this happens,
// and there's no logger, print to stdout.
_process.stdout.transform(utf8.decoder).listen(logger ?? print);
// Treat anything written to stderr as the DAP crashing and fail the test.
_process.stderr.transform(utf8.decoder).listen((error) {
logger?.call(error);
_errors.add(error);
@ -111,20 +97,37 @@ class OutOfProcessDapTestServer extends DapTestServer {
final dapServerScript =
path.join(ddsLibFolder, '../tool/dap/run_server.dart');
final port = OutOfProcessDapTestServer._nextPort++;
final host = 'localhost';
final _process = await Process.start(
Platform.resolvedExecutable,
[
dapServerScript,
'dap',
'--host=$host',
'--port=$port',
...?additionalArgs,
if (logger != null) '--verbose'
],
);
final startedCompleter = Completer<void>();
late String host;
late int port;
// Scrape the `started` event to get the host/port. Any other output
// should be sent to the logger (as it may be verbose output for diagnostic
// purposes).
_process.stdout.transform(utf8.decoder).listen((text) {
if (!startedCompleter.isCompleted) {
final event = jsonDecode(text);
if (event['state'] == 'started') {
host = event['dapHost'];
port = event['dapPort'];
startedCompleter.complete();
return;
}
}
logger?.call(text);
});
await startedCompleter.future;
return OutOfProcessDapTestServer._(_process, host, port, logger);
}
}

View file

@ -2,6 +2,7 @@
// 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.
import 'dart:convert';
import 'dart:io';
import 'package:args/command_runner.dart';
@ -44,7 +45,7 @@ class DapCommand extends Command {
..addOption(
argPort,
abbr: 'p',
defaultsTo: DapServer.defaultPort.toString(),
defaultsTo: '0',
help: 'The port to bind the server to',
)
..addFlag(
@ -69,12 +70,18 @@ class DapCommand extends Command {
final port = int.parse(args[argPort]);
final host = args[argHost];
await DapServer.create(
final server = await DapServer.create(
host: host,
port: port,
enableDdds: args[argDds],
enableAuthCodes: args[argAuthCodes],
logger: args[argVerbose] ? print : null,
);
stdout.write(jsonEncode({
'state': 'started',
'dapHost': server.host,
'dapPort': server.port,
}));
}
}