Chromium Code Reviews| 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; | 7 import "dart:convert" show LineSplitter, UTF8; |
| 8 import "dart:core"; | 8 import "dart:core"; |
| 9 import "dart:io"; | 9 import "dart:io"; |
| 10 | 10 |
| (...skipping 613 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 624 | 624 |
| 625 | 625 |
| 626 class Firefox extends Browser { | 626 class Firefox extends Browser { |
| 627 static const String enablePopUp = | 627 static const String enablePopUp = |
| 628 'user_pref("dom.disable_open_during_load", false);'; | 628 'user_pref("dom.disable_open_during_load", false);'; |
| 629 static const String disableDefaultCheck = | 629 static const String disableDefaultCheck = |
| 630 'user_pref("browser.shell.checkDefaultBrowser", false);'; | 630 'user_pref("browser.shell.checkDefaultBrowser", false);'; |
| 631 static const String disableScriptTimeLimit = | 631 static const String disableScriptTimeLimit = |
| 632 'user_pref("dom.max_script_run_time", 0);'; | 632 'user_pref("dom.max_script_run_time", 0);'; |
| 633 | 633 |
| 634 Future _createPreferenceFile(var path) { | 634 void _createPreferenceFile(var path) { |
| 635 var file = new File("${path.toString()}/user.js"); | 635 var file = new File("${path.toString()}/user.js"); |
| 636 var randomFile = file.openSync(mode: FileMode.WRITE); | 636 var randomFile = file.openSync(mode: FileMode.WRITE); |
| 637 randomFile.writeStringSync(enablePopUp); | 637 randomFile.writeStringSync(enablePopUp); |
| 638 randomFile.writeStringSync(disableDefaultCheck); | 638 randomFile.writeStringSync(disableDefaultCheck); |
| 639 randomFile.writeStringSync(disableScriptTimeLimit); | 639 randomFile.writeStringSync(disableScriptTimeLimit); |
| 640 randomFile.close(); | 640 randomFile.close(); |
| 641 } | 641 } |
| 642 | 642 |
| 643 Future<bool> start(String url) { | 643 Future<bool> start(String url) { |
| 644 _logEvent("Starting firefox browser on: $url"); | 644 _logEvent("Starting firefox browser on: $url"); |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 675 */ | 675 */ |
| 676 class BrowserTestingStatus { | 676 class BrowserTestingStatus { |
| 677 Browser browser; | 677 Browser browser; |
| 678 BrowserTest currentTest; | 678 BrowserTest currentTest; |
| 679 | 679 |
| 680 // This is currently not used for anything except for error reporting. | 680 // This is currently not used for anything except for error reporting. |
| 681 // Given the usefulness of this in debugging issues this should not be | 681 // Given the usefulness of this in debugging issues this should not be |
| 682 // removed even when we have really stable system. | 682 // removed even when we have really stable system. |
| 683 BrowserTest lastTest; | 683 BrowserTest lastTest; |
| 684 bool timeout = false; | 684 bool timeout = false; |
| 685 Timer nextTestTimeout; | |
| 686 | |
| 685 BrowserTestingStatus(Browser this.browser); | 687 BrowserTestingStatus(Browser this.browser); |
| 686 } | 688 } |
| 687 | 689 |
| 688 | 690 |
| 689 /** | 691 /** |
| 690 * Describes a single test to be run int the browser. | 692 * Describes a single test to be run int the browser. |
| 691 */ | 693 */ |
| 692 class BrowserTest { | 694 class BrowserTest { |
| 693 // TODO(ricow): Add timeout callback instead of the string passing hack. | 695 // TODO(ricow): Add timeout callback instead of the string passing hack. |
| 694 Function doneCallback; | 696 Function doneCallback; |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 729 this.browserOutput, {this.didTimeout: false}); | 731 this.browserOutput, {this.didTimeout: false}); |
| 730 } | 732 } |
| 731 | 733 |
| 732 /** | 734 /** |
| 733 * Encapsulates all the functionality for running tests in browsers. | 735 * Encapsulates all the functionality for running tests in browsers. |
| 734 * The interface is rather simple. After starting, the runner tests | 736 * The interface is rather simple. After starting, the runner tests |
| 735 * are simply added to the queue and a the supplied callbacks are called | 737 * are simply added to the queue and a the supplied callbacks are called |
| 736 * whenever a test completes. | 738 * whenever a test completes. |
| 737 */ | 739 */ |
| 738 class BrowserTestRunner { | 740 class BrowserTestRunner { |
| 741 static const int MAX_NEXT_TEST_TIMEOUTS = 10; | |
| 742 static const Duration NEXT_TEST_TIMEOUT = const Duration(seconds: 60); | |
| 743 | |
| 739 final Map globalConfiguration; | 744 final Map globalConfiguration; |
| 740 final bool checkedMode; // needed for dartium | 745 final bool checkedMode; // needed for dartium |
| 741 | 746 |
| 742 String localIp; | 747 String localIp; |
| 743 String browserName; | 748 String browserName; |
| 744 int maxNumBrowsers; | 749 int maxNumBrowsers; |
| 745 // Used to send back logs from the browser (start, stop etc) | 750 // Used to send back logs from the browser (start, stop etc) |
| 746 Function logger; | 751 Function logger; |
| 747 int browserIdCount = 0; | 752 int browserIdCount = 0; |
| 748 | 753 |
| 749 bool underTermination = false; | 754 bool underTermination = false; |
| 755 int numBrowserGetTestTimeouts = 0; | |
| 750 | 756 |
| 751 List<BrowserTest> testQueue = new List<BrowserTest>(); | 757 List<BrowserTest> testQueue = new List<BrowserTest>(); |
| 752 Map<String, BrowserTestingStatus> browserStatus = | 758 Map<String, BrowserTestingStatus> browserStatus = |
| 753 new Map<String, BrowserTestingStatus>(); | 759 new Map<String, BrowserTestingStatus>(); |
| 754 | 760 |
| 755 var adbDeviceMapping = new Map<String, AdbDevice>(); | 761 var adbDeviceMapping = new Map<String, AdbDevice>(); |
| 756 // This cache is used to guarantee that we never see double reporting. | 762 // This cache is used to guarantee that we never see double reporting. |
| 757 // If we do we need to provide developers with this information. | 763 // If we do we need to provide developers with this information. |
| 758 // We don't add urls to the cache until we have run it. | 764 // We don't add urls to the cache until we have run it. |
| 759 Map<int, String> testCache = new Map<int, String>(); | 765 Map<int, String> testCache = new Map<int, String>(); |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 786 testingServer.testDoneCallBack = handleResults; | 792 testingServer.testDoneCallBack = handleResults; |
| 787 testingServer.testStatusUpdateCallBack = handleStatusUpdate; | 793 testingServer.testStatusUpdateCallBack = handleStatusUpdate; |
| 788 testingServer.testStartedCallBack = handleStarted; | 794 testingServer.testStartedCallBack = handleStarted; |
| 789 testingServer.nextTestCallBack = getNextTest; | 795 testingServer.nextTestCallBack = getNextTest; |
| 790 return getBrowsers().then((browsers) { | 796 return getBrowsers().then((browsers) { |
| 791 var futures = []; | 797 var futures = []; |
| 792 for (var browser in browsers) { | 798 for (var browser in browsers) { |
| 793 var url = testingServer.getDriverUrl(browser.id); | 799 var url = testingServer.getDriverUrl(browser.id); |
| 794 var future = browser.start(url).then((success) { | 800 var future = browser.start(url).then((success) { |
| 795 if (success) { | 801 if (success) { |
| 796 browserStatus[browser.id] = new BrowserTestingStatus(browser); | 802 var status = new BrowserTestingStatus(browser); |
| 803 browserStatus[browser.id] = status; | |
| 804 status.nextTestTimeout = createNextTestTimer(status); | |
| 797 } | 805 } |
| 798 return success; | 806 return success; |
| 799 }); | 807 }); |
| 800 futures.add(future); | 808 futures.add(future); |
| 801 } | 809 } |
| 802 return Future.wait(futures).then((values) { | 810 return Future.wait(futures).then((values) { |
| 803 return !values.contains(false); | 811 return !values.contains(false); |
| 804 }); | 812 }); |
| 805 }); | 813 }); |
| 806 }); | 814 }); |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 869 | 877 |
| 870 if (status.currentTest.id != testId) { | 878 if (status.currentTest.id != testId) { |
| 871 print("Expected test id ${status.currentTest.id} for" | 879 print("Expected test id ${status.currentTest.id} for" |
| 872 "${status.currentTest.url}"); | 880 "${status.currentTest.url}"); |
| 873 print("Got test id ${testId}"); | 881 print("Got test id ${testId}"); |
| 874 print("Last test id was ${status.lastTest.id} for " | 882 print("Last test id was ${status.lastTest.id} for " |
| 875 "${status.currentTest.url}"); | 883 "${status.currentTest.url}"); |
| 876 throw("This should never happen, wrong test id"); | 884 throw("This should never happen, wrong test id"); |
| 877 } | 885 } |
| 878 testCache[testId] = status.currentTest.url; | 886 testCache[testId] = status.currentTest.url; |
| 879 Stopwatch watch = new Stopwatch()..start(); | |
| 880 | 887 |
| 881 // Report that the test is finished now | 888 // Report that the test is finished now |
| 882 var browserTestOutput = new BrowserTestOutput( | 889 var browserTestOutput = new BrowserTestOutput( |
| 883 status.currentTest.delayUntilTestStarted, | 890 status.currentTest.delayUntilTestStarted, |
| 884 status.currentTest.stopwatch.elapsed, | 891 status.currentTest.stopwatch.elapsed, |
| 885 output, | 892 output, |
| 886 status.browser.testBrowserOutput); | 893 status.browser.testBrowserOutput); |
| 887 status.currentTest.doneCallback(browserTestOutput); | 894 status.currentTest.doneCallback(browserTestOutput); |
| 888 | 895 |
| 889 watch.stop(); | |
| 890 status.lastTest = status.currentTest; | 896 status.lastTest = status.currentTest; |
| 891 status.currentTest = null; | 897 status.currentTest = null; |
| 898 status.nextTestTimeout = createNextTestTimer(status); | |
| 892 } else { | 899 } else { |
| 893 print("\nThis is bad, should never happen, handleResult no test"); | 900 print("\nThis is bad, should never happen, handleResult no test"); |
| 894 print("URL: ${status.lastTest.url}"); | 901 print("URL: ${status.lastTest.url}"); |
| 895 print(output); | 902 print(output); |
| 896 terminate().then((_) { | 903 terminate().then((_) { |
| 897 exit(1); | 904 exit(1); |
| 898 }); | 905 }); |
| 899 } | 906 } |
| 900 } | 907 } |
| 901 | 908 |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 944 status.currentTest.delayUntilTestStarted, | 951 status.currentTest.delayUntilTestStarted, |
| 945 status.currentTest.stopwatch.elapsed, | 952 status.currentTest.stopwatch.elapsed, |
| 946 lastKnownMessage, | 953 lastKnownMessage, |
| 947 status.browser.testBrowserOutput, | 954 status.browser.testBrowserOutput, |
| 948 didTimeout: true); | 955 didTimeout: true); |
| 949 status.currentTest.doneCallback(browserTestOutput); | 956 status.currentTest.doneCallback(browserTestOutput); |
| 950 status.currentTest = null; | 957 status.currentTest = null; |
| 951 | 958 |
| 952 // We don't want to start a new browser if we are terminating. | 959 // We don't want to start a new browser if we are terminating. |
| 953 if (underTermination) return; | 960 if (underTermination) return; |
| 954 var browser; | 961 restartBrowser(id); |
| 955 var new_id = id; | 962 }); |
| 956 if (browserName == 'chromeOnAndroid') { | 963 } |
| 957 browser = new AndroidChrome(adbDeviceMapping[id]); | 964 |
| 958 } else if (browserName == 'ContentShellOnAndroid') { | 965 void restartBrowser(String id) { |
| 959 browser = new AndroidBrowser(adbDeviceMapping[id], | 966 var browser; |
| 960 contentShellOnAndroidConfig, | 967 var new_id = id; |
| 961 checkedMode); | 968 if (browserName == 'chromeOnAndroid') { |
| 962 } else if (browserName == 'DartiumOnAndroid') { | 969 browser = new AndroidChrome(adbDeviceMapping[id]); |
| 963 browser = new AndroidBrowser(adbDeviceMapping[id], | 970 } else if (browserName == 'ContentShellOnAndroid') { |
| 964 dartiumOnAndroidConfig, | 971 browser = new AndroidBrowser(adbDeviceMapping[id], |
| 965 checkedMode); | 972 contentShellOnAndroidConfig, |
| 966 } else { | 973 checkedMode); |
| 967 browserStatus.remove(id); | 974 } else if (browserName == 'DartiumOnAndroid') { |
| 968 browser = getInstance(); | 975 browser = new AndroidBrowser(adbDeviceMapping[id], |
| 969 new_id = "BROWSER$browserIdCount"; | 976 dartiumOnAndroidConfig, |
| 970 browserIdCount++; | 977 checkedMode); |
| 971 browserStatus[new_id] = new BrowserTestingStatus(browser); | 978 } else { |
| 979 browserStatus.remove(id); | |
| 980 browser = getInstance(); | |
| 981 new_id = "BROWSER$browserIdCount"; | |
| 982 browserIdCount++; | |
| 983 } | |
| 984 browser.id = new_id; | |
| 985 var status = new BrowserTestingStatus(browser); | |
| 986 browserStatus[new_id] = status; | |
| 987 status.nextTestTimeout = createNextTestTimer(status); | |
| 988 browser.start(testingServer.getDriverUrl(new_id)).then((success) { | |
| 989 // We may have started terminating in the mean time. | |
| 990 if (underTermination) { | |
| 991 browser.close().then((success) { | |
| 992 if (status.nextTestTimeout != null) { | |
| 993 status.nextTestTimeout.cancel(); | |
| 994 status.nextTestTimeout = null; | |
| 995 } | |
|
kustermann
2014/04/03 12:18:56
You can move the cancelling before browser.close()
| |
| 996 // We should never hit this, print it out. | |
| 997 if (!success) { | |
| 998 print("Could not kill browser ($id) started due to timeout"); | |
| 999 } | |
| 1000 }); | |
| 1001 return; | |
| 972 } | 1002 } |
| 973 browser.id = new_id; | 1003 if (!success) { |
| 974 browser.start(testingServer.getDriverUrl(new_id)).then((success) { | 1004 // TODO(ricow): Handle this better. |
| 975 // We may have started terminating in the mean time. | 1005 print("This is bad, should never happen, could not start browser"); |
| 976 if (underTermination) { | 1006 exit(1); |
| 977 browser.close().then((success) { | 1007 } |
| 978 // We should never hit this, print it out. | |
| 979 if (!success) { | |
| 980 print("Could not kill browser ($id) started due to timeout"); | |
| 981 } | |
| 982 }); | |
| 983 return; | |
| 984 } | |
| 985 if (success) { | |
| 986 browserStatus[browser.id] = new BrowserTestingStatus(browser); | |
| 987 } else { | |
| 988 // TODO(ricow): Handle this better. | |
| 989 print("This is bad, should never happen, could not start browser"); | |
| 990 exit(1); | |
| 991 } | |
| 992 }); | |
| 993 }); | 1008 }); |
| 994 } | 1009 } |
| 995 | 1010 |
| 996 BrowserTest getNextTest(String browserId) { | 1011 BrowserTest getNextTest(String browserId) { |
| 997 if (testQueue.isEmpty) return null; | |
| 998 var status = browserStatus[browserId]; | 1012 var status = browserStatus[browserId]; |
| 999 if (status == null) return null; | 1013 if (status == null) return null; |
| 1014 if (status.nextTestTimeout != null) { | |
| 1015 status.nextTestTimeout.cancel(); | |
| 1016 status.nextTestTimeout = null; | |
| 1017 } | |
| 1018 if (testQueue.isEmpty) return null; | |
| 1000 | 1019 |
| 1001 // We are currently terminating this browser, don't start a new test. | 1020 // We are currently terminating this browser, don't start a new test. |
| 1002 if (status.timeout) return null; | 1021 if (status.timeout) return null; |
| 1003 | 1022 |
| 1004 BrowserTest test = testQueue.removeLast(); | 1023 BrowserTest test = testQueue.removeLast(); |
| 1005 if (status.currentTest == null) { | 1024 if (status.currentTest == null) { |
| 1006 status.currentTest = test; | 1025 status.currentTest = test; |
| 1007 status.currentTest.lastKnownMessage = ''; | 1026 status.currentTest.lastKnownMessage = ''; |
| 1008 } else { | 1027 } else { |
| 1009 // TODO(ricow): Handle this better. | 1028 // TODO(ricow): Handle this better. |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 1021 status.currentTest.stopwatch = new Stopwatch()..start(); | 1040 status.currentTest.stopwatch = new Stopwatch()..start(); |
| 1022 | 1041 |
| 1023 // Reset the test specific output information (stdout, stderr) on the | 1042 // Reset the test specific output information (stdout, stderr) on the |
| 1024 // browser since a new test is begin started. | 1043 // browser since a new test is begin started. |
| 1025 status.browser.resetTestBrowserOutput(); | 1044 status.browser.resetTestBrowserOutput(); |
| 1026 | 1045 |
| 1027 return test; | 1046 return test; |
| 1028 } | 1047 } |
| 1029 | 1048 |
| 1030 Timer createTimeoutTimer(BrowserTest test, BrowserTestingStatus status) { | 1049 Timer createTimeoutTimer(BrowserTest test, BrowserTestingStatus status) { |
| 1031 return new Timer( | 1050 return new Timer(new Duration(seconds: test.timeout), |
| 1032 new Duration(seconds: test.timeout), () { handleTimeout(status); }); | 1051 () { handleTimeout(status); }); |
| 1052 } | |
| 1053 | |
| 1054 Timer createNextTestTimer(BrowserTestingStatus status) { | |
| 1055 return new Timer(BrowserTestRunner.NEXT_TEST_TIMEOUT, | |
| 1056 () { handleNextTestTimeout(status); }); | |
| 1057 } | |
| 1058 | |
| 1059 void handleNextTestTimeout(status) { | |
| 1060 DebugLogger.warning( | |
| 1061 "Browser timed out before getting next test. Restarting"); | |
| 1062 numBrowserGetTestTimeouts++; | |
| 1063 if (numBrowserGetTestTimeouts >= MAX_NEXT_TEST_TIMEOUTS) { | |
| 1064 DebugLogger.error( | |
| 1065 "Too many browser timeouts before getting next test. Terminating"); | |
| 1066 terminate().then((_) => exit(1)); | |
| 1067 } else { | |
| 1068 status.browser.close().then((_) => restartBrowser(status.browser.id)); | |
| 1069 } | |
| 1033 } | 1070 } |
| 1034 | 1071 |
| 1035 void queueTest(BrowserTest test) { | 1072 void queueTest(BrowserTest test) { |
| 1036 testQueue.add(test); | 1073 testQueue.add(test); |
| 1037 } | 1074 } |
| 1038 | 1075 |
| 1039 void printDoubleReportingTests() { | 1076 void printDoubleReportingTests() { |
| 1040 if (doubleReportingOutputs.length == 0) return; | 1077 if (doubleReportingOutputs.length == 0) return; |
| 1041 // TODO(ricow): die on double reporting. | 1078 // TODO(ricow): die on double reporting. |
| 1042 // Currently we just report this here, we could have a callback to the | 1079 // Currently we just report this here, we could have a callback to the |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 1055 DebugLogger.warning(""); | 1092 DebugLogger.warning(""); |
| 1056 } | 1093 } |
| 1057 } | 1094 } |
| 1058 | 1095 |
| 1059 Future<bool> terminate() { | 1096 Future<bool> terminate() { |
| 1060 var futures = []; | 1097 var futures = []; |
| 1061 underTermination = true; | 1098 underTermination = true; |
| 1062 testingServer.underTermination = true; | 1099 testingServer.underTermination = true; |
| 1063 for (BrowserTestingStatus status in browserStatus.values) { | 1100 for (BrowserTestingStatus status in browserStatus.values) { |
| 1064 futures.add(status.browser.close()); | 1101 futures.add(status.browser.close()); |
| 1102 if (status.nextTestTimeout != null) { | |
| 1103 status.nextTestTimeout.cancel(); | |
| 1104 status.nextTestTimeout = null; | |
| 1105 } | |
| 1065 } | 1106 } |
| 1066 return Future.wait(futures).then((values) { | 1107 return Future.wait(futures).then((values) { |
| 1067 testingServer.httpServer.close(); | 1108 testingServer.httpServer.close(); |
| 1068 testingServer.errorReportingServer.close(); | 1109 testingServer.errorReportingServer.close(); |
| 1069 printDoubleReportingTests(); | 1110 printDoubleReportingTests(); |
| 1070 return !values.contains(false); | 1111 return !values.contains(false); |
| 1071 }); | 1112 }); |
| 1072 } | 1113 } |
| 1073 | 1114 |
| 1074 Browser getInstance() { | 1115 Browser getInstance() { |
| (...skipping 378 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1453 Dart test driver, number of tests: <div id="number"></div><br> | 1494 Dart test driver, number of tests: <div id="number"></div><br> |
| 1454 Currently executing: <div id="currently_executing"></div><br> | 1495 Currently executing: <div id="currently_executing"></div><br> |
| 1455 Unhandled error: <div id="unhandled_error"></div> | 1496 Unhandled error: <div id="unhandled_error"></div> |
| 1456 <iframe id="embedded_iframe"></iframe> | 1497 <iframe id="embedded_iframe"></iframe> |
| 1457 </body> | 1498 </body> |
| 1458 </html> | 1499 </html> |
| 1459 """; | 1500 """; |
| 1460 return driverContent; | 1501 return driverContent; |
| 1461 } | 1502 } |
| 1462 } | 1503 } |
| OLD | NEW |