Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library test.runner.browser.content_shell; | 5 library test.runner.browser.content_shell; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 import 'dart:convert'; | |
| 8 import 'dart:io'; | 9 import 'dart:io'; |
| 9 | 10 |
| 11 import '../application_exception.dart'; | |
| 10 import 'browser.dart'; | 12 import 'browser.dart'; |
| 11 | 13 |
| 14 /// A converter that transforms a byte stream into a stream of lines. | |
| 15 final _lines = UTF8.decoder.fuse(const LineSplitter()); | |
| 16 | |
| 12 /// A class for running an instance of the Dartium content shell. | 17 /// A class for running an instance of the Dartium content shell. |
| 13 /// | 18 /// |
| 14 /// Most of the communication with the browser is expected to happen via HTTP, | 19 /// Most of the communication with the browser is expected to happen via HTTP, |
| 15 /// so this exposes a bare-bones API. The browser starts as soon as the class is | 20 /// so this exposes a bare-bones API. The browser starts as soon as the class is |
| 16 /// constructed, and is killed when [close] is called. | 21 /// constructed, and is killed when [close] is called. |
| 17 /// | 22 /// |
| 18 /// Any errors starting or running the process are reported through [onExit]. | 23 /// Any errors starting or running the process are reported through [onExit]. |
| 19 class ContentShell implements Browser { | 24 class ContentShell implements Browser { |
| 20 /// The underlying process. | 25 /// The underlying process. |
| 21 Process _process; | 26 Process _process; |
| 22 | 27 |
| 23 Future get onExit => _onExitCompleter.future; | 28 Future get onExit => _onExitCompleter.future; |
| 24 final _onExitCompleter = new Completer(); | 29 final _onExitCompleter = new Completer(); |
| 25 | 30 |
| 26 /// A future that completes when the browser process has started. | 31 /// A future that completes when the browser process has started. |
| 27 /// | 32 /// |
| 28 /// This is used to ensure that [close] works regardless of when it's called. | 33 /// This is used to ensure that [close] works regardless of when it's called. |
| 29 Future get _onProcessStarted => _onProcessStartedCompleter.future; | 34 Future get _onProcessStarted => _onProcessStartedCompleter.future; |
| 30 final _onProcessStartedCompleter = new Completer(); | 35 final _onProcessStartedCompleter = new Completer(); |
| 31 | 36 |
| 32 /// Starts a new instance of content shell open to the given [url], which may | 37 /// Starts a new instance of content shell open to the given [url], which may |
| 33 /// be a [Uri] or a [String]. | 38 /// be a [Uri] or a [String]. |
| 34 /// | 39 /// |
| 35 /// If [executable] is passed, it's used as the content shell executable. | 40 /// If [executable] is passed, it's used as the content shell executable. |
| 36 /// Otherwise the default executable name for the current OS will be used. | 41 /// Otherwise the default executable name for the current OS will be used. |
| 37 ContentShell(url, {String executable}) { | 42 ContentShell(url, {String executable}) { |
| 38 if (executable == null) executable = _defaultExecutable(); | 43 if (executable == null) executable = _defaultExecutable(); |
| 39 | 44 |
| 45 // Whether we killed content shell because it used an expired Dart version. | |
| 46 var expired = false; | |
| 47 | |
| 40 // Don't return a Future here because there's no need for the caller to wait | 48 // Don't return a Future here because there's no need for the caller to wait |
| 41 // for the process to actually start. They should just wait for the HTTP | 49 // for the process to actually start. They should just wait for the HTTP |
| 42 // request instead. | 50 // request instead. |
| 43 Process.start(executable, ["--dump-render-tree", url.toString()], | 51 Process.start(executable, ["--dump-render-tree", url.toString()], |
| 44 environment: {"DART_FLAGS": "--checked"}).then((process) { | 52 environment: {"DART_FLAGS": "--checked"}).then((process) { |
| 53 _lines.bind(process.stderr).listen((line) { | |
| 54 if (line != "[dartToStderr]: Dartium build has expired") return; | |
| 55 expired = true; | |
| 56 process.kill(); | |
| 57 }); | |
| 58 | |
| 45 _process = process; | 59 _process = process; |
| 46 _onProcessStartedCompleter.complete(); | 60 _onProcessStartedCompleter.complete(); |
| 47 return _process.exitCode; | 61 return _process.exitCode; |
| 48 }).then((exitCode) { | 62 }).then((exitCode) { |
| 63 if (expired) { | |
| 64 throw new ApplicationException( | |
|
kevmoo
2015/04/14 22:52:12
Add a TODO to point to the dart site for content_s
nweiz
2015/04/14 23:05:31
Done.
| |
| 65 "You're using an expired content_shell. Upgrade to the latest " | |
| 66 "version:\n" | |
| 67 "http://gsdview.appspot.com/dart-archive/channels/stable/release/" | |
| 68 "latest/dartium/"); | |
| 69 } | |
| 70 | |
| 49 if (exitCode != 0) throw "Content shell failed with exit code $exitCode."; | 71 if (exitCode != 0) throw "Content shell failed with exit code $exitCode."; |
| 50 }).then(_onExitCompleter.complete) | 72 }).then(_onExitCompleter.complete) |
| 51 .catchError(_onExitCompleter.completeError); | 73 .catchError(_onExitCompleter.completeError); |
| 52 } | 74 } |
| 53 | 75 |
| 54 Future close() { | 76 Future close() { |
| 55 _onProcessStarted.then((_) => _process.kill()); | 77 _onProcessStarted.then((_) => _process.kill()); |
| 56 | 78 |
| 57 // Swallow exceptions. The user should explicitly use [onExit] for these. | 79 // Swallow exceptions. The user should explicitly use [onExit] for these. |
| 58 return onExit.catchError((_) {}); | 80 return onExit.catchError((_) {}); |
| 59 } | 81 } |
| 60 | 82 |
| 61 /// Return the default executable for the current operating system. | 83 /// Return the default executable for the current operating system. |
| 62 String _defaultExecutable() => | 84 String _defaultExecutable() => |
| 63 Platform.isWindows ? "content_shell.exe" : "content_shell"; | 85 Platform.isWindows ? "content_shell.exe" : "content_shell"; |
| 64 } | 86 } |
| OLD | NEW |