| 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:core"; | 7 import "dart:core"; |
| 8 import "dart:io"; | 8 import "dart:io"; |
| 9 | 9 |
| 10 import 'android.dart'; | 10 import 'android.dart'; |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 43 * Id of the browser | 43 * Id of the browser |
| 44 */ | 44 */ |
| 45 String id; | 45 String id; |
| 46 | 46 |
| 47 /** Callback that will be executed when the browser has closed */ | 47 /** Callback that will be executed when the browser has closed */ |
| 48 Function onClose; | 48 Function onClose; |
| 49 | 49 |
| 50 /** Print everything (stdout, stderr, usageLog) whenever we add to it */ | 50 /** Print everything (stdout, stderr, usageLog) whenever we add to it */ |
| 51 bool debugPrint = false; | 51 bool debugPrint = false; |
| 52 | 52 |
| 53 // We use this to gracefully handle double calls to close. | 53 // This future will be lazily set when calling close() and will complete once |
| 54 bool underTermination = false; | 54 // the process did exit. |
| 55 Future browserTerminationFuture; |
| 55 | 56 |
| 56 Browser(); | 57 Browser(); |
| 57 | 58 |
| 58 factory Browser.byName(String name) { | 59 factory Browser.byName(String name) { |
| 59 if (name == 'ff' || name == 'firefox') { | 60 if (name == 'ff' || name == 'firefox') { |
| 60 return new Firefox(); | 61 return new Firefox(); |
| 61 } else if (name == 'chrome') { | 62 } else if (name == 'chrome') { |
| 62 return new Chrome(); | 63 return new Chrome(); |
| 63 } else if (name == 'safari') { | 64 } else if (name == 'safari') { |
| 64 return new Safari(); | 65 return new Safari(); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 88 void _addStdout(String output) { | 89 void _addStdout(String output) { |
| 89 if (debugPrint) print("stdout: $output"); | 90 if (debugPrint) print("stdout: $output"); |
| 90 _stdout.write(output); | 91 _stdout.write(output); |
| 91 } | 92 } |
| 92 | 93 |
| 93 void _addStderr(String output) { | 94 void _addStderr(String output) { |
| 94 if (debugPrint) print("stderr: $output"); | 95 if (debugPrint) print("stderr: $output"); |
| 95 _stderr.write(output); | 96 _stderr.write(output); |
| 96 } | 97 } |
| 97 | 98 |
| 98 // Kill the underlying process using the supplied kill function | 99 Future close() { |
| 99 // If there is a alternativeKillFunction we will use that after trying | 100 _logEvent("Close called on browser"); |
| 100 // the default killFunction. | 101 if (browserTerminationFuture == null) { |
| 101 Future _killIt(killFunction, retries, [alternativeKillFunction = null]) { | 102 var completer = new Completer(); |
| 102 Completer<bool> completer = new Completer<bool>(); | 103 browserTerminationFuture = completer.future; |
| 103 | 104 |
| 104 // To capture non successfull attempts we set up a timer that will | 105 if (process != null) { |
| 105 // trigger a retry (using the alternativeKillFunction if supplied). | 106 // Make sure we intercept onExit calls and complete. |
| 106 Timer timer = new Timer(killRepeatInternal, () { | 107 _processClosed = () { |
| 107 // Remove the handler, we will set this again in the call to killIt | 108 _processClosed = null; |
| 108 // below | 109 process = null; |
| 109 if (retries <= 0) { | 110 completer.complete(true); |
| 110 _logEvent("Could not kill the process, not trying anymore"); | 111 }; |
| 111 // TODO(ricow): Should we crash the test script here and | 112 |
| 112 // write out all our log. This is basically not a situation | 113 if (process.kill(ProcessSignal.SIGKILL)) { |
| 113 // that we want to ignore. We could potentially have a handler we | 114 _logEvent("Successfully sent kill signal to process."); |
| 114 // can call if this happens, which will shutdown the main process | 115 } else { |
| 115 // with info that people should contact [ricow,kustermann,?] | 116 _logEvent("Sending kill signal failed."); |
| 116 completer.complete(false); | 117 } |
| 118 } else { |
| 119 _logEvent("The process is already dead."); |
| 120 completer.complete(true); |
| 117 } | 121 } |
| 118 _logEvent("Could not kill the process, retrying"); | |
| 119 var nextKillFunction = killFunction; | |
| 120 if (alternativeKillFunction != null) { | |
| 121 nextKillFunction = alternativeKillFunction; | |
| 122 } | |
| 123 _killIt(nextKillFunction, retries - 1).then((success) { | |
| 124 completer.complete(success); | |
| 125 }); | |
| 126 }); | |
| 127 | |
| 128 // Make sure we intercept onExit calls and eliminate the timer. | |
| 129 _processClosed = () { | |
| 130 timer.cancel(); | |
| 131 _logEvent("Proccess exited, cancel timer in kill loop"); | |
| 132 _processClosed = null; | |
| 133 process = null; | |
| 134 completer.complete(true); | |
| 135 }; | |
| 136 | |
| 137 | |
| 138 _logEvent("calling kill function"); | |
| 139 if (process != null && killFunction()) { | |
| 140 // We successfully sent the signal. | |
| 141 _logEvent("killing signal sent"); | |
| 142 } else { | |
| 143 _logEvent("The process is already dead, kill signal could not be send"); | |
| 144 completer.complete(true); | |
| 145 } | 122 } |
| 146 return completer.future; | 123 return browserTerminationFuture; |
| 147 } | |
| 148 | |
| 149 | |
| 150 /** Close the browser */ | |
| 151 Future<bool> close() { | |
| 152 _logEvent("Close called on browser"); | |
| 153 if (underTermination) { | |
| 154 _logEvent("Browser already under termination."); | |
| 155 return new Future.immediate(true); | |
| 156 } | |
| 157 underTermination = true; | |
| 158 if (process == null) { | |
| 159 _logEvent("No process open, nothing to kill."); | |
| 160 return new Future.immediate(true); | |
| 161 } | |
| 162 var killFunction = process.kill; | |
| 163 // We use a SIGKILL signal if we don't kill the process in the first go. | |
| 164 var alternativeKillFunction = | |
| 165 () { return process.kill(ProcessSignal.SIGKILL);}; | |
| 166 return _killIt(killFunction, killRetries, alternativeKillFunction); | |
| 167 } | 124 } |
| 168 | 125 |
| 169 /** | 126 /** |
| 170 * Start the browser using the supplied argument. | 127 * Start the browser using the supplied argument. |
| 171 * This sets up the error handling and usage logging. | 128 * This sets up the error handling and usage logging. |
| 172 */ | 129 */ |
| 173 Future<bool> startBrowser(String command, List<String> arguments) { | 130 Future<bool> startBrowser(String command, List<String> arguments) { |
| 174 return Process.start(command, arguments).then((startedProcess) { | 131 return Process.start(command, arguments).then((startedProcess) { |
| 175 process = startedProcess; | 132 process = startedProcess; |
| 176 process.stdout.transform(new StringDecoder()).listen((data) { | 133 process.stdout.transform(new StringDecoder()).listen((data) { |
| (...skipping 783 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 960 </head> | 917 </head> |
| 961 <body onload="startTesting()"> | 918 <body onload="startTesting()"> |
| 962 Dart test driver, number of tests: <div id="number"></div> | 919 Dart test driver, number of tests: <div id="number"></div> |
| 963 <iframe id="embedded_iframe"></iframe> | 920 <iframe id="embedded_iframe"></iframe> |
| 964 </body> | 921 </body> |
| 965 </html> | 922 </html> |
| 966 """; | 923 """; |
| 967 return driverContent; | 924 return driverContent; |
| 968 } | 925 } |
| 969 } | 926 } |
| OLD | NEW |