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