OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 | 4 |
5 /** | 5 /** |
6 * Classes and methods for enumerating and preparing tests. | 6 * Classes and methods for enumerating and preparing tests. |
7 * | 7 * |
8 * This library includes: | 8 * This library includes: |
9 * | 9 * |
10 * - Creating tests by listing all the Dart files in certain directories, | 10 * - Creating tests by listing all the Dart files in certain directories, |
11 * and creating [TestCase]s for those files that meet the relevant criteria. | 11 * and creating [TestCase]s for those files that meet the relevant criteria. |
12 * - Preparing tests, including copying files and frameworks to temporary | 12 * - Preparing tests, including copying files and frameworks to temporary |
13 * directories, and computing the command line and arguments to be run. | 13 * directories, and computing the command line and arguments to be run. |
14 */ | 14 */ |
15 library test_suite; | 15 library test_suite; |
16 | 16 |
17 import "dart:async"; | 17 import "dart:async"; |
18 import "dart:io"; | 18 import "dart:io"; |
19 import "dart:isolate"; | 19 import "dart:isolate"; |
20 import "dart:uri"; | 20 import "dart:uri"; |
21 import "drt_updater.dart"; | 21 import "drt_updater.dart"; |
22 import "multitest.dart"; | 22 import "multitest.dart"; |
23 import "status_file_parser.dart"; | 23 import "status_file_parser.dart"; |
24 import "test_runner.dart"; | 24 import "test_runner.dart"; |
25 import "utils.dart"; | 25 import "utils.dart"; |
26 | 26 import "http_server.dart" show PREFIX_BUILDDIR, PREFIX_DARTDIR; |
27 // TODO(efortuna,whess): Remove this import. | |
28 import 'vendored_pkg/path/path.dart' as pathLib; | |
29 | 27 |
30 part "browser_test.dart"; | 28 part "browser_test.dart"; |
31 | 29 |
32 | 30 |
33 // TODO(rnystrom): Add to dart:core? | 31 // TODO(rnystrom): Add to dart:core? |
34 /** | 32 /** |
35 * A simple function that tests [arg] and returns `true` or `false`. | 33 * A simple function that tests [arg] and returns `true` or `false`. |
36 */ | 34 */ |
37 typedef bool Predicate<T>(T arg); | 35 typedef bool Predicate<T>(T arg); |
38 | 36 |
(...skipping 766 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
805 hasCompileError, | 803 hasCompileError, |
806 hasRuntimeError, | 804 hasRuntimeError, |
807 isNegativeIfChecked, | 805 isNegativeIfChecked, |
808 hasFatalTypeErrors, | 806 hasFatalTypeErrors, |
809 multitestOutcome); | 807 multitestOutcome); |
810 cachedTests.add(info); | 808 cachedTests.add(info); |
811 enqueueTestCaseFromTestInformation(info); | 809 enqueueTestCaseFromTestInformation(info); |
812 }; | 810 }; |
813 } | 811 } |
814 | 812 |
815 /** | 813 |
| 814 /** |
| 815 * _createUrlPathFromFile takes a [file], which is either located in the dart |
| 816 * or in the build directory, and will return a String representing |
| 817 * the relative path to either the dart or the build directory. |
| 818 * Thus, the returned [String] will be the path component of the URL |
| 819 * corresponding to [file] (the http server serves files relative to the |
| 820 * dart/build directories). |
| 821 */ |
| 822 String _createUrlPathFromFile(Path file) { |
| 823 file = TestUtils.absolutePath(file); |
| 824 |
| 825 var relativeBuildDir = new Path(TestUtils.buildDir(configuration)); |
| 826 var buildDir = TestUtils.absolutePath(relativeBuildDir); |
| 827 var dartDir = TestUtils.absolutePath(TestUtils.dartDir()); |
| 828 |
| 829 var fileString = file.toString(); |
| 830 if (fileString.startsWith(buildDir.toString())) { |
| 831 var fileRelativeToBuildDir = file.relativeTo(buildDir); |
| 832 return "/$PREFIX_BUILDDIR/$fileRelativeToBuildDir"; |
| 833 } else if (fileString.startsWith(dartDir.toString())) { |
| 834 var fileRelativeToDartDir = file.relativeTo(dartDir); |
| 835 return "/$PREFIX_DARTDIR/$fileRelativeToDartDir"; |
| 836 } |
| 837 // Unreachable |
| 838 Except.fail('This should be unreachable.'); |
| 839 } |
| 840 |
| 841 void _getUriForBrowserTest(TestInformation info, |
| 842 String pathComponent, |
| 843 subtestNames, |
| 844 subtestIndex) { |
| 845 // Note: If we run test.py with the "--list" option, no http servers |
| 846 // will be started. Therefore serverList is an empty list in this |
| 847 // case. So we use PORT/CROSS_ORIGIN_PORT instead of real ports. |
| 848 var serverPort = "PORT"; |
| 849 var crossOriginPort = "CROSS_ORIGIN_PORT"; |
| 850 if (!configuration['list']) { |
| 851 serverPort = serverList[0].port.toString(); |
| 852 crossOriginPort = serverList[1].port.toString(); |
| 853 } |
| 854 |
| 855 var url= 'http://127.0.0.1:$serverPort$pathComponent' |
| 856 '?crossOriginPort=$crossOriginPort'; |
| 857 if (info.optionsFromFile['isMultiHtmlTest'] && subtestNames.length > 0) { |
| 858 url= '${url}&group=${subtestNames[subtestIndex]}'; |
| 859 } |
| 860 return url; |
| 861 } |
| 862 |
| 863 void _createWrapperFile(String dartWrapperFilename, dartLibraryFilename) { |
| 864 File file = new File(dartWrapperFilename); |
| 865 RandomAccessFile dartWrapper = file.openSync(FileMode.WRITE); |
| 866 |
| 867 var usePackageImport = dartLibraryFilename.segments().contains("pkg"); |
| 868 var libraryPathComponent = _createUrlPathFromFile(dartLibraryFilename); |
| 869 dartWrapper.writeStringSync(dartTestWrapper(usePackageImport, |
| 870 libraryPathComponent)); |
| 871 dartWrapper.closeSync(); |
| 872 } |
| 873 |
| 874 void _createLibraryWrapperFile(Path dartLibraryFilename, filePath) { |
| 875 File file = new File(dartLibraryFilename.toNativePath()); |
| 876 RandomAccessFile dartLibrary = file.openSync(FileMode.WRITE); |
| 877 var requestPath = new Path(PREFIX_DARTDIR) |
| 878 .join(filePath.relativeTo(TestUtils.dartDir())); |
| 879 dartLibrary.writeStringSync(wrapDartTestInLibrary(requestPath)); |
| 880 dartLibrary.closeSync(); |
| 881 } |
| 882 |
| 883 /** |
816 * The [StandardTestSuite] has support for tests that | 884 * The [StandardTestSuite] has support for tests that |
817 * compile a test from Dart to JavaScript, and then run the resulting | 885 * compile a test from Dart to JavaScript, and then run the resulting |
818 * JavaScript. This function creates a working directory to hold the | 886 * JavaScript. This function creates a working directory to hold the |
819 * JavaScript version of the test, and copies the appropriate framework | 887 * JavaScript version of the test, and copies the appropriate framework |
820 * files to that directory. It creates a [BrowserTestCase], which has | 888 * files to that directory. It creates a [BrowserTestCase], which has |
821 * two sequential steps to be run by the [ProcessQueue] when the test is | 889 * two sequential steps to be run by the [ProcessQueue] when the test is |
822 * executed: a compilation step and an execution step, both with the | 890 * executed: a compilation step and an execution step, both with the |
823 * appropriate executable and arguments. The [expectations] object can be | 891 * appropriate executable and arguments. The [expectations] object can be |
824 * either a Set<String> if the test is a regular test, or a Map<String | 892 * either a Set<String> if the test is a regular test, or a Map<String |
825 * subTestName, Set<String>> if we are running a browser multi-test (one | 893 * subTestName, Set<String>> if we are running a browser multi-test (one |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
860 String compiledDartWrapperFilename = '$tempDir/test.js'; | 928 String compiledDartWrapperFilename = '$tempDir/test.js'; |
861 | 929 |
862 String htmlPath = '$tempDir/test.html'; | 930 String htmlPath = '$tempDir/test.html'; |
863 if (isWrappingRequired && !isWebTest) { | 931 if (isWrappingRequired && !isWebTest) { |
864 // test.dart will import the dart test directly, if it is a library, | 932 // test.dart will import the dart test directly, if it is a library, |
865 // or indirectly through test_as_library.dart, if it is not. | 933 // or indirectly through test_as_library.dart, if it is not. |
866 Path dartLibraryFilename = filePath; | 934 Path dartLibraryFilename = filePath; |
867 if (!isLibraryDefinition) { | 935 if (!isLibraryDefinition) { |
868 dartLibraryFilename = new Path(tempDir).append( | 936 dartLibraryFilename = new Path(tempDir).append( |
869 'test_as_library.dart'); | 937 'test_as_library.dart'); |
870 File file = new File(dartLibraryFilename.toNativePath()); | 938 _createLibraryWrapperFile(dartLibraryFilename, filePath); |
871 RandomAccessFile dartLibrary = file.openSync(FileMode.WRITE); | |
872 dartLibrary.writeStringSync( | |
873 wrapDartTestInLibrary(filePath, file.name)); | |
874 dartLibrary.closeSync(); | |
875 } | 939 } |
876 | 940 _createWrapperFile(dartWrapperFilename, dartLibraryFilename); |
877 File file = new File(dartWrapperFilename); | |
878 RandomAccessFile dartWrapper = file.openSync(FileMode.WRITE); | |
879 dartWrapper.writeStringSync( | |
880 dartTestWrapper(dartDir, file.name, dartLibraryFilename)); | |
881 dartWrapper.closeSync(); | |
882 } else { | 941 } else { |
883 dartWrapperFilename = filename; | 942 dartWrapperFilename = filename; |
884 // TODO(whesse): Once test.py is retired, adjust the relative path in | 943 // TODO(whesse): Once test.py is retired, adjust the relative path in |
885 // the client/samples/dartcombat test to its css file, remove the | 944 // the client/samples/dartcombat test to its css file, remove the |
886 // "../../" from this path, and move this out of the isWebTest guard. | 945 // "../../" from this path, and move this out of the isWebTest guard. |
887 // Also remove getHtmlName, and just use test.html. | 946 // Also remove getHtmlName, and just use test.html. |
888 // TODO(efortuna): this shortening of htmlFilename is a band-aid until | 947 // TODO(efortuna): this shortening of htmlFilename is a band-aid until |
889 // the above TODO gets fixed. Windows cannot have paths that are longer | 948 // the above TODO gets fixed. Windows cannot have paths that are longer |
890 // than 260 characters, and without this hack, we were running past the | 949 // than 260 characters, and without this hack, we were running past the |
891 // the limit. | 950 // the limit. |
892 String htmlFilename = getHtmlName(filename); | 951 String htmlFilename = getHtmlName(filename); |
893 while ('$tempDir/../$htmlFilename'.length >= 260) { | 952 while ('$tempDir/../$htmlFilename'.length >= 260) { |
894 htmlFilename = htmlFilename.substring(htmlFilename.length~/2); | 953 htmlFilename = htmlFilename.substring(htmlFilename.length~/2); |
895 } | 954 } |
896 htmlPath = '$tempDir/../$htmlFilename'; | 955 htmlPath = '$tempDir/../$htmlFilename'; |
897 } | 956 } |
898 final String scriptPath = (compiler == 'none') ? | 957 String scriptPath = (compiler == 'none') ? |
899 dartWrapperFilename : compiledDartWrapperFilename; | 958 dartWrapperFilename : compiledDartWrapperFilename; |
| 959 scriptPath = _createUrlPathFromFile(new Path(scriptPath)); |
| 960 |
900 // Create the HTML file for the test. | 961 // Create the HTML file for the test. |
901 RandomAccessFile htmlTest = new File(htmlPath).openSync(FileMode.WRITE); | 962 RandomAccessFile htmlTest = new File(htmlPath).openSync(FileMode.WRITE); |
902 String content = null; | 963 String content = null; |
903 Path dir = filePath.directoryPath; | 964 Path dir = filePath.directoryPath; |
904 String nameNoExt = filePath.filenameWithoutExtension; | 965 String nameNoExt = filePath.filenameWithoutExtension; |
905 Path pngPath = dir.append('$nameNoExt.png'); | 966 Path pngPath = dir.append('$nameNoExt.png'); |
906 Path txtPath = dir.append('$nameNoExt.txt'); | 967 Path txtPath = dir.append('$nameNoExt.txt'); |
907 Path expectedOutput = null; | 968 Path expectedOutput = null; |
908 if (new File.fromPath(pngPath).existsSync()) { | 969 if (new File.fromPath(pngPath).existsSync()) { |
909 expectedOutput = pngPath; | 970 expectedOutput = pngPath; |
910 // TODO(efortuna): Unify path libraries in test.dart. | 971 content = getHtmlLayoutContents(scriptType, new Path("$scriptPath")); |
911 content = getHtmlLayoutContents(scriptType, pathLib.relative(scriptPath, | |
912 from: pathLib.dirname(htmlPath))); | |
913 } else if (new File.fromPath(txtPath).existsSync()) { | 972 } else if (new File.fromPath(txtPath).existsSync()) { |
914 expectedOutput = txtPath; | 973 expectedOutput = txtPath; |
915 content = getHtmlLayoutContents(scriptType, pathLib.relative(scriptPath, | 974 content = getHtmlLayoutContents(scriptType, new Path("$scriptPath")); |
916 from: pathLib.dirname(htmlPath))); | |
917 } else { | 975 } else { |
918 final htmlLocation = new Path(htmlPath); | 976 content = getHtmlContents(filename, scriptType, |
919 content = getHtmlContents( | 977 new Path("$scriptPath")); |
920 filename, | |
921 dartDir.append('pkg/unittest/lib/test_controller.js') | |
922 .relativeTo(htmlLocation), | |
923 dartDir.append('pkg/browser/lib/dart.js').relativeTo(htmlLocation), | |
924 scriptType, | |
925 new Path(scriptPath).relativeTo(htmlLocation)); | |
926 } | 978 } |
927 htmlTest.writeStringSync(content); | 979 htmlTest.writeStringSync(content); |
928 htmlTest.closeSync(); | 980 htmlTest.closeSync(); |
929 | 981 |
930 // Construct the command(s) that compile all the inputs needed by the | 982 // Construct the command(s) that compile all the inputs needed by the |
931 // browser test. For running Dart in DRT, this will be noop commands. | 983 // browser test. For running Dart in DRT, this will be noop commands. |
932 List<Command> commands = []; | 984 List<Command> commands = []; |
933 if (compiler != 'none') { | 985 if (compiler != 'none') { |
934 commands.add(_compileCommand( | 986 commands.add(_compileCommand( |
935 dartWrapperFilename, compiledDartWrapperFilename, | 987 dartWrapperFilename, compiledDartWrapperFilename, |
(...skipping 19 matching lines...) Expand all Loading... |
955 // Construct the command that executes the browser test | 1007 // Construct the command that executes the browser test |
956 do { | 1008 do { |
957 List<Command> commandSet = new List<Command>.from(commands); | 1009 List<Command> commandSet = new List<Command>.from(commands); |
958 if (subtestIndex != 0) { | 1010 if (subtestIndex != 0) { |
959 // NOTE: The first time we enter this loop, all the compilation | 1011 // NOTE: The first time we enter this loop, all the compilation |
960 // commands will be executed. On subsequent loop iterations, we | 1012 // commands will be executed. On subsequent loop iterations, we |
961 // don't need to do any compilations. Thus we set "commandSet = []". | 1013 // don't need to do any compilations. Thus we set "commandSet = []". |
962 commandSet = []; | 1014 commandSet = []; |
963 } | 1015 } |
964 | 1016 |
| 1017 var htmlPath_subtest = _createUrlPathFromFile(new Path(htmlPath)); |
| 1018 var fullHtmlPath = _getUriForBrowserTest(info, htmlPath_subtest, |
| 1019 subtestNames, subtestIndex); |
| 1020 |
965 List<String> args = <String>[]; | 1021 List<String> args = <String>[]; |
966 var basePath = TestUtils.dartDir().toString(); | |
967 if (!htmlPath.startsWith('/') && !htmlPath.startsWith('http')) { | |
968 htmlPath = '/$htmlPath'; | |
969 } | |
970 htmlPath = htmlPath.startsWith(basePath) ? | |
971 htmlPath.substring(basePath.length) : htmlPath; | |
972 String fullHtmlPath = htmlPath; | |
973 var searchStr = '?'; | |
974 if (!htmlPath.startsWith('http')) { | |
975 // Note: If we run test.py with the "--list" option, no http servers | |
976 // will be started. Therefore serverList is an empty list in this | |
977 // case. So we use PORT/CROSS_ORIGIN_PORT instead of real ports. | |
978 var serverPort = "PORT"; | |
979 var crossOriginPort = "CROSS_ORIGIN_PORT"; | |
980 if (!configuration['list']) { | |
981 serverPort = serverList[0].port.toString(); | |
982 crossOriginPort = serverList[1].port.toString(); | |
983 } | |
984 fullHtmlPath = 'http://127.0.0.1:$serverPort$htmlPath${searchStr}' | |
985 'crossOriginPort=$crossOriginPort'; | |
986 searchStr = '&'; | |
987 } | |
988 if (info.optionsFromFile['isMultiHtmlTest'] | |
989 && subtestNames.length > 0) { | |
990 fullHtmlPath = '${fullHtmlPath}${searchStr}group=' | |
991 '${subtestNames[subtestIndex]}'; | |
992 } | |
993 | |
994 if (TestUtils.usesWebDriver(runtime)) { | 1022 if (TestUtils.usesWebDriver(runtime)) { |
995 args = [ | 1023 args = [ |
996 dartDir.append('tools/testing/run_selenium.py').toNativePath(), | 1024 dartDir.append('tools/testing/run_selenium.py').toNativePath(), |
997 '--browser=$runtime', | 1025 '--browser=$runtime', |
998 '--timeout=${configuration["timeout"] - 2}', | 1026 '--timeout=${configuration["timeout"] - 2}', |
999 '--out="$fullHtmlPath"']; | 1027 '--out="$fullHtmlPath"']; |
1000 if (runtime == 'dartium') { | 1028 if (runtime == 'dartium') { |
1001 args.add('--executable=$dartiumFilename'); | 1029 args.add('--executable=$dartiumFilename'); |
1002 } | 1030 } |
1003 if (subtestIndex != 0) { | 1031 if (subtestIndex != 0) { |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1118 } | 1146 } |
1119 | 1147 |
1120 // Create '[build dir]/generated_tests/$compiler-$runtime/$testUniqueName', | 1148 // Create '[build dir]/generated_tests/$compiler-$runtime/$testUniqueName', |
1121 // including any intermediate directories that don't exist. | 1149 // including any intermediate directories that don't exist. |
1122 // If the tests are run in checked or minified mode we add that to the | 1150 // If the tests are run in checked or minified mode we add that to the |
1123 // '$compile-$runtime' directory name. | 1151 // '$compile-$runtime' directory name. |
1124 var checked = configuration['checked'] ? '-checked' : ''; | 1152 var checked = configuration['checked'] ? '-checked' : ''; |
1125 var minified = configuration['minified'] ? '-minified' : ''; | 1153 var minified = configuration['minified'] ? '-minified' : ''; |
1126 var dirName = "${configuration['compiler']}-${configuration['runtime']}" | 1154 var dirName = "${configuration['compiler']}-${configuration['runtime']}" |
1127 "$checked$minified"; | 1155 "$checked$minified"; |
1128 Path generatedTestPath = new Path(dartDir.toNativePath()) | 1156 Path generatedTestPath = new Path(buildDir) |
1129 .append(buildDir) | |
1130 .append('generated_tests') | 1157 .append('generated_tests') |
1131 .append(dirName) | 1158 .append(dirName) |
1132 .append(testUniqueName); | 1159 .append(testUniqueName); |
1133 | 1160 |
1134 TestUtils.mkdirRecursive(new Path('.'), generatedTestPath); | 1161 TestUtils.mkdirRecursive(new Path('.'), generatedTestPath); |
1135 return new File.fromPath(generatedTestPath).fullPathSync() | 1162 return new File.fromPath(generatedTestPath).fullPathSync() |
1136 .replaceAll('\\', '/'); | 1163 .replaceAll('\\', '/'); |
1137 } | 1164 } |
1138 | 1165 |
1139 String get scriptType { | 1166 String get scriptType { |
(...skipping 669 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1809 return BROWSERS.contains(runtime); | 1836 return BROWSERS.contains(runtime); |
1810 } | 1837 } |
1811 | 1838 |
1812 static bool isBrowserRuntime(String runtime) => | 1839 static bool isBrowserRuntime(String runtime) => |
1813 runtime == 'drt' || TestUtils.usesWebDriver(runtime); | 1840 runtime == 'drt' || TestUtils.usesWebDriver(runtime); |
1814 | 1841 |
1815 static bool isJsCommandLineRuntime(String runtime) => | 1842 static bool isJsCommandLineRuntime(String runtime) => |
1816 const ['d8', 'jsshell'].contains(runtime); | 1843 const ['d8', 'jsshell'].contains(runtime); |
1817 | 1844 |
1818 static String buildDir(Map configuration) { | 1845 static String buildDir(Map configuration) { |
| 1846 // FIXME(kustermann,ricow): Our code assumes that the returned 'buildDir' |
| 1847 // is relative to the current working directory. |
| 1848 // Thus, if we pass in an absolute path (e.g. '--build-directory=/tmp/out') |
| 1849 // we get into trouble. |
1819 if (configuration['build_directory'] != '') { | 1850 if (configuration['build_directory'] != '') { |
1820 return configuration['build_directory']; | 1851 return configuration['build_directory']; |
1821 } | 1852 } |
1822 var outputDir = ''; | 1853 var outputDir = ''; |
1823 var system = configuration['system']; | 1854 var system = configuration['system']; |
1824 if (system == 'linux') { | 1855 if (system == 'linux') { |
1825 outputDir = 'out/'; | 1856 outputDir = 'out/'; |
1826 } else if (system == 'macos') { | 1857 } else if (system == 'macos') { |
1827 outputDir = 'xcodebuild/'; | 1858 outputDir = 'xcodebuild/'; |
1828 } else if (system == 'windows') { | 1859 } else if (system == 'windows') { |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1910 * $pass tests are expected to pass | 1941 * $pass tests are expected to pass |
1911 * $failOk tests are expected to fail that we won't fix | 1942 * $failOk tests are expected to fail that we won't fix |
1912 * $fail tests are expected to fail that we should fix | 1943 * $fail tests are expected to fail that we should fix |
1913 * $crash tests are expected to crash that we should fix | 1944 * $crash tests are expected to crash that we should fix |
1914 * $timeout tests are allowed to timeout | 1945 * $timeout tests are allowed to timeout |
1915 * $compileErrorSkip tests are skipped on browsers due to compile-time error | 1946 * $compileErrorSkip tests are skipped on browsers due to compile-time error |
1916 """; | 1947 """; |
1917 print(report); | 1948 print(report); |
1918 } | 1949 } |
1919 } | 1950 } |
OLD | NEW |