| Index: lib/src/runner/plugin/platform_helpers.dart
|
| diff --git a/lib/src/runner/plugin/platform_helpers.dart b/lib/src/runner/plugin/platform_helpers.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..d9732925252d5487f7649ca2f9e0d4f020fe4306
|
| --- /dev/null
|
| +++ b/lib/src/runner/plugin/platform_helpers.dart
|
| @@ -0,0 +1,135 @@
|
| +// Copyright (c) 2016, 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.
|
| +
|
| +import 'dart:async';
|
| +
|
| +import 'package:stack_trace/stack_trace.dart';
|
| +import 'package:stream_channel/stream_channel.dart';
|
| +
|
| +import '../../backend/group.dart';
|
| +import '../../backend/metadata.dart';
|
| +import '../../backend/test.dart';
|
| +import '../../backend/test_platform.dart';
|
| +import '../../util/io.dart';
|
| +import '../../util/remote_exception.dart';
|
| +import '../environment.dart';
|
| +import '../load_exception.dart';
|
| +import '../runner_suite.dart';
|
| +import '../runner_test.dart';
|
| +
|
| +typedef StackTrace _MapTrace(StackTrace trace);
|
| +
|
| +/// A helper method for creating a [RunnerSuiteController] containing tests
|
| +/// that communicate over [channel].
|
| +///
|
| +/// This returns a controller so that the caller has a chance to control the
|
| +/// runner suite's debugging state based on plugin-specific logic.
|
| +///
|
| +/// If the suite is closed, this will close [channel].
|
| +///
|
| +/// If [mapTrace] is passed, it will be used to adjust stack traces for any
|
| +/// errors emitted by tests.
|
| +Future<RunnerSuiteController> deserializeSuite(String path,
|
| + TestPlatform platform, Metadata metadata, Environment environment,
|
| + StreamChannel channel, {StackTrace mapTrace(StackTrace trace)}) async {
|
| + if (mapTrace == null) mapTrace = (trace) => trace;
|
| +
|
| + var disconnector = new Disconnector();
|
| + var suiteChannel = new MultiChannel(channel.transform(disconnector));
|
| +
|
| + suiteChannel.sink.add({
|
| + 'platform': platform.identifier,
|
| + 'metadata': metadata.serialize(),
|
| + 'os': platform == TestPlatform.vm ? currentOS.name : null
|
| + });
|
| +
|
| + var completer = new Completer();
|
| +
|
| + handleError(error, stackTrace) {
|
| + disconnector.disconnect();
|
| +
|
| + if (completer.isCompleted) {
|
| + // If we've already provided a controller, send the error to the
|
| + // LoadSuite. This will cause the virtual load test to fail, which will
|
| + // notify the user of the error.
|
| + Zone.current.handleUncaughtError(error, mapTrace(stackTrace));
|
| + } else {
|
| + completer.completeError(error, mapTrace(stackTrace));
|
| + }
|
| + }
|
| +
|
| + suiteChannel.stream.listen((response) {
|
| + switch (response["type"]) {
|
| + case "print":
|
| + print(response["line"]);
|
| + break;
|
| +
|
| + case "loadException":
|
| + handleError(
|
| + new LoadException(path, response["message"]),
|
| + new Trace.current());
|
| + break;
|
| +
|
| + case "error":
|
| + var asyncError = RemoteException.deserialize(response["error"]);
|
| + handleError(
|
| + new LoadException(path, asyncError.error),
|
| + mapTrace(asyncError.stackTrace));
|
| + break;
|
| +
|
| + case "success":
|
| + var deserializer = new _Deserializer(suiteChannel, mapTrace);
|
| + completer.complete(deserializer.deserializeGroup(response["root"]));
|
| + break;
|
| + }
|
| + }, onError: handleError, onDone: () {
|
| + if (completer.isCompleted) return;
|
| + completer.completeError(
|
| + new LoadException(
|
| + path, "Connection closed before test suite loaded."),
|
| + new Trace.current());
|
| + });
|
| +
|
| + return new RunnerSuiteController(
|
| + environment,
|
| + await completer.future,
|
| + path: path,
|
| + platform: platform,
|
| + os: currentOS,
|
| + onClose: disconnector.disconnect);
|
| +}
|
| +
|
| +/// A utility class for storing state while deserializing tests.
|
| +class _Deserializer {
|
| + /// The channel over which tests communicate.
|
| + final MultiChannel _channel;
|
| +
|
| + /// The function used to errors' map stack traces.
|
| + final _MapTrace _mapTrace;
|
| +
|
| + _Deserializer(this._channel, this._mapTrace);
|
| +
|
| + /// Deserializes [group] into a concrete [Group].
|
| + Group deserializeGroup(Map group) {
|
| + var metadata = new Metadata.deserialize(group['metadata']);
|
| + return new Group(group['name'], group['entries'].map((entry) {
|
| + if (entry['type'] == 'group') return deserializeGroup(entry);
|
| + return _deserializeTest(entry);
|
| + }),
|
| + metadata: metadata,
|
| + setUpAll: _deserializeTest(group['setUpAll']),
|
| + tearDownAll: _deserializeTest(group['tearDownAll']));
|
| + }
|
| +
|
| + /// Deserializes [test] into a concrete [Test] class.
|
| + ///
|
| + /// Returns `null` if [test] is `null`.
|
| + Test _deserializeTest(Map test) {
|
| + if (test == null) return null;
|
| +
|
| + var metadata = new Metadata.deserialize(test['metadata']);
|
| + var testChannel = _channel.virtualChannel(test['channel']);
|
| + return new RunnerTest(test['name'], metadata, testChannel, _mapTrace);
|
| + }
|
| +}
|
|
|