Index: tools/testing/dart/test_runner.dart |
diff --git a/tools/testing/dart/test_runner.dart b/tools/testing/dart/test_runner.dart |
index 0d641366b737a25db8168df207f5e5105243306f..09e2b06823e9ac8462e116b9186f1a6688a64089 100644 |
--- a/tools/testing/dart/test_runner.dart |
+++ b/tools/testing/dart/test_runner.dart |
@@ -18,6 +18,7 @@ import "dart:convert" show LineSplitter, UTF8, JSON; |
// CommandOutput.exitCode in subclasses of CommandOutput. |
import "dart:io" as io; |
import "dart:math" as math; |
+import 'android.dart'; |
import 'dependency_graph.dart' as dgraph; |
import "browser_controller.dart"; |
import "path.dart"; |
@@ -344,6 +345,33 @@ class VmCommand extends ProcessCommand { |
: super._("vm", executable, arguments, environmentOverrides); |
} |
+class AdbPrecompilationCommand extends Command { |
+ final String precompiledRunnerFilename; |
+ final String precompiledTestDirectory; |
+ final bool useBlobs; |
+ |
+ AdbPrecompilationCommand._(this.precompiledRunnerFilename, |
+ this.precompiledTestDirectory, |
+ this.useBlobs) |
+ : super._("adb_precompilation"); |
+ |
+ void _buildHashCode(HashCodeBuilder builder) { |
+ super._buildHashCode(builder); |
+ builder.add(precompiledRunnerFilename); |
+ builder.add(precompiledTestDirectory); |
+ builder.add(useBlobs); |
+ } |
+ |
+ bool _equal(AdbPrecompilationCommand other) => |
+ super._equal(other) && |
+ precompiledRunnerFilename == other.precompiledRunnerFilename && |
+ useBlobs == other.useBlobs && |
+ precompiledTestDirectory == other.precompiledTestDirectory; |
+ |
+ String toString() => 'Steps to push precompiled runner and precompiled code ' |
+ 'to an attached device. Uses (and requires) adb.'; |
+} |
+ |
class JSCommandlineCommand extends ProcessCommand { |
JSCommandlineCommand._( |
String displayName, String executable, List<String> arguments, |
@@ -610,6 +638,14 @@ class CommandBuilder { |
return _getUniqueCommand(command); |
} |
+ AdbPrecompilationCommand getAdbPrecompiledCommand(String precompiledRunner, |
+ String testDirectory, |
+ bool useBlobs) { |
+ var command = new AdbPrecompilationCommand._( |
+ precompiledRunner, testDirectory, useBlobs); |
+ return _getUniqueCommand(command); |
+ } |
+ |
Command getJSCommandlineCommand(String displayName, executable, arguments, |
[environment = null]) { |
var command = new JSCommandlineCommand._( |
@@ -1625,6 +1661,9 @@ CommandOutput createCommandOutput(Command command, int exitCode, bool timedOut, |
} else if (command is VmCommand) { |
return new VmCommandOutputImpl( |
command, exitCode, timedOut, stdout, stderr, time, pid); |
+ } else if (command is AdbPrecompilationCommand) { |
+ return new VmCommandOutputImpl( |
+ command, exitCode, timedOut, stdout, stderr, time, pid); |
} else if (command is CompilationCommand) { |
if (command.displayName == 'precompiler' || |
command.displayName == 'dart2snapshot') { |
@@ -2396,6 +2435,7 @@ class CommandExecutorImpl implements CommandExecutor { |
final Map globalConfiguration; |
final int maxProcesses; |
final int maxBrowserProcesses; |
+ AdbDevicePool adbDevicePool; |
// For dart2js and analyzer batch processing, |
// we keep a list of batch processes. |
@@ -2406,7 +2446,8 @@ class CommandExecutorImpl implements CommandExecutor { |
bool _finishing = false; |
CommandExecutorImpl( |
- this.globalConfiguration, this.maxProcesses, this.maxBrowserProcesses); |
+ this.globalConfiguration, this.maxProcesses, this.maxBrowserProcesses, |
+ {this.adbDevicePool}); |
Future cleanup() { |
assert(!_finishing); |
@@ -2460,11 +2501,92 @@ class CommandExecutorImpl implements CommandExecutor { |
.runCommand(command.flavor, command, timeout, command.arguments); |
} else if (command is ScriptCommand) { |
return command.run(); |
+ } else if (command is AdbPrecompilationCommand) { |
+ assert(adbDevicePool != null); |
+ return adbDevicePool.aquireDevice().then((AdbDevice device) { |
Florian Schneider
2016/04/27 13:53:05
s/aquire/acquire/
kustermann
2016/05/02 10:40:23
Done.
|
+ return _runAdbPrecompilationCommand(device, command).whenComplete(() { |
+ adbDevicePool.releaseDevice(device); |
+ }); |
+ }); |
} else { |
return new RunningProcess(command, timeout).run(); |
} |
} |
+ Future<CommandOutput> _runAdbPrecompilationCommand( |
+ AdbDevice device, AdbPrecompilationCommand command) async { |
+ var runner = command.precompiledRunnerFilename; |
+ var testdir = command.precompiledTestDirectory; |
+ var devicedir = '/data/local/tmp/precompilation-testing'; |
+ |
+ // We copy all the files which the vm precompiler puts into the test |
+ // directory. |
+ List<String> files = new io.Directory(testdir) |
+ .listSync() |
+ .where((fse) => fse is io.File) |
+ .map((file) => file.path) |
+ .map((path) => path.substring(path.lastIndexOf('/') + 1)) |
+ .toList(); |
+ |
+ // All closures are of type "Future<AdbCommandResult> run()" |
+ List<Function> steps = []; |
+ |
+ steps.add(() => device.runAdbShellCommand( |
+ ['rm', '-Rf', devicedir])); |
+ steps.add(() => device.runAdbShellCommand( |
+ ['mkdir', devicedir])); |
+ steps.add(() => device.runAdbCommand( |
+ ['push', runner, '$devicedir/runner'])); |
Florian Schneider
2016/04/28 13:18:30
Maybe add a TODO that we should push the runner (d
kustermann
2016/05/02 10:40:23
Done.
|
+ steps.add(() => device.runAdbShellCommand( |
+ ['chmod', '777', '$devicedir/runner'])); |
+ |
+ for (var file in files) { |
+ steps.add(() => device.runAdbCommand( |
+ ['push', '$testdir/$file', '$devicedir/$file'])); |
+ } |
+ |
+ if (command.useBlobs) { |
+ steps.add(() => device.runAdbShellCommand( |
+ ['$devicedir/runner', '--run-precompiled-snapshot=$devicedir', |
+ '--use_blobs', 'ignored.dart'])); |
+ } else { |
+ steps.add(() => device.runAdbShellCommand( |
+ ['$devicedir/runner', '--run-precompiled-snapshot=$devicedir', |
+ 'ignored.dart'])); |
+ } |
+ |
+ var stopwatch = new Stopwatch()..start(); |
+ var writer = new StringBuffer(); |
+ |
+ await device.waitForBootCompleted(); |
+ await device.waitForDevice(); |
+ |
+ AdbCommandResult result; |
+ for (var i = 0; i < steps.length; i++) { |
+ var fun = steps[i]; |
+ var commandStopwatch = new Stopwatch()..start(); |
+ result = await fun(); |
+ |
+ writer.writeln("Executing ${result.command}"); |
+ if (result.stdout.length > 0) { |
+ writer.writeln("Stdout:\n${result.stdout.trim()}"); |
+ } |
+ if (result.stderr.length > 0) { |
+ writer.writeln("Stderr:\n${result.stderr.trim()}"); |
+ } |
+ writer.writeln("ExitCode: ${result.exitCode}"); |
+ writer.writeln("Time: ${commandStopwatch.elapsed}"); |
+ writer.writeln(""); |
+ |
+ // If one command fails, we stop processing the others and return |
+ // immediately. |
+ if (result.exitCode != 0) break; |
+ } |
+ return createCommandOutput( |
+ command, result.exitCode, false, UTF8.encode('$writer'), |
+ [], stopwatch.elapsed, false); |
+ } |
+ |
BatchRunnerProcess _getBatchRunner(String identifier) { |
// Start batch processes if needed |
var runners = _batchProcesses[identifier]; |
@@ -2716,7 +2838,8 @@ class ProcessQueue { |
DateTime startTime, testSuites, this._eventListener, this._allDone, |
[bool verbose = false, |
String recordingOutputFile, |
- String recordedInputFile]) { |
+ String recordedInputFile, |
+ AdbDevicePool adbDevicePool]) { |
void setupForListing(TestCaseEnqueuer testCaseEnqueuer) { |
_graph.events |
.where((event) => event is dgraph.GraphSealedEvent) |
@@ -2817,7 +2940,8 @@ class ProcessQueue { |
executor = new ReplayingCommandExecutor(new Path(recordedInputFile)); |
} else { |
executor = new CommandExecutorImpl( |
- _globalConfiguration, maxProcesses, maxBrowserProcesses); |
+ _globalConfiguration, maxProcesses, |
+ maxBrowserProcesses, adbDevicePool: adbDevicePool); |
} |
// Run "runnable commands" using [executor] subject to |