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

Side by Side Diff: lib/src/runner/browser/suite.dart

Issue 1422963004: Add RunnerSuite.{on,is}Debugging properties. (Closed) Base URL: git@github.com:dart-lang/test@master
Patch Set: Created 5 years, 1 month 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.suite;
6
7 import 'dart:async';
8
9 import 'package:async/async.dart';
10
11 import '../../backend/group.dart';
12 import '../../backend/metadata.dart';
13 import '../../backend/test.dart';
14 import '../../backend/test_platform.dart';
15 import '../../util/multi_channel.dart';
16 import '../../util/remote_exception.dart';
17 import '../../util/stack_trace_mapper.dart';
18 import '../../util/stream_channel.dart';
19 import '../../utils.dart';
20 import '../environment.dart';
21 import '../load_exception.dart';
22 import '../runner_suite.dart';
23 import 'iframe_test.dart';
24
25 /// Loads a [RunnerSuite] for a browser.
26 ///
27 /// [channel] should connect to the iframe containing the suite, which should
28 /// eventually emit a message containing the suite's test information.
29 /// [environment], [path], [platform], and [onClose] are passed to the
30 /// [RunnerSuite]. If passed, [mapper] is used to reformat the test's stack
31 /// traces.
32 Future<RunnerSuite> loadBrowserSuite(StreamChannel channel,
33 Environment environment, String path, {StackTraceMapper mapper,
34 TestPlatform platform, AsyncFunction onClose}) async {
35 // The controller for the returned suite. This is set once we've loaded the
36 // information about the tests in the suite.
37 var controller;
38
39 // A timer that's reset whenever we receive a message from the browser.
40 // Because the browser stops running code when the user is actively debugging,
41 // this lets us detect whether they're debugging reasonably accurately.
42 //
43 // The duration should be short enough that the debugging console is open as
44 // soon as the user is done setting breakpoints, but long enough that a test
45 // doing a lot of synchronous work doesn't trigger a false positive.
46 var timer = new RestartableTimer(new Duration(seconds: 3), () {
kevmoo 2015/11/06 18:13:56 const
47 controller.setDebugging(true);
48 })..cancel();
kevmoo 2015/11/06 18:13:56 What the immediate cancel?
nweiz 2015/11/16 20:27:00 Commented.
49
50 // Even though [channel] is probably a [MultiChannel] already, create a
51 // nested MultiChannel because the iframe will be using a channel wrapped
52 // within the host's channel.
53 var suiteChannel = new MultiChannel(channel.stream.map((message) {
54 // Whenever we get a message, no matter which child channel it's for, we the
55 // browser is still running code which means the using isn't debugging.
56 if (controller != null) {
57 timer.reset();
58 controller.setDebugging(false);
59 }
60
61 return message;
62 }), channel.sink);
63
64 var response = await _getResponse(suiteChannel.stream)
65 .timeout(new Duration(minutes: 1), onTimeout: () {
66 suiteChannel.sink.close();
67 throw new LoadException(
68 path,
69 "Timed out waiting for the test suite to connect.");
70 });
71
72 try {
73 _validateResponse(path, response);
74 } catch (_) {
75 suiteChannel.sink.close();
76 rethrow;
77 }
78
79 controller = new RunnerSuiteController(environment,
80 _deserializeGroup(suiteChannel, response["root"], mapper),
81 platform: platform, path: path,
82 onClose: () {
83 suiteChannel.sink.close();
84 timer.cancel();
85 return onClose == null ? null : onClose();
86 });
87
88 // Start the debugging timer counting down.
89 timer.reset();
90 return controller.suite;
91 }
92
93 /// Listens for responses from the iframe on [stream].
94 ///
95 /// Returns the serialized representation of the the root group for the suite,
96 /// or a response indicating that an error occurred.
97 Future<Map> _getResponse(Stream stream) {
kevmoo 2015/11/06 18:13:56 This would be a bit cleaner using async with await
nweiz 2015/11/16 20:27:00 I don't think that would allow it to be restructur
98 var completer = new Completer();
99 stream.listen((response) {
100 if (response["type"] == "print") {
101 print(response["line"]);
102 } else if (response["type"] != "ping") {
103 completer.complete(response);
104 }
105 }, onDone: () {
106 if (!completer.isCompleted) completer.complete();
107 });
108
109 return completer.future;
110 }
111
112 /// Throws an error encoded in [response], if there is one.
113 ///
114 /// [path] is used for the error's metadata.
115 Future _validateResponse(String path, Map response) {
kevmoo 2015/11/06 18:13:56 why not async? You're being called from an async
nweiz 2015/11/16 20:27:00 Why would it be async? We shouldn't just use async
kevmoo 2015/11/16 23:21:23 Consistency is nice. As is maintenance. It's not
nweiz 2015/11/16 23:48:14 We consistently only use async where it provides b
116 if (response == null) {
117 throw new LoadException(
118 path, "Connection closed before test suite loaded.");
119 }
120
121 if (response["type"] == "loadException") {
122 throw new LoadException(path, response["message"]);
123 }
124
125 if (response["type"] == "error") {
126 var asyncError = RemoteException.deserialize(response["error"]);
127 return new Future.error(
128 new LoadException(path, asyncError.error),
129 asyncError.stackTrace);
130 }
131
132 return new Future.value();
133 }
134
135 /// Deserializes [group] into a concrete [Group] class.
136 Group _deserializeGroup(MultiChannel suiteChannel, Map group,
137 [StackTraceMapper mapper]) {
138 var metadata = new Metadata.deserialize(group['metadata']);
139 return new Group(group['name'], group['entries'].map((entry) {
140 if (entry['type'] == 'group') {
141 return _deserializeGroup(suiteChannel, entry, mapper);
142 }
143
144 return _deserializeTest(suiteChannel, entry, mapper);
145 }),
146 metadata: metadata,
147 setUpAll: _deserializeTest(suiteChannel, group['setUpAll'], mapper),
148 tearDownAll:
149 _deserializeTest(suiteChannel, group['tearDownAll'], mapper));
150 }
151
152 /// Deserializes [test] into a concrete [Test] class.
153 ///
154 /// Returns `null` if [test] is `null`.
155 Test _deserializeTest(MultiChannel suiteChannel, Map test,
156 [StackTraceMapper mapper]) {
157 if (test == null) return null;
158
159 var metadata = new Metadata.deserialize(test['metadata']);
160 var testChannel = suiteChannel.virtualChannel(test['channel']);
161 return new IframeTest(test['name'], metadata, testChannel,
162 mapper: mapper);
163 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698