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

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

Issue 28533003: Capture and report stdout/stderr of the browser while running a test (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 2 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | tools/testing/dart/test_runner.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; 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
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
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
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « no previous file | tools/testing/dart/test_runner.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698