| 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 30 matching lines...) Expand all Loading... |
| 41 * Id of the browser | 41 * Id of the browser |
| 42 */ | 42 */ |
| 43 String id; | 43 String id; |
| 44 | 44 |
| 45 /** Callback that will be executed when the browser has closed */ | 45 /** Callback that will be executed when the browser has closed */ |
| 46 Function onClose; | 46 Function onClose; |
| 47 | 47 |
| 48 /** Print everything (stdout, stderr, usageLog) whenever we add to it */ | 48 /** Print everything (stdout, stderr, usageLog) whenever we add to it */ |
| 49 bool debugPrint = true; | 49 bool debugPrint = true; |
| 50 | 50 |
| 51 // We use this to gracefully handle double calls to close. |
| 52 bool underTermination = false; |
| 53 |
| 51 void _logEvent(String event) { | 54 void _logEvent(String event) { |
| 52 String toLog = "$this ($id) - ${new DateTime.now()}: $event \n"; | 55 String toLog = "$this ($id) - ${new DateTime.now()}: $event \n"; |
| 53 if (debugPrint) print("usageLog: $toLog"); | 56 if (debugPrint) print("usageLog: $toLog"); |
| 54 _usageLog.write(toLog); | 57 _usageLog.write(toLog); |
| 55 } | 58 } |
| 56 | 59 |
| 57 void _addStdout(String output) { | 60 void _addStdout(String output) { |
| 58 if (debugPrint) print("stdout: $output"); | 61 if (debugPrint) print("stdout: $output"); |
| 59 _stdout.write(output); | 62 _stdout.write(output); |
| 60 } | 63 } |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 112 _logEvent("The process is already dead, kill signal could not be send"); | 115 _logEvent("The process is already dead, kill signal could not be send"); |
| 113 completer.complete(true); | 116 completer.complete(true); |
| 114 } | 117 } |
| 115 return completer.future; | 118 return completer.future; |
| 116 } | 119 } |
| 117 | 120 |
| 118 | 121 |
| 119 /** Close the browser */ | 122 /** Close the browser */ |
| 120 Future<bool> close() { | 123 Future<bool> close() { |
| 121 _logEvent("Close called on browser"); | 124 _logEvent("Close called on browser"); |
| 125 if (underTermination) { |
| 126 _logEvent("Browser already under termination."); |
| 127 return new Future.immediate(true); |
| 128 } |
| 129 underTermination = true; |
| 122 if (process == null) { | 130 if (process == null) { |
| 123 _logEvent("No process open, nothing to kill."); | 131 _logEvent("No process open, nothing to kill."); |
| 124 return new Future.immediate(true); | 132 return new Future.immediate(true); |
| 125 } | 133 } |
| 126 var killFunction = process.kill; | 134 var killFunction = process.kill; |
| 127 // We use a SIGKILL signal if we don't kill the process in the first go. | 135 // We use a SIGKILL signal if we don't kill the process in the first go. |
| 128 var alternativeKillFunction = | 136 var alternativeKillFunction = |
| 129 () { return process.kill(ProcessSignal.SIGKILL);}; | 137 () { return process.kill(ProcessSignal.SIGKILL);}; |
| 130 return _killIt(killFunction, killRetries, alternativeKillFunction); | 138 return _killIt(killFunction, killRetries, alternativeKillFunction); |
| 131 } | 139 } |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 171 */ | 179 */ |
| 172 String get stdout => _stdout.toString(); | 180 String get stdout => _stdout.toString(); |
| 173 String get stderr => _stderr.toString(); | 181 String get stderr => _stderr.toString(); |
| 174 String get usageLog => _usageLog.toString(); | 182 String get usageLog => _usageLog.toString(); |
| 175 | 183 |
| 176 String toString(); | 184 String toString(); |
| 177 /** Starts the browser loading the given url */ | 185 /** Starts the browser loading the given url */ |
| 178 Future<bool> start(String url); | 186 Future<bool> start(String url); |
| 179 } | 187 } |
| 180 | 188 |
| 189 class Safari extends Browser { |
| 190 /** |
| 191 * The binary used to run safari - changing this can be nececcary for |
| 192 * testing or using non standard safari installation. |
| 193 */ |
| 194 const String binary = "/Applications/Safari.app/Contents/MacOS/Safari"; |
| 195 |
| 196 /** |
| 197 * We get the safari version by parsing a version file |
| 198 */ |
| 199 const String versionFile = "/Applications/Safari.app/Contents/version.plist"; |
| 200 |
| 201 Future<String> getVersion() { |
| 202 /** |
| 203 * Example of the file: |
| 204 * <?xml version="1.0" encoding="UTF-8"?> |
| 205 * <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.co
m/DTDs/PropertyList-1.0.dtd"> |
| 206 * <plist version="1.0"> |
| 207 * <dict> |
| 208 * <key>BuildVersion</key> |
| 209 * <string>2</string> |
| 210 * <key>CFBundleShortVersionString</key> |
| 211 * <string>6.0.4</string> |
| 212 * <key>CFBundleVersion</key> |
| 213 * <string>8536.29.13</string> |
| 214 * <key>ProjectName</key> |
| 215 * <string>WebBrowser</string> |
| 216 * <key>SourceVersion</key> |
| 217 * <string>7536029013000000</string> |
| 218 * </dict> |
| 219 * </plist> |
| 220 */ |
| 221 File f = new File(versionFile); |
| 222 return f.readAsLines().then((content) { |
| 223 bool versionOnNextLine = false; |
| 224 for (var line in content) { |
| 225 if (versionOnNextLine) return line; |
| 226 if (line.contains("CFBundleShortVersionString")) { |
| 227 versionOnNextLine = true; |
| 228 } |
| 229 } |
| 230 return null; |
| 231 }); |
| 232 } |
| 233 |
| 234 void _createLaunchHTML(var path, var url) { |
| 235 var file = new File("${path}/launch.html"); |
| 236 var randomFile = file.openSync(FileMode.WRITE); |
| 237 var content = '<script language="JavaScript">location = "$url"</script>'; |
| 238 randomFile.writeStringSync(content); |
| 239 randomFile.close(); |
| 240 } |
| 241 |
| 242 Future<bool> start(String url) { |
| 243 _logEvent("Starting Safari browser on: $url"); |
| 244 // Get the version and log that. |
| 245 return getVersion().then((version) { |
| 246 _logEvent("Got version: $version"); |
| 247 var args = ["'$url'"]; |
| 248 return new Directory('').createTemp().then((userDir) { |
| 249 _cleanup = () { userDir.delete(recursive: true); }; |
| 250 _createLaunchHTML(userDir.path, url); |
| 251 var args = ["${userDir.path}/launch.html"]; |
| 252 return startBrowser(binary, args); |
| 253 }); |
| 254 }).catchError((e) { |
| 255 _logEvent("Running $binary --version failed with $e"); |
| 256 return false; |
| 257 }); |
| 258 } |
| 259 |
| 260 String toString() => "Safari"; |
| 261 } |
| 262 |
| 263 |
| 181 class Chrome extends Browser { | 264 class Chrome extends Browser { |
| 182 /** | 265 /** |
| 183 * The binary used to run chrome - changing this can be nececcary for | 266 * The binary used to run chrome - changing this can be nececcary for |
| 184 * testing or using non standard chrome installation. | 267 * testing or using non standard chrome installation. |
| 185 */ | 268 */ |
| 186 const String binary = "google-chrome"; | 269 const String binary = "google-chrome"; |
| 187 | 270 |
| 188 Future<bool> start(String url) { | 271 Future<bool> start(String url) { |
| 189 _logEvent("Starting chrome browser on: $url"); | 272 _logEvent("Starting chrome browser on: $url"); |
| 190 // Get the version and log that. | 273 // Get the version and log that. |
| (...skipping 320 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 511 // We could be smarter here, but it does not seems like it is worth it. | 594 // We could be smarter here, but it does not seems like it is worth it. |
| 512 status.timeout = true; | 595 status.timeout = true; |
| 513 timedOut.add(status.currentTest.url); | 596 timedOut.add(status.currentTest.url); |
| 514 var id = status.browser.id; | 597 var id = status.browser.id; |
| 515 status.browser.close().then((closed) { | 598 status.browser.close().then((closed) { |
| 516 if (!closed) { | 599 if (!closed) { |
| 517 // Very bad, we could not kill the browser. | 600 // Very bad, we could not kill the browser. |
| 518 print("could not kill browser $id"); | 601 print("could not kill browser $id"); |
| 519 return; | 602 return; |
| 520 } | 603 } |
| 604 // We don't want to start a new browser if we are terminating. |
| 605 if (underTermination) return; |
| 606 |
| 521 var browser; | 607 var browser; |
| 522 if (browserName == 'chromeOnAndroid') { | 608 if (browserName == 'chromeOnAndroid') { |
| 523 browser = new AndroidChrome(adbDeviceMapping[id]); | 609 browser = new AndroidChrome(adbDeviceMapping[id]); |
| 524 } else { | 610 } else { |
| 525 browser = getInstance(); | 611 browser = getInstance(); |
| 526 } | 612 } |
| 527 browser.start(testingServer.getDriverUrl(id)).then((success) { | 613 browser.start(testingServer.getDriverUrl(id)).then((success) { |
| 528 // We may have started terminating in the mean time. | 614 // We may have started terminating in the mean time. |
| 529 if (underTermination) { | 615 if (underTermination) { |
| 530 browser.close().then((success) { | 616 browser.close().then((success) { |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 604 printDoubleReportingTests(); | 690 printDoubleReportingTests(); |
| 605 return !values.contains(false); | 691 return !values.contains(false); |
| 606 }); | 692 }); |
| 607 } | 693 } |
| 608 | 694 |
| 609 Browser getInstance() { | 695 Browser getInstance() { |
| 610 if (browserName == "chrome") { | 696 if (browserName == "chrome") { |
| 611 return new Chrome(); | 697 return new Chrome(); |
| 612 } else if (browserName == "ff") { | 698 } else if (browserName == "ff") { |
| 613 return new Firefox(); | 699 return new Firefox(); |
| 700 } else if (browserName == "safari") { |
| 701 return new Safari(); |
| 614 } else { | 702 } else { |
| 615 throw "Non supported browser for browser controller"; | 703 throw "Non supported browser for browser controller"; |
| 616 } | 704 } |
| 617 } | 705 } |
| 618 } | 706 } |
| 619 | 707 |
| 620 class BrowserTestingServer { | 708 class BrowserTestingServer { |
| 621 /// Interface of the testing server: | 709 /// Interface of the testing server: |
| 622 /// | 710 /// |
| 623 /// GET /driver/BROWSER_ID -- This will get the driver page to fetch | 711 /// GET /driver/BROWSER_ID -- This will get the driver page to fetch |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 666 textResponse = getDriverPage(browserId); | 754 textResponse = getDriverPage(browserId); |
| 667 } else if (request.uri.path.startsWith(nextTestPath)) { | 755 } else if (request.uri.path.startsWith(nextTestPath)) { |
| 668 var browserId = request.uri.path.substring(nextTestPath.length + 1); | 756 var browserId = request.uri.path.substring(nextTestPath.length + 1); |
| 669 textResponse = getNextTest(browserId); | 757 textResponse = getNextTest(browserId); |
| 670 } else { | 758 } else { |
| 671 // We silently ignore other requests. | 759 // We silently ignore other requests. |
| 672 } | 760 } |
| 673 request.response.write(textResponse); | 761 request.response.write(textResponse); |
| 674 request.listen((_) {}, onDone: request.response.close); | 762 request.listen((_) {}, onDone: request.response.close); |
| 675 request.response.done.catchError((error) { | 763 request.response.done.catchError((error) { |
| 676 if (!underTermination) { | 764 if (!underTermination) { |
| 677 print("URI ${request.uri}"); | 765 print("URI ${request.uri}"); |
| 678 print("Textresponse $textResponse"); | 766 print("Textresponse $textResponse"); |
| 679 throw("Error returning content to browser: $error"); | 767 throw "Error returning content to browser: $error"; |
| 680 } | 768 } |
| 681 }); | 769 }); |
| 682 } | 770 } |
| 683 void errorHandler(e) { | 771 void errorHandler(e) { |
| 684 if (!underTermination) print("Error occured in httpserver: $e"); | 772 if (!underTermination) print("Error occured in httpserver: $e"); |
| 685 }; | 773 }; |
| 686 httpServer.listen(handler, onError: errorHandler); | 774 httpServer.listen(handler, onError: errorHandler); |
| 687 return true; | 775 return true; |
| 688 }); | 776 }); |
| 689 } | 777 } |
| 690 | 778 |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 821 </script> | 909 </script> |
| 822 </head> | 910 </head> |
| 823 <body> | 911 <body> |
| 824 Dart test driver, number of tests: <div id="number"></div> | 912 Dart test driver, number of tests: <div id="number"></div> |
| 825 </body> | 913 </body> |
| 826 </html> | 914 </html> |
| 827 """; | 915 """; |
| 828 return driverContent; | 916 return driverContent; |
| 829 } | 917 } |
| 830 } | 918 } |
| OLD | NEW |