// 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.md file. library testing.stdio_process; import 'dart:async' show EventSink, Future, Stream, StreamTransformer, Timer; import 'dart:convert' show utf8; import 'dart:io' show Process, ProcessSignal, Stdout; import 'dart:io' as io show stderr, stdout; import 'chain.dart' show Result; import 'expectation.dart' show ExpectationSet; class StdioProcess { final int exitCode; final String output; StdioProcess(this.exitCode, this.output); Result toResult({int expected: 0}) { if (exitCode == expected) { return new Result.pass(exitCode); } else { return new Result( exitCode, ExpectationSet.Default["RuntimeError"], output, null); } } static StreamTransformer transformToStdio(Stdout stdio) { return new StreamTransformer.fromHandlers( handleData: (String data, EventSink sink) { sink.add(data); stdio.write(data); }); } static Future run(String executable, List arguments, {String input, Duration timeout: const Duration(seconds: 60), bool suppressOutput: true, bool runInShell: false}) async { Process process = await Process.start(executable, arguments, runInShell: runInShell); Timer timer; StringBuffer sb = new StringBuffer(); if (timeout != null) { timer = new Timer(timeout, () { sb.write("Process timed out: "); sb.write(executable); sb.write(" "); sb.writeAll(arguments, " "); sb.writeln(); sb.writeln("Sending SIGTERM to process"); process.kill(); timer = new Timer(const Duration(seconds: 10), () { sb.writeln("Sending SIGKILL to process"); process.kill(ProcessSignal.sigkill); }); }); } if (input != null) { process.stdin.write(input); await process.stdin.flush(); } Future closeFuture = process.stdin.close(); Stream stdoutStream = process.stdout.transform(utf8.decoder); Stream stderrStream = process.stderr.transform(utf8.decoder); if (!suppressOutput) { stdoutStream = stdoutStream.transform(transformToStdio(io.stdout)); stderrStream = stderrStream.transform(transformToStdio(io.stderr)); } Future> stdoutFuture = stdoutStream.toList(); Future> stderrFuture = stderrStream.toList(); int exitCode = await process.exitCode; timer?.cancel(); sb.writeAll(await stdoutFuture); sb.writeAll(await stderrFuture); await closeFuture; return new StdioProcess(exitCode, "$sb"); } }