OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 library browser; | 4 library browser; |
5 | 5 |
6 import "dart:async"; | 6 import "dart:async"; |
7 import "dart:convert" show LineSplitter, UTF8, JSON; | 7 import "dart:convert" show LineSplitter, UTF8, JSON; |
8 import "dart:core"; | 8 import "dart:core"; |
9 import "dart:io"; | 9 import "dart:io"; |
10 import "dart:math" show max, min; | 10 import "dart:math" show max, min; |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
60 | 60 |
61 /** Print everything (stdout, stderr, usageLog) whenever we add to it */ | 61 /** Print everything (stdout, stderr, usageLog) whenever we add to it */ |
62 bool debugPrint = false; | 62 bool debugPrint = false; |
63 | 63 |
64 // This future returns when the process exits. It is also the return value | 64 // This future returns when the process exits. It is also the return value |
65 // of close() | 65 // of close() |
66 Future done; | 66 Future done; |
67 | 67 |
68 Browser(); | 68 Browser(); |
69 | 69 |
70 factory Browser.byName(String name, | 70 factory Browser.byName(String name, String executablePath, |
71 String executablePath, | 71 [bool checkedMode = false]) { |
72 [bool checkedMode = false]) { | |
73 var browser; | 72 var browser; |
74 if (name == 'firefox') { | 73 if (name == 'firefox') { |
75 browser = new Firefox(); | 74 browser = new Firefox(); |
76 } else if (name == 'chrome') { | 75 } else if (name == 'chrome') { |
77 browser = new Chrome(); | 76 browser = new Chrome(); |
78 } else if (name == 'dartium') { | 77 } else if (name == 'dartium') { |
79 browser = new Dartium(checkedMode); | 78 browser = new Dartium(checkedMode); |
80 } else if (name == 'safari') { | 79 } else if (name == 'safari') { |
81 browser = new Safari(); | 80 browser = new Safari(); |
82 } else if (name == 'safarimobilesim') { | 81 } else if (name == 'safarimobilesim') { |
83 browser = new SafariMobileSimulator(); | 82 browser = new SafariMobileSimulator(); |
84 } else if (name.startsWith('ie')) { | 83 } else if (name.startsWith('ie')) { |
85 browser = new IE(); | 84 browser = new IE(); |
86 } else { | 85 } else { |
87 throw "Non supported browser"; | 86 throw "Non supported browser"; |
88 } | 87 } |
89 browser._binary = executablePath; | 88 browser._binary = executablePath; |
90 return browser; | 89 return browser; |
91 } | 90 } |
92 | 91 |
93 static const List<String> SUPPORTED_BROWSERS = | 92 static const List<String> SUPPORTED_BROWSERS = const [ |
94 const ['safari', 'ff', 'firefox', 'chrome', 'ie9', 'ie10', | 93 'safari', |
95 'ie11', 'dartium']; | 94 'ff', |
| 95 'firefox', |
| 96 'chrome', |
| 97 'ie9', |
| 98 'ie10', |
| 99 'ie11', |
| 100 'dartium' |
| 101 ]; |
96 | 102 |
97 static const List<String> BROWSERS_WITH_WINDOW_SUPPORT = | 103 static const List<String> BROWSERS_WITH_WINDOW_SUPPORT = const [ |
98 const ['ie11', 'ie10']; | 104 'ie11', |
| 105 'ie10' |
| 106 ]; |
99 | 107 |
100 // TODO(kustermann): add standard support for chrome on android | 108 // TODO(kustermann): add standard support for chrome on android |
101 static bool supportedBrowser(String name) { | 109 static bool supportedBrowser(String name) { |
102 return SUPPORTED_BROWSERS.contains(name); | 110 return SUPPORTED_BROWSERS.contains(name); |
103 } | 111 } |
104 | 112 |
105 void _logEvent(String event) { | 113 void _logEvent(String event) { |
106 String toLog = "$this ($id) - $event \n"; | 114 String toLog = "$this ($id) - $event \n"; |
107 if (debugPrint) print("usageLog: $toLog"); | 115 if (debugPrint) print("usageLog: $toLog"); |
108 if (logger != null) logger(toLog); | 116 if (logger != null) logger(toLog); |
(...skipping 28 matching lines...) Expand all Loading... |
137 } else { | 145 } else { |
138 _logEvent("The process is already dead."); | 146 _logEvent("The process is already dead."); |
139 return new Future.value(true); | 147 return new Future.value(true); |
140 } | 148 } |
141 } | 149 } |
142 | 150 |
143 /** | 151 /** |
144 * Start the browser using the supplied argument. | 152 * Start the browser using the supplied argument. |
145 * This sets up the error handling and usage logging. | 153 * This sets up the error handling and usage logging. |
146 */ | 154 */ |
147 Future<bool> startBrowserProcess(String command, | 155 Future<bool> startBrowserProcess(String command, List<String> arguments, |
148 List<String> arguments, | 156 {Map<String, String> environment}) { |
149 {Map<String,String> environment}) { | 157 return Process |
150 return Process.start(command, arguments, environment: environment) | 158 .start(command, arguments, environment: environment) |
151 .then((startedProcess) { | 159 .then((startedProcess) { |
152 _logEvent("Started browser using $command ${arguments.join(' ')}"); | 160 _logEvent("Started browser using $command ${arguments.join(' ')}"); |
153 process = startedProcess; | 161 process = startedProcess; |
154 // Used to notify when exiting, and as a return value on calls to | 162 // Used to notify when exiting, and as a return value on calls to |
155 // close(). | 163 // close(). |
156 var doneCompleter = new Completer(); | 164 var doneCompleter = new Completer(); |
157 done = doneCompleter.future; | 165 done = doneCompleter.future; |
158 | 166 |
159 Completer stdoutDone = new Completer(); | 167 Completer stdoutDone = new Completer(); |
160 Completer stderrDone = new Completer(); | 168 Completer stderrDone = new Completer(); |
161 | 169 |
162 bool stdoutIsDone = false; | 170 bool stdoutIsDone = false; |
163 bool stderrIsDone = false; | 171 bool stderrIsDone = false; |
164 StreamSubscription stdoutSubscription; | 172 StreamSubscription stdoutSubscription; |
165 StreamSubscription stderrSubscription; | 173 StreamSubscription stderrSubscription; |
166 | 174 |
167 // This timer is used to close stdio to the subprocess once we got | 175 // This timer is used to close stdio to the subprocess once we got |
168 // the exitCode. Sometimes descendants of the subprocess keep stdio | 176 // the exitCode. Sometimes descendants of the subprocess keep stdio |
169 // handles alive even though the direct subprocess is dead. | 177 // handles alive even though the direct subprocess is dead. |
170 Timer watchdogTimer; | 178 Timer watchdogTimer; |
171 | 179 |
172 void closeStdout([_]){ | 180 void closeStdout([_]) { |
173 if (!stdoutIsDone) { | 181 if (!stdoutIsDone) { |
174 stdoutDone.complete(); | 182 stdoutDone.complete(); |
175 stdoutIsDone = true; | 183 stdoutIsDone = true; |
176 | 184 |
177 if (stderrIsDone && watchdogTimer != null) { | 185 if (stderrIsDone && watchdogTimer != null) { |
178 watchdogTimer.cancel(); | 186 watchdogTimer.cancel(); |
179 } | 187 } |
180 } | 188 } |
181 } | 189 } |
182 | 190 |
183 void closeStderr([_]) { | 191 void closeStderr([_]) { |
184 if (!stderrIsDone) { | 192 if (!stderrIsDone) { |
185 stderrDone.complete(); | 193 stderrDone.complete(); |
186 stderrIsDone = true; | 194 stderrIsDone = true; |
187 | 195 |
188 if (stdoutIsDone && watchdogTimer != null) { | 196 if (stdoutIsDone && watchdogTimer != null) { |
189 watchdogTimer.cancel(); | 197 watchdogTimer.cancel(); |
190 } | 198 } |
191 } | 199 } |
192 } | 200 } |
193 | 201 |
194 stdoutSubscription = | 202 stdoutSubscription = |
195 process.stdout.transform(UTF8.decoder).listen((data) { | 203 process.stdout.transform(UTF8.decoder).listen((data) { |
196 _addStdout(data); | 204 _addStdout(data); |
197 }, onError: (error) { | 205 }, onError: (error) { |
198 // This should _never_ happen, but we really want this in the log | 206 // This should _never_ happen, but we really want this in the log |
199 // if it actually does due to dart:io or vm bug. | 207 // if it actually does due to dart:io or vm bug. |
200 _logEvent("An error occured in the process stdout handling: $error"); | 208 _logEvent("An error occured in the process stdout handling: $error"); |
201 }, onDone: closeStdout); | 209 }, onDone: closeStdout); |
202 | 210 |
203 stderrSubscription = | 211 stderrSubscription = |
204 process.stderr.transform(UTF8.decoder).listen((data) { | 212 process.stderr.transform(UTF8.decoder).listen((data) { |
205 _addStderr(data); | 213 _addStderr(data); |
206 }, onError: (error) { | 214 }, onError: (error) { |
207 // This should _never_ happen, but we really want this in the log | 215 // This should _never_ happen, but we really want this in the log |
208 // if it actually does due to dart:io or vm bug. | 216 // if it actually does due to dart:io or vm bug. |
209 _logEvent("An error occured in the process stderr handling: $error"); | 217 _logEvent("An error occured in the process stderr handling: $error"); |
210 }, onDone: closeStderr); | 218 }, onDone: closeStderr); |
211 | 219 |
212 process.exitCode.then((exitCode) { | 220 process.exitCode.then((exitCode) { |
213 _logEvent("Browser closed with exitcode $exitCode"); | 221 _logEvent("Browser closed with exitcode $exitCode"); |
214 | 222 |
215 if (!stdoutIsDone || !stderrIsDone) { | 223 if (!stdoutIsDone || !stderrIsDone) { |
216 watchdogTimer = new Timer(MAX_STDIO_DELAY, () { | 224 watchdogTimer = new Timer(MAX_STDIO_DELAY, () { |
217 DebugLogger.warning( | 225 DebugLogger |
218 "$MAX_STDIO_DELAY_PASSED_MESSAGE (browser: $this)"); | 226 .warning("$MAX_STDIO_DELAY_PASSED_MESSAGE (browser: $this)"); |
219 watchdogTimer = null; | 227 watchdogTimer = null; |
220 stdoutSubscription.cancel(); | 228 stdoutSubscription.cancel(); |
221 stderrSubscription.cancel(); | 229 stderrSubscription.cancel(); |
222 closeStdout(); | 230 closeStdout(); |
223 closeStderr(); | 231 closeStderr(); |
224 }); | 232 }); |
225 } | 233 } |
226 | 234 |
227 Future.wait([stdoutDone.future, stderrDone.future]).then((_) { | 235 Future.wait([stdoutDone.future, stderrDone.future]).then((_) { |
228 process = null; | 236 process = null; |
(...skipping 19 matching lines...) Expand all Loading... |
248 | 256 |
249 void resetTestBrowserOutput() { | 257 void resetTestBrowserOutput() { |
250 _testBrowserOutput = new BrowserOutput(); | 258 _testBrowserOutput = new BrowserOutput(); |
251 } | 259 } |
252 | 260 |
253 /** | 261 /** |
254 * Add useful info about the browser to the _testBrowserOutput.stdout, | 262 * Add useful info about the browser to the _testBrowserOutput.stdout, |
255 * where it will be reported for failing tests. Used to report which | 263 * where it will be reported for failing tests. Used to report which |
256 * android device a failing test is running on. | 264 * android device a failing test is running on. |
257 */ | 265 */ |
258 void logBrowserInfoToTestBrowserOutput() { } | 266 void logBrowserInfoToTestBrowserOutput() {} |
259 | 267 |
260 String toString(); | 268 String toString(); |
261 | 269 |
262 /** Starts the browser loading the given url */ | 270 /** Starts the browser loading the given url */ |
263 Future<bool> start(String url); | 271 Future<bool> start(String url); |
264 } | 272 } |
265 | 273 |
266 class Safari extends Browser { | 274 class Safari extends Browser { |
267 /** | 275 /** |
268 * We get the safari version by parsing a version file | 276 * We get the safari version by parsing a version file |
269 */ | 277 */ |
270 static const String versionFile = | 278 static const String versionFile = |
271 "/Applications/Safari.app/Contents/version.plist"; | 279 "/Applications/Safari.app/Contents/version.plist"; |
272 | 280 |
273 /** | 281 /** |
274 * Directories where safari stores state. We delete these if the deleteCache | 282 * Directories where safari stores state. We delete these if the deleteCache |
275 * is set | 283 * is set |
276 */ | 284 */ |
277 static const List<String> CACHE_DIRECTORIES = | 285 static const List<String> CACHE_DIRECTORIES = const [ |
278 const ["Library/Caches/com.apple.Safari", | 286 "Library/Caches/com.apple.Safari", |
279 "Library/Safari", | 287 "Library/Safari", |
280 "Library/Saved Application State/com.apple.Safari.savedState", | 288 "Library/Saved Application State/com.apple.Safari.savedState", |
281 "Library/Caches/Metadata/Safari"]; | 289 "Library/Caches/Metadata/Safari" |
282 | 290 ]; |
283 | 291 |
284 Future<bool> allowPopUps() { | 292 Future<bool> allowPopUps() { |
285 var command = "defaults"; | 293 var command = "defaults"; |
286 var args = ["write", "com.apple.safari", | 294 var args = [ |
287 "com.apple.Safari.ContentPageGroupIdentifier." | 295 "write", |
288 "WebKit2JavaScriptCanOpenWindowsAutomatically", | 296 "com.apple.safari", |
289 "1"]; | 297 "com.apple.Safari.ContentPageGroupIdentifier." |
| 298 "WebKit2JavaScriptCanOpenWindowsAutomatically", |
| 299 "1" |
| 300 ]; |
290 return Process.run(command, args).then((result) { | 301 return Process.run(command, args).then((result) { |
291 if (result.exitCode != 0) { | 302 if (result.exitCode != 0) { |
292 _logEvent("Could not disable pop-up blocking for safari"); | 303 _logEvent("Could not disable pop-up blocking for safari"); |
293 return false; | 304 return false; |
294 } | 305 } |
295 return true; | 306 return true; |
296 }); | 307 }); |
297 } | 308 } |
298 | 309 |
299 Future<bool> deleteIfExists(Iterator<String> paths) { | 310 Future<bool> deleteIfExists(Iterator<String> paths) { |
300 if (!paths.moveNext()) return new Future.value(true); | 311 if (!paths.moveNext()) return new Future.value(true); |
301 Directory directory = new Directory(paths.current); | 312 Directory directory = new Directory(paths.current); |
302 return directory.exists().then((exists) { | 313 return directory.exists().then((exists) { |
303 if (exists) { | 314 if (exists) { |
304 _logEvent("Deleting ${paths.current}"); | 315 _logEvent("Deleting ${paths.current}"); |
305 return directory.delete(recursive: true) | 316 return directory |
306 » .then((_) => deleteIfExists(paths)) | 317 .delete(recursive: true) |
307 » .catchError((error) { | 318 .then((_) => deleteIfExists(paths)) |
308 » _logEvent("Failure trying to delete ${paths.current}: $error"); | 319 .catchError((error) { |
309 » return false; | 320 _logEvent("Failure trying to delete ${paths.current}: $error"); |
310 » }); | 321 return false; |
| 322 }); |
311 } else { | 323 } else { |
312 _logEvent("${paths.current} is not present"); | 324 _logEvent("${paths.current} is not present"); |
313 return deleteIfExists(paths); | 325 return deleteIfExists(paths); |
314 } | 326 } |
315 }); | 327 }); |
316 } | 328 } |
317 | 329 |
318 // Clears the cache if the static deleteCache flag is set. | 330 // Clears the cache if the static deleteCache flag is set. |
319 // Returns false if the command to actually clear the cache did not complete. | 331 // Returns false if the command to actually clear the cache did not complete. |
320 Future<bool> clearCache() { | 332 Future<bool> clearCache() { |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
373 } | 385 } |
374 return clearCache().then((cleared) { | 386 return clearCache().then((cleared) { |
375 if (!cleared) { | 387 if (!cleared) { |
376 _logEvent("Could not clear cache"); | 388 _logEvent("Could not clear cache"); |
377 return false; | 389 return false; |
378 } | 390 } |
379 // Get the version and log that. | 391 // Get the version and log that. |
380 return getVersion().then((version) { | 392 return getVersion().then((version) { |
381 _logEvent("Got version: $version"); | 393 _logEvent("Got version: $version"); |
382 return Directory.systemTemp.createTemp().then((userDir) { | 394 return Directory.systemTemp.createTemp().then((userDir) { |
383 _cleanup = () { userDir.deleteSync(recursive: true); }; | 395 _cleanup = () { |
| 396 userDir.deleteSync(recursive: true); |
| 397 }; |
384 _createLaunchHTML(userDir.path, url); | 398 _createLaunchHTML(userDir.path, url); |
385 var args = ["${userDir.path}/launch.html"]; | 399 var args = ["${userDir.path}/launch.html"]; |
386 return startBrowserProcess(_binary, args); | 400 return startBrowserProcess(_binary, args); |
387 }); | 401 }); |
388 }).catchError((error) { | 402 }).catchError((error) { |
389 _logEvent("Running $_binary --version failed with $error"); | 403 _logEvent("Running $_binary --version failed with $error"); |
390 return false; | 404 return false; |
391 }); | 405 }); |
392 }); | 406 }); |
393 }); | 407 }); |
394 } | 408 } |
395 | 409 |
396 String toString() => "Safari"; | 410 String toString() => "Safari"; |
397 } | 411 } |
398 | 412 |
399 | |
400 class Chrome extends Browser { | 413 class Chrome extends Browser { |
401 String _version = "Version not found yet"; | 414 String _version = "Version not found yet"; |
402 | 415 |
403 Map<String, String> _getEnvironment() => null; | 416 Map<String, String> _getEnvironment() => null; |
404 | 417 |
405 Future<bool> _getVersion() { | 418 Future<bool> _getVersion() { |
406 if (Platform.isWindows) { | 419 if (Platform.isWindows) { |
407 // The version flag does not work on windows. | 420 // The version flag does not work on windows. |
408 // See issue: | 421 // See issue: |
409 // https://code.google.com/p/chromium/issues/detail?id=158372 | 422 // https://code.google.com/p/chromium/issues/detail?id=158372 |
(...skipping 13 matching lines...) Expand all Loading... |
423 if (versionResult.exitCode != 0) { | 436 if (versionResult.exitCode != 0) { |
424 _logEvent("Failed to chrome get version"); | 437 _logEvent("Failed to chrome get version"); |
425 _logEvent("Make sure $_binary is a valid program for running chrome"); | 438 _logEvent("Make sure $_binary is a valid program for running chrome"); |
426 return false; | 439 return false; |
427 } | 440 } |
428 _version = versionResult.stdout; | 441 _version = versionResult.stdout; |
429 return true; | 442 return true; |
430 }); | 443 }); |
431 } | 444 } |
432 | 445 |
433 | |
434 Future<bool> start(String url) { | 446 Future<bool> start(String url) { |
435 _logEvent("Starting chrome browser on: $url"); | 447 _logEvent("Starting chrome browser on: $url"); |
436 // Get the version and log that. | 448 // Get the version and log that. |
437 return _getVersion().then((success) { | 449 return _getVersion().then((success) { |
438 if (!success) return false; | 450 if (!success) return false; |
439 _logEvent("Got version: $_version"); | 451 _logEvent("Got version: $_version"); |
440 | 452 |
441 return Directory.systemTemp.createTemp().then((userDir) { | 453 return Directory.systemTemp.createTemp().then((userDir) { |
442 _cleanup = () { userDir.deleteSync(recursive: true); }; | 454 _cleanup = () { |
443 var args = ["--user-data-dir=${userDir.path}", url, | 455 userDir.deleteSync(recursive: true); |
444 "--disable-extensions", "--disable-popup-blocking", | 456 }; |
445 "--bwsi", "--no-first-run"]; | 457 var args = [ |
446 return startBrowserProcess(_binary, args, environment: _getEnvironment()
); | 458 "--user-data-dir=${userDir.path}", |
| 459 url, |
| 460 "--disable-extensions", |
| 461 "--disable-popup-blocking", |
| 462 "--bwsi", |
| 463 "--no-first-run" |
| 464 ]; |
| 465 return startBrowserProcess(_binary, args, |
| 466 environment: _getEnvironment()); |
447 }); | 467 }); |
448 }).catchError((e) { | 468 }).catchError((e) { |
449 _logEvent("Running $_binary --version failed with $e"); | 469 _logEvent("Running $_binary --version failed with $e"); |
450 return false; | 470 return false; |
451 }); | 471 }); |
452 } | 472 } |
453 | 473 |
454 String toString() => "Chrome"; | 474 String toString() => "Chrome"; |
455 } | 475 } |
456 | 476 |
457 | |
458 class SafariMobileSimulator extends Safari { | 477 class SafariMobileSimulator extends Safari { |
459 /** | 478 /** |
460 * Directories where safari simulator stores state. We delete these if the | 479 * Directories where safari simulator stores state. We delete these if the |
461 * deleteCache is set | 480 * deleteCache is set |
462 */ | 481 */ |
463 static const List<String> CACHE_DIRECTORIES = | 482 static const List<String> CACHE_DIRECTORIES = const [ |
464 const ["Library/Application Support/iPhone Simulator/7.1/Applications"]; | 483 "Library/Application Support/iPhone Simulator/7.1/Applications" |
| 484 ]; |
465 | 485 |
466 // Clears the cache if the static deleteCache flag is set. | 486 // Clears the cache if the static deleteCache flag is set. |
467 // Returns false if the command to actually clear the cache did not complete. | 487 // Returns false if the command to actually clear the cache did not complete. |
468 Future<bool> clearCache() { | 488 Future<bool> clearCache() { |
469 if (!Browser.deleteCache) return new Future.value(true); | 489 if (!Browser.deleteCache) return new Future.value(true); |
470 var home = Platform.environment['HOME']; | 490 var home = Platform.environment['HOME']; |
471 Iterator iterator = CACHE_DIRECTORIES.map((s) => "$home/$s").iterator; | 491 Iterator iterator = CACHE_DIRECTORIES.map((s) => "$home/$s").iterator; |
472 return deleteIfExists(iterator); | 492 return deleteIfExists(iterator); |
473 } | 493 } |
474 | 494 |
475 Future<bool> start(String url) { | 495 Future<bool> start(String url) { |
476 _logEvent("Starting safari mobile simulator browser on: $url"); | 496 _logEvent("Starting safari mobile simulator browser on: $url"); |
477 return clearCache().then((success) { | 497 return clearCache().then((success) { |
478 if (!success) { | 498 if (!success) { |
479 _logEvent("Could not clear cache, exiting"); | 499 _logEvent("Could not clear cache, exiting"); |
480 » return false; | 500 return false; |
481 } | 501 } |
482 var args = ["-SimulateApplication", | 502 var args = [ |
483 "/Applications/Xcode.app/Contents/Developer/Platforms/" | 503 "-SimulateApplication", |
484 "iPhoneSimulator.platform/Developer/SDKs/" | 504 "/Applications/Xcode.app/Contents/Developer/Platforms/" |
485 "iPhoneSimulator7.1.sdk/Applications/MobileSafari.app/" | 505 "iPhoneSimulator.platform/Developer/SDKs/" |
486 "MobileSafari", | 506 "iPhoneSimulator7.1.sdk/Applications/MobileSafari.app/" |
487 "-u", url]; | 507 "MobileSafari", |
488 return startBrowserProcess(_binary, args) | 508 "-u", |
489 .catchError((e) { | 509 url |
490 _logEvent("Running $_binary --version failed with $e"); | 510 ]; |
491 return false; | 511 return startBrowserProcess(_binary, args).catchError((e) { |
492 }); | 512 _logEvent("Running $_binary --version failed with $e"); |
| 513 return false; |
| 514 }); |
493 }); | 515 }); |
494 } | 516 } |
495 | 517 |
496 String toString() => "SafariMobileSimulator"; | 518 String toString() => "SafariMobileSimulator"; |
497 } | 519 } |
498 | 520 |
499 | |
500 class Dartium extends Chrome { | 521 class Dartium extends Chrome { |
501 final bool checkedMode; | 522 final bool checkedMode; |
502 | 523 |
503 Dartium(this.checkedMode); | 524 Dartium(this.checkedMode); |
504 | 525 |
505 Map<String, String> _getEnvironment() { | 526 Map<String, String> _getEnvironment() { |
506 var environment = new Map<String,String>.from(Platform.environment); | 527 var environment = new Map<String, String>.from(Platform.environment); |
507 // By setting this environment variable, dartium will forward "print()" | 528 // By setting this environment variable, dartium will forward "print()" |
508 // calls in dart to the top-level javascript function "dartPrint()" if | 529 // calls in dart to the top-level javascript function "dartPrint()" if |
509 // available. | 530 // available. |
510 environment['DART_FORWARDING_PRINT'] = '1'; | 531 environment['DART_FORWARDING_PRINT'] = '1'; |
511 if (checkedMode) { | 532 if (checkedMode) { |
512 environment['DART_FLAGS'] = '--checked'; | 533 environment['DART_FLAGS'] = '--checked'; |
513 } | 534 } |
514 return environment; | 535 return environment; |
515 } | 536 } |
516 | 537 |
517 String toString() => "Dartium"; | 538 String toString() => "Dartium"; |
518 } | 539 } |
519 | 540 |
520 class IE extends Browser { | 541 class IE extends Browser { |
521 Future<String> getVersion() { | 542 Future<String> getVersion() { |
522 var args = ["query", | 543 var args = [ |
523 "HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Internet Explorer", | 544 "query", |
524 "/v", | 545 "HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Internet Explorer", |
525 "svcVersion"]; | 546 "/v", |
| 547 "svcVersion" |
| 548 ]; |
526 return Process.run("reg", args).then((result) { | 549 return Process.run("reg", args).then((result) { |
527 if (result.exitCode == 0) { | 550 if (result.exitCode == 0) { |
528 // The string we get back looks like this: | 551 // The string we get back looks like this: |
529 // HKEY_LOCAL_MACHINE\Software\Microsoft\Internet Explorer | 552 // HKEY_LOCAL_MACHINE\Software\Microsoft\Internet Explorer |
530 // version REG_SZ 9.0.8112.16421 | 553 // version REG_SZ 9.0.8112.16421 |
531 var findString = "REG_SZ"; | 554 var findString = "REG_SZ"; |
532 var index = result.stdout.indexOf(findString); | 555 var index = result.stdout.indexOf(findString); |
533 if (index > 0) { | 556 if (index > 0) { |
534 return result.stdout.substring(index + findString.length).trim(); | 557 return result.stdout.substring(index + findString.length).trim(); |
535 } | 558 } |
536 } | 559 } |
537 return "Could not get the version of internet explorer"; | 560 return "Could not get the version of internet explorer"; |
538 }); | 561 }); |
539 } | 562 } |
540 | 563 |
541 // Clears the recovery cache if the static deleteCache flag is set. | 564 // Clears the recovery cache if the static deleteCache flag is set. |
542 Future<bool> clearCache() { | 565 Future<bool> clearCache() { |
543 if (!Browser.deleteCache) return new Future.value(true); | 566 if (!Browser.deleteCache) return new Future.value(true); |
544 var localAppData = Platform.environment['LOCALAPPDATA']; | 567 var localAppData = Platform.environment['LOCALAPPDATA']; |
545 | 568 |
546 Directory dir = new Directory("$localAppData\\Microsoft\\" | 569 Directory dir = new Directory("$localAppData\\Microsoft\\" |
547 "Internet Explorer\\Recovery"); | 570 "Internet Explorer\\Recovery"); |
548 return dir.delete(recursive: true) | 571 return dir.delete(recursive: true).then((_) { |
549 .then((_) { return true; }) | 572 return true; |
550 .catchError((error) { | 573 }).catchError((error) { |
551 _logEvent("Deleting recovery dir failed with $error"); | 574 _logEvent("Deleting recovery dir failed with $error"); |
552 return false; | 575 return false; |
553 }); | 576 }); |
554 } | 577 } |
555 | 578 |
556 Future<bool> start(String url) { | 579 Future<bool> start(String url) { |
557 _logEvent("Starting ie browser on: $url"); | 580 _logEvent("Starting ie browser on: $url"); |
558 return clearCache().then((_) => getVersion()).then((version) { | 581 return clearCache().then((_) => getVersion()).then((version) { |
559 _logEvent("Got version: $version"); | 582 _logEvent("Got version: $version"); |
560 return startBrowserProcess(_binary, [url]); | 583 return startBrowserProcess(_binary, [url]); |
561 }); | 584 }); |
562 } | 585 } |
| 586 |
563 String toString() => "IE"; | 587 String toString() => "IE"; |
564 | |
565 } | 588 } |
566 | 589 |
567 | |
568 class AndroidBrowserConfig { | 590 class AndroidBrowserConfig { |
569 final String name; | 591 final String name; |
570 final String package; | 592 final String package; |
571 final String activity; | 593 final String activity; |
572 final String action; | 594 final String action; |
573 AndroidBrowserConfig(this.name, this.package, this.activity, this.action); | 595 AndroidBrowserConfig(this.name, this.package, this.activity, this.action); |
574 } | 596 } |
575 | 597 |
576 | |
577 final contentShellOnAndroidConfig = new AndroidBrowserConfig( | 598 final contentShellOnAndroidConfig = new AndroidBrowserConfig( |
578 'ContentShellOnAndroid', | 599 'ContentShellOnAndroid', |
579 'org.chromium.content_shell_apk', | 600 'org.chromium.content_shell_apk', |
580 '.ContentShellActivity', | 601 '.ContentShellActivity', |
581 'android.intent.action.VIEW'); | 602 'android.intent.action.VIEW'); |
582 | 603 |
583 | 604 final dartiumOnAndroidConfig = new AndroidBrowserConfig('DartiumOnAndroid', |
584 final dartiumOnAndroidConfig = new AndroidBrowserConfig( | 605 'com.google.android.apps.chrome', '.Main', 'android.intent.action.VIEW'); |
585 'DartiumOnAndroid', | |
586 'com.google.android.apps.chrome', | |
587 '.Main', | |
588 'android.intent.action.VIEW'); | |
589 | |
590 | 606 |
591 class AndroidBrowser extends Browser { | 607 class AndroidBrowser extends Browser { |
592 final bool checkedMode; | 608 final bool checkedMode; |
593 AdbDevice _adbDevice; | 609 AdbDevice _adbDevice; |
594 AndroidBrowserConfig _config; | 610 AndroidBrowserConfig _config; |
595 | 611 |
596 AndroidBrowser(this._adbDevice, this._config, this.checkedMode, apkPath) { | 612 AndroidBrowser(this._adbDevice, this._config, this.checkedMode, apkPath) { |
597 _binary = apkPath; | 613 _binary = apkPath; |
598 } | 614 } |
599 | 615 |
600 Future<bool> start(String url) { | 616 Future<bool> start(String url) { |
601 var intent = new Intent( | 617 var intent = |
602 _config.action, _config.package, _config.activity, url); | 618 new Intent(_config.action, _config.package, _config.activity, url); |
603 return _adbDevice.waitForBootCompleted().then((_) { | 619 return _adbDevice.waitForBootCompleted().then((_) { |
604 return _adbDevice.forceStop(_config.package); | 620 return _adbDevice.forceStop(_config.package); |
605 }).then((_) { | 621 }).then((_) { |
606 return _adbDevice.killAll(); | 622 return _adbDevice.killAll(); |
607 }).then((_) { | 623 }).then((_) { |
608 return _adbDevice.adbRoot(); | 624 return _adbDevice.adbRoot(); |
609 }).then((_) { | 625 }).then((_) { |
610 return _adbDevice.setProp("DART_FORWARDING_PRINT", "1"); | 626 return _adbDevice.setProp("DART_FORWARDING_PRINT", "1"); |
611 }).then((_) { | 627 }).then((_) { |
612 if (checkedMode) { | 628 if (checkedMode) { |
(...skipping 11 matching lines...) Expand all Loading... |
624 Future<bool> close() { | 640 Future<bool> close() { |
625 if (_adbDevice != null) { | 641 if (_adbDevice != null) { |
626 return _adbDevice.forceStop(_config.package).then((_) { | 642 return _adbDevice.forceStop(_config.package).then((_) { |
627 return _adbDevice.killAll().then((_) => true); | 643 return _adbDevice.killAll().then((_) => true); |
628 }); | 644 }); |
629 } | 645 } |
630 return new Future.value(true); | 646 return new Future.value(true); |
631 } | 647 } |
632 | 648 |
633 void logBrowserInfoToTestBrowserOutput() { | 649 void logBrowserInfoToTestBrowserOutput() { |
634 _testBrowserOutput.stdout.write( | 650 _testBrowserOutput.stdout |
635 'Android device id: ${_adbDevice.deviceId}\n'); | 651 .write('Android device id: ${_adbDevice.deviceId}\n'); |
636 } | 652 } |
637 | 653 |
638 String toString() => _config.name; | 654 String toString() => _config.name; |
639 } | 655 } |
640 | 656 |
641 | |
642 class AndroidChrome extends Browser { | 657 class AndroidChrome extends Browser { |
643 static const String viewAction = 'android.intent.action.VIEW'; | 658 static const String viewAction = 'android.intent.action.VIEW'; |
644 static const String mainAction = 'android.intent.action.MAIN'; | 659 static const String mainAction = 'android.intent.action.MAIN'; |
645 static const String chromePackage = 'com.android.chrome'; | 660 static const String chromePackage = 'com.android.chrome'; |
646 static const String browserPackage = 'com.android.browser'; | 661 static const String browserPackage = 'com.android.browser'; |
647 static const String firefoxPackage = 'org.mozilla.firefox'; | 662 static const String firefoxPackage = 'org.mozilla.firefox'; |
648 static const String turnScreenOnPackage = 'com.google.dart.turnscreenon'; | 663 static const String turnScreenOnPackage = 'com.google.dart.turnscreenon'; |
649 | 664 |
650 AdbDevice _adbDevice; | 665 AdbDevice _adbDevice; |
651 | 666 |
652 AndroidChrome(this._adbDevice); | 667 AndroidChrome(this._adbDevice); |
653 | 668 |
654 Future<bool> start(String url) { | 669 Future<bool> start(String url) { |
655 var browserIntent = new Intent( | 670 var browserIntent = |
656 viewAction, browserPackage, '.BrowserActivity', url); | 671 new Intent(viewAction, browserPackage, '.BrowserActivity', url); |
657 var chromeIntent = new Intent(viewAction, chromePackage, '.Main', url); | 672 var chromeIntent = new Intent(viewAction, chromePackage, '.Main', url); |
658 var firefoxIntent = new Intent(viewAction, firefoxPackage, '.App', url); | 673 var firefoxIntent = new Intent(viewAction, firefoxPackage, '.App', url); |
659 var turnScreenOnIntent = | 674 var turnScreenOnIntent = |
660 new Intent(mainAction, turnScreenOnPackage, '.Main'); | 675 new Intent(mainAction, turnScreenOnPackage, '.Main'); |
661 | 676 |
662 var testing_resources_dir = | 677 var testing_resources_dir = |
663 new Path('third_party/android_testing_resources'); | 678 new Path('third_party/android_testing_resources'); |
664 if (!new Directory(testing_resources_dir.toNativePath()).existsSync()) { | 679 if (!new Directory(testing_resources_dir.toNativePath()).existsSync()) { |
665 DebugLogger.error("$testing_resources_dir doesn't exist. Exiting now."); | 680 DebugLogger.error("$testing_resources_dir doesn't exist. Exiting now."); |
666 exit(1); | 681 exit(1); |
(...skipping 28 matching lines...) Expand all Loading... |
695 Future<bool> close() { | 710 Future<bool> close() { |
696 if (_adbDevice != null) { | 711 if (_adbDevice != null) { |
697 return _adbDevice.forceStop(chromePackage).then((_) { | 712 return _adbDevice.forceStop(chromePackage).then((_) { |
698 return _adbDevice.killAll().then((_) => true); | 713 return _adbDevice.killAll().then((_) => true); |
699 }); | 714 }); |
700 } | 715 } |
701 return new Future.value(true); | 716 return new Future.value(true); |
702 } | 717 } |
703 | 718 |
704 void logBrowserInfoToTestBrowserOutput() { | 719 void logBrowserInfoToTestBrowserOutput() { |
705 _testBrowserOutput.stdout.write( | 720 _testBrowserOutput.stdout |
706 'Android device id: ${_adbDevice.deviceId}\n'); | 721 .write('Android device id: ${_adbDevice.deviceId}\n'); |
707 } | 722 } |
708 | 723 |
709 String toString() => "chromeOnAndroid"; | 724 String toString() => "chromeOnAndroid"; |
710 } | 725 } |
711 | 726 |
712 | |
713 class Firefox extends Browser { | 727 class Firefox extends Browser { |
714 static const String enablePopUp = | 728 static const String enablePopUp = |
715 'user_pref("dom.disable_open_during_load", false);'; | 729 'user_pref("dom.disable_open_during_load", false);'; |
716 static const String disableDefaultCheck = | 730 static const String disableDefaultCheck = |
717 'user_pref("browser.shell.checkDefaultBrowser", false);'; | 731 'user_pref("browser.shell.checkDefaultBrowser", false);'; |
718 static const String disableScriptTimeLimit = | 732 static const String disableScriptTimeLimit = |
719 'user_pref("dom.max_script_run_time", 0);'; | 733 'user_pref("dom.max_script_run_time", 0);'; |
720 | 734 |
721 void _createPreferenceFile(var path) { | 735 void _createPreferenceFile(var path) { |
722 var file = new File("${path.toString()}/user.js"); | 736 var file = new File("${path.toString()}/user.js"); |
(...skipping 11 matching lines...) Expand all Loading... |
734 if (versionResult.exitCode != 0) { | 748 if (versionResult.exitCode != 0) { |
735 _logEvent("Failed to firefox get version"); | 749 _logEvent("Failed to firefox get version"); |
736 _logEvent("Make sure $_binary is a valid program for running firefox"); | 750 _logEvent("Make sure $_binary is a valid program for running firefox"); |
737 return new Future.value(false); | 751 return new Future.value(false); |
738 } | 752 } |
739 version = versionResult.stdout; | 753 version = versionResult.stdout; |
740 _logEvent("Got version: $version"); | 754 _logEvent("Got version: $version"); |
741 | 755 |
742 return Directory.systemTemp.createTemp().then((userDir) { | 756 return Directory.systemTemp.createTemp().then((userDir) { |
743 _createPreferenceFile(userDir.path); | 757 _createPreferenceFile(userDir.path); |
744 _cleanup = () { userDir.deleteSync(recursive: true); }; | 758 _cleanup = () { |
745 var args = ["-profile", "${userDir.path}", | 759 userDir.deleteSync(recursive: true); |
746 "-no-remote", "-new-instance", url]; | 760 }; |
747 var environment = new Map<String,String>.from(Platform.environment); | 761 var args = [ |
| 762 "-profile", |
| 763 "${userDir.path}", |
| 764 "-no-remote", |
| 765 "-new-instance", |
| 766 url |
| 767 ]; |
| 768 var environment = new Map<String, String>.from(Platform.environment); |
748 environment["MOZ_CRASHREPORTER_DISABLE"] = "1"; | 769 environment["MOZ_CRASHREPORTER_DISABLE"] = "1"; |
749 return startBrowserProcess(_binary, args, environment: environment); | 770 return startBrowserProcess(_binary, args, environment: environment); |
750 | |
751 }); | 771 }); |
752 }).catchError((e) { | 772 }).catchError((e) { |
753 _logEvent("Running $_binary --version failed with $e"); | 773 _logEvent("Running $_binary --version failed with $e"); |
754 return false; | 774 return false; |
755 }); | 775 }); |
756 } | 776 } |
757 | 777 |
758 String toString() => "Firefox"; | 778 String toString() => "Firefox"; |
759 } | 779 } |
760 | 780 |
761 | |
762 /** | 781 /** |
763 * Describes the current state of a browser used for testing. | 782 * Describes the current state of a browser used for testing. |
764 */ | 783 */ |
765 class BrowserStatus { | 784 class BrowserStatus { |
766 Browser browser; | 785 Browser browser; |
767 BrowserTest currentTest; | 786 BrowserTest currentTest; |
768 | 787 |
769 // This is currently not used for anything except for error reporting. | 788 // This is currently not used for anything except for error reporting. |
770 // Given the usefulness of this in debugging issues this should not be | 789 // Given the usefulness of this in debugging issues this should not be |
771 // removed even when we have a really stable system. | 790 // removed even when we have a really stable system. |
772 BrowserTest lastTest; | 791 BrowserTest lastTest; |
773 bool timeout = false; | 792 bool timeout = false; |
774 Timer nextTestTimeout; | 793 Timer nextTestTimeout; |
775 Stopwatch timeSinceRestart = new Stopwatch()..start(); | 794 Stopwatch timeSinceRestart = new Stopwatch()..start(); |
776 | 795 |
777 BrowserStatus(Browser this.browser); | 796 BrowserStatus(Browser this.browser); |
778 } | 797 } |
779 | 798 |
780 | |
781 /** | 799 /** |
782 * Describes a single test to be run in the browser. | 800 * Describes a single test to be run in the browser. |
783 */ | 801 */ |
784 class BrowserTest { | 802 class BrowserTest { |
785 // TODO(ricow): Add timeout callback instead of the string passing hack. | 803 // TODO(ricow): Add timeout callback instead of the string passing hack. |
786 Function doneCallback; | 804 Function doneCallback; |
787 String url; | 805 String url; |
788 int timeout; | 806 int timeout; |
789 String lastKnownMessage = ''; | 807 String lastKnownMessage = ''; |
790 Stopwatch stopwatch; | 808 Stopwatch stopwatch; |
791 | 809 |
792 // This might be null | 810 // This might be null |
793 Duration delayUntilTestStarted; | 811 Duration delayUntilTestStarted; |
794 | 812 |
795 // We store this here for easy access when tests time out (instead of | 813 // We store this here for easy access when tests time out (instead of |
796 // capturing this in a closure) | 814 // capturing this in a closure) |
797 Timer timeoutTimer; | 815 Timer timeoutTimer; |
798 | 816 |
799 // Used for debugging, this is simply a unique identifier assigned to each | 817 // Used for debugging, this is simply a unique identifier assigned to each |
800 // test. | 818 // test. |
801 int id; | 819 int id; |
802 static int _idCounter = 0; | 820 static int _idCounter = 0; |
803 | 821 |
804 BrowserTest(this.url, this.doneCallback, this.timeout) { | 822 BrowserTest(this.url, this.doneCallback, this.timeout) { |
805 id = _idCounter++; | 823 id = _idCounter++; |
806 } | 824 } |
807 | 825 |
808 String toJSON() => JSON.encode({'url': url, | 826 String toJSON() => JSON.encode({'url': url, 'id': id, 'isHtmlTest': false}); |
809 'id': id, | |
810 'isHtmlTest': false}); | |
811 } | 827 } |
812 | 828 |
813 | |
814 /** | 829 /** |
815 * Describes a test with a custom HTML page to be run in the browser. | 830 * Describes a test with a custom HTML page to be run in the browser. |
816 */ | 831 */ |
817 class HtmlTest extends BrowserTest { | 832 class HtmlTest extends BrowserTest { |
818 List<String> expectedMessages; | 833 List<String> expectedMessages; |
819 | 834 |
820 HtmlTest(url, doneCallback, timeout, this.expectedMessages) | 835 HtmlTest(url, doneCallback, timeout, this.expectedMessages) |
821 : super(url, doneCallback, timeout) { } | 836 : super(url, doneCallback, timeout) {} |
822 | 837 |
823 String toJSON() => JSON.encode({'url': url, | 838 String toJSON() => JSON.encode({ |
824 'id': id, | 839 'url': url, |
825 'isHtmlTest': true, | 840 'id': id, |
826 'expectedMessages': expectedMessages}); | 841 'isHtmlTest': true, |
| 842 'expectedMessages': expectedMessages |
| 843 }); |
827 } | 844 } |
828 | 845 |
829 | |
830 /* Describes the output of running the test in a browser */ | 846 /* Describes the output of running the test in a browser */ |
831 class BrowserTestOutput { | 847 class BrowserTestOutput { |
832 final Duration delayUntilTestStarted; | 848 final Duration delayUntilTestStarted; |
833 final Duration duration; | 849 final Duration duration; |
834 | 850 |
835 final String lastKnownMessage; | 851 final String lastKnownMessage; |
836 | 852 |
837 final BrowserOutput browserOutput; | 853 final BrowserOutput browserOutput; |
838 final bool didTimeout; | 854 final bool didTimeout; |
839 | 855 |
840 BrowserTestOutput( | 856 BrowserTestOutput(this.delayUntilTestStarted, this.duration, |
841 this.delayUntilTestStarted, this.duration, this.lastKnownMessage, | 857 this.lastKnownMessage, this.browserOutput, |
842 this.browserOutput, {this.didTimeout: false}); | 858 {this.didTimeout: false}); |
843 } | 859 } |
844 | 860 |
845 | |
846 /// Encapsulates all the functionality for running tests in browsers. | 861 /// Encapsulates all the functionality for running tests in browsers. |
847 /// Tests are added to the queue and the supplied callbacks are called | 862 /// Tests are added to the queue and the supplied callbacks are called |
848 /// when a test completes. | 863 /// when a test completes. |
849 /// BrowserTestRunner starts up to maxNumBrowser instances of the browser, | 864 /// BrowserTestRunner starts up to maxNumBrowser instances of the browser, |
850 /// to run the tests, starting them sequentially, as needed, so only | 865 /// to run the tests, starting them sequentially, as needed, so only |
851 /// one is starting up at a time. | 866 /// one is starting up at a time. |
852 /// BrowserTestRunner starts a BrowserTestingServer, which serves a | 867 /// BrowserTestRunner starts a BrowserTestingServer, which serves a |
853 /// driver page to the browsers, serves tests, and receives results and | 868 /// driver page to the browsers, serves tests, and receives results and |
854 /// requests back from the browsers. | 869 /// requests back from the browsers. |
855 class BrowserTestRunner { | 870 class BrowserTestRunner { |
(...skipping 16 matching lines...) Expand all Loading... |
872 Function logger; | 887 Function logger; |
873 | 888 |
874 int browserIdCounter = 1; | 889 int browserIdCounter = 1; |
875 | 890 |
876 bool testingServerStarted = false; | 891 bool testingServerStarted = false; |
877 bool underTermination = false; | 892 bool underTermination = false; |
878 int numBrowserGetTestTimeouts = 0; | 893 int numBrowserGetTestTimeouts = 0; |
879 DateTime lastEmptyTestQueueTime = new DateTime.now(); | 894 DateTime lastEmptyTestQueueTime = new DateTime.now(); |
880 String _currentStartingBrowserId; | 895 String _currentStartingBrowserId; |
881 List<BrowserTest> testQueue = new List<BrowserTest>(); | 896 List<BrowserTest> testQueue = new List<BrowserTest>(); |
882 Map<String, BrowserStatus> browserStatus = | 897 Map<String, BrowserStatus> browserStatus = new Map<String, BrowserStatus>(); |
883 new Map<String, BrowserStatus>(); | |
884 | 898 |
885 var adbDeviceMapping = new Map<String, AdbDevice>(); | 899 var adbDeviceMapping = new Map<String, AdbDevice>(); |
886 List<AdbDevice> idleAdbDevices; | 900 List<AdbDevice> idleAdbDevices; |
887 | 901 |
888 // This cache is used to guarantee that we never see double reporting. | 902 // This cache is used to guarantee that we never see double reporting. |
889 // If we do we need to provide developers with this information. | 903 // If we do we need to provide developers with this information. |
890 // We don't add urls to the cache until we have run it. | 904 // We don't add urls to the cache until we have run it. |
891 Map<int, String> testCache = new Map<int, String>(); | 905 Map<int, String> testCache = new Map<int, String>(); |
892 | 906 |
893 Map<int, String> doubleReportingOutputs = new Map<int, String>(); | 907 Map<int, String> doubleReportingOutputs = new Map<int, String>(); |
894 List<String> timedOut = []; | 908 List<String> timedOut = []; |
895 | 909 |
896 // We will start a new browser when the test queue hasn't been empty | 910 // We will start a new browser when the test queue hasn't been empty |
897 // recently, we have fewer than maxNumBrowsers browsers, and there is | 911 // recently, we have fewer than maxNumBrowsers browsers, and there is |
898 // no other browser instance currently starting up. | 912 // no other browser instance currently starting up. |
899 bool get queueWasEmptyRecently { | 913 bool get queueWasEmptyRecently { |
900 return testQueue.isEmpty || | 914 return testQueue.isEmpty || |
901 new DateTime.now().difference(lastEmptyTestQueueTime) < | 915 new DateTime.now().difference(lastEmptyTestQueueTime) < |
902 MIN_NONEMPTY_QUEUE_TIME; | 916 MIN_NONEMPTY_QUEUE_TIME; |
903 } | 917 } |
904 | 918 |
905 // While a browser is starting, but has not requested its first test, its | 919 // While a browser is starting, but has not requested its first test, its |
906 // browserId is stored in _currentStartingBrowserId. | 920 // browserId is stored in _currentStartingBrowserId. |
907 // When no browser is currently starting, _currentStartingBrowserId is null. | 921 // When no browser is currently starting, _currentStartingBrowserId is null. |
908 bool get aBrowserIsCurrentlyStarting => _currentStartingBrowserId != null; | 922 bool get aBrowserIsCurrentlyStarting => _currentStartingBrowserId != null; |
909 void markCurrentlyStarting(String id) { | 923 void markCurrentlyStarting(String id) { |
910 _currentStartingBrowserId = id; | 924 _currentStartingBrowserId = id; |
911 } | 925 } |
| 926 |
912 void markNotCurrentlyStarting(String id) { | 927 void markNotCurrentlyStarting(String id) { |
913 if (_currentStartingBrowserId == id) _currentStartingBrowserId = null; | 928 if (_currentStartingBrowserId == id) _currentStartingBrowserId = null; |
914 } | 929 } |
915 | 930 |
916 // If [browserName] doesn't support opening new windows, we use new iframes | 931 // If [browserName] doesn't support opening new windows, we use new iframes |
917 // instead. | 932 // instead. |
918 bool get useIframe => | 933 bool get useIframe => |
919 !Browser.BROWSERS_WITH_WINDOW_SUPPORT.contains(browserName); | 934 !Browser.BROWSERS_WITH_WINDOW_SUPPORT.contains(browserName); |
920 | 935 |
921 /// The optional testingServer parameter allows callers to pass in | 936 /// The optional testingServer parameter allows callers to pass in |
922 /// a testing server with different behavior than the default | 937 /// a testing server with different behavior than the default |
923 /// BrowserTestServer. The url handlers of the testingServer are | 938 /// BrowserTestServer. The url handlers of the testingServer are |
924 /// overwritten, so an existing handler can't be shared between instances. | 939 /// overwritten, so an existing handler can't be shared between instances. |
925 BrowserTestRunner(this.configuration, | 940 BrowserTestRunner( |
926 this.localIp, | 941 this.configuration, this.localIp, this.browserName, this.maxNumBrowsers, |
927 this.browserName, | 942 {BrowserTestingServer this.testingServer}) { |
928 this.maxNumBrowsers, | |
929 {BrowserTestingServer this.testingServer}) { | |
930 checkedMode = configuration['checked']; | 943 checkedMode = configuration['checked']; |
931 if (browserName == 'ff') browserName = 'firefox'; | 944 if (browserName == 'ff') browserName = 'firefox'; |
932 } | 945 } |
933 | 946 |
934 Future start() async { | 947 Future start() async { |
935 if (testingServer == null) { | 948 if (testingServer == null) { |
936 testingServer = new BrowserTestingServer( | 949 testingServer = |
937 configuration, localIp, useIframe); | 950 new BrowserTestingServer(configuration, localIp, useIframe); |
938 } | 951 } |
939 await testingServer.start(); | 952 await testingServer.start(); |
940 testingServer | 953 testingServer |
941 ..testDoneCallBack = handleResults | 954 ..testDoneCallBack = handleResults |
942 ..testStatusUpdateCallBack = handleStatusUpdate | 955 ..testStatusUpdateCallBack = handleStatusUpdate |
943 ..testStartedCallBack = handleStarted | 956 ..testStartedCallBack = handleStarted |
944 ..nextTestCallBack = getNextTest; | 957 ..nextTestCallBack = getNextTest; |
945 if (browserName == 'chromeOnAndroid') { | 958 if (browserName == 'chromeOnAndroid') { |
946 var idbNames = await AdbHelper.listDevices(); | 959 var idbNames = await AdbHelper.listDevices(); |
947 idleAdbDevices = new List.from(idbNames.map((id) => new AdbDevice(id))); | 960 idleAdbDevices = new List.from(idbNames.map((id) => new AdbDevice(id))); |
948 maxNumBrowsers = min(maxNumBrowsers, idleAdbDevices.length); | 961 maxNumBrowsers = min(maxNumBrowsers, idleAdbDevices.length); |
949 } | 962 } |
950 testingServerStarted = true; | 963 testingServerStarted = true; |
951 requestBrowser(); | 964 requestBrowser(); |
952 } | 965 } |
953 | 966 |
954 /// requestBrowser() is called whenever we might want to start an additional | 967 /// requestBrowser() is called whenever we might want to start an additional |
(...skipping 12 matching lines...) Expand all Loading... |
967 createBrowser(); | 980 createBrowser(); |
968 } | 981 } |
969 | 982 |
970 String getNextBrowserId() => "BROWSER${browserIdCounter++}"; | 983 String getNextBrowserId() => "BROWSER${browserIdCounter++}"; |
971 | 984 |
972 void createBrowser() { | 985 void createBrowser() { |
973 final String id = getNextBrowserId(); | 986 final String id = getNextBrowserId(); |
974 final String url = testingServer.getDriverUrl(id); | 987 final String url = testingServer.getDriverUrl(id); |
975 Browser browser; | 988 Browser browser; |
976 if (browserName == 'chromeOnAndroid') { | 989 if (browserName == 'chromeOnAndroid') { |
977 AdbDevice device = idleAdbDevices.removeLast(); | 990 AdbDevice device = idleAdbDevices.removeLast(); |
978 adbDeviceMapping[id] = device; | 991 adbDeviceMapping[id] = device; |
979 browser = new AndroidChrome(device); | 992 browser = new AndroidChrome(device); |
980 } else { | 993 } else { |
981 String path = Locations.getBrowserLocation(browserName, configuration); | 994 String path = Locations.getBrowserLocation(browserName, configuration); |
982 browser = new Browser.byName(browserName, path, checkedMode); | 995 browser = new Browser.byName(browserName, path, checkedMode); |
983 browser.logger = logger; | 996 browser.logger = logger; |
984 } | 997 } |
985 browser.id = id; | 998 browser.id = id; |
986 markCurrentlyStarting(id); | 999 markCurrentlyStarting(id); |
987 final status = new BrowserStatus(browser); | 1000 final status = new BrowserStatus(browser); |
(...skipping 13 matching lines...) Expand all Loading... |
1001 if (status == null || status.timeout) { | 1014 if (status == null || status.timeout) { |
1002 // We don't do anything, this browser is currently being killed and | 1015 // We don't do anything, this browser is currently being killed and |
1003 // replaced. The browser here can be null if we decided to kill the | 1016 // replaced. The browser here can be null if we decided to kill the |
1004 // browser. | 1017 // browser. |
1005 } else if (status.currentTest != null) { | 1018 } else if (status.currentTest != null) { |
1006 status.currentTest.timeoutTimer.cancel(); | 1019 status.currentTest.timeoutTimer.cancel(); |
1007 status.currentTest.stopwatch.stop(); | 1020 status.currentTest.stopwatch.stop(); |
1008 | 1021 |
1009 if (status.currentTest.id != testId) { | 1022 if (status.currentTest.id != testId) { |
1010 print("Expected test id ${status.currentTest.id} for" | 1023 print("Expected test id ${status.currentTest.id} for" |
1011 "${status.currentTest.url}"); | 1024 "${status.currentTest.url}"); |
1012 print("Got test id ${testId}"); | 1025 print("Got test id ${testId}"); |
1013 print("Last test id was ${status.lastTest.id} for " | 1026 print("Last test id was ${status.lastTest.id} for " |
1014 "${status.currentTest.url}"); | 1027 "${status.currentTest.url}"); |
1015 throw("This should never happen, wrong test id"); | 1028 throw ("This should never happen, wrong test id"); |
1016 } | 1029 } |
1017 testCache[testId] = status.currentTest.url; | 1030 testCache[testId] = status.currentTest.url; |
1018 | 1031 |
1019 // Report that the test is finished now | 1032 // Report that the test is finished now |
1020 var browserTestOutput = new BrowserTestOutput( | 1033 var browserTestOutput = new BrowserTestOutput( |
1021 status.currentTest.delayUntilTestStarted, | 1034 status.currentTest.delayUntilTestStarted, |
1022 status.currentTest.stopwatch.elapsed, | 1035 status.currentTest.stopwatch.elapsed, |
1023 output, | 1036 output, |
1024 status.browser.testBrowserOutput); | 1037 status.browser.testBrowserOutput); |
1025 status.currentTest.doneCallback(browserTestOutput); | 1038 status.currentTest.doneCallback(browserTestOutput); |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1058 createTimeoutTimer(status.currentTest, status); | 1071 createTimeoutTimer(status.currentTest, status); |
1059 status.currentTest.delayUntilTestStarted = | 1072 status.currentTest.delayUntilTestStarted = |
1060 status.currentTest.stopwatch.elapsed; | 1073 status.currentTest.stopwatch.elapsed; |
1061 } | 1074 } |
1062 } | 1075 } |
1063 | 1076 |
1064 void handleTimeout(BrowserStatus status) { | 1077 void handleTimeout(BrowserStatus status) { |
1065 // We simply kill the browser and starts up a new one! | 1078 // We simply kill the browser and starts up a new one! |
1066 // We could be smarter here, but it does not seems like it is worth it. | 1079 // We could be smarter here, but it does not seems like it is worth it. |
1067 if (status.timeout) { | 1080 if (status.timeout) { |
1068 DebugLogger.error( | 1081 DebugLogger.error("Got test timeout for an already restarting browser"); |
1069 "Got test timeout for an already restarting browser"); | |
1070 return; | 1082 return; |
1071 } | 1083 } |
1072 status.timeout = true; | 1084 status.timeout = true; |
1073 timedOut.add(status.currentTest.url); | 1085 timedOut.add(status.currentTest.url); |
1074 var id = status.browser.id; | 1086 var id = status.browser.id; |
1075 | 1087 |
1076 status.currentTest.stopwatch.stop(); | 1088 status.currentTest.stopwatch.stop(); |
1077 status.browser.close().then((_) { | 1089 status.browser.close().then((_) { |
1078 var lastKnownMessage = | 1090 var lastKnownMessage = |
1079 'Dom could not be fetched, since the test timed out.'; | 1091 'Dom could not be fetched, since the test timed out.'; |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1120 status.nextTestTimeout = null; | 1132 status.nextTestTimeout = null; |
1121 } | 1133 } |
1122 if (testQueue.isEmpty) return null; | 1134 if (testQueue.isEmpty) return null; |
1123 | 1135 |
1124 // We are currently terminating this browser, don't start a new test. | 1136 // We are currently terminating this browser, don't start a new test. |
1125 if (status.timeout) return null; | 1137 if (status.timeout) return null; |
1126 | 1138 |
1127 // Restart Internet Explorer if it has been | 1139 // Restart Internet Explorer if it has been |
1128 // running for longer than RESTART_BROWSER_INTERVAL. The tests have | 1140 // running for longer than RESTART_BROWSER_INTERVAL. The tests have |
1129 // had flaky timeouts, and this may help. | 1141 // had flaky timeouts, and this may help. |
1130 if ((browserName == 'ie10' || | 1142 if ((browserName == 'ie10' || browserName == 'ie11') && |
1131 browserName == 'ie11') && | |
1132 status.timeSinceRestart.elapsed > RESTART_BROWSER_INTERVAL) { | 1143 status.timeSinceRestart.elapsed > RESTART_BROWSER_INTERVAL) { |
1133 var id = status.browser.id; | 1144 var id = status.browser.id; |
1134 // Reset stopwatch so we don't trigger again before restarting. | 1145 // Reset stopwatch so we don't trigger again before restarting. |
1135 status.timeout = true; | 1146 status.timeout = true; |
1136 status.browser.close().then((_) { | 1147 status.browser.close().then((_) { |
1137 // We don't want to start a new browser if we are terminating. | 1148 // We don't want to start a new browser if we are terminating. |
1138 if (underTermination) return; | 1149 if (underTermination) return; |
1139 removeBrowser(id); | 1150 removeBrowser(id); |
1140 requestBrowser(); | 1151 requestBrowser(); |
1141 }); | 1152 }); |
(...skipping 29 matching lines...) Expand all Loading... |
1171 | 1182 |
1172 // Reset the test specific output information (stdout, stderr) on the | 1183 // Reset the test specific output information (stdout, stderr) on the |
1173 // browser, since a new test is being started. | 1184 // browser, since a new test is being started. |
1174 status.browser.resetTestBrowserOutput(); | 1185 status.browser.resetTestBrowserOutput(); |
1175 status.browser.logBrowserInfoToTestBrowserOutput(); | 1186 status.browser.logBrowserInfoToTestBrowserOutput(); |
1176 return test; | 1187 return test; |
1177 } | 1188 } |
1178 | 1189 |
1179 /// Creates a timer that is active while a test is running on a browser. | 1190 /// Creates a timer that is active while a test is running on a browser. |
1180 Timer createTimeoutTimer(BrowserTest test, BrowserStatus status) { | 1191 Timer createTimeoutTimer(BrowserTest test, BrowserStatus status) { |
1181 return new Timer(new Duration(seconds: test.timeout), | 1192 return new Timer(new Duration(seconds: test.timeout), () { |
1182 () { handleTimeout(status); }); | 1193 handleTimeout(status); |
| 1194 }); |
1183 } | 1195 } |
1184 | 1196 |
1185 /// Creates a timer that is active while no test is running on the | 1197 /// Creates a timer that is active while no test is running on the |
1186 /// browser. It has finished one test, and it has not requested a new test. | 1198 /// browser. It has finished one test, and it has not requested a new test. |
1187 Timer createNextTestTimer(BrowserStatus status) { | 1199 Timer createNextTestTimer(BrowserStatus status) { |
1188 return new Timer(BrowserTestRunner.NEXT_TEST_TIMEOUT, | 1200 return new Timer(BrowserTestRunner.NEXT_TEST_TIMEOUT, () { |
1189 () { handleNextTestTimeout(status); }); | 1201 handleNextTestTimeout(status); |
| 1202 }); |
1190 } | 1203 } |
1191 | 1204 |
1192 void handleNextTestTimeout(status) { | 1205 void handleNextTestTimeout(status) { |
1193 DebugLogger.warning( | 1206 DebugLogger |
1194 "Browser timed out before getting next test. Restarting"); | 1207 .warning("Browser timed out before getting next test. Restarting"); |
1195 if (status.timeout) return; | 1208 if (status.timeout) return; |
1196 numBrowserGetTestTimeouts++; | 1209 numBrowserGetTestTimeouts++; |
1197 if (numBrowserGetTestTimeouts >= MAX_NEXT_TEST_TIMEOUTS) { | 1210 if (numBrowserGetTestTimeouts >= MAX_NEXT_TEST_TIMEOUTS) { |
1198 DebugLogger.error( | 1211 DebugLogger.error( |
1199 "Too many browser timeouts before getting next test. Terminating"); | 1212 "Too many browser timeouts before getting next test. Terminating"); |
1200 terminate().then((_) => exit(1)); | 1213 terminate().then((_) => exit(1)); |
1201 } else { | 1214 } else { |
1202 status.timeout = true; | 1215 status.timeout = true; |
1203 status.browser.close().then((_) { | 1216 status.browser.close().then((_) { |
1204 removeBrowser(status.browser.id); | 1217 removeBrowser(status.browser.id); |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1248 for (Browser b in browsers) { | 1261 for (Browser b in browsers) { |
1249 await b.close(); | 1262 await b.close(); |
1250 } | 1263 } |
1251 testingServer.errorReportingServer.close(); | 1264 testingServer.errorReportingServer.close(); |
1252 printDoubleReportingTests(); | 1265 printDoubleReportingTests(); |
1253 } | 1266 } |
1254 } | 1267 } |
1255 | 1268 |
1256 class BrowserTestingServer { | 1269 class BrowserTestingServer { |
1257 final Map configuration; | 1270 final Map configuration; |
| 1271 |
1258 /// Interface of the testing server: | 1272 /// Interface of the testing server: |
1259 /// | 1273 /// |
1260 /// GET /driver/BROWSER_ID -- This will get the driver page to fetch | 1274 /// GET /driver/BROWSER_ID -- This will get the driver page to fetch |
1261 /// and run tests ... | 1275 /// and run tests ... |
1262 /// GET /next_test/BROWSER_ID -- returns "WAIT" "TERMINATE" or "url#id" | 1276 /// GET /next_test/BROWSER_ID -- returns "WAIT" "TERMINATE" or "url#id" |
1263 /// where url is the test to run, and id is the id of the test. | 1277 /// where url is the test to run, and id is the id of the test. |
1264 /// If there are currently no available tests the waitSignal is send | 1278 /// If there are currently no available tests the waitSignal is send |
1265 /// back. If we are in the process of terminating the terminateSignal | 1279 /// back. If we are in the process of terminating the terminateSignal |
1266 /// is send back and the browser will stop requesting new tasks. | 1280 /// is send back and the browser will stop requesting new tasks. |
1267 /// POST /report/BROWSER_ID?id=NUM -- sends back the dom of the executed | 1281 /// POST /report/BROWSER_ID?id=NUM -- sends back the dom of the executed |
(...skipping 16 matching lines...) Expand all Loading... |
1284 | 1298 |
1285 Function testDoneCallBack; | 1299 Function testDoneCallBack; |
1286 Function testStatusUpdateCallBack; | 1300 Function testStatusUpdateCallBack; |
1287 Function testStartedCallBack; | 1301 Function testStartedCallBack; |
1288 Function nextTestCallBack; | 1302 Function nextTestCallBack; |
1289 | 1303 |
1290 BrowserTestingServer(this.configuration, this.localIp, this.useIframe); | 1304 BrowserTestingServer(this.configuration, this.localIp, this.useIframe); |
1291 | 1305 |
1292 Future start() { | 1306 Future start() { |
1293 var test_driver_error_port = configuration['test_driver_error_port']; | 1307 var test_driver_error_port = configuration['test_driver_error_port']; |
1294 return HttpServer.bind(localIp, test_driver_error_port) | 1308 return HttpServer |
1295 .then(setupErrorServer) | 1309 .bind(localIp, test_driver_error_port) |
1296 .then(setupDispatchingServer); | 1310 .then(setupErrorServer) |
| 1311 .then(setupDispatchingServer); |
1297 } | 1312 } |
1298 | 1313 |
1299 void setupErrorServer(HttpServer server) { | 1314 void setupErrorServer(HttpServer server) { |
1300 errorReportingServer = server; | 1315 errorReportingServer = server; |
1301 void errorReportingHandler(HttpRequest request) { | 1316 void errorReportingHandler(HttpRequest request) { |
1302 StringBuffer buffer = new StringBuffer(); | 1317 StringBuffer buffer = new StringBuffer(); |
1303 request.transform(UTF8.decoder).listen((data) { | 1318 request.transform(UTF8.decoder).listen((data) { |
1304 buffer.write(data); | 1319 buffer.write(data); |
1305 }, onDone: () { | 1320 }, onDone: () { |
1306 String back = buffer.toString(); | 1321 String back = buffer.toString(); |
1307 request.response.headers.set("Access-Control-Allow-Origin", "*"); | 1322 request.response.headers.set("Access-Control-Allow-Origin", "*"); |
1308 request.response.done.catchError((error) { | 1323 request.response.done.catchError((error) { |
1309 DebugLogger.error("Error getting error from browser" | 1324 DebugLogger.error("Error getting error from browser" |
1310 "on uri ${request.uri.path}: $error"); | 1325 "on uri ${request.uri.path}: $error"); |
1311 }); | 1326 }); |
1312 request.response.close(); | 1327 request.response.close(); |
1313 DebugLogger.error("Error from browser on : " | 1328 DebugLogger.error("Error from browser on : " |
1314 "${request.uri.path}, data: $back"); | 1329 "${request.uri.path}, data: $back"); |
1315 }, onError: (error) { print(error); }); | 1330 }, onError: (error) { |
| 1331 print(error); |
| 1332 }); |
1316 } | 1333 } |
1317 void errorHandler(e) { | 1334 void errorHandler(e) { |
1318 if (!underTermination) print("Error occured in httpserver: $e"); | 1335 if (!underTermination) print("Error occured in httpserver: $e"); |
1319 } | 1336 } |
1320 errorReportingServer.listen(errorReportingHandler, onError: errorHandler); | 1337 errorReportingServer.listen(errorReportingHandler, onError: errorHandler); |
1321 } | 1338 } |
1322 | 1339 |
1323 void setupDispatchingServer(_) { | 1340 void setupDispatchingServer(_) { |
1324 DispatchingServer server = configuration['_servers_'].server; | 1341 DispatchingServer server = configuration['_servers_'].server; |
1325 void noCache(request) { | 1342 void noCache(request) { |
1326 request.response.headers.set("Cache-Control", | 1343 request.response.headers |
1327 "no-cache, no-store, must-revalidate"); | 1344 .set("Cache-Control", "no-cache, no-store, must-revalidate"); |
1328 } | 1345 } |
1329 int testId(request) => | 1346 int testId(request) => int.parse(request.uri.queryParameters["id"]); |
1330 int.parse(request.uri.queryParameters["id"]); | |
1331 String browserId(request, prefix) => | 1347 String browserId(request, prefix) => |
1332 request.uri.path.substring(prefix.length + 1); | 1348 request.uri.path.substring(prefix.length + 1); |
1333 | 1349 |
1334 | |
1335 server.addHandler(reportPath, (HttpRequest request) { | 1350 server.addHandler(reportPath, (HttpRequest request) { |
1336 noCache(request); | 1351 noCache(request); |
1337 handleReport(request, browserId(request, reportPath), | 1352 handleReport(request, browserId(request, reportPath), testId(request), |
1338 testId(request), isStatusUpdate: false); | 1353 isStatusUpdate: false); |
1339 }); | 1354 }); |
1340 server.addHandler(statusUpdatePath, (HttpRequest request) { | 1355 server.addHandler(statusUpdatePath, (HttpRequest request) { |
1341 noCache(request); | 1356 noCache(request); |
1342 handleReport(request, browserId(request, statusUpdatePath), | 1357 handleReport( |
1343 testId(request), isStatusUpdate: true); | 1358 request, browserId(request, statusUpdatePath), testId(request), |
| 1359 isStatusUpdate: true); |
1344 }); | 1360 }); |
1345 server.addHandler(startedPath, (HttpRequest request) { | 1361 server.addHandler(startedPath, (HttpRequest request) { |
1346 noCache(request); | 1362 noCache(request); |
1347 handleStarted(request, browserId(request, startedPath), | 1363 handleStarted(request, browserId(request, startedPath), testId(request)); |
1348 testId(request)); | |
1349 }); | 1364 }); |
1350 | 1365 |
1351 makeSendPageHandler(String prefix) => (HttpRequest request) { | 1366 makeSendPageHandler(String prefix) => (HttpRequest request) { |
1352 noCache(request); | 1367 noCache(request); |
1353 var textResponse = ""; | 1368 var textResponse = ""; |
1354 if (prefix == driverPath) { | 1369 if (prefix == driverPath) { |
1355 textResponse = getDriverPage(browserId(request, prefix)); | 1370 textResponse = getDriverPage(browserId(request, prefix)); |
1356 request.response.headers.set('Content-Type', 'text/html'); | 1371 request.response.headers.set('Content-Type', 'text/html'); |
1357 } | 1372 } |
1358 if (prefix == nextTestPath) { | 1373 if (prefix == nextTestPath) { |
1359 textResponse = getNextTest(browserId(request, prefix)); | 1374 textResponse = getNextTest(browserId(request, prefix)); |
1360 request.response.headers.set('Content-Type', 'text/plain'); | 1375 request.response.headers.set('Content-Type', 'text/plain'); |
1361 } | 1376 } |
1362 request.response.write(textResponse); | 1377 request.response.write(textResponse); |
1363 request.listen((_) {}, onDone: request.response.close); | 1378 request.listen((_) {}, onDone: request.response.close); |
1364 request.response.done.catchError((error) { | 1379 request.response.done.catchError((error) { |
1365 if (!underTermination) { | 1380 if (!underTermination) { |
1366 print("URI ${request.uri}"); | 1381 print("URI ${request.uri}"); |
1367 print("Textresponse $textResponse"); | 1382 print("Textresponse $textResponse"); |
1368 throw "Error returning content to browser: $error"; | 1383 throw "Error returning content to browser: $error"; |
1369 } | 1384 } |
1370 }); | 1385 }); |
1371 }; | 1386 }; |
1372 server.addHandler(driverPath, makeSendPageHandler(driverPath)); | 1387 server.addHandler(driverPath, makeSendPageHandler(driverPath)); |
1373 server.addHandler(nextTestPath, makeSendPageHandler(nextTestPath)); | 1388 server.addHandler(nextTestPath, makeSendPageHandler(nextTestPath)); |
1374 } | 1389 } |
1375 | 1390 |
1376 void handleReport(HttpRequest request, String browserId, var testId, | 1391 void handleReport(HttpRequest request, String browserId, var testId, |
1377 {bool isStatusUpdate}) { | 1392 {bool isStatusUpdate}) { |
1378 StringBuffer buffer = new StringBuffer(); | 1393 StringBuffer buffer = new StringBuffer(); |
1379 request.transform(UTF8.decoder).listen((data) { | 1394 request.transform(UTF8.decoder).listen((data) { |
1380 buffer.write(data); | 1395 buffer.write(data); |
1381 }, onDone: () { | 1396 }, onDone: () { |
1382 String back = buffer.toString(); | 1397 String back = buffer.toString(); |
1383 request.response.close(); | 1398 request.response.close(); |
1384 if (isStatusUpdate) { | 1399 if (isStatusUpdate) { |
1385 testStatusUpdateCallBack(browserId, back, testId); | 1400 testStatusUpdateCallBack(browserId, back, testId); |
1386 } else { | 1401 } else { |
1387 testDoneCallBack(browserId, back, testId); | 1402 testDoneCallBack(browserId, back, testId); |
1388 } | 1403 } |
1389 // TODO(ricow): We should do something smart if we get an error here. | 1404 // TODO(ricow): We should do something smart if we get an error here. |
1390 }, onError: (error) { DebugLogger.error("$error"); }); | 1405 }, onError: (error) { |
| 1406 DebugLogger.error("$error"); |
| 1407 }); |
1391 } | 1408 } |
1392 | 1409 |
1393 void handleStarted(HttpRequest request, String browserId, var testId) { | 1410 void handleStarted(HttpRequest request, String browserId, var testId) { |
1394 StringBuffer buffer = new StringBuffer(); | 1411 StringBuffer buffer = new StringBuffer(); |
1395 // If an error occurs while receiving the data from the request stream, | 1412 // If an error occurs while receiving the data from the request stream, |
1396 // we don't handle it specially. We can safely ignore it, since the started | 1413 // we don't handle it specially. We can safely ignore it, since the started |
1397 // events are not crucial. | 1414 // events are not crucial. |
1398 request.transform(UTF8.decoder).listen((data) { | 1415 request.transform(UTF8.decoder).listen((data) { |
1399 buffer.write(data); | 1416 buffer.write(data); |
1400 }, onDone: () { | 1417 }, onDone: () { |
1401 String back = buffer.toString(); | 1418 String back = buffer.toString(); |
1402 request.response.close(); | 1419 request.response.close(); |
1403 testStartedCallBack(browserId, back, testId); | 1420 testStartedCallBack(browserId, back, testId); |
1404 }, onError: (error) { DebugLogger.error("$error"); }); | 1421 }, onError: (error) { |
| 1422 DebugLogger.error("$error"); |
| 1423 }); |
1405 } | 1424 } |
1406 | 1425 |
1407 String getNextTest(String browserId) { | 1426 String getNextTest(String browserId) { |
1408 var nextTest = nextTestCallBack(browserId); | 1427 var nextTest = nextTestCallBack(browserId); |
1409 if (underTermination) { | 1428 if (underTermination) { |
1410 // Browsers will be killed shortly, send them a terminate signal so | 1429 // Browsers will be killed shortly, send them a terminate signal so |
1411 // that they stop pulling. | 1430 // that they stop pulling. |
1412 return terminateSignal; | 1431 return terminateSignal; |
1413 } | 1432 } |
1414 return nextTest == null ? waitSignal : nextTest.toJSON(); | 1433 return nextTest == null ? waitSignal : nextTest.toJSON(); |
1415 } | 1434 } |
1416 | 1435 |
1417 String getDriverUrl(String browserId) { | 1436 String getDriverUrl(String browserId) { |
1418 if (errorReportingServer == null) { | 1437 if (errorReportingServer == null) { |
1419 print("Bad browser testing server, you are not started yet. Can't " | 1438 print("Bad browser testing server, you are not started yet. Can't " |
1420 "produce driver url"); | 1439 "produce driver url"); |
1421 exit(1); | 1440 exit(1); |
1422 // This should never happen - exit immediately; | 1441 // This should never happen - exit immediately; |
1423 } | 1442 } |
1424 var port = configuration['_servers_'].port; | 1443 var port = configuration['_servers_'].port; |
1425 return "http://$localIp:$port/driver/$browserId"; | 1444 return "http://$localIp:$port/driver/$browserId"; |
1426 } | 1445 } |
1427 | 1446 |
1428 | |
1429 String getDriverPage(String browserId) { | 1447 String getDriverPage(String browserId) { |
1430 var errorReportingUrl = | 1448 var errorReportingUrl = |
1431 "http://$localIp:${errorReportingServer.port}/$browserId"; | 1449 "http://$localIp:${errorReportingServer.port}/$browserId"; |
1432 String driverContent = """ | 1450 String driverContent = """ |
1433 <!DOCTYPE html><html> | 1451 <!DOCTYPE html><html> |
1434 <head> | 1452 <head> |
1435 <style> | 1453 <style> |
1436 body { | 1454 body { |
1437 margin: 0; | 1455 margin: 0; |
1438 } | 1456 } |
(...skipping 322 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1761 </div> | 1779 </div> |
1762 <div id="embedded_iframe_div" class="test box"> | 1780 <div id="embedded_iframe_div" class="test box"> |
1763 <iframe style="width:100%;height:100%;" id="embedded_iframe"></iframe> | 1781 <iframe style="width:100%;height:100%;" id="embedded_iframe"></iframe> |
1764 </div> | 1782 </div> |
1765 </body> | 1783 </body> |
1766 </html> | 1784 </html> |
1767 """; | 1785 """; |
1768 return driverContent; | 1786 return driverContent; |
1769 } | 1787 } |
1770 } | 1788 } |
OLD | NEW |