
When the engine dies unexpectedly during test execution, we have to terminate any tests running in that engine. Previously, they would just hang. For some reason that I was never able to satisfactorily explain, the WebSocket doesn't die in a way I can detect in this case. So instead, we hand in a future that we only complete when we detect the server subprocess ends.
95 lines
3.1 KiB
Dart
95 lines
3.1 KiB
Dart
// Copyright 2015 The Chromium Authors. 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:test/src/backend/live_test.dart';
|
|
import 'package:test/src/backend/live_test_controller.dart';
|
|
import 'package:test/src/backend/metadata.dart';
|
|
import 'package:test/src/backend/operating_system.dart';
|
|
import 'package:test/src/backend/state.dart';
|
|
import 'package:test/src/backend/suite.dart';
|
|
import 'package:test/src/backend/test.dart';
|
|
import 'package:test/src/backend/test_platform.dart';
|
|
import 'package:test/src/util/remote_exception.dart';
|
|
|
|
import 'package:sky_tools/src/test/json_socket.dart';
|
|
|
|
class RemoteTest extends Test {
|
|
RemoteTest(this.name, this.metadata, this._socket, this._index);
|
|
|
|
final String name;
|
|
final Metadata metadata;
|
|
final JSONSocket _socket;
|
|
final int _index;
|
|
|
|
LiveTest load(Suite suite) {
|
|
LiveTestController controller;
|
|
StreamSubscription subscription;
|
|
|
|
controller = new LiveTestController(suite, this, () async {
|
|
|
|
controller.setState(const State(Status.running, Result.success));
|
|
_socket.send({'command': 'run', 'index': _index});
|
|
|
|
subscription = _socket.stream.listen((message) {
|
|
if (message['type'] == 'error') {
|
|
AsyncError asyncError = RemoteException.deserialize(message['error']);
|
|
controller.addError(asyncError.error, asyncError.stackTrace);
|
|
} else if (message['type'] == 'state-change') {
|
|
controller.setState(
|
|
new State(
|
|
new Status.parse(message['status']),
|
|
new Result.parse(message['result'])));
|
|
} else if (message['type'] == 'print') {
|
|
controller.print(message['line']);
|
|
} else {
|
|
assert(message['type'] == 'complete');
|
|
subscription.cancel();
|
|
subscription = null;
|
|
controller.completer.complete();
|
|
}
|
|
});
|
|
|
|
_socket.unusualTermination.then((_) {
|
|
if (subscription != null) {
|
|
controller.addError(new Exception('Unexpected subprocess termination.'), new Trace.current());
|
|
controller.setState(new State(Status.complete, Result.error));
|
|
subscription.cancel();
|
|
subscription = null;
|
|
controller.completer.complete();
|
|
}
|
|
});
|
|
|
|
}, () async {
|
|
_socket.send({'command': 'close'});
|
|
if (subscription != null) {
|
|
subscription.cancel();
|
|
subscription = null;
|
|
}
|
|
});
|
|
return controller.liveTest;
|
|
}
|
|
|
|
Test change({String name, Metadata metadata}) {
|
|
if (name == name && metadata == this.metadata) return this;
|
|
if (name == null) name = this.name;
|
|
if (metadata == null) metadata = this.metadata;
|
|
return new RemoteTest(name, metadata, _socket, _index);
|
|
}
|
|
|
|
// TODO(ianh): Implement this if we need it.
|
|
Test forPlatform(TestPlatform platform, {OperatingSystem os}) {
|
|
if (!metadata.testOn.evaluate(platform, os: os))
|
|
return null;
|
|
return new RemoteTest(
|
|
name,
|
|
metadata.forPlatform(platform, os: os),
|
|
_socket,
|
|
_index
|
|
);
|
|
}
|
|
}
|