Commit 47de5155 authored by Ian Hickson's avatar Ian Hickson Committed by GitHub

Provide a feature to set the ports when running tests. (#7558)

This brings the feature back, since removing it broke one of our more
exotic sets of customers.
parent 3f1d6d3b
...@@ -13,6 +13,7 @@ import 'package:test/src/backend/test_platform.dart'; // ignore: implementation_ ...@@ -13,6 +13,7 @@ import 'package:test/src/backend/test_platform.dart'; // ignore: implementation_
import 'package:test/src/runner/plugin/platform.dart'; // ignore: implementation_imports import 'package:test/src/runner/plugin/platform.dart'; // ignore: implementation_imports
import 'package:test/src/runner/plugin/hack_register_platform.dart' as hack; // ignore: implementation_imports import 'package:test/src/runner/plugin/hack_register_platform.dart' as hack; // ignore: implementation_imports
import '../base/common.dart';
import '../base/file_system.dart'; import '../base/file_system.dart';
import '../base/io.dart'; import '../base/io.dart';
import '../base/process_manager.dart'; import '../base/process_manager.dart';
...@@ -42,10 +43,25 @@ const String _kStartTimeoutTimerMessage = 'sky_shell test process has entered ma ...@@ -42,10 +43,25 @@ const String _kStartTimeoutTimerMessage = 'sky_shell test process has entered ma
/// processes will host the Observatory server. /// processes will host the Observatory server.
final InternetAddress _kHost = InternetAddress.LOOPBACK_IP_V4; final InternetAddress _kHost = InternetAddress.LOOPBACK_IP_V4;
void installHook({ @required String shellPath, CoverageCollector collector }) { /// Configure the `test` package to work with Flutter.
///
/// On systems where each [FlutterPlatform] is only used to run one test suite
/// (that is, one Dart file with a `*_test.dart` file name and a single `void
/// main()`), you can set an observatory port and a diagnostic port explicitly.
void installHook({
@required String shellPath,
CoverageCollector collector,
int observatoryPort,
int diagnosticPort,
}) {
hack.registerPlatformPlugin( hack.registerPlatformPlugin(
<TestPlatform>[TestPlatform.vm], <TestPlatform>[TestPlatform.vm],
() => new FlutterPlatform(shellPath: shellPath, collector: collector), () => new FlutterPlatform(
shellPath: shellPath,
collector: collector,
explicitObservatoryPort: observatoryPort,
explicitDiagnosticPort: diagnosticPort,
),
); );
} }
...@@ -54,12 +70,14 @@ enum _TestResult { crashed, harnessBailed, testBailed } ...@@ -54,12 +70,14 @@ enum _TestResult { crashed, harnessBailed, testBailed }
typedef Future<Null> _Finalizer(); typedef Future<Null> _Finalizer();
class FlutterPlatform extends PlatformPlugin { class FlutterPlatform extends PlatformPlugin {
FlutterPlatform({ this.shellPath, this.collector }) { FlutterPlatform({ this.shellPath, this.collector, this.explicitObservatoryPort, this.explicitDiagnosticPort }) {
assert(shellPath != null); assert(shellPath != null);
} }
final String shellPath; final String shellPath;
final CoverageCollector collector; final CoverageCollector collector;
final int explicitObservatoryPort;
final int explicitDiagnosticPort;
// Each time loadChannel() is called, we spin up a local WebSocket server, // Each time loadChannel() is called, we spin up a local WebSocket server,
// then spin up the engine in a subprocess. We pass the engine a Dart file // then spin up the engine in a subprocess. We pass the engine a Dart file
...@@ -68,8 +86,16 @@ class FlutterPlatform extends PlatformPlugin { ...@@ -68,8 +86,16 @@ class FlutterPlatform extends PlatformPlugin {
// crashes, we inject an error into that stream. When the process closes, // crashes, we inject an error into that stream. When the process closes,
// we clean everything up. // we clean everything up.
int _testCount = 0;
@override @override
StreamChannel<dynamic> loadChannel(String testPath, TestPlatform platform) { StreamChannel<dynamic> loadChannel(String testPath, TestPlatform platform) {
if (explicitObservatoryPort != null || explicitDiagnosticPort != null) {
if (_testCount > 0)
throwToolExit('installHook() was called with an observatory port or a diagnostic port (or both) but then more than one test suite was run.');
}
int ourTestCount = _testCount;
_testCount += 1;
StreamController<dynamic> localController = new StreamController<dynamic>(); StreamController<dynamic> localController = new StreamController<dynamic>();
StreamController<dynamic> remoteController = new StreamController<dynamic>(); StreamController<dynamic> remoteController = new StreamController<dynamic>();
Completer<Null> testCompleteCompleter = new Completer<Null>(); Completer<Null> testCompleteCompleter = new Completer<Null>();
...@@ -85,17 +111,13 @@ class FlutterPlatform extends PlatformPlugin { ...@@ -85,17 +111,13 @@ class FlutterPlatform extends PlatformPlugin {
localController.stream, localController.stream,
remoteSink, remoteSink,
); );
_startTest(testPath, localChannel).whenComplete(() { _startTest(testPath, localChannel, ourTestCount).whenComplete(() {
testCompleteCompleter.complete(); testCompleteCompleter.complete();
}); });
return remoteChannel; return remoteChannel;
} }
int _testCount = 0; Future<Null> _startTest(String testPath, StreamChannel<dynamic> controller, int ourTestCount) async {
Future<Null> _startTest(String testPath, StreamChannel<dynamic> controller) async {
int ourTestCount = _testCount;
_testCount += 1;
printTrace('test $ourTestCount: starting test $testPath'); printTrace('test $ourTestCount: starting test $testPath');
final List<_Finalizer> finalizers = <_Finalizer>[]; final List<_Finalizer> finalizers = <_Finalizer>[];
...@@ -150,6 +172,8 @@ class FlutterPlatform extends PlatformPlugin { ...@@ -150,6 +172,8 @@ class FlutterPlatform extends PlatformPlugin {
listenerFile.path, listenerFile.path,
packages: PackageMap.globalPackagesPath, packages: PackageMap.globalPackagesPath,
enableObservatory: collector != null, enableObservatory: collector != null,
observatoryPort: explicitObservatoryPort,
diagnosticPort: explicitDiagnosticPort,
); );
subprocessActive = true; subprocessActive = true;
finalizers.add(() async { finalizers.add(() async {
...@@ -172,10 +196,11 @@ class FlutterPlatform extends PlatformPlugin { ...@@ -172,10 +196,11 @@ class FlutterPlatform extends PlatformPlugin {
int processObservatoryPort; int processObservatoryPort;
_pipeStandardStreamsToConsole( _pipeStandardStreamsToConsole(
process, process,
storeObservatoryPort: (int observatoryPort) { storeObservatoryPort: (int detectedPort) {
assert(processObservatoryPort == null); assert(processObservatoryPort == null);
printTrace('test $ourTestCount: using observatory port $observatoryPort from pid ${process.pid} to collect coverage'); assert(explicitObservatoryPort == null || explicitObservatoryPort == detectedPort);
processObservatoryPort = observatoryPort; printTrace('test $ourTestCount: using observatory port $detectedPort from pid ${process.pid} to collect coverage');
processObservatoryPort = detectedPort;
}, },
startTimeoutTimer: () { startTimeoutTimer: () {
new Future<_InitialResult>.delayed(_kTestStartupTimeout, () => timeout.complete()); new Future<_InitialResult>.delayed(_kTestStartupTimeout, () => timeout.complete());
...@@ -377,12 +402,33 @@ void main() { ...@@ -377,12 +402,33 @@ void main() {
return _cachedFontConfig; return _cachedFontConfig;
} }
Future<Process> _startProcess(
Future<Process> _startProcess(String executable, String testPath, { String packages, bool enableObservatory: false }) { String executable,
String testPath, {
String packages,
bool enableObservatory: false,
int observatoryPort,
int diagnosticPort,
}) {
assert(executable != null); // Please provide the path to the shell in the SKY_SHELL environment variable. assert(executable != null); // Please provide the path to the shell in the SKY_SHELL environment variable.
List<String> arguments = <String>[]; List<String> arguments = <String>[];
if (!enableObservatory) if (enableObservatory) {
arguments.add('--disable-observatory'); // Some systems drive the FlutterPlatform class in an unusual way, where
// only one test file is processed at a time, and the operating
// environment hands out specific ports ahead of time in a cooperative
// manner, where we're only allowed to open ports that were given to us in
// advance like this. For those esoteric systems, we have this feature
// whereby you can create FlutterPlatform with a pair of ports.
//
// I mention this only so that you won't be tempted, as I was, to apply
// the obvious simplification to this code and remove this entire feature.
if (observatoryPort != null)
arguments.add('--observatory-port=$observatoryPort');
if (diagnosticPort != null)
arguments.add('--diagnostic-port=$diagnosticPort');
} else {
arguments.addAll(<String>['--disable-observatory', '--disable-diagnostic']);
}
arguments.addAll(<String>[ arguments.addAll(<String>[
'--enable-dart-profiling', '--enable-dart-profiling',
'--non-interactive', '--non-interactive',
...@@ -404,7 +450,7 @@ void main() { ...@@ -404,7 +450,7 @@ void main() {
void _pipeStandardStreamsToConsole( void _pipeStandardStreamsToConsole(
Process process, { Process process, {
void startTimeoutTimer(), void startTimeoutTimer(),
void storeObservatoryPort(int port) void storeObservatoryPort(int port),
}) { }) {
for (Stream<List<int>> stream in for (Stream<List<int>> stream in
<Stream<List<int>>>[process.stderr, process.stdout]) { <Stream<List<int>>>[process.stderr, process.stdout]) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment