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 |
| 11 import 'android.dart'; | 11 import 'android.dart'; |
| 12 import 'utils.dart'; | 12 import 'utils.dart'; |
| 13 | 13 |
| 14 class BrowserOutput { | |
| 15 final StringBuffer stdout = new StringBuffer(); | |
| 16 final StringBuffer stderr = new StringBuffer(); | |
| 17 final StringBuffer eventLog = new StringBuffer(); | |
| 18 } | |
| 19 | |
| 14 /** Class describing the interface for communicating with browsers. */ | 20 /** Class describing the interface for communicating with browsers. */ |
| 15 abstract class Browser { | 21 abstract class Browser { |
| 16 StringBuffer _stdout = new StringBuffer(); | 22 BrowserOutput _allBrowserOutput = new BrowserOutput(); |
| 17 StringBuffer _stderr = new StringBuffer(); | 23 BrowserOutput _testBrowserOutput = new BrowserOutput(); |
| 18 StringBuffer _usageLog = new StringBuffer(); | 24 |
| 19 // This is called after the process is closed, before the done future | 25 // This is called after the process is closed, before the done future |
| 20 // is completed. | 26 // is completed. |
| 21 // Subclasses can use this to cleanup any browser specific resources | 27 // Subclasses can use this to cleanup any browser specific resources |
| 22 // (temp directories, profiles, etc). The function is expected to do | 28 // (temp directories, profiles, etc). The function is expected to do |
| 23 // it's work synchronously. | 29 // it's work synchronously. |
| 24 Function _cleanup; | 30 Function _cleanup; |
| 25 | 31 |
| 26 /** The version of the browser - normally set when starting a browser */ | 32 /** The version of the browser - normally set when starting a browser */ |
| 27 String version = ""; | 33 String version = ""; |
| 28 /** | 34 /** |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 72 | 78 |
| 73 // TODO(kustermann): add standard support for chrome on android | 79 // TODO(kustermann): add standard support for chrome on android |
| 74 static bool supportedBrowser(String name) { | 80 static bool supportedBrowser(String name) { |
| 75 return SUPPORTED_BROWSERS.contains(name); | 81 return SUPPORTED_BROWSERS.contains(name); |
| 76 } | 82 } |
| 77 | 83 |
| 78 void _logEvent(String event) { | 84 void _logEvent(String event) { |
| 79 String toLog = "$this ($id) - $event \n"; | 85 String toLog = "$this ($id) - $event \n"; |
| 80 if (debugPrint) print("usageLog: $toLog"); | 86 if (debugPrint) print("usageLog: $toLog"); |
| 81 if (logger != null) logger(toLog); | 87 if (logger != null) logger(toLog); |
| 82 _usageLog.write(toLog); | 88 |
| 89 _allBrowserOutput.eventLog.write(toLog); | |
| 90 _testBrowserOutput.eventLog.write(toLog); | |
| 83 } | 91 } |
| 84 | 92 |
| 85 void _addStdout(String output) { | 93 void _addStdout(String output) { |
| 86 if (debugPrint) print("stdout: $output"); | 94 if (debugPrint) print("stdout: $output"); |
| 87 _stdout.write(output); | 95 |
| 96 _allBrowserOutput.stdout.write(output); | |
| 97 _testBrowserOutput.stdout.write(output); | |
| 88 } | 98 } |
| 89 | 99 |
| 90 void _addStderr(String output) { | 100 void _addStderr(String output) { |
| 91 if (debugPrint) print("stderr: $output"); | 101 if (debugPrint) print("stderr: $output"); |
| 92 _stderr.write(output); | 102 |
| 103 _allBrowserOutput.stderr.write(output); | |
| 104 _testBrowserOutput.stderr.write(output); | |
| 93 } | 105 } |
| 94 | 106 |
| 95 Future close() { | 107 Future close() { |
| 96 _logEvent("Close called on browser"); | 108 _logEvent("Close called on browser"); |
| 97 if (process != null) { | 109 if (process != null) { |
| 98 if (process.kill(ProcessSignal.SIGKILL)) { | 110 if (process.kill(ProcessSignal.SIGKILL)) { |
| 99 _logEvent("Successfully sent kill signal to process."); | 111 _logEvent("Successfully sent kill signal to process."); |
| 100 } else { | 112 } else { |
| 101 _logEvent("Sending kill signal failed."); | 113 _logEvent("Sending kill signal failed."); |
| 102 } | 114 } |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 157 }).whenComplete(() => doneCompleter.complete(true)); | 169 }).whenComplete(() => doneCompleter.complete(true)); |
| 158 }); | 170 }); |
| 159 return true; | 171 return true; |
| 160 }).catchError((error) { | 172 }).catchError((error) { |
| 161 _logEvent("Running $command $arguments failed with $error"); | 173 _logEvent("Running $command $arguments failed with $error"); |
| 162 return false; | 174 return false; |
| 163 }); | 175 }); |
| 164 } | 176 } |
| 165 | 177 |
| 166 /** | 178 /** |
| 167 * Get any stdout that the browser wrote during execution. | 179 * Get the output that was written so far to stdout/stderr/eventLog. |
| 168 */ | 180 */ |
| 169 String get stdout => _stdout.toString(); | 181 BrowserOutput get allBrowserOutput => _allBrowserOutput; |
| 170 String get stderr => _stderr.toString(); | 182 BrowserOutput get testBrowserOutput => _testBrowserOutput; |
| 171 String get usageLog => _usageLog.toString(); | 183 |
|
kustermann
2013/10/18 12:02:25
I couldn't find any uses of these. I hope it's oka
| |
| 184 void resetTestBrowserOutput() { | |
| 185 _testBrowserOutput = new BrowserOutput(); | |
| 186 } | |
| 172 | 187 |
| 173 String toString(); | 188 String toString(); |
| 189 | |
| 174 /** Starts the browser loading the given url */ | 190 /** Starts the browser loading the given url */ |
| 175 Future<bool> start(String url); | 191 Future<bool> start(String url); |
| 176 } | 192 } |
| 177 | 193 |
| 178 class Safari extends Browser { | 194 class Safari extends Browser { |
| 179 /** | 195 /** |
| 180 * The binary used to run safari - changing this can be nececcary for | 196 * The binary used to run safari - changing this can be nececcary for |
| 181 * testing or using non standard safari installation. | 197 * testing or using non standard safari installation. |
| 182 */ | 198 */ |
| 183 static const String binary = "/Applications/Safari.app/Contents/MacOS/Safari"; | 199 static const String binary = "/Applications/Safari.app/Contents/MacOS/Safari"; |
| (...skipping 429 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 613 // Used for debugging, this is simply a unique identifier assigned to each | 629 // Used for debugging, this is simply a unique identifier assigned to each |
| 614 // test. | 630 // test. |
| 615 int id; | 631 int id; |
| 616 static int _idCounter = 0; | 632 static int _idCounter = 0; |
| 617 | 633 |
| 618 BrowserTest(this.url, this.doneCallback, this.timeout) { | 634 BrowserTest(this.url, this.doneCallback, this.timeout) { |
| 619 id = _idCounter++; | 635 id = _idCounter++; |
| 620 } | 636 } |
| 621 } | 637 } |
| 622 | 638 |
| 639 /* Describes the output of running the test in a browser */ | |
| 640 class BrowserTestOutput { | |
| 641 final bool didTimeout; | |
| 642 final Duration delayUntilTestStarted; | |
| 643 final Duration duration; | |
| 644 final BrowserOutput browserOutput; | |
| 645 final String dom; | |
| 646 | |
| 647 BrowserTestOutput( | |
| 648 this.delayUntilTestStarted, this.duration, this.dom, | |
| 649 this.browserOutput, {this.didTimeout: false}); | |
| 650 } | |
| 623 | 651 |
| 624 /** | 652 /** |
| 625 * Encapsulates all the functionality for running tests in browsers. | 653 * Encapsulates all the functionality for running tests in browsers. |
| 626 * The interface is rather simple. After starting the runner tests | 654 * The interface is rather simple. After starting the runner tests |
| 627 * are simply added to the queue and a the supplied callbacks are called | 655 * are simply added to the queue and a the supplied callbacks are called |
| 628 * whenever a test completes. | 656 * whenever a test completes. |
| 629 */ | 657 */ |
| 630 class BrowserTestRunner { | 658 class BrowserTestRunner { |
| 631 final Map globalConfiguration; | 659 final Map globalConfiguration; |
| 632 | 660 |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 743 if (status.currentTest.id != testId) { | 771 if (status.currentTest.id != testId) { |
| 744 print("Expected test id ${status.currentTest.id} for" | 772 print("Expected test id ${status.currentTest.id} for" |
| 745 "${status.currentTest.url}"); | 773 "${status.currentTest.url}"); |
| 746 print("Got test id ${testId}"); | 774 print("Got test id ${testId}"); |
| 747 print("Last test id was ${status.lastTest.id} for " | 775 print("Last test id was ${status.lastTest.id} for " |
| 748 "${status.currentTest.url}"); | 776 "${status.currentTest.url}"); |
| 749 throw("This should never happen, wrong test id"); | 777 throw("This should never happen, wrong test id"); |
| 750 } | 778 } |
| 751 testCache[testId] = status.currentTest.url; | 779 testCache[testId] = status.currentTest.url; |
| 752 Stopwatch watch = new Stopwatch()..start(); | 780 Stopwatch watch = new Stopwatch()..start(); |
| 753 status.currentTest.doneCallback(output, | 781 |
| 754 status.currentTest.delayUntilTestStarted, | 782 // Report that the test is finished now |
| 755 status.currentTest.stopwatch.elapsed); | 783 var browserTestOutput = new BrowserTestOutput( |
| 784 status.currentTest.delayUntilTestStarted, | |
| 785 status.currentTest.stopwatch.elapsed, | |
| 786 output, | |
| 787 status.browser.testBrowserOutput); | |
| 788 status.currentTest.doneCallback(browserTestOutput); | |
| 789 | |
| 756 watch.stop(); | 790 watch.stop(); |
| 757 status.lastTest = status.currentTest; | 791 status.lastTest = status.currentTest; |
| 758 status.currentTest = null; | 792 status.currentTest = null; |
| 759 } else { | 793 } else { |
| 760 print("\nThis is bad, should never happen, handleResult no test"); | 794 print("\nThis is bad, should never happen, handleResult no test"); |
| 761 print("URL: ${status.lastTest.url}"); | 795 print("URL: ${status.lastTest.url}"); |
| 762 print(output); | 796 print(output); |
| 763 terminate().then((_) { | 797 terminate().then((_) { |
| 764 exit(1); | 798 exit(1); |
| 765 }); | 799 }); |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 778 } | 812 } |
| 779 } | 813 } |
| 780 | 814 |
| 781 void handleTimeout(BrowserTestingStatus status) { | 815 void handleTimeout(BrowserTestingStatus status) { |
| 782 // We simply kill the browser and starts up a new one! | 816 // We simply kill the browser and starts up a new one! |
| 783 // We could be smarter here, but it does not seems like it is worth it. | 817 // We could be smarter here, but it does not seems like it is worth it. |
| 784 status.timeout = true; | 818 status.timeout = true; |
| 785 timedOut.add(status.currentTest.url); | 819 timedOut.add(status.currentTest.url); |
| 786 var id = status.browser.id; | 820 var id = status.browser.id; |
| 787 status.browser.close().then((_) { | 821 status.browser.close().then((_) { |
| 822 // Wait until the browser is closed before reporting the test as timeout. | |
| 823 // This will enable us to capture stdout/stderr from the browser | |
| 824 // (which might provide us with information about what went wrong). | |
| 825 var browserTestOutput = new BrowserTestOutput( | |
| 826 status.currentTest.delayUntilTestStarted, | |
| 827 status.currentTest.stopwatch.elapsed, | |
| 828 'Dom could not be fetched, since the test timed out.', | |
| 829 status.browser.testBrowserOutput, | |
| 830 didTimeout: true); | |
| 831 status.currentTest.stopwatch.stop(); | |
| 832 status.currentTest.doneCallback(browserTestOutput); | |
| 833 status.currentTest = null; | |
| 834 | |
| 788 // We don't want to start a new browser if we are terminating. | 835 // We don't want to start a new browser if we are terminating. |
| 789 if (underTermination) return; | 836 if (underTermination) return; |
| 790 var browser; | 837 var browser; |
| 791 var new_id = id; | 838 var new_id = id; |
| 792 if (browserName == 'chromeOnAndroid') { | 839 if (browserName == 'chromeOnAndroid') { |
| 793 browser = new AndroidChrome(adbDeviceMapping[id]); | 840 browser = new AndroidChrome(adbDeviceMapping[id]); |
| 794 } else { | 841 } else { |
| 795 browserStatus.remove(id); | 842 browserStatus.remove(id); |
| 796 browser = getInstance(); | 843 browser = getInstance(); |
| 797 new_id = "BROWSER$browserIdCount"; | 844 new_id = "BROWSER$browserIdCount"; |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 812 } | 859 } |
| 813 if (success) { | 860 if (success) { |
| 814 browserStatus[browser.id] = new BrowserTestingStatus(browser); | 861 browserStatus[browser.id] = new BrowserTestingStatus(browser); |
| 815 } else { | 862 } else { |
| 816 // TODO(ricow): Handle this better. | 863 // TODO(ricow): Handle this better. |
| 817 print("This is bad, should never happen, could not start browser"); | 864 print("This is bad, should never happen, could not start browser"); |
| 818 exit(1); | 865 exit(1); |
| 819 } | 866 } |
| 820 }); | 867 }); |
| 821 }); | 868 }); |
| 822 status.currentTest.stopwatch.stop(); | |
| 823 status.currentTest.doneCallback("TIMEOUT", | |
| 824 status.currentTest.delayUntilTestStarted, | |
| 825 status.currentTest.stopwatch.elapsed); | |
| 826 status.currentTest = null; | |
| 827 } | 869 } |
| 828 | 870 |
| 829 BrowserTest getNextTest(String browserId) { | 871 BrowserTest getNextTest(String browserId) { |
| 830 if (testQueue.isEmpty) return null; | 872 if (testQueue.isEmpty) return null; |
| 831 var status = browserStatus[browserId]; | 873 var status = browserStatus[browserId]; |
| 832 if (status == null) return null; | 874 if (status == null) return null; |
| 833 | 875 |
| 834 // We are currently terminating this browser, don't start a new test. | 876 // We are currently terminating this browser, don't start a new test. |
| 835 if (status.timeout) return null; | 877 if (status.timeout) return null; |
| 878 | |
| 836 BrowserTest test = testQueue.removeLast(); | 879 BrowserTest test = testQueue.removeLast(); |
| 837 if (status.currentTest == null) { | 880 if (status.currentTest == null) { |
| 838 status.currentTest = test; | 881 status.currentTest = test; |
| 839 } else { | 882 } else { |
| 840 // TODO(ricow): Handle this better. | 883 // TODO(ricow): Handle this better. |
| 841 print("This is bad, should never happen, getNextTest all full"); | 884 print("This is bad, should never happen, getNextTest all full"); |
| 842 print("This happened for browser $browserId"); | 885 print("This happened for browser $browserId"); |
| 843 print("Old test was: ${status.currentTest.url}"); | 886 print("Old test was: ${status.currentTest.url}"); |
| 844 print("Timed out tests:"); | 887 print("Timed out tests:"); |
| 845 for (var v in timedOut) { | 888 for (var v in timedOut) { |
| 846 print(" $v"); | 889 print(" $v"); |
| 847 } | 890 } |
| 848 exit(1); | 891 exit(1); |
| 849 } | 892 } |
| 850 | 893 |
| 851 status.currentTest.timeoutTimer = createTimeoutTimer(test, status); | 894 status.currentTest.timeoutTimer = createTimeoutTimer(test, status); |
| 852 status.currentTest.stopwatch = new Stopwatch()..start(); | 895 status.currentTest.stopwatch = new Stopwatch()..start(); |
| 896 | |
| 897 // Reset the test specific output information (stdout, stderr) on the | |
| 898 // browser since a new test is begin started. | |
| 899 status.browser.resetTestBrowserOutput(); | |
| 900 | |
| 853 return test; | 901 return test; |
| 854 } | 902 } |
| 855 | 903 |
| 856 Timer createTimeoutTimer(BrowserTest test, BrowserTestingStatus status) { | 904 Timer createTimeoutTimer(BrowserTest test, BrowserTestingStatus status) { |
| 857 return new Timer( | 905 return new Timer( |
| 858 new Duration(seconds: test.timeout), () { handleTimeout(status); }); | 906 new Duration(seconds: test.timeout), () { handleTimeout(status); }); |
| 859 } | 907 } |
| 860 | 908 |
| 861 void queueTest(BrowserTest test) { | 909 void queueTest(BrowserTest test) { |
| 862 testQueue.add(test); | 910 testQueue.add(test); |
| (...skipping 354 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1217 Dart test driver, number of tests: <div id="number"></div><br> | 1265 Dart test driver, number of tests: <div id="number"></div><br> |
| 1218 Currently executing: <div id="currently_executing"></div><br> | 1266 Currently executing: <div id="currently_executing"></div><br> |
| 1219 Unhandled error: <div id="unhandled_error"></div> | 1267 Unhandled error: <div id="unhandled_error"></div> |
| 1220 <iframe id="embedded_iframe"></iframe> | 1268 <iframe id="embedded_iframe"></iframe> |
| 1221 </body> | 1269 </body> |
| 1222 </html> | 1270 </html> |
| 1223 """; | 1271 """; |
| 1224 return driverContent; | 1272 return driverContent; |
| 1225 } | 1273 } |
| 1226 } | 1274 } |
| OLD | NEW |