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

Side by Side Diff: tools/testing/dart/browser_controller.dart

Issue 1871883002: Make Safari tests more robust. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Address comments. Created 4 years, 6 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
« no previous file with comments | « tools/safari_factory_reset.py ('k') | tools/testing/dart/reset_safari.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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;
11 11
12 import 'android.dart'; 12 import 'android.dart';
13 import 'http_server.dart'; 13 import 'http_server.dart';
14 import 'path.dart'; 14 import 'path.dart';
15 import 'utils.dart'; 15 import 'utils.dart';
16 16
17 import 'reset_safari.dart' show
18 killAndResetSafari;
19
17 class BrowserOutput { 20 class BrowserOutput {
18 final StringBuffer stdout = new StringBuffer(); 21 final StringBuffer stdout = new StringBuffer();
19 final StringBuffer stderr = new StringBuffer(); 22 final StringBuffer stderr = new StringBuffer();
20 final StringBuffer eventLog = new StringBuffer(); 23 final StringBuffer eventLog = new StringBuffer();
21 } 24 }
22 25
23 /** Class describing the interface for communicating with browsers. */ 26 /** Class describing the interface for communicating with browsers. */
24 abstract class Browser { 27 abstract class Browser {
25 BrowserOutput _allBrowserOutput = new BrowserOutput(); 28 BrowserOutput _allBrowserOutput = new BrowserOutput();
26 BrowserOutput _testBrowserOutput = new BrowserOutput(); 29 BrowserOutput _testBrowserOutput = new BrowserOutput();
(...skipping 19 matching lines...) Expand all
46 Process process; 49 Process process;
47 50
48 Function logger; 51 Function logger;
49 52
50 /** 53 /**
51 * Id of the browser 54 * Id of the browser
52 */ 55 */
53 String id; 56 String id;
54 57
55 /** 58 /**
56 * Delete the browser specific caches on startup. 59 * Reset the browser to a known configuration on start-up.
57 * Browser specific implementations are free to ignore this. 60 * Browser specific implementations are free to ignore this.
58 */ 61 */
59 static bool deleteCache = false; 62 static bool resetBrowserConfiguration = false;
60 63
61 /** Print everything (stdout, stderr, usageLog) whenever we add to it */ 64 /** Print everything (stdout, stderr, usageLog) whenever we add to it */
62 bool debugPrint = false; 65 bool debugPrint = false;
63 66
64 // This future returns when the process exits. It is also the return value 67 // This future returns when the process exits. It is also the return value
65 // of close() 68 // of close()
66 Future done; 69 Future done;
67 70
68 Browser(); 71 Browser();
69 72
(...skipping 28 matching lines...) Expand all
98 'ie10', 101 'ie10',
99 'ie11', 102 'ie11',
100 'dartium' 103 'dartium'
101 ]; 104 ];
102 105
103 static const List<String> BROWSERS_WITH_WINDOW_SUPPORT = const [ 106 static const List<String> BROWSERS_WITH_WINDOW_SUPPORT = const [
104 'ie11', 107 'ie11',
105 'ie10' 108 'ie10'
106 ]; 109 ];
107 110
111 /// If [browserName] doesn't support Window.open, we use iframes instead.
112 static bool requiresIframe(String browserName) {
113 return !BROWSERS_WITH_WINDOW_SUPPORT.contains(browserName);
114 }
115
116 static bool requiresFocus(String browserName) {
117 return browserName == "safari";
118 }
119
108 // TODO(kustermann): add standard support for chrome on android 120 // TODO(kustermann): add standard support for chrome on android
109 static bool supportedBrowser(String name) { 121 static bool supportedBrowser(String name) {
110 return SUPPORTED_BROWSERS.contains(name); 122 return SUPPORTED_BROWSERS.contains(name);
111 } 123 }
112 124
113 void _logEvent(String event) { 125 void _logEvent(String event) {
114 String toLog = "$this ($id) - $event \n"; 126 String toLog = "$this ($id) - $event \n";
115 if (debugPrint) print("usageLog: $toLog"); 127 if (debugPrint) print("usageLog: $toLog");
116 if (logger != null) logger(toLog); 128 if (logger != null) logger(toLog);
117 129
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after
262 * Add useful info about the browser to the _testBrowserOutput.stdout, 274 * Add useful info about the browser to the _testBrowserOutput.stdout,
263 * where it will be reported for failing tests. Used to report which 275 * where it will be reported for failing tests. Used to report which
264 * android device a failing test is running on. 276 * android device a failing test is running on.
265 */ 277 */
266 void logBrowserInfoToTestBrowserOutput() {} 278 void logBrowserInfoToTestBrowserOutput() {}
267 279
268 String toString(); 280 String toString();
269 281
270 /** Starts the browser loading the given url */ 282 /** Starts the browser loading the given url */
271 Future<bool> start(String url); 283 Future<bool> start(String url);
284
285 /// Called when the driver page is requested, that is, when the browser first
286 /// contacts the test server. At this time, it's safe to assume that the
287 /// browser process has started and opened its first window.
288 ///
289 /// This is used by [Safari] to ensure the browser window has focus.
290 Future<Null> onDriverPageRequested() => new Future<Null>.value();
272 } 291 }
273 292
274 class Safari extends Browser { 293 class Safari extends Browser {
275 /** 294 /**
276 * We get the safari version by parsing a version file 295 * We get the safari version by parsing a version file
277 */ 296 */
278 static const String versionFile = 297 static const String versionFile =
279 "/Applications/Safari.app/Contents/version.plist"; 298 "/Applications/Safari.app/Contents/version.plist";
280 299
281 /** 300 static const String safariBundleLocation = "/Applications/Safari.app/";
282 * Directories where safari stores state. We delete these if the deleteCache
283 * is set
284 */
285 static const List<String> CACHE_DIRECTORIES = const [
286 "Library/Caches/com.apple.Safari",
287 "Library/Safari",
288 "Library/Saved Application State/com.apple.Safari.savedState",
289 "Library/Caches/Metadata/Safari"
290 ];
291 301
292 Future<bool> allowPopUps() { 302 // Clears the cache if the static resetBrowserConfiguration flag is set.
293 var command = "defaults"; 303 // Returns false if the command to actually clear the cache did not complete.
294 var args = [ 304 Future<bool> resetConfiguration() async {
295 "write", 305 if (!Browser.resetBrowserConfiguration) return true;
296 "com.apple.safari", 306
297 "com.apple.Safari.ContentPageGroupIdentifier." 307 Completer completer = new Completer();
298 "WebKit2JavaScriptCanOpenWindowsAutomatically", 308 handleUncaughtError(error, StackTrace stackTrace) {
299 "1" 309 if (!completer.isCompleted) {
300 ]; 310 completer.completeError(error, stackTrace);
301 return Process.run(command, args).then((result) { 311 } else {
302 if (result.exitCode != 0) { 312 throw new AsyncError(error, stackTrace);
303 _logEvent("Could not disable pop-up blocking for safari");
304 return false;
305 } 313 }
314 }
315 Zone parent = Zone.current;
316 ZoneSpecification specification = new ZoneSpecification(
317 print: (Zone self, ZoneDelegate delegate, Zone zone, String line) {
318 delegate.run(parent, () {
319 _logEvent(line);
320 });
321 });
322 Future zoneWrapper() {
323 Uri safariUri = Uri.base.resolve(safariBundleLocation);
324 return new Future(() => killAndResetSafari(bundle: safariUri))
325 .then(completer.complete);
326 }
327
328 // We run killAndResetSafari in a Zone as opposed to running an external
329 // process. The Zone allows us to collect its output, and protect the rest
330 // of the test infrastructure against errors in it.
331 runZoned(
332 zoneWrapper, zoneSpecification: specification,
333 onError: handleUncaughtError);
334
335 try {
336 await completer.future;
306 return true; 337 return true;
307 }); 338 } catch (error, st) {
308 } 339 _logEvent("Unable to reset Safari: $error$st");
309 340 return false;
310 Future<bool> deleteIfExists(Iterator<String> paths) { 341 }
311 if (!paths.moveNext()) return new Future.value(true);
312 Directory directory = new Directory(paths.current);
313 return directory.exists().then((exists) {
314 if (exists) {
315 _logEvent("Deleting ${paths.current}");
316 return directory
317 .delete(recursive: true)
318 .then((_) => deleteIfExists(paths))
319 .catchError((error) {
320 _logEvent("Failure trying to delete ${paths.current}: $error");
321 return false;
322 });
323 } else {
324 _logEvent("${paths.current} is not present");
325 return deleteIfExists(paths);
326 }
327 });
328 }
329
330 // Clears the cache if the static deleteCache flag is set.
331 // Returns false if the command to actually clear the cache did not complete.
332 Future<bool> clearCache() {
333 if (!Browser.deleteCache) return new Future.value(true);
334 var home = Platform.environment['HOME'];
335 Iterator iterator = CACHE_DIRECTORIES.map((s) => "$home/$s").iterator;
336 return deleteIfExists(iterator);
337 } 342 }
338 343
339 Future<String> getVersion() { 344 Future<String> getVersion() {
340 /** 345 /**
341 * Example of the file: 346 * Example of the file:
342 * <?xml version="1.0" encoding="UTF-8"?> 347 * <?xml version="1.0" encoding="UTF-8"?>
343 * <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.co m/DTDs/PropertyList-1.0.dtd"> 348 * <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.co m/DTDs/PropertyList-1.0.dtd">
344 * <plist version="1.0"> 349 * <plist version="1.0">
345 * <dict> 350 * <dict>
346 * <key>BuildVersion</key> 351 * <key>BuildVersion</key>
(...skipping 15 matching lines...) Expand all
362 for (var line in content) { 367 for (var line in content) {
363 if (versionOnNextLine) return line; 368 if (versionOnNextLine) return line;
364 if (line.contains("CFBundleShortVersionString")) { 369 if (line.contains("CFBundleShortVersionString")) {
365 versionOnNextLine = true; 370 versionOnNextLine = true;
366 } 371 }
367 } 372 }
368 return null; 373 return null;
369 }); 374 });
370 } 375 }
371 376
372 void _createLaunchHTML(var path, var url) { 377 Future<Null> _createLaunchHTML(var path, var url) async {
373 var file = new File("${path}/launch.html"); 378 var file = new File("${path}/launch.html");
374 var randomFile = file.openSync(mode: FileMode.WRITE); 379 var randomFile = await file.open(mode: FileMode.WRITE);
375 var content = '<script language="JavaScript">location = "$url"</script>'; 380 var content = '<script language="JavaScript">location = "$url"</script>';
376 randomFile.writeStringSync(content); 381 await randomFile.writeString(content);
377 randomFile.close(); 382 await randomFile.close();
378 } 383 }
379 384
380 Future<bool> start(String url) { 385 Future<bool> start(String url) async {
381 _logEvent("Starting Safari browser on: $url"); 386 _logEvent("Starting Safari browser on: $url");
382 return allowPopUps().then((success) { 387 if (!await resetConfiguration()) {
383 if (!success) { 388 _logEvent("Could not clear cache");
384 return false; 389 return false;
385 } 390 }
386 return clearCache().then((cleared) { 391 String version;
387 if (!cleared) { 392 try {
388 _logEvent("Could not clear cache"); 393 version = await getVersion();
389 return false; 394 } catch (error) {
390 } 395 _logEvent("Running $_binary --version failed with $error");
391 // Get the version and log that. 396 return false;
392 return getVersion().then((version) { 397 }
393 _logEvent("Got version: $version"); 398 _logEvent("Got version: $version");
394 return Directory.systemTemp.createTemp().then((userDir) { 399 Directory userDir;
395 _cleanup = () { 400 try {
396 userDir.deleteSync(recursive: true); 401 userDir = await Directory.systemTemp.createTemp();
397 }; 402 } catch (error) {
398 _createLaunchHTML(userDir.path, url); 403 _logEvent("Error creating temporary directory: $error");
399 var args = ["${userDir.path}/launch.html"]; 404 return false;
400 return startBrowserProcess(_binary, args); 405 }
401 }); 406 _cleanup = () {
402 }).catchError((error) { 407 userDir.deleteSync(recursive: true);
403 _logEvent("Running $_binary --version failed with $error"); 408 };
404 return false; 409 try {
405 }); 410 await _createLaunchHTML(userDir.path, url);
406 }); 411 } catch (error) {
407 }); 412 _logEvent("Error creating launch HTML: $error");
413 return false;
414 }
415 var args = [
416 "-d", "-i", "-m", "-s", "-u", _binary,
417 "${userDir.path}/launch.html"];
418 try {
419 return startBrowserProcess("/usr/bin/caffeinate", args);
420 } catch (error) {
421 _logEvent("Error starting browser process: $error");
422 return false;
423 }
424 }
425
426 Future<Null> onDriverPageRequested() async {
427 await Process.run("/usr/bin/osascript",
428 ['-e', 'tell application "Safari" to activate']);
408 } 429 }
409 430
410 String toString() => "Safari"; 431 String toString() => "Safari";
411 } 432 }
412 433
413 class Chrome extends Browser { 434 class Chrome extends Browser {
414 String _version = "Version not found yet"; 435 String _version = "Version not found yet";
415 436
416 Map<String, String> _getEnvironment() => null; 437 Map<String, String> _getEnvironment() => null;
417 438
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
470 return false; 491 return false;
471 }); 492 });
472 } 493 }
473 494
474 String toString() => "Chrome"; 495 String toString() => "Chrome";
475 } 496 }
476 497
477 class SafariMobileSimulator extends Safari { 498 class SafariMobileSimulator extends Safari {
478 /** 499 /**
479 * Directories where safari simulator stores state. We delete these if the 500 * Directories where safari simulator stores state. We delete these if the
480 * deleteCache is set 501 * resetBrowserConfiguration is set
481 */ 502 */
482 static const List<String> CACHE_DIRECTORIES = const [ 503 static const List<String> CACHE_DIRECTORIES = const [
483 "Library/Application Support/iPhone Simulator/7.1/Applications" 504 "Library/Application Support/iPhone Simulator/7.1/Applications"
484 ]; 505 ];
485 506
486 // Clears the cache if the static deleteCache flag is set. 507 // Clears the cache if the static resetBrowserConfiguration flag is set.
487 // Returns false if the command to actually clear the cache did not complete. 508 // Returns false if the command to actually clear the cache did not complete.
488 Future<bool> clearCache() { 509 Future<bool> resetConfiguration() {
489 if (!Browser.deleteCache) return new Future.value(true); 510 if (!Browser.resetBrowserConfiguration) return new Future.value(true);
490 var home = Platform.environment['HOME']; 511 var home = Platform.environment['HOME'];
491 Iterator iterator = CACHE_DIRECTORIES.map((s) => "$home/$s").iterator; 512 Iterator iterator = CACHE_DIRECTORIES.map((s) => "$home/$s").iterator;
492 return deleteIfExists(iterator); 513 return deleteIfExists(iterator);
493 } 514 }
494 515
495 Future<bool> start(String url) { 516 Future<bool> start(String url) {
496 _logEvent("Starting safari mobile simulator browser on: $url"); 517 _logEvent("Starting safari mobile simulator browser on: $url");
497 return clearCache().then((success) { 518 return resetConfiguration().then((success) {
498 if (!success) { 519 if (!success) {
499 _logEvent("Could not clear cache, exiting"); 520 _logEvent("Could not clear cache, exiting");
500 return false; 521 return false;
501 } 522 }
502 var args = [ 523 var args = [
503 "-SimulateApplication", 524 "-SimulateApplication",
504 "/Applications/Xcode.app/Contents/Developer/Platforms/" 525 "/Applications/Xcode.app/Contents/Developer/Platforms/"
505 "iPhoneSimulator.platform/Developer/SDKs/" 526 "iPhoneSimulator.platform/Developer/SDKs/"
506 "iPhoneSimulator7.1.sdk/Applications/MobileSafari.app/" 527 "iPhoneSimulator7.1.sdk/Applications/MobileSafari.app/"
507 "MobileSafari", 528 "MobileSafari",
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
554 var findString = "REG_SZ"; 575 var findString = "REG_SZ";
555 var index = result.stdout.indexOf(findString); 576 var index = result.stdout.indexOf(findString);
556 if (index > 0) { 577 if (index > 0) {
557 return result.stdout.substring(index + findString.length).trim(); 578 return result.stdout.substring(index + findString.length).trim();
558 } 579 }
559 } 580 }
560 return "Could not get the version of internet explorer"; 581 return "Could not get the version of internet explorer";
561 }); 582 });
562 } 583 }
563 584
564 // Clears the recovery cache if the static deleteCache flag is set. 585 // Clears the recovery cache if the static resetBrowserConfiguration flag is
565 Future<bool> clearCache() { 586 // set.
566 if (!Browser.deleteCache) return new Future.value(true); 587 Future<bool> resetConfiguration() {
588 if (!Browser.resetBrowserConfiguration) return new Future.value(true);
567 var localAppData = Platform.environment['LOCALAPPDATA']; 589 var localAppData = Platform.environment['LOCALAPPDATA'];
568 590
569 Directory dir = new Directory("$localAppData\\Microsoft\\" 591 Directory dir = new Directory("$localAppData\\Microsoft\\"
570 "Internet Explorer\\Recovery"); 592 "Internet Explorer\\Recovery");
571 return dir.delete(recursive: true).then((_) { 593 return dir.delete(recursive: true).then((_) {
572 return true; 594 return true;
573 }).catchError((error) { 595 }).catchError((error) {
574 _logEvent("Deleting recovery dir failed with $error"); 596 _logEvent("Deleting recovery dir failed with $error");
575 return false; 597 return false;
576 }); 598 });
577 } 599 }
578 600
579 Future<bool> start(String url) { 601 Future<bool> start(String url) {
580 _logEvent("Starting ie browser on: $url"); 602 _logEvent("Starting ie browser on: $url");
581 return clearCache().then((_) => getVersion()).then((version) { 603 return resetConfiguration().then((_) => getVersion()).then((version) {
582 _logEvent("Got version: $version"); 604 _logEvent("Got version: $version");
583 return startBrowserProcess(_binary, [url]); 605 return startBrowserProcess(_binary, [url]);
584 }); 606 });
585 } 607 }
586 608
587 String toString() => "IE"; 609 String toString() => "IE";
588 } 610 }
589 611
590 class AndroidBrowserConfig { 612 class AndroidBrowserConfig {
591 final String name; 613 final String name;
(...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after
869 /// requests back from the browsers. 891 /// requests back from the browsers.
870 class BrowserTestRunner { 892 class BrowserTestRunner {
871 static const int MAX_NEXT_TEST_TIMEOUTS = 10; 893 static const int MAX_NEXT_TEST_TIMEOUTS = 10;
872 static const Duration NEXT_TEST_TIMEOUT = const Duration(seconds: 60); 894 static const Duration NEXT_TEST_TIMEOUT = const Duration(seconds: 60);
873 static const Duration RESTART_BROWSER_INTERVAL = const Duration(seconds: 60); 895 static const Duration RESTART_BROWSER_INTERVAL = const Duration(seconds: 60);
874 896
875 /// If the queue was recently empty, don't start another browser. 897 /// If the queue was recently empty, don't start another browser.
876 static const Duration MIN_NONEMPTY_QUEUE_TIME = const Duration(seconds: 1); 898 static const Duration MIN_NONEMPTY_QUEUE_TIME = const Duration(seconds: 1);
877 899
878 final Map configuration; 900 final Map configuration;
879 BrowserTestingServer testingServer; 901 final BrowserTestingServer testingServer;
880 902
881 final String localIp; 903 final String localIp;
882 String browserName; 904 final String browserName;
883 int maxNumBrowsers; 905 final int maxNumBrowsers;
884 bool checkedMode; 906 final bool checkedMode;
885 int numBrowsers = 0; 907 int numBrowsers = 0;
886 // Used to send back logs from the browser (start, stop etc) 908 // Used to send back logs from the browser (start, stop etc)
887 Function logger; 909 Function logger;
888 910
889 int browserIdCounter = 1; 911 int browserIdCounter = 1;
890 912
891 bool testingServerStarted = false; 913 bool testingServerStarted = false;
892 bool underTermination = false; 914 bool underTermination = false;
893 int numBrowserGetTestTimeouts = 0; 915 int numBrowserGetTestTimeouts = 0;
894 DateTime lastEmptyTestQueueTime = new DateTime.now(); 916 DateTime lastEmptyTestQueueTime = new DateTime.now();
(...skipping 26 matching lines...) Expand all
921 // When no browser is currently starting, _currentStartingBrowserId is null. 943 // When no browser is currently starting, _currentStartingBrowserId is null.
922 bool get aBrowserIsCurrentlyStarting => _currentStartingBrowserId != null; 944 bool get aBrowserIsCurrentlyStarting => _currentStartingBrowserId != null;
923 void markCurrentlyStarting(String id) { 945 void markCurrentlyStarting(String id) {
924 _currentStartingBrowserId = id; 946 _currentStartingBrowserId = id;
925 } 947 }
926 948
927 void markNotCurrentlyStarting(String id) { 949 void markNotCurrentlyStarting(String id) {
928 if (_currentStartingBrowserId == id) _currentStartingBrowserId = null; 950 if (_currentStartingBrowserId == id) _currentStartingBrowserId = null;
929 } 951 }
930 952
931 // If [browserName] doesn't support opening new windows, we use new iframes
932 // instead.
933 bool get useIframe =>
934 !Browser.BROWSERS_WITH_WINDOW_SUPPORT.contains(browserName);
935
936 /// The optional testingServer parameter allows callers to pass in
937 /// a testing server with different behavior than the default
938 /// BrowserTestServer. The url handlers of the testingServer are
939 /// overwritten, so an existing handler can't be shared between instances.
940 BrowserTestRunner( 953 BrowserTestRunner(
941 this.configuration, this.localIp, this.browserName, this.maxNumBrowsers, 954 Map configuration,
942 {BrowserTestingServer this.testingServer}) { 955 String localIp,
943 checkedMode = configuration['checked']; 956 String browserName,
944 if (browserName == 'ff') browserName = 'firefox'; 957 this.maxNumBrowsers)
958 : configuration = configuration,
959 localIp = localIp,
960 browserName = (browserName == 'ff') ? 'firefox' : browserName,
961 checkedMode = configuration['checked'],
962 testingServer = new BrowserTestingServer(
963 configuration, localIp,
964 Browser.requiresIframe(browserName),
965 Browser.requiresFocus(browserName)) {
966 testingServer.testRunner = this;
945 } 967 }
946 968
947 Future start() async { 969 Future start() async {
948 if (testingServer == null) {
949 testingServer =
950 new BrowserTestingServer(configuration, localIp, useIframe);
951 }
952 await testingServer.start(); 970 await testingServer.start();
953 testingServer 971 testingServer
954 ..testDoneCallBack = handleResults 972 ..testDoneCallBack = handleResults
955 ..testStatusUpdateCallBack = handleStatusUpdate 973 ..testStatusUpdateCallBack = handleStatusUpdate
956 ..testStartedCallBack = handleStarted 974 ..testStartedCallBack = handleStarted
957 ..nextTestCallBack = getNextTest; 975 ..nextTestCallBack = getNextTest;
958 if (browserName == 'chromeOnAndroid') { 976 if (browserName == 'chromeOnAndroid') {
959 var idbNames = await AdbHelper.listDevices(); 977 var idbNames = await AdbHelper.listDevices();
960 idleAdbDevices = new List.from(idbNames.map((id) => new AdbDevice(id))); 978 idleAdbDevices = new List.from(idbNames.map((id) => new AdbDevice(id)));
961 maxNumBrowsers = min(maxNumBrowsers, idleAdbDevices.length); 979 maxNumBrowsers = min(maxNumBrowsers, idleAdbDevices.length);
(...skipping 316 matching lines...) Expand 10 before | Expand all | Expand 10 after
1278 /// and run tests ... 1296 /// and run tests ...
1279 /// GET /next_test/BROWSER_ID -- returns "WAIT" "TERMINATE" or "url#id" 1297 /// GET /next_test/BROWSER_ID -- returns "WAIT" "TERMINATE" or "url#id"
1280 /// where url is the test to run, and id is the id of the test. 1298 /// where url is the test to run, and id is the id of the test.
1281 /// If there are currently no available tests the waitSignal is send 1299 /// If there are currently no available tests the waitSignal is send
1282 /// back. If we are in the process of terminating the terminateSignal 1300 /// back. If we are in the process of terminating the terminateSignal
1283 /// is send back and the browser will stop requesting new tasks. 1301 /// is send back and the browser will stop requesting new tasks.
1284 /// POST /report/BROWSER_ID?id=NUM -- sends back the dom of the executed 1302 /// POST /report/BROWSER_ID?id=NUM -- sends back the dom of the executed
1285 /// test 1303 /// test
1286 1304
1287 final String localIp; 1305 final String localIp;
1306 final bool useIframe;
1307 final bool requiresFocus;
1308 BrowserTestRunner testRunner;
1288 1309
1289 static const String driverPath = "/driver"; 1310 static const String driverPath = "/driver";
1290 static const String nextTestPath = "/next_test"; 1311 static const String nextTestPath = "/next_test";
1291 static const String reportPath = "/report"; 1312 static const String reportPath = "/report";
1292 static const String statusUpdatePath = "/status_update"; 1313 static const String statusUpdatePath = "/status_update";
1293 static const String startedPath = "/started"; 1314 static const String startedPath = "/started";
1294 static const String waitSignal = "WAIT"; 1315 static const String waitSignal = "WAIT";
1295 static const String terminateSignal = "TERMINATE"; 1316 static const String terminateSignal = "TERMINATE";
1296 1317
1297 var testCount = 0; 1318 var testCount = 0;
1298 var errorReportingServer; 1319 var errorReportingServer;
1299 bool underTermination = false; 1320 bool underTermination = false;
1300 bool useIframe = false;
1301 1321
1302 Function testDoneCallBack; 1322 Function testDoneCallBack;
1303 Function testStatusUpdateCallBack; 1323 Function testStatusUpdateCallBack;
1304 Function testStartedCallBack; 1324 Function testStartedCallBack;
1305 Function nextTestCallBack; 1325 Function nextTestCallBack;
1306 1326
1307 BrowserTestingServer(this.configuration, this.localIp, this.useIframe); 1327 BrowserTestingServer(
1328 this.configuration, this.localIp, this.useIframe, this.requiresFocus);
1308 1329
1309 Future start() { 1330 Future start() {
1310 var test_driver_error_port = configuration['test_driver_error_port']; 1331 var test_driver_error_port = configuration['test_driver_error_port'];
1311 return HttpServer 1332 return HttpServer
1312 .bind(localIp, test_driver_error_port) 1333 .bind(localIp, test_driver_error_port)
1313 .then(setupErrorServer) 1334 .then(setupErrorServer)
1314 .then(setupDispatchingServer); 1335 .then(setupDispatchingServer);
1315 } 1336 }
1316 1337
1317 void setupErrorServer(HttpServer server) { 1338 void setupErrorServer(HttpServer server) {
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
1359 noCache(request); 1380 noCache(request);
1360 handleReport( 1381 handleReport(
1361 request, browserId(request, statusUpdatePath), testId(request), 1382 request, browserId(request, statusUpdatePath), testId(request),
1362 isStatusUpdate: true); 1383 isStatusUpdate: true);
1363 }); 1384 });
1364 server.addHandler(startedPath, (HttpRequest request) { 1385 server.addHandler(startedPath, (HttpRequest request) {
1365 noCache(request); 1386 noCache(request);
1366 handleStarted(request, browserId(request, startedPath), testId(request)); 1387 handleStarted(request, browserId(request, startedPath), testId(request));
1367 }); 1388 });
1368 1389
1369 makeSendPageHandler(String prefix) => (HttpRequest request) { 1390 void sendPageHandler(HttpRequest request) {
1370 noCache(request); 1391 // Do NOT make this method async. We need to call catchError below
1371 var textResponse = ""; 1392 // synchronously to avoid unhandled asynchronous errors.
1372 if (prefix == driverPath) { 1393 noCache(request);
1373 textResponse = getDriverPage(browserId(request, prefix)); 1394 Future<String> textResponse;
1374 request.response.headers.set('Content-Type', 'text/html'); 1395 if (request.uri.path.startsWith(driverPath)) {
1375 } 1396 textResponse = getDriverPage(browserId(request, driverPath));
1376 if (prefix == nextTestPath) { 1397 request.response.headers.set('Content-Type', 'text/html');
1377 textResponse = getNextTest(browserId(request, prefix)); 1398 } else if (request.uri.path.startsWith(nextTestPath)) {
1378 request.response.headers.set('Content-Type', 'text/plain'); 1399 textResponse = new Future<String>.value(
1379 } 1400 getNextTest(browserId(request, nextTestPath)));
1380 request.response.write(textResponse); 1401 request.response.headers.set('Content-Type', 'text/plain');
1381 request.listen((_) {}, onDone: request.response.close); 1402 } else {
1382 request.response.done.catchError((error) { 1403 textResponse = new Future<String>.value("");
1383 if (!underTermination) { 1404 }
1384 print("URI ${request.uri}"); 1405 request.response.done.catchError((error) {
1385 print("Textresponse $textResponse"); 1406 if (!underTermination) {
1386 throw "Error returning content to browser: $error"; 1407 return textResponse.then((String text) {
1387 } 1408 print("URI ${request.uri}");
1409 print("textResponse $textResponse");
1410 throw "Error returning content to browser: $error";
1388 }); 1411 });
1389 }; 1412 }
1390 server.addHandler(driverPath, makeSendPageHandler(driverPath)); 1413 });
1391 server.addHandler(nextTestPath, makeSendPageHandler(nextTestPath)); 1414 textResponse.then((String text) async {
1415 request.response.write(text);
1416 await request.listen(null).asFuture();
1417 // Ignoring the returned closure as it returns the 'done' future
1418 // which alread has catchError installed above.
1419 request.response.close();
1420 });
1421 }
1422
1423 server.addHandler(driverPath, sendPageHandler);
1424 server.addHandler(nextTestPath, sendPageHandler);
1392 } 1425 }
1393 1426
1394 void handleReport(HttpRequest request, String browserId, var testId, 1427 void handleReport(HttpRequest request, String browserId, var testId,
1395 {bool isStatusUpdate}) { 1428 {bool isStatusUpdate}) {
1396 StringBuffer buffer = new StringBuffer(); 1429 StringBuffer buffer = new StringBuffer();
1397 request.transform(UTF8.decoder).listen((data) { 1430 request.transform(UTF8.decoder).listen((data) {
1398 buffer.write(data); 1431 buffer.write(data);
1399 }, onDone: () { 1432 }, onDone: () {
1400 String back = buffer.toString(); 1433 String back = buffer.toString();
1401 request.response.close(); 1434 request.response.close();
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
1440 if (errorReportingServer == null) { 1473 if (errorReportingServer == null) {
1441 print("Bad browser testing server, you are not started yet. Can't " 1474 print("Bad browser testing server, you are not started yet. Can't "
1442 "produce driver url"); 1475 "produce driver url");
1443 exit(1); 1476 exit(1);
1444 // This should never happen - exit immediately; 1477 // This should never happen - exit immediately;
1445 } 1478 }
1446 var port = configuration['_servers_'].port; 1479 var port = configuration['_servers_'].port;
1447 return "http://$localIp:$port/driver/$browserId"; 1480 return "http://$localIp:$port/driver/$browserId";
1448 } 1481 }
1449 1482
1450 String getDriverPage(String browserId) { 1483 Future<String> getDriverPage(String browserId) async {
1484 await testRunner.browserStatus[browserId].browser.onDriverPageRequested();
1451 var errorReportingUrl = 1485 var errorReportingUrl =
1452 "http://$localIp:${errorReportingServer.port}/$browserId"; 1486 "http://$localIp:${errorReportingServer.port}/$browserId";
1453 String driverContent = """ 1487 String driverContent = """
1454 <!DOCTYPE html><html> 1488 <!DOCTYPE html><html>
1455 <head> 1489 <head>
1490 <title>Driving page</title>
1456 <style> 1491 <style>
1457 body { 1492 .big-notice {
1458 margin: 0; 1493 background-color: red;
1459 } 1494 color: white;
1460 .box { 1495 font-weight: bold;
1461 overflow: hidden; 1496 font-size: xx-large;
1462 overflow-y: auto; 1497 text-align: center;
1463 position: absolute; 1498 }
1464 left: 0; 1499 .controller.box {
1465 right: 0; 1500 white-space: nowrap;
1466 } 1501 overflow: scroll;
1467 .controller.box { 1502 height: 6em;
1468 height: 75px; 1503 }
1469 top: 0; 1504 body {
1470 } 1505 font-family: sans-serif;
1471 .test.box { 1506 }
1472 top: 75px; 1507 body div {
1473 bottom: 0; 1508 padding-top: 10px;
1474 } 1509 }
1475 </style> 1510 </style>
1476 <title>Driving page</title>
1477 <script type='text/javascript'> 1511 <script type='text/javascript'>
1478 var STATUS_UPDATE_INTERVAL = 10000; 1512 var STATUS_UPDATE_INTERVAL = 10000;
1479 1513
1480 function startTesting() { 1514 function startTesting() {
1481 var number_of_tests = 0; 1515 var number_of_tests = 0;
1482 var current_id; 1516 var current_id;
1483 var next_id; 1517 var next_id;
1484 1518
1485 // Has the test in the current iframe reported that it is done? 1519 // Has the test in the current iframe reported that it is done?
1486 var test_completed = true; 1520 var test_completed = true;
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after
1596 if (use_iframe) { 1630 if (use_iframe) {
1597 if (html_test) { 1631 if (html_test) {
1598 window.addEventListener('detect_errors', setChildHandlers, false); 1632 window.addEventListener('detect_errors', setChildHandlers, false);
1599 embedded_iframe.onload = checkChildHandlersInstalled; 1633 embedded_iframe.onload = checkChildHandlersInstalled;
1600 } else { 1634 } else {
1601 embedded_iframe.onload = null; 1635 embedded_iframe.onload = null;
1602 } 1636 }
1603 embedded_iframe_div.removeChild(embedded_iframe); 1637 embedded_iframe_div.removeChild(embedded_iframe);
1604 embedded_iframe = document.createElement('iframe'); 1638 embedded_iframe = document.createElement('iframe');
1605 embedded_iframe.id = "embedded_iframe"; 1639 embedded_iframe.id = "embedded_iframe";
1606 embedded_iframe.style="width:100%;height:100%"; 1640 embedded_iframe.width='800px';
1641 embedded_iframe.height='600px';
1607 embedded_iframe_div.appendChild(embedded_iframe); 1642 embedded_iframe_div.appendChild(embedded_iframe);
1608 embedded_iframe.src = url; 1643 embedded_iframe.src = url;
1609 } else { 1644 } else {
1610 if (typeof testing_window != 'undefined') { 1645 if (typeof testing_window != 'undefined') {
1611 testing_window.close(); 1646 testing_window.close();
1612 } 1647 }
1613 testing_window = window.open(url); 1648 testing_window = window.open(url);
1614 } 1649 }
1615 test_started = false; 1650 test_started = false;
1616 test_completed = false; 1651 test_completed = false;
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after
1768 1803
1769 if (!html_test) { 1804 if (!html_test) {
1770 window.addEventListener('message', messageHandler, false); 1805 window.addEventListener('message', messageHandler, false);
1771 waitForDone = false; 1806 waitForDone = false;
1772 } 1807 }
1773 getNextTask(); 1808 getNextTask();
1774 } 1809 }
1775 </script> 1810 </script>
1776 </head> 1811 </head>
1777 <body onload="startTesting()"> 1812 <body onload="startTesting()">
1813
1814 <div class='big-notice'>
1815 Please keep this window in focus at all times.
1816 </div>
1817
1818 <div>
1819 Some browsers, Safari, in particular, may pause JavaScript when not
1820 visible to conserve power consumption and CPU resources. In addition,
1821 some tests of focus events will not work correctly if this window doesn't
1822 have focus. It's also advisable to close any other programs that may open
1823 modal dialogs, for example, Chrome with Calendar open.
1824 </div>
1825
1778 <div class="controller box"> 1826 <div class="controller box">
1779 Dart test driver, number of tests: <span id="number"></span><br> 1827 Dart test driver, number of tests: <span id="number"></span><br>
1780 Currently executing: <span id="currently_executing"></span><br> 1828 Currently executing: <span id="currently_executing"></span><br>
1781 Unhandled error: <span id="unhandled_error"></span> 1829 Unhandled error: <span id="unhandled_error"></span>
1782 </div> 1830 </div>
1783 <div id="embedded_iframe_div" class="test box"> 1831 <div id="embedded_iframe_div" class="test box">
1784 <iframe style="width:100%;height:100%;" id="embedded_iframe"></iframe> 1832 <iframe id="embedded_iframe"></iframe>
1785 </div> 1833 </div>
1786 </body> 1834 </body>
1787 </html> 1835 </html>
1788 """; 1836 """;
1789 return driverContent; 1837 return driverContent;
1790 } 1838 }
1791 } 1839 }
OLDNEW
« no previous file with comments | « tools/safari_factory_reset.py ('k') | tools/testing/dart/reset_safari.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698