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.browser_manager; | 5 library test.runner.browser.browser_manager; |
6 | 6 |
7 import 'dart:async'; | 7 import 'dart:async'; |
8 import 'dart:convert'; | 8 import 'dart:convert'; |
9 | 9 |
10 import 'package:async/async.dart'; | 10 import 'package:async/async.dart'; |
11 import 'package:http_parser/http_parser.dart'; | 11 import 'package:http_parser/http_parser.dart'; |
12 import 'package:pool/pool.dart'; | 12 import 'package:pool/pool.dart'; |
13 | 13 |
14 import '../../backend/group.dart'; | |
15 import '../../backend/metadata.dart'; | 14 import '../../backend/metadata.dart'; |
16 import '../../backend/test.dart'; | |
17 import '../../backend/test_platform.dart'; | 15 import '../../backend/test_platform.dart'; |
18 import '../../util/multi_channel.dart'; | 16 import '../../util/multi_channel.dart'; |
19 import '../../util/remote_exception.dart'; | |
20 import '../../util/stack_trace_mapper.dart'; | 17 import '../../util/stack_trace_mapper.dart'; |
21 import '../../utils.dart'; | 18 import '../../utils.dart'; |
22 import '../application_exception.dart'; | 19 import '../application_exception.dart'; |
23 import '../environment.dart'; | 20 import '../environment.dart'; |
24 import '../load_exception.dart'; | |
25 import '../runner_suite.dart'; | 21 import '../runner_suite.dart'; |
26 import 'browser.dart'; | 22 import 'browser.dart'; |
27 import 'chrome.dart'; | 23 import 'chrome.dart'; |
28 import 'content_shell.dart'; | 24 import 'content_shell.dart'; |
29 import 'dartium.dart'; | 25 import 'dartium.dart'; |
30 import 'firefox.dart'; | 26 import 'firefox.dart'; |
31 import 'iframe_test.dart'; | |
32 import 'internet_explorer.dart'; | 27 import 'internet_explorer.dart'; |
33 import 'phantom_js.dart'; | 28 import 'phantom_js.dart'; |
34 import 'safari.dart'; | 29 import 'safari.dart'; |
| 30 import 'suite.dart'; |
35 | 31 |
36 /// A class that manages the connection to a single running browser. | 32 /// A class that manages the connection to a single running browser. |
37 /// | 33 /// |
38 /// This is in charge of telling the browser which test suites to load and | 34 /// This is in charge of telling the browser which test suites to load and |
39 /// converting its responses into [Suite] objects. | 35 /// converting its responses into [Suite] objects. |
40 class BrowserManager { | 36 class BrowserManager { |
41 /// The browser instance that this is connected to via [_channel]. | 37 /// The browser instance that this is connected to via [_channel]. |
42 final Browser _browser; | 38 final Browser _browser; |
43 | 39 |
44 // TODO(nweiz): Consider removing the duplication between this and | 40 // TODO(nweiz): Consider removing the duplication between this and |
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
173 {StackTraceMapper mapper}) async { | 169 {StackTraceMapper mapper}) async { |
174 url = url.replace(fragment: Uri.encodeFull(JSON.encode({ | 170 url = url.replace(fragment: Uri.encodeFull(JSON.encode({ |
175 "metadata": metadata.serialize(), | 171 "metadata": metadata.serialize(), |
176 "browser": _platform.identifier | 172 "browser": _platform.identifier |
177 }))); | 173 }))); |
178 | 174 |
179 // The stream may close before emitting a value if the browser is killed | 175 // The stream may close before emitting a value if the browser is killed |
180 // prematurely (e.g. via Control-C). | 176 // prematurely (e.g. via Control-C). |
181 var suiteVirtualChannel = _channel.virtualChannel(); | 177 var suiteVirtualChannel = _channel.virtualChannel(); |
182 var suiteId = _suiteId++; | 178 var suiteId = _suiteId++; |
183 var suiteChannel; | |
184 | 179 |
185 closeIframe() { | 180 closeIframe() { |
186 if (_closed) return; | 181 if (_closed) return; |
187 suiteChannel.sink.close(); | |
188 _channel.sink.add({ | 182 _channel.sink.add({ |
189 "command": "closeSuite", | 183 "command": "closeSuite", |
190 "id": suiteId | 184 "id": suiteId |
191 }); | 185 }); |
192 } | 186 } |
193 | 187 |
194 var response = await _pool.withResource(() { | 188 return await _pool.withResource(() async { |
195 _channel.sink.add({ | 189 _channel.sink.add({ |
196 "command": "loadSuite", | 190 "command": "loadSuite", |
197 "url": url.toString(), | 191 "url": url.toString(), |
198 "id": suiteId, | 192 "id": suiteId, |
199 "channel": suiteVirtualChannel.id | 193 "channel": suiteVirtualChannel.id |
200 }); | 194 }); |
201 | 195 |
202 // Create a nested MultiChannel because the iframe will be using a channel | 196 try { |
203 // wrapped within the host's channel. | 197 return await loadBrowserSuite( |
204 suiteChannel = new MultiChannel( | 198 suiteVirtualChannel, await _environment, path, |
205 suiteVirtualChannel.stream, suiteVirtualChannel.sink); | 199 mapper: mapper, platform: _platform, onClose: () => closeIframe()); |
206 | 200 } catch (_) { |
207 var completer = new Completer(); | 201 closeIframe(); |
208 suiteChannel.stream.listen((response) { | 202 rethrow; |
209 if (response["type"] == "print") { | 203 } |
210 print(response["line"]); | |
211 } else { | |
212 completer.complete(response); | |
213 } | |
214 }, onDone: () { | |
215 if (!completer.isCompleted) completer.complete(); | |
216 }); | |
217 | |
218 return completer.future.timeout(new Duration(minutes: 1), onTimeout: () { | |
219 throw new LoadException( | |
220 path, | |
221 "Timed out waiting for the test suite to connect on " | |
222 "${_platform.name}."); | |
223 }); | |
224 }); | 204 }); |
225 | |
226 if (response == null) { | |
227 closeIframe(); | |
228 throw new LoadException( | |
229 path, "Connection closed before test suite loaded."); | |
230 } | |
231 | |
232 if (response["type"] == "loadException") { | |
233 closeIframe(); | |
234 throw new LoadException(path, response["message"]); | |
235 } | |
236 | |
237 if (response["type"] == "error") { | |
238 closeIframe(); | |
239 var asyncError = RemoteException.deserialize(response["error"]); | |
240 await new Future.error( | |
241 new LoadException(path, asyncError.error), | |
242 asyncError.stackTrace); | |
243 } | |
244 | |
245 return new RunnerSuite( | |
246 await _environment, | |
247 _deserializeGroup(suiteChannel, mapper, response["root"]), | |
248 platform: _platform, | |
249 path: path, | |
250 onClose: () => closeIframe()); | |
251 } | |
252 | |
253 /// Deserializes [group] into a concrete [Group] class. | |
254 Group _deserializeGroup(MultiChannel suiteChannel, | |
255 StackTraceMapper mapper, Map group) { | |
256 var metadata = new Metadata.deserialize(group['metadata']); | |
257 return new Group(group['name'], group['entries'].map((entry) { | |
258 if (entry['type'] == 'group') { | |
259 return _deserializeGroup(suiteChannel, mapper, entry); | |
260 } | |
261 | |
262 return _deserializeTest(suiteChannel, mapper, entry); | |
263 }), | |
264 metadata: metadata, | |
265 setUpAll: _deserializeTest(suiteChannel, mapper, group['setUpAll']), | |
266 tearDownAll: | |
267 _deserializeTest(suiteChannel, mapper, group['tearDownAll'])); | |
268 } | |
269 | |
270 /// Deserializes [test] into a concrete [Test] class. | |
271 /// | |
272 /// Returns `null` if [test] is `null`. | |
273 Test _deserializeTest(MultiChannel suiteChannel, StackTraceMapper mapper, | |
274 Map test) { | |
275 if (test == null) return null; | |
276 | |
277 var metadata = new Metadata.deserialize(test['metadata']); | |
278 var testChannel = suiteChannel.virtualChannel(test['channel']); | |
279 return new IframeTest(test['name'], metadata, testChannel, | |
280 mapper: mapper); | |
281 } | 205 } |
282 | 206 |
283 /// An implementation of [Environment.displayPause]. | 207 /// An implementation of [Environment.displayPause]. |
284 CancelableOperation _displayPause() { | 208 CancelableOperation _displayPause() { |
285 if (_pauseCompleter != null) return _pauseCompleter.operation; | 209 if (_pauseCompleter != null) return _pauseCompleter.operation; |
286 | 210 |
287 _pauseCompleter = new CancelableCompleter(onCancel: () { | 211 _pauseCompleter = new CancelableCompleter(onCancel: () { |
288 _channel.sink.add({"command": "resume"}); | 212 _channel.sink.add({"command": "resume"}); |
289 _pauseCompleter = null; | 213 _pauseCompleter = null; |
290 }); | 214 }); |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
324 | 248 |
325 final Uri observatoryUrl; | 249 final Uri observatoryUrl; |
326 | 250 |
327 final Uri remoteDebuggerUrl; | 251 final Uri remoteDebuggerUrl; |
328 | 252 |
329 _BrowserEnvironment(this._manager, this.observatoryUrl, | 253 _BrowserEnvironment(this._manager, this.observatoryUrl, |
330 this.remoteDebuggerUrl); | 254 this.remoteDebuggerUrl); |
331 | 255 |
332 CancelableOperation displayPause() => _manager._displayPause(); | 256 CancelableOperation displayPause() => _manager._displayPause(); |
333 } | 257 } |
OLD | NEW |