| 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 30 matching lines...) Expand all Loading... |
| 41 | 41 |
| 42 /** Print everything (stdout, stderr, usageLog) whenever we add to it */ | 42 /** Print everything (stdout, stderr, usageLog) whenever we add to it */ |
| 43 bool debugPrint = false; | 43 bool debugPrint = false; |
| 44 | 44 |
| 45 // This future returns when the process exits. It is also the return value | 45 // This future returns when the process exits. It is also the return value |
| 46 // of close() | 46 // of close() |
| 47 Future done; | 47 Future done; |
| 48 | 48 |
| 49 Browser(); | 49 Browser(); |
| 50 | 50 |
| 51 factory Browser.byName(String name) { | 51 factory Browser.byName(String name, [Map globalConfiguration = const {}]) { |
| 52 if (name == 'ff' || name == 'firefox') { | 52 if (name == 'ff' || name == 'firefox') { |
| 53 return new Firefox(); | 53 return new Firefox(); |
| 54 } else if (name == 'chrome') { | 54 } else if (name == 'chrome') { |
| 55 return new Chrome(); | 55 return new Chrome(); |
| 56 } else if (name == 'dartium') { | 56 } else if (name == 'dartium') { |
| 57 return new Dartium(); | 57 return new Dartium(globalConfiguration); |
| 58 } else if (name == 'safari') { | 58 } else if (name == 'safari') { |
| 59 return new Safari(); | 59 return new Safari(); |
| 60 } else if (name.startsWith('ie')) { | 60 } else if (name.startsWith('ie')) { |
| 61 return new IE(); | 61 return new IE(); |
| 62 } else { | 62 } else { |
| 63 throw "Non supported browser"; | 63 throw "Non supported browser"; |
| 64 } | 64 } |
| 65 } | 65 } |
| 66 | 66 |
| 67 static const List<String> SUPPORTED_BROWSERS = | 67 static const List<String> SUPPORTED_BROWSERS = |
| (...skipping 318 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 386 }).catchError((e) { | 386 }).catchError((e) { |
| 387 _logEvent("Running $_binary --version failed with $e"); | 387 _logEvent("Running $_binary --version failed with $e"); |
| 388 return false; | 388 return false; |
| 389 }); | 389 }); |
| 390 } | 390 } |
| 391 | 391 |
| 392 String toString() => "Chrome"; | 392 String toString() => "Chrome"; |
| 393 } | 393 } |
| 394 | 394 |
| 395 class Dartium extends Chrome { | 395 class Dartium extends Chrome { |
| 396 final Map globalConfiguration; |
| 397 |
| 398 Dartium(this.globalConfiguration); |
| 399 |
| 396 String _getBinary() { | 400 String _getBinary() { |
| 397 if (Platform.operatingSystem == 'macos') { | 401 return Locations.getDartiumLocation(globalConfiguration); |
| 398 return new Path('client/tests/dartium/Chromium.app/Contents/' | |
| 399 'MacOS/Chromium').toNativePath(); | |
| 400 } | |
| 401 return new Path('client/tests/dartium/chrome').toNativePath(); | |
| 402 } | 402 } |
| 403 | 403 |
| 404 Map<String, String> _getEnvironment() { | 404 Map<String, String> _getEnvironment() { |
| 405 var environment = new Map<String,String>.from(Platform.environment); | 405 var environment = new Map<String,String>.from(Platform.environment); |
| 406 // By setting this environment variable, dartium will forward "print()" | 406 // By setting this environment variable, dartium will forward "print()" |
| 407 // calls in dart to the top-level javascript function "dartPrint()" if | 407 // calls in dart to the top-level javascript function "dartPrint()" if |
| 408 // available. | 408 // available. |
| 409 environment['DART_FORWARDING_PRINT'] = '1'; | 409 environment['DART_FORWARDING_PRINT'] = '1'; |
| 410 return environment; | 410 return environment; |
| 411 } | 411 } |
| (...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 621 } | 621 } |
| 622 | 622 |
| 623 | 623 |
| 624 /** | 624 /** |
| 625 * Encapsulates all the functionality for running tests in browsers. | 625 * Encapsulates all the functionality for running tests in browsers. |
| 626 * The interface is rather simple. After starting the runner tests | 626 * The interface is rather simple. After starting the runner tests |
| 627 * are simply added to the queue and a the supplied callbacks are called | 627 * are simply added to the queue and a the supplied callbacks are called |
| 628 * whenever a test completes. | 628 * whenever a test completes. |
| 629 */ | 629 */ |
| 630 class BrowserTestRunner { | 630 class BrowserTestRunner { |
| 631 String local_ip; | 631 final Map globalConfiguration; |
| 632 |
| 633 String localIp; |
| 632 String browserName; | 634 String browserName; |
| 633 int maxNumBrowsers; | 635 int maxNumBrowsers; |
| 634 // Used to send back logs from the browser (start, stop etc) | 636 // Used to send back logs from the browser (start, stop etc) |
| 635 Function logger; | 637 Function logger; |
| 636 int browserIdCount = 0; | 638 int browserIdCount = 0; |
| 637 | 639 |
| 638 bool underTermination = false; | 640 bool underTermination = false; |
| 639 | 641 |
| 640 List<BrowserTest> testQueue = new List<BrowserTest>(); | 642 List<BrowserTest> testQueue = new List<BrowserTest>(); |
| 641 Map<String, BrowserTestingStatus> browserStatus = | 643 Map<String, BrowserTestingStatus> browserStatus = |
| 642 new Map<String, BrowserTestingStatus>(); | 644 new Map<String, BrowserTestingStatus>(); |
| 643 | 645 |
| 644 var adbDeviceMapping = new Map<String, AdbDevice>(); | 646 var adbDeviceMapping = new Map<String, AdbDevice>(); |
| 645 // This cache is used to guarantee that we never see double reporting. | 647 // This cache is used to guarantee that we never see double reporting. |
| 646 // If we do we need to provide developers with this information. | 648 // If we do we need to provide developers with this information. |
| 647 // We don't add urls to the cache until we have run it. | 649 // We don't add urls to the cache until we have run it. |
| 648 Map<int, String> testCache = new Map<int, String>(); | 650 Map<int, String> testCache = new Map<int, String>(); |
| 649 Map<int, String> doubleReportingOutputs = new Map<int, String>(); | 651 Map<int, String> doubleReportingOutputs = new Map<int, String>(); |
| 650 | 652 |
| 651 BrowserTestingServer testingServer; | 653 BrowserTestingServer testingServer; |
| 652 | 654 |
| 653 BrowserTestRunner(this.local_ip, this.browserName, this.maxNumBrowsers); | 655 BrowserTestRunner(this.globalConfiguration, |
| 656 this.localIp, |
| 657 this.browserName, |
| 658 this.maxNumBrowsers); |
| 654 | 659 |
| 655 Future<bool> start() { | 660 Future<bool> start() { |
| 656 // If [browserName] doesn't support opening new windows, we use new iframes | 661 // If [browserName] doesn't support opening new windows, we use new iframes |
| 657 // instead. | 662 // instead. |
| 658 bool useIframe = | 663 bool useIframe = |
| 659 !Browser.BROWSERS_WITH_WINDOW_SUPPORT.contains(browserName); | 664 !Browser.BROWSERS_WITH_WINDOW_SUPPORT.contains(browserName); |
| 660 testingServer = new BrowserTestingServer(local_ip, useIframe); | 665 testingServer = new BrowserTestingServer(localIp, useIframe); |
| 661 return testingServer.start().then((_) { | 666 return testingServer.start().then((_) { |
| 662 testingServer.testDoneCallBack = handleResults; | 667 testingServer.testDoneCallBack = handleResults; |
| 663 testingServer.testStartedCallBack = handleStarted; | 668 testingServer.testStartedCallBack = handleStarted; |
| 664 testingServer.nextTestCallBack = getNextTest; | 669 testingServer.nextTestCallBack = getNextTest; |
| 665 return getBrowsers().then((browsers) { | 670 return getBrowsers().then((browsers) { |
| 666 var futures = []; | 671 var futures = []; |
| 667 for (var browser in browsers) { | 672 for (var browser in browsers) { |
| 668 var url = testingServer.getDriverUrl(browser.id); | 673 var url = testingServer.getDriverUrl(browser.id); |
| 669 var future = browser.start(url).then((success) { | 674 var future = browser.start(url).then((success) { |
| 670 if (success) { | 675 if (success) { |
| (...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 886 } | 891 } |
| 887 return Future.wait(futures).then((values) { | 892 return Future.wait(futures).then((values) { |
| 888 testingServer.httpServer.close(); | 893 testingServer.httpServer.close(); |
| 889 testingServer.errorReportingServer.close(); | 894 testingServer.errorReportingServer.close(); |
| 890 printDoubleReportingTests(); | 895 printDoubleReportingTests(); |
| 891 return !values.contains(false); | 896 return !values.contains(false); |
| 892 }); | 897 }); |
| 893 } | 898 } |
| 894 | 899 |
| 895 Browser getInstance() { | 900 Browser getInstance() { |
| 896 var browser = new Browser.byName(browserName); | 901 var browser = new Browser.byName(browserName, globalConfiguration); |
| 897 browser.logger = logger; | 902 browser.logger = logger; |
| 898 return browser; | 903 return browser; |
| 899 } | 904 } |
| 900 } | 905 } |
| 901 | 906 |
| 902 class BrowserTestingServer { | 907 class BrowserTestingServer { |
| 903 /// Interface of the testing server: | 908 /// Interface of the testing server: |
| 904 /// | 909 /// |
| 905 /// GET /driver/BROWSER_ID -- This will get the driver page to fetch | 910 /// GET /driver/BROWSER_ID -- This will get the driver page to fetch |
| 906 /// and run tests ... | 911 /// and run tests ... |
| 907 /// GET /next_test/BROWSER_ID -- returns "WAIT" "TERMINATE" or "url#id" | 912 /// GET /next_test/BROWSER_ID -- returns "WAIT" "TERMINATE" or "url#id" |
| 908 /// where url is the test to run, and id is the id of the test. | 913 /// where url is the test to run, and id is the id of the test. |
| 909 /// If there are currently no available tests the waitSignal is send | 914 /// If there are currently no available tests the waitSignal is send |
| 910 /// back. If we are in the process of terminating the terminateSignal | 915 /// back. If we are in the process of terminating the terminateSignal |
| 911 /// is send back and the browser will stop requesting new tasks. | 916 /// is send back and the browser will stop requesting new tasks. |
| 912 /// POST /report/BROWSER_ID?id=NUM -- sends back the dom of the executed | 917 /// POST /report/BROWSER_ID?id=NUM -- sends back the dom of the executed |
| 913 /// test | 918 /// test |
| 914 | 919 |
| 915 final String local_ip; | 920 final String localIp; |
| 916 | 921 |
| 917 static const String driverPath = "/driver"; | 922 static const String driverPath = "/driver"; |
| 918 static const String nextTestPath = "/next_test"; | 923 static const String nextTestPath = "/next_test"; |
| 919 static const String reportPath = "/report"; | 924 static const String reportPath = "/report"; |
| 920 static const String startedPath = "/started"; | 925 static const String startedPath = "/started"; |
| 921 static const String waitSignal = "WAIT"; | 926 static const String waitSignal = "WAIT"; |
| 922 static const String terminateSignal = "TERMINATE"; | 927 static const String terminateSignal = "TERMINATE"; |
| 923 | 928 |
| 924 var testCount = 0; | 929 var testCount = 0; |
| 925 var httpServer; | 930 var httpServer; |
| 926 var errorReportingServer; | 931 var errorReportingServer; |
| 927 bool underTermination = false; | 932 bool underTermination = false; |
| 928 bool useIframe = false; | 933 bool useIframe = false; |
| 929 | 934 |
| 930 Function testDoneCallBack; | 935 Function testDoneCallBack; |
| 931 Function testStartedCallBack; | 936 Function testStartedCallBack; |
| 932 Function nextTestCallBack; | 937 Function nextTestCallBack; |
| 933 | 938 |
| 934 BrowserTestingServer(this.local_ip, this.useIframe); | 939 BrowserTestingServer(this.localIp, this.useIframe); |
| 935 | 940 |
| 936 Future start() { | 941 Future start() { |
| 937 return HttpServer.bind(local_ip, 0).then((createdServer) { | 942 return HttpServer.bind(localIp, 0).then((createdServer) { |
| 938 httpServer = createdServer; | 943 httpServer = createdServer; |
| 939 void handler(HttpRequest request) { | 944 void handler(HttpRequest request) { |
| 940 // Don't allow caching of resources from the browser controller, i.e., | 945 // Don't allow caching of resources from the browser controller, i.e., |
| 941 // we don't want the browser to cache the result of getNextTest. | 946 // we don't want the browser to cache the result of getNextTest. |
| 942 request.response.headers.set("Cache-Control", | 947 request.response.headers.set("Cache-Control", |
| 943 "no-cache, no-store, must-revalidate"); | 948 "no-cache, no-store, must-revalidate"); |
| 944 if (request.uri.path.startsWith(reportPath)) { | 949 if (request.uri.path.startsWith(reportPath)) { |
| 945 var browserId = request.uri.path.substring(reportPath.length + 1); | 950 var browserId = request.uri.path.substring(reportPath.length + 1); |
| 946 var testId = | 951 var testId = |
| 947 int.parse(request.uri.queryParameters["id"].split("=")[1]); | 952 int.parse(request.uri.queryParameters["id"].split("=")[1]); |
| (...skipping 30 matching lines...) Expand all Loading... |
| 978 }); | 983 }); |
| 979 } | 984 } |
| 980 void errorHandler(e) { | 985 void errorHandler(e) { |
| 981 if (!underTermination) print("Error occured in httpserver: $e"); | 986 if (!underTermination) print("Error occured in httpserver: $e"); |
| 982 }; | 987 }; |
| 983 | 988 |
| 984 httpServer.listen(handler, onError: errorHandler); | 989 httpServer.listen(handler, onError: errorHandler); |
| 985 | 990 |
| 986 // Set up the error reporting server that enables us to send back | 991 // Set up the error reporting server that enables us to send back |
| 987 // errors from the browser. | 992 // errors from the browser. |
| 988 return HttpServer.bind(local_ip, 0).then((createdReportServer) { | 993 return HttpServer.bind(localIp, 0).then((createdReportServer) { |
| 989 errorReportingServer = createdReportServer; | 994 errorReportingServer = createdReportServer; |
| 990 void errorReportingHandler(HttpRequest request) { | 995 void errorReportingHandler(HttpRequest request) { |
| 991 StringBuffer buffer = new StringBuffer(); | 996 StringBuffer buffer = new StringBuffer(); |
| 992 request.transform(UTF8.decoder).listen((data) { | 997 request.transform(UTF8.decoder).listen((data) { |
| 993 buffer.write(data); | 998 buffer.write(data); |
| 994 }, onDone: () { | 999 }, onDone: () { |
| 995 String back = buffer.toString(); | 1000 String back = buffer.toString(); |
| 996 request.response.headers.set("Access-Control-Allow-Origin", "*"); | 1001 request.response.headers.set("Access-Control-Allow-Origin", "*"); |
| 997 request.response.done.catchError((error) { | 1002 request.response.done.catchError((error) { |
| 998 DebugLogger.error("Error getting error from browser" | 1003 DebugLogger.error("Error getting error from browser" |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1050 } | 1055 } |
| 1051 } | 1056 } |
| 1052 | 1057 |
| 1053 String getDriverUrl(String browserId) { | 1058 String getDriverUrl(String browserId) { |
| 1054 if (httpServer == null) { | 1059 if (httpServer == null) { |
| 1055 print("Bad browser testing server, you are not started yet. Can't " | 1060 print("Bad browser testing server, you are not started yet. Can't " |
| 1056 "produce driver url"); | 1061 "produce driver url"); |
| 1057 exit(1); | 1062 exit(1); |
| 1058 // This should never happen - exit immediately; | 1063 // This should never happen - exit immediately; |
| 1059 } | 1064 } |
| 1060 return "http://$local_ip:${httpServer.port}/driver/$browserId"; | 1065 return "http://$localIp:${httpServer.port}/driver/$browserId"; |
| 1061 } | 1066 } |
| 1062 | 1067 |
| 1063 | 1068 |
| 1064 String getDriverPage(String browserId) { | 1069 String getDriverPage(String browserId) { |
| 1065 var errorReportingUrl = | 1070 var errorReportingUrl = |
| 1066 "http://$local_ip:${errorReportingServer.port}/$browserId"; | 1071 "http://$localIp:${errorReportingServer.port}/$browserId"; |
| 1067 String driverContent = """ | 1072 String driverContent = """ |
| 1068 <!DOCTYPE html><html> | 1073 <!DOCTYPE html><html> |
| 1069 <head> | 1074 <head> |
| 1070 <title>Driving page</title> | 1075 <title>Driving page</title> |
| 1071 <script type='text/javascript'> | 1076 <script type='text/javascript'> |
| 1072 | 1077 |
| 1073 function startTesting() { | 1078 function startTesting() { |
| 1074 var number_of_tests = 0; | 1079 var number_of_tests = 0; |
| 1075 var current_id; | 1080 var current_id; |
| 1076 var next_id; | 1081 var next_id; |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1212 Dart test driver, number of tests: <div id="number"></div><br> | 1217 Dart test driver, number of tests: <div id="number"></div><br> |
| 1213 Currently executing: <div id="currently_executing"></div><br> | 1218 Currently executing: <div id="currently_executing"></div><br> |
| 1214 Unhandled error: <div id="unhandled_error"></div> | 1219 Unhandled error: <div id="unhandled_error"></div> |
| 1215 <iframe id="embedded_iframe"></iframe> | 1220 <iframe id="embedded_iframe"></iframe> |
| 1216 </body> | 1221 </body> |
| 1217 </html> | 1222 </html> |
| 1218 """; | 1223 """; |
| 1219 return driverContent; | 1224 return driverContent; |
| 1220 } | 1225 } |
| 1221 } | 1226 } |
| OLD | NEW |