Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(424)

Side by Side Diff: mojo/public/dart/third_party/test/lib/src/runner/browser/browser.dart

Issue 1346773002: Stop running pub get at gclient sync time and fix build bugs (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 library test.runner.browser.browser;
6
7 import 'dart:async';
8 import 'dart:io';
9
10 import 'package:stack_trace/stack_trace.dart';
11
12 import '../../utils.dart';
13 import '../application_exception.dart';
14
15 typedef Future<Process> StartBrowserFn();
16
17 /// An interface for running browser instances.
18 ///
19 /// This is intentionally coarse-grained: browsers are controlled primary from
20 /// inside a single tab. Thus this interface only provides support for closing
21 /// the browser and seeing if it closes itself.
22 ///
23 /// Any errors starting or running the browser process are reported through
24 /// [onExit].
25 abstract class Browser {
26 String get name;
27
28 /// The Observatory URL for this browser.
29 ///
30 /// This will throw an [UnsupportedError] for browsers that aren't running the
31 /// Dart VM, and return `null` if the Observatory URL can't be found.
32 Future<Uri> get observatoryUrl =>
33 throw new UnsupportedError("$name doesn't support Observatory.");
34
35 /// The remote debugger URL for this browser.
36 ///
37 /// This will throw an [UnsupportedError] for browsers that don't support
38 /// remote debugging, and return `null` if the remote debugging URL can't be
39 /// found.
40 Future<Uri> get remoteDebuggerUrl =>
41 throw new UnsupportedError("$name doesn't support remote debugging.");
42
43 /// The underlying process.
44 ///
45 /// This will fire once the process has started successfully.
46 Future<Process> get _process => _processCompleter.future;
47 final _processCompleter = new Completer<Process>();
48
49 /// Whether [close] has been called.
50 var _closed = false;
51
52 /// A future that completes when the browser exits.
53 ///
54 /// If there's a problem starting or running the browser, this will complete
55 /// with an error.
56 Future get onExit => _onExitCompleter.future;
57 final _onExitCompleter = new Completer();
58
59 /// Creates a new browser.
60 ///
61 /// This is intended to be called by subclasses. They pass in [startBrowser],
62 /// which asynchronously returns the browser process. Any errors in
63 /// [startBrowser] (even those raised asynchronously after it returns) are
64 /// piped to [onExit] and will cause the browser to be killed.
65 Browser(Future<Process> startBrowser()) {
66 // Don't return a Future here because there's no need for the caller to wait
67 // for the process to actually start. They should just wait for the HTTP
68 // request instead.
69 runZoned(() async {
70 var process = await startBrowser();
71 _processCompleter.complete(process);
72
73 var exitCode = await process.exitCode;
74
75 // This hack dodges an otherwise intractable race condition. When the user
76 // presses Control-C, the signal is sent to the browser and the test
77 // runner at the same time. It's possible for the browser to exit before
78 // the [Browser.close] is called, which would trigger the error below.
79 //
80 // A negative exit code signals that the process exited due to a signal.
81 // However, it's possible that this signal didn't come from the user's
82 // Control-C, in which case we do want to throw the error. The only way to
83 // resolve the ambiguity is to wait a brief amount of time and see if this
84 // browser is actually closed.
85 if (!_closed && exitCode < 0) {
86 await new Future.delayed(new Duration(milliseconds: 200));
87 }
88
89 if (!_closed && exitCode != 0) {
90 throw new ApplicationException(
91 "$name failed with exit code $exitCode.");
92 }
93
94 _onExitCompleter.complete();
95 }, onError: (error, stackTrace) {
96 // Ignore any errors after the browser has been closed.
97 if (_closed) return;
98
99 // Make sure the process dies even if the error wasn't fatal.
100 _process.then((process) => process.kill());
101
102 if (stackTrace == null) stackTrace = new Trace.current();
103 _onExitCompleter.completeError(
104 new ApplicationException(
105 "Failed to run $name: ${getErrorMessage(error)}."),
106 stackTrace);
107 });
108 }
109
110 /// Kills the browser process.
111 ///
112 /// Returns the same [Future] as [onExit], except that it won't emit
113 /// exceptions.
114 Future close() {
115 _closed = true;
116 _process.then((process) => process.kill());
117
118 // Swallow exceptions. The user should explicitly use [onExit] for these.
119 return onExit.catchError((_) {});
120 }
121 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698