25825e2a7734a6db18b556e09cf136672ee62ec1
[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 Term::ANSIColor qw(colored);
40
41 sub buildTestTool();
42 sub dumpAllTests();
43 sub populateTests();
44 sub runAllTests();
45 sub runAllTestsInSuite($);
46 sub runTest($$);
47 sub possiblyColored($$);
48 sub prepareEnvironmentForRunningTestTool();
49 sub testToolPath();
50
51 # Timeout for individual test, in sec
52 my $timeout = 10;
53
54 my $showHelp = 0;
55 my $verbose = 0;
56 my $dump = 0;
57 my $build = 1;
58 my $buildDefault = $build ? "build" : "do not build";
59
60 my $programName = basename($0);
61 my $usage = <<EOF;
62 Usage: $programName [options]
63   --help                Show this help message
64   -v|--verbose          Verbose output
65   -d|--dump-tests       Dump the names of testcases without running them
66   --[no-]build          Build (or do not build) unit tests prior to running (default: $buildDefault)
67 EOF
68
69 GetOptions(
70     'help' => \$showHelp,
71     'verbose|v' => \$verbose,
72     'dump|d' => \$dump,
73     'build!' => \$build
74 );
75
76 if ($showHelp) {
77    print STDERR $usage;
78    exit 1;
79 }
80
81 setConfiguration();
82 buildTestTool() if $build;
83 setPathForRunningWebKitApp(\%ENV);
84 my %testsToRun = populateTests();
85
86 if ($dump) {
87     dumpAllTests();
88     exit 0;
89 }
90
91 if (runAllTests()) {
92     exit 1;
93 }
94
95 sub dumpAllTests()
96 {
97     print "Dumping test cases\n";
98     print "------------------\n";
99     for my $suite (keys %testsToRun) {
100         print $suite . ":\n";
101         print map { "   " . $_ . "\n" } @{ $testsToRun{$suite} };
102     }
103     print "------------------\n";
104 }
105
106 sub runAllTests()
107 {
108     my $anyFailures = 0;
109     for my $suite (sort keys %testsToRun) {
110         my $failed = runAllTestsInSuite($suite);
111         if ($failed) {
112             $anyFailures = 1;
113         }
114     }
115     return $anyFailures;
116 }
117
118 sub runAllTestsInSuite($)
119 {
120     my ($suite) = @_;
121     print "Suite: $suite\n" unless $verbose;
122
123     my $anyFailures = 0;
124     for my $test (sort @{$testsToRun{$suite}}) {
125         my $failed = runTest($suite, $test);
126         if ($failed) {
127             $anyFailures = 1;
128         }
129     }
130    
131     return $anyFailures;
132 }
133
134 sub runTest($$)
135 {
136     my ($suite, $testName) = @_;
137     my $test = $suite . "." . $testName;
138
139     my $gtestArg = "--gtest_filter=" . $test;
140
141     print "    Test: $testName -> " unless $verbose;
142
143     my $result = 0;
144     my $timedOut = 0;
145
146     die "run-api-tests is not supported on this platform.\n" unless isAppleMacWebKit() || isAppleWinWebKit();
147
148     prepareEnvironmentForRunningTestTool();
149
150     local *DEVNULL;
151     my ($childIn, $childOut, $childErr);
152     if ($verbose) {
153         $childOut = ">&STDERR";
154         $childErr = ">&STDERR";
155     } else {
156         open(DEVNULL, ">", File::Spec->devnull()) or die "Failed to open /dev/null";
157         $childOut = ">&DEVNULL";
158         $childErr = ">&DEVNULL";
159     }
160
161     my $pid;
162     if (isAppleMacWebKit() && architecture()) {
163         $pid = open3($childIn, $childOut, $childErr, "arch", "-" . architecture(), testToolPath(), $gtestArg, @ARGV) or die "Failed to run test: $test.";
164     } else {
165         $pid = open3($childIn, $childOut, $childErr, testToolPath(), $gtestArg, @ARGV) or die "Failed to run test: $test.";
166     }
167
168     close($childIn);
169     close($childOut);
170     close($childErr);
171     close(DEVNULL) unless ($verbose);
172     eval {
173         local $SIG{ALRM} = sub { die "alarm\n" };
174         alarm $timeout;
175         waitpid($pid, 0);
176         alarm 0;
177         $result = $?;
178     };
179     if ($@) {
180         die unless $@ eq "alarm\n";
181         kill SIGTERM, $pid or kill SIGKILL, $pid;
182         $timedOut = 1;
183     }
184
185     if ($timedOut) {
186         print possiblyColored("bold yellow", "Timeout"), "\n";
187     } elsif (!$verbose) {
188         if ($result) {
189             print possiblyColored("bold red", "Failed"), "\n";
190         } else {
191             print possiblyColored("bold green", "Passed"), "\n";
192         }
193     }
194
195     return $timedOut || $result;
196 }
197
198 sub populateTests()
199 {
200     my @tests;
201     my $timedOut;
202
203     die "run-api-tests is not supported on this platform.\n" unless isAppleMacWebKit() || isAppleWinWebKit();
204
205     prepareEnvironmentForRunningTestTool();
206
207     local *DEVNULL;
208     my ($childIn, $childOut, $childErr);
209     if ($verbose) {
210         $childErr = ">&STDERR";
211     } else {
212         open(DEVNULL, ">", File::Spec->devnull()) or die "Failed to open /dev/null";
213         $childErr = ">&DEVNULL";
214     }
215
216     my $pid;
217     if (isAppleMacWebKit() && architecture()) {
218         $pid = open3($childIn, $childOut, $childErr, "arch", "-" . architecture(), testToolPath(), "--gtest_list_tests") or die "Failed to build list of tests!";
219     } else {
220         $pid = open3($childIn, $childOut, $childErr, testToolPath(), "--gtest_list_tests") or die "Failed to build list of tests!";
221     }
222
223     close($childIn);
224     @tests = <$childOut>;
225     close($childOut);
226     close($childErr);
227     close(DEVNULL) unless ($verbose);
228
229     waitpid($pid, 0);
230     my $result = $?;
231
232     if ($result) {
233         print STDERR "Failed to build list of tests!\n";
234         exit exitStatus($result);
235     }
236
237     my %keyedTests = ();
238     my $suite;
239     for my $test (@tests) {
240        $test =~ s/[\r\n]*$//;
241        if ($test =~ m/\.$/) {
242           $test =~ s/\.$//;
243           $suite = $test;
244        } else {
245           $test =~ s/^\s*//;
246           push @{$keyedTests{$suite}}, $test;
247         }
248     }
249  
250     return %keyedTests;
251 }
252
253
254 sub buildTestTool()
255 {
256     my $originalCwd = getcwd();
257
258     chdirWebKit();
259
260     my $buildTestTool = "build-api-tests";
261     print STDERR "Running $buildTestTool\n";
262
263     local *DEVNULL;
264     my ($childIn, $childOut, $childErr);
265     if ($verbose) {
266         # When not quiet, let the child use our stdout/stderr.
267         $childOut = ">&STDOUT";
268         $childErr = ">&STDERR";
269     } else {
270         open(DEVNULL, ">", File::Spec->devnull()) or die "Failed to open /dev/null";
271         $childOut = ">&DEVNULL";
272         $childErr = ">&DEVNULL";
273     }
274
275     my @args = argumentsForConfiguration();
276     my $buildProcess = open3($childIn, $childOut, $childErr, "Tools/Scripts/$buildTestTool", @args) or die "Failed to run " . $buildTestTool;
277
278     close($childIn);
279     close($childOut);
280     close($childErr);
281     close(DEVNULL) unless ($verbose);
282
283     waitpid($buildProcess, 0);
284     my $buildResult = $?;
285
286     if ($buildResult) {
287         print STDERR "Compiling TestWebKitAPI failed!\n";
288         exit exitStatus($buildResult);
289     }
290
291     chdir $originalCwd;
292 }
293
294 sub possiblyColored($$)
295 {
296     my ($colors, $string) = @_;
297
298     if (-t STDOUT) {
299         return colored([$colors], $string);
300     } else {
301         return $string;
302     }
303 }
304
305 sub prepareEnvironmentForRunningTestTool()
306 {
307     return unless isAppleMacWebKit();
308
309     $ENV{DYLD_FRAMEWORK_PATH} = productDir();
310     $ENV{WEBKIT_UNSET_DYLD_FRAMEWORK_PATH} = "YES";
311 }
312
313 sub testToolPath()
314 {
315     my $path = File::Spec->catfile(productDir(), "TestWebKitAPI");
316     return $path unless isAppleWinWebKit();
317
318     my $suffix;
319     if (configurationForVisualStudio() eq "Debug_All") {
320         $suffix = "_debug";
321     } else {
322         $suffix = "";
323     }
324     return "$path$suffix.exe";
325 }