run-api-tests 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. #!/usr/bin/perl -w
  2. # Copyright (C) 2010, 2011, 2012 Apple Inc. All rights reserved.
  3. #
  4. # Redistribution and use in source and binary forms, with or without
  5. # modification, are permitted provided that the following conditions
  6. # are met:
  7. # 1. Redistributions of source code must retain the above copyright
  8. # notice, this list of conditions and the following disclaimer.
  9. # 2. Redistributions in binary form must reproduce the above copyright
  10. # notice, this list of conditions and the following disclaimer in the
  11. # documentation and/or other materials provided with the distribution.
  12. #
  13. # THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
  14. # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  15. # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  16. # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
  17. # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  18. # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  19. # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  20. # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  21. # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  22. # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  23. # THE POSSIBILITY OF SUCH DAMAGE.
  24. use strict;
  25. use warnings;
  26. use File::Basename;
  27. use FindBin;
  28. use Getopt::Long qw(:config pass_through);
  29. use IPC::Open3;
  30. use lib $FindBin::Bin;
  31. use webkitdirs;
  32. use VCSUtils;
  33. sub buildTestTool();
  34. sub dumpTestsBySuite(\@);
  35. sub listAllTests();
  36. sub runTest($$$);
  37. sub runTestsBySuite(\@$);
  38. sub prepareEnvironmentForRunningTestTool();
  39. sub testToolPath();
  40. # Defined in VCSUtils.
  41. sub possiblyColored($$);
  42. # Timeout for individual test, in sec
  43. my $timeout = 10;
  44. my $showHelp = 0;
  45. my $verbose = 0;
  46. my $dumpTests = 0;
  47. my $build = 1;
  48. my $root;
  49. my $buildDefault = $build ? "build" : "do not build";
  50. my @testsFailed;
  51. my @testsTimedOut;
  52. my $programName = basename($0);
  53. my $usage = <<EOF;
  54. Usage: $programName [options] [suite or test prefixes]
  55. --help Show this help message
  56. -v|--verbose Verbose output
  57. -d|--dump-tests Dump the names of testcases without running them
  58. --[no-]build Build (or do not build) unit tests prior to running (default: $buildDefault)
  59. --root= Path to the pre-built root containing TestWebKitAPI
  60. EOF
  61. GetOptions(
  62. 'help' => \$showHelp,
  63. 'verbose|v' => \$verbose,
  64. 'dump|d' => \$dumpTests,
  65. 'build!' => \$build,
  66. 'root=s' => \$root
  67. );
  68. if ($showHelp) {
  69. print STDERR $usage;
  70. exit 1;
  71. }
  72. setConfiguration();
  73. setConfigurationProductDir(Cwd::abs_path($root)) if (defined($root));
  74. buildTestTool() if $build && !defined($root);
  75. setPathForRunningWebKitApp(\%ENV);
  76. my @testsToRun = listAllTests();
  77. @testsToRun = grep { my $test = $_; grep { $test =~ m/^\Q$_\E/ } @ARGV; } @testsToRun if @ARGV;
  78. if ($dumpTests) {
  79. dumpTestsBySuite(@testsToRun);
  80. exit 0;
  81. }
  82. exit runTestsBySuite(@testsToRun, $verbose);
  83. sub isSupportedPlatform()
  84. {
  85. return isAppleMacWebKit() || isAppleWinWebKit();
  86. }
  87. sub dumpTestsBySuite(\@)
  88. {
  89. my ($tests) = @_;
  90. print "Dumping test cases\n";
  91. print "------------------\n";
  92. my $lastSuite = "";
  93. for my $suiteAndTest (sort @$tests) {
  94. my ($suite, $test) = split(/\./, $suiteAndTest);
  95. if ($lastSuite ne $suite) {
  96. $lastSuite = $suite;
  97. print "$suite:\n";
  98. }
  99. print " $test\n";
  100. }
  101. print "------------------\n";
  102. }
  103. sub runTestsBySuite(\@$)
  104. {
  105. my ($tests, $verbose) = @_;
  106. my $anyFailures = 0;
  107. my $lastSuite = "";
  108. for my $suiteAndTest (sort @$tests) {
  109. my ($suite, $test) = split(/\./, $suiteAndTest);
  110. if ($lastSuite ne $suite) {
  111. $lastSuite = $suite;
  112. print "Suite: $suite\n" unless $verbose;
  113. }
  114. my $failed = runTest($suite, $test, $verbose);
  115. $anyFailures ||= $failed;
  116. }
  117. if ($verbose) {
  118. if (@testsFailed) {
  119. print "Tests that failed:\n";
  120. for my $test (@testsFailed) {
  121. print " $test\n";
  122. }
  123. }
  124. if (@testsTimedOut) {
  125. print "Tests that timed out:\n";
  126. for my $test (@testsTimedOut) {
  127. print " $test\n";
  128. }
  129. }
  130. }
  131. return $anyFailures;
  132. }
  133. sub runTest($$$)
  134. {
  135. my ($suite, $testName, $verbose) = @_;
  136. my $test = $suite . "." . $testName;
  137. my $gtestArg = "--gtest_filter=" . $test;
  138. print " Test: $testName -> " unless $verbose;
  139. my $result = 0;
  140. my $timedOut = 0;
  141. die "run-api-tests is not supported on this platform.\n" unless isSupportedPlatform();
  142. prepareEnvironmentForRunningTestTool();
  143. local *DEVNULL;
  144. my ($childIn, $childOut, $childErr);
  145. if ($verbose) {
  146. $childOut = ">&STDERR";
  147. $childErr = ">&STDERR";
  148. } else {
  149. open(DEVNULL, ">", File::Spec->devnull()) or die "Failed to open /dev/null";
  150. $childOut = ">&DEVNULL";
  151. $childErr = ">&DEVNULL";
  152. }
  153. my $pid;
  154. if (isAppleMacWebKit() && architecture()) {
  155. $pid = open3($childIn, $childOut, $childErr, "arch", "-" . architecture(), testToolPath(), $gtestArg, @ARGV) or die "Failed to run test: $test.";
  156. } else {
  157. $pid = open3($childIn, $childOut, $childErr, testToolPath(), $gtestArg, @ARGV) or die "Failed to run test: $test.";
  158. }
  159. close($childIn);
  160. close($childOut);
  161. close($childErr);
  162. close(DEVNULL) unless ($verbose);
  163. eval {
  164. local $SIG{ALRM} = sub { die "alarm\n" };
  165. alarm $timeout;
  166. waitpid($pid, 0);
  167. alarm 0;
  168. $result = $?;
  169. };
  170. if ($@) {
  171. die unless $@ eq "alarm\n";
  172. kill SIGTERM, $pid or kill SIGKILL, $pid;
  173. $timedOut = 1;
  174. }
  175. if ($result) {
  176. push @testsFailed, $test;
  177. }
  178. if ($timedOut) {
  179. push @testsTimedOut, $test;
  180. print possiblyColored("bold yellow", "Timeout"), "\n";
  181. } elsif (!$verbose) {
  182. if ($result) {
  183. print possiblyColored("bold red", "Failed"), "\n";
  184. } else {
  185. print possiblyColored("bold green", "Passed"), "\n";
  186. }
  187. }
  188. return $timedOut || $result;
  189. }
  190. sub listAllTests()
  191. {
  192. my @toolOutput;
  193. my $timedOut;
  194. die "run-api-tests is not supported on this platform.\n" unless isSupportedPlatform();
  195. prepareEnvironmentForRunningTestTool();
  196. local *DEVNULL;
  197. my ($childIn, $childOut, $childErr);
  198. if ($verbose) {
  199. $childErr = ">&STDERR";
  200. } else {
  201. open(DEVNULL, ">", File::Spec->devnull()) or die "Failed to open /dev/null";
  202. $childErr = ">&DEVNULL";
  203. }
  204. my $pid;
  205. if (isAppleMacWebKit() && architecture()) {
  206. $pid = open3($childIn, $childOut, $childErr, "arch", "-" . architecture(), testToolPath(), "--gtest_list_tests") or die "Failed to build list of tests!";
  207. } else {
  208. $pid = open3($childIn, $childOut, $childErr, testToolPath(), "--gtest_list_tests") or die "Failed to build list of tests!";
  209. }
  210. close($childIn);
  211. @toolOutput = <$childOut>;
  212. close($childOut);
  213. close($childErr);
  214. close(DEVNULL) unless ($verbose);
  215. waitpid($pid, 0);
  216. my $result = $?;
  217. if ($result) {
  218. print STDERR "Failed to build list of tests!\n";
  219. exit exitStatus($result);
  220. }
  221. my @tests = ();
  222. my $suite;
  223. for my $line (@toolOutput) {
  224. $line =~ s/[\r\n]*$//;
  225. if ($line =~ m/\.$/) {
  226. $suite = $line; # "SuiteName."
  227. } else {
  228. # Disabling WebKit2 API test on Windows since we will be disabling WebKit2 on Windows.
  229. next if (isAppleWinWebKit() && $suite =~ m/WebKit2*/);
  230. $line =~ s/^\s*//; # "TestName"
  231. push @tests, $suite . $line; # "SuiteName.TestName"
  232. }
  233. }
  234. return @tests;
  235. }
  236. sub buildTestTool()
  237. {
  238. my $originalCwd = getcwd();
  239. chdirWebKit();
  240. my $buildTestTool = "build-api-tests";
  241. print STDERR "Running $buildTestTool\n";
  242. local *DEVNULL;
  243. my ($childIn, $childOut, $childErr);
  244. if ($verbose) {
  245. # When not quiet, let the child use our stdout/stderr.
  246. $childOut = ">&STDOUT";
  247. $childErr = ">&STDERR";
  248. } else {
  249. open(DEVNULL, ">", File::Spec->devnull()) or die "Failed to open /dev/null";
  250. $childOut = ">&DEVNULL";
  251. $childErr = ">&DEVNULL";
  252. }
  253. my @args = argumentsForConfiguration();
  254. my $pathToBuildTestTool = File::Spec->catfile("Tools", "Scripts", $buildTestTool);
  255. my $buildProcess = open3($childIn, $childOut, $childErr, "perl", $pathToBuildTestTool, @args) or die "Failed to run " . $buildTestTool;
  256. close($childIn);
  257. close($childOut);
  258. close($childErr);
  259. close(DEVNULL) unless ($verbose);
  260. waitpid($buildProcess, 0);
  261. my $buildResult = $?;
  262. if ($buildResult) {
  263. print STDERR "Compiling TestWebKitAPI failed!\n";
  264. exit exitStatus($buildResult);
  265. }
  266. chdir $originalCwd;
  267. }
  268. sub prepareEnvironmentForRunningTestTool()
  269. {
  270. return unless isAppleMacWebKit();
  271. $ENV{DYLD_FRAMEWORK_PATH} = productDir();
  272. $ENV{WEBKIT_UNSET_DYLD_FRAMEWORK_PATH} = "YES";
  273. }
  274. sub testToolPath()
  275. {
  276. my $path = File::Spec->catfile(productDir(), "TestWebKitAPI");
  277. return $path unless isAppleWinWebKit();
  278. my $suffix;
  279. if (configurationForVisualStudio() eq "Debug_All") {
  280. $suffix = "_debug";
  281. } else {
  282. $suffix = "";
  283. }
  284. return "$path$suffix.exe";
  285. }