b19a27211b79a2097075b5957fe41004913dd8b0
[WebKit-https.git] / Tools / Scripts / run-api-tests
1 #!/usr/bin/perl -w
2
3 # Copyright (C) 2010, 2011, 2012 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 use strict;
27 use warnings;
28
29 use File::Basename;
30 use FindBin;
31 use Getopt::Long qw(:config pass_through);
32 use IPC::Open3;
33 use lib $FindBin::Bin;
34 use webkitdirs;
35 use VCSUtils;
36
37 sub buildTestTool();
38 sub dumpTestsBySuite(\@);
39 sub listAllTests();
40 sub runTest($$$);
41 sub runTestsBySuite(\@$);
42 sub prepareEnvironmentForRunningTestTool();
43 sub testToolPath();
44
45 # Defined in VCSUtils.
46 sub possiblyColored($$);
47
48 # Timeout for individual test, in sec
49 my $timeout = 10;
50
51 my $showHelp = 0;
52 my $verbose = 0;
53 my $dumpTests = 0;
54 my $build = 1;
55 my $root;
56 my $buildDefault = $build ? "build" : "do not build";
57 my @testsFailed;
58 my @testsTimedOut;
59
60 my $programName = basename($0);
61 my $usage = <<EOF;
62 Usage: $programName [options] [suite or test prefixes]
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   --root=               Path to the pre-built root containing TestWebKitAPI
68
69 Examples
70
71 The following command will run a single test:
72     $programName WebKit2.AboutBlank
73
74 The following command will run all tests in suites that begin with 'WebKit2':
75     $programName WebKit2
76
77 EOF
78
79 GetOptions(
80     'help' => \$showHelp,
81     'verbose|v' => \$verbose,
82     'dump|d' => \$dumpTests,
83     'build!' => \$build,
84     'root=s' => \$root
85 );
86
87 if ($showHelp) {
88    print STDERR $usage;
89    exit 1;
90 }
91
92 setConfiguration();
93
94 setConfigurationProductDir(Cwd::abs_path($root)) if (defined($root));
95
96 buildTestTool() if $build && !defined($root);
97 setPathForRunningWebKitApp(\%ENV);
98 my @testsToRun = listAllTests();
99
100 @testsToRun = grep { my $test = $_; grep { $test =~ m/^\Q$_\E/ } @ARGV; } @testsToRun if @ARGV;
101
102 if ($dumpTests) {
103     dumpTestsBySuite(@testsToRun);
104     exit 0;
105 }
106
107 exit runTestsBySuite(@testsToRun, $verbose);
108
109 sub isSupportedPlatform()
110 {
111     return isAppleMacWebKit() || isAppleWinWebKit();
112 }
113
114 sub dumpTestsBySuite(\@)
115 {
116     my ($tests) = @_;
117     print "Dumping test cases\n";
118     print "------------------\n";
119     my $lastSuite = "";
120     for my $suiteAndTest (sort @$tests) {
121         my ($suite, $test) = split(/\./, $suiteAndTest);
122         if ($lastSuite ne $suite) {
123             $lastSuite = $suite;
124             print "$suite:\n";
125         }
126         print "   $test\n";
127     }
128     print "------------------\n";
129 }
130
131 sub runTestsBySuite(\@$)
132 {
133     my ($tests, $verbose) = @_;
134     my $anyFailures = 0;
135     my $lastSuite = "";
136     for my $suiteAndTest (sort @$tests) {
137         my ($suite, $test) = split(/\./, $suiteAndTest);
138         if ($lastSuite ne $suite) {
139             $lastSuite = $suite;
140             print "Suite: $suite\n" unless $verbose;
141         }
142         my $failed = runTest($suite, $test, $verbose);
143         $anyFailures ||= $failed;
144     }
145     
146     if ($verbose) {
147         if (@testsFailed) {
148             print "Tests that failed:\n";
149             for my $test (@testsFailed) {
150                 print "  $test\n";
151             }
152         }
153         if (@testsTimedOut) {
154             print "Tests that timed out:\n";
155             for my $test (@testsTimedOut) {
156                 print "  $test\n";
157             }
158         }
159     }
160     return $anyFailures;
161 }
162
163 sub runTest($$$)
164 {
165     my ($suite, $testName, $verbose) = @_;
166     my $test = $suite . "." . $testName;
167
168     my $gtestArg = "--gtest_filter=" . $test;
169
170     print "    Test: $testName -> " unless $verbose;
171
172     my $result = 0;
173     my $timedOut = 0;
174
175     die "run-api-tests is not supported on this platform.\n" unless isSupportedPlatform();
176
177     prepareEnvironmentForRunningTestTool();
178
179     local *DEVNULL;
180     my ($childIn, $childOut, $childErr);
181     if ($verbose) {
182         $childOut = ">&STDERR";
183         $childErr = ">&STDERR";
184     } else {
185         open(DEVNULL, ">", File::Spec->devnull()) or die "Failed to open /dev/null";
186         $childOut = ">&DEVNULL";
187         $childErr = ">&DEVNULL";
188     }
189
190     my $pid;
191     if (isAppleMacWebKit() && architecture()) {
192         $pid = open3($childIn, $childOut, $childErr, "arch", "-" . architecture(), testToolPath(), $gtestArg, @ARGV) or die "Failed to run test: $test.";
193     } else {
194         $pid = open3($childIn, $childOut, $childErr, testToolPath(), $gtestArg, @ARGV) or die "Failed to run test: $test.";
195     }
196
197     close($childIn);
198     close($childOut);
199     close($childErr);
200     close(DEVNULL) unless ($verbose);
201     eval {
202         local $SIG{ALRM} = sub { die "alarm\n" };
203         alarm $timeout;
204         waitpid($pid, 0);
205         alarm 0;
206         $result = $?;
207     };
208     if ($@) {
209         die unless $@ eq "alarm\n";
210         kill SIGTERM, $pid or kill SIGKILL, $pid;
211         $timedOut = 1;
212     }
213
214     if ($result) {
215         push @testsFailed, $test;
216     }
217     if ($timedOut) {
218         push @testsTimedOut, $test;
219         print possiblyColored("bold yellow", "Timeout"), "\n";
220     } elsif (!$verbose) {
221         if ($result) {
222             print possiblyColored("bold red", "Failed"), "\n";
223         } else {
224             print possiblyColored("bold green", "Passed"), "\n";
225         }
226     }
227
228     return $timedOut || $result;
229 }
230
231 sub listAllTests()
232 {
233     my @toolOutput;
234     my $timedOut;
235
236     die "run-api-tests is not supported on this platform.\n" unless isSupportedPlatform();
237
238     prepareEnvironmentForRunningTestTool();
239
240     local *DEVNULL;
241     my ($childIn, $childOut, $childErr);
242     if ($verbose) {
243         $childErr = ">&STDERR";
244     } else {
245         open(DEVNULL, ">", File::Spec->devnull()) or die "Failed to open /dev/null";
246         $childErr = ">&DEVNULL";
247     }
248
249     my $pid;
250     if (isAppleMacWebKit() && architecture()) {
251         $pid = open3($childIn, $childOut, $childErr, "arch", "-" . architecture(), testToolPath(), "--gtest_list_tests") or die "Failed to build list of tests!";
252     } else {
253         $pid = open3($childIn, $childOut, $childErr, testToolPath(), "--gtest_list_tests") or die "Failed to build list of tests!";
254     }
255
256     close($childIn);
257     @toolOutput = <$childOut>;
258     close($childOut);
259     close($childErr);
260     close(DEVNULL) unless ($verbose);
261
262     waitpid($pid, 0);
263     my $result = $?;
264
265     if ($result) {
266         print STDERR "Failed to build list of tests!\n";
267         exit exitStatus($result);
268     }
269
270     my @tests = ();
271     my $suite;
272     for my $line (@toolOutput) {
273        $line =~ s/[\r\n]*$//;
274        if ($line =~ m/\.$/) {
275           $suite = $line; # "SuiteName."
276        } else {
277           # Disabling WebKit2 API test on Windows since we will be disabling WebKit2 on Windows.
278           next if (isAppleWinWebKit() && $suite =~ m/WebKit2*/);       
279           $line =~ s/^\s*//; # "TestName"
280           push @tests, $suite . $line; # "SuiteName.TestName"
281         }
282     }
283
284     return @tests;
285 }
286
287 sub buildTestTool()
288 {
289     my $originalCwd = getcwd();
290
291     chdirWebKit();
292
293     my $buildTestTool = "build-api-tests";
294     print STDERR "Running $buildTestTool\n";
295
296     local *DEVNULL;
297     my ($childIn, $childOut, $childErr);
298     if ($verbose) {
299         # When not quiet, let the child use our stdout/stderr.
300         $childOut = ">&STDOUT";
301         $childErr = ">&STDERR";
302     } else {
303         open(DEVNULL, ">", File::Spec->devnull()) or die "Failed to open /dev/null";
304         $childOut = ">&DEVNULL";
305         $childErr = ">&DEVNULL";
306     }
307
308     my @args = argumentsForConfiguration();
309     my $pathToBuildTestTool = File::Spec->catfile("Tools", "Scripts", $buildTestTool);
310     my $buildProcess = open3($childIn, $childOut, $childErr, "perl", $pathToBuildTestTool, @args) or die "Failed to run " . $buildTestTool;
311
312     close($childIn);
313     close($childOut);
314     close($childErr);
315     close(DEVNULL) unless ($verbose);
316
317     waitpid($buildProcess, 0);
318     my $buildResult = $?;
319
320     if ($buildResult) {
321         print STDERR "Compiling TestWebKitAPI failed!\n";
322         exit exitStatus($buildResult);
323     }
324
325     chdir $originalCwd;
326 }
327
328 sub prepareEnvironmentForRunningTestTool()
329 {
330     return unless isAppleMacWebKit();
331
332     $ENV{DYLD_FRAMEWORK_PATH} = productDir();
333     $ENV{WEBKIT_UNSET_DYLD_FRAMEWORK_PATH} = "YES";
334 }
335
336 sub testToolPath()
337 {
338     my $path = File::Spec->catfile(productDir(), "TestWebKitAPI");
339     return $path unless isAppleWinWebKit();
340
341     my $suffix;
342     if (configuration() eq "Debug_All") {
343         $suffix = "_debug";
344     } else {
345         $suffix = "";
346     }
347     return "$path$suffix.exe";
348 }