13ae3f1fa0e2e86efd28b7070c610c21502b8597
[WebKit-https.git] / Tools / Scripts / run-javascriptcore-tests
1 #!/usr/bin/perl -w
2
3 # Copyright (C) 2005, 2013-2016 Apple Inc.  All rights reserved.
4 # Copyright (C) 2007 Eric Seidel <eric@webkit.org>
5 #
6 # Redistribution and use in source and binary forms, with or without
7 # modification, are permitted provided that the following conditions
8 # are met:
9 #
10 # 1.  Redistributions of source code must retain the above copyright
11 #     notice, this list of conditions and the following disclaimer.
12 # 2.  Redistributions in binary form must reproduce the above copyright
13 #     notice, this list of conditions and the following disclaimer in the
14 #     documentation and/or other materials provided with the distribution.
15 # 3.  Neither the name of Apple Inc. ("Apple") nor the names of
16 #     its contributors may be used to endorse or promote products derived
17 #     from this software without specific prior written permission.
18 #
19 # THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
20 # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 # DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
23 # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30 # Script to run the WebKit Open Source Project JavaScriptCore tests (adapted from Mozilla),
31 # as well as other tests: testapi on Mac and LayoutTests/js.
32
33 use strict;
34 use File::Spec;
35 use FindBin;
36 use Getopt::Long qw(:config pass_through);
37 use JSON::PP;
38 use lib $FindBin::Bin;
39 use List::Util qw(min max);
40 use POSIX;
41 use webkitdirs;
42
43 # determine configuration
44 setConfiguration();
45 my $configuration = configuration();
46
47 # These variables are intentionally left undefined.
48 my $root;
49 my $showHelp;
50 my $extraTests;
51 my $jsDriverArgs;
52 my $childProcesses;
53 my $shellRunner;
54 my $makeRunner;
55
56 my $buildJSC = 1;
57
58 my $runTestAPI = isAppleMacWebKit() || isAppleWinWebKit() || isWinCairo();
59
60 my $runJSCStress = 1;
61 my $runJITStressTests = 1;
62 my $runQuickMode = 0;
63 my $envVars = "";
64 my $gmallocPath = undef;
65 my $gmallocDefaultPath = "/usr/lib/libgmalloc.dylib";
66
67 my $enableFTL = isAppleMacWebKit() || isX86_64() && (isGtk() || isEfl());
68 my $createTarball = 0;
69 my $remoteHost = 0;
70 my $failFast = 1;
71 my %jsonData = ();
72 my $remoteConfigFile;
73 my $jsonFileName;
74
75 my $programName = basename($0);
76 my $buildJSCDefault = $buildJSC ? "will check" : "will not check";
77 my $testapiDefault = $runTestAPI ? "will run" : "will not run";
78 my $jscStressDefault = $runJSCStress ? "will run" : " will not run";
79 my $jitStressTestsDefault = $runJITStressTests ? "will run" : " will not run";
80 my $quickModeDefault = $runQuickMode ? "some" : "all";
81 my $failFastDefault = $failFast ? "fail fast" : "don't fail fast";
82 my $filter;
83 my $usage = <<EOF;
84 Usage: $programName [options] [options to pass to build system]
85   --help                        Show this help message
86   --root=                       Path to pre-built root containing jsc
87   --[no-]ftl-jit                Turn the FTL JIT on or off
88   --[no-]build                  Check (or don't check) to see if the jsc build is up-to-date (default: $buildJSCDefault)
89   --[no-]testapi                Run (or don't run) testapi (default: $testapiDefault)
90   --[no-]jsc-stress             Run (or don't run) the JSC stress tests (default: $jscStressDefault)
91   --[no-]jit-stress-tests       Run (or don't run) the JIT stress tests (default: $jitStressTestsDefault)
92   --[no-]quick                  Run some (or all) of the regular testing modes (default: $quickModeDefault)
93                                 If the runner only runs some it will run the default and no-cjit-validate modes.
94                                 Note, this will not change the behavior of tests that specify their own modes.
95
96   --[no-]fail-fast              Stop this script when a test family reports an error or failure (default: $failFastDefault)
97   --json-output=                Create a file at specified path, listing failed stress tests in JSON format.
98   --tarball                     Create a tarball of the bundle produced by running the JSC stress tests.
99   --remote=                     Run the JSC stress tests on the specified remote host. Implies --tarball.
100   --remote-config-file=         Same as remote, but read config from JSON file.
101   --extra-tests=                Path to a file containing extra tests
102   --child-processes=            Specify the number of child processes.
103   --shell-runner                Uses the shell-based test runner instead of the default make-based runner.
104                                 In general the shell runner is slower than the make runner.
105   --make-runner                 Uses the faster make-based runner.
106   --filter                      Only run tests whose name matches the given regular expression.
107   --env-vars                    Pass a list of environment variables to set before running tests.
108                                 Each environment variable should be separated by a space.
109                                 e.g. \"foo=bar x=y\" (no quotes).
110   --gmalloc:                    Run tests with Guard Malloc enabled (if no path is given: $gmallocDefaultPath is used)
111
112 EOF
113
114 GetOptions(
115     'root=s' => \$root,
116     'extra-tests=s' => \$extraTests,
117     'build!' => \$buildJSC,
118     'ftl-jit!' => \$enableFTL,
119     'testapi!' => \$runTestAPI,
120     'jsc-stress!' => \$runJSCStress,
121     'jit-stress-tests!' => \$runJITStressTests,
122     'quick!' => \$runQuickMode,
123     'fail-fast!' => \$failFast,
124     'json-output=s' => \$jsonFileName,
125     'tarball!' => \$createTarball,
126     'remote=s' => \$remoteHost,
127     'remote-config-file=s' => \$remoteConfigFile,
128     'child-processes=s' => \$childProcesses,
129     'shell-runner' => \$shellRunner,
130     'make-runner' => \$makeRunner,
131     'filter=s' => \$filter,
132     'help' => \$showHelp,
133     'env-vars=s' => \$envVars,
134     'gmalloc:s' => \$gmallocPath,
135 );
136
137 # Assume any arguments left over from GetOptions are assumed to be build arguments
138 my @buildArgs = @ARGV;
139
140 # The --ftl-jit argument gets passed as a build argument.
141 if ($enableFTL) {
142     push(@buildArgs, '--ftl-jit');
143 }
144
145 if ($showHelp) {
146    print STDERR $usage;
147    exit 1;
148 }
149
150 setConfigurationProductDir(Cwd::abs_path($root)) if (defined($root));
151
152 if (defined($jsonFileName)) {
153     $jsonFileName = File::Spec->rel2abs($jsonFileName);
154 }
155
156 if (!defined($root) && $buildJSC) {
157     chdirWebKit();
158
159     push(@buildArgs, argumentsForConfiguration());
160
161     print "Running: build-jsc " . join(" ", @buildArgs) . "\n";
162     my $buildResult = system "perl", File::Spec->catfile("Tools", "Scripts", "build-jsc"), @buildArgs;
163     if ($buildResult) {
164         print STDERR "Compiling jsc failed!\n";
165         exit exitStatus($buildResult);
166     }
167 }
168
169 if (defined($gmallocPath)) {
170     if ($gmallocPath eq "") {
171         $envVars .= " DYLD_INSERT_LIBRARIES=" . $gmallocDefaultPath;
172     } else {
173         $envVars .= " DYLD_INSERT_LIBRARIES=" . $gmallocPath;
174     }
175 }
176
177 my $productDir = jscProductDir();
178 $ENV{DYLD_FRAMEWORK_PATH} = $productDir;
179 $ENV{JSCTEST_timeout} = 60 unless $ENV{JSCTEST_timeout}; # Set a 60 second timeout on all jsc tests (if environment variable not defined already).
180 $ENV{TZ}="US/Pacific"; # Some tests fail if the time zone is not set to US/Pacific (<https://webkit.org/b/136363>)
181 setPathForRunningWebKitApp(\%ENV) if isCygwin();
182
183 sub testapiPath($)
184 {
185     my ($productDir) = @_;
186     my $jscName = "testapi";
187     $jscName .= "_debug" if configuration() eq "Debug_All";
188     return File::Spec->catfile($productDir, $jscName);
189 }
190
191 #run api tests
192 if ($runTestAPI) {
193     chdirWebKit();
194     chdir($productDir) or die "Failed to switch directory to '$productDir'\n";
195     my @command = (testapiPath($productDir));
196     unshift @command, ("xcrun", "-sdk", xcodeSDK(), "sim") if willUseIOSSimulatorSDK();
197
198     if ($envVars ne "") {
199         foreach my $var (split(/\s+/, $envVars)) {
200             if ($var =~ /([^=]*)=(.*)/) {
201                 $ENV{$1} = $2;
202             }
203         }
204     }
205
206     # Use an "indirect object" so that system() won't get confused if the path
207     # contains spaces (see perldoc -f exec).
208     my $testapiResult = system { $command[0] } @command;
209     my $exitStatus = exitStatus($testapiResult);
210     print "testAPI completed with rc=$testapiResult ($exitStatus)\n";
211
212     if (defined($jsonFileName)) {
213         my $apiStatus = ($exitStatus == 0)? JSON::PP::true: JSON::PP::false;
214         $jsonData{'allApiTestsPassed'} = $apiStatus;
215     }
216
217     if ($testapiResult && $failFast) {
218         writeJsonDataIfApplicable();
219         exit exitStatus($testapiResult);
220     }
221 }
222
223 # Find JavaScriptCore directory
224 chdirWebKit();
225
226 runJSCStressTests();
227
228 sub runJSCStressTests
229 {
230     my $jscStressResultsDir = $productDir . "/jsc-stress-results";
231
232     my @testList;
233     if ($runJSCStress) {
234         @testList = (
235             "PerformanceTests/SunSpider/tests/sunspider-1.0",
236             "PerformanceTests/JetStream/cdjs/cdjs-tests.yaml",
237             # Skip this while we figure out how to handle timeouts in debug.
238             # "PerformanceTests/JSAir/jsair-tests.yaml",
239             "Source/JavaScriptCore/tests/executableAllocationFuzz.yaml",
240             "Source/JavaScriptCore/tests/exceptionFuzz.yaml",
241             "PerformanceTests/SunSpider/no-architecture-specific-optimizations.yaml",
242             "PerformanceTests/SunSpider/shadow-chicken.yaml",
243             "PerformanceTests/SunSpider/tests/v8-v6",
244             "Source/JavaScriptCore/tests/mozilla/mozilla-tests.yaml",
245             "Source/JavaScriptCore/tests/stress",
246             "LayoutTests/js/regress/script-tests",
247             "PerformanceTests/SunSpider/profiler-test.yaml",
248             "LayoutTests/jsc-layout-tests.yaml",
249             "Source/JavaScriptCore/tests/typeProfiler.yaml",
250             "Source/JavaScriptCore/tests/controlFlowProfiler.yaml",
251             "Source/JavaScriptCore/tests/es6.yaml",
252             "Source/JavaScriptCore/tests/modules.yaml");
253     } else {
254         @testList = ("Source/JavaScriptCore/tests/mozilla/mozilla-tests.yaml");
255     }
256
257
258     # Set LANG environment variable so the stress tests will work with newer ruby (<rdar://problem/15010705>)
259     $ENV{LANG}="en_US.UTF-8";
260     my @jscStressDriverCmd = (
261         "/usr/bin/env", "ruby", "Tools/Scripts/run-jsc-stress-tests",
262         "-j", jscPath($productDir), "-o", $jscStressResultsDir);
263
264     push(@jscStressDriverCmd, @testList);
265
266     if (isWindows() && !isCygwin()) {
267         shift @jscStressDriverCmd; # Remove /usr/bin/env
268     }
269
270     if (configuration() eq "Debug") {
271         push(@jscStressDriverCmd, "--debug");
272     }
273
274     if ($envVars ne "") {
275             push(@jscStressDriverCmd, "--env-vars");
276             push(@jscStressDriverCmd, $envVars);
277     }
278
279     if ($runQuickMode) {
280         push(@jscStressDriverCmd, "--quick");
281     }
282
283     if (!$runJITStressTests) {
284         push(@jscStressDriverCmd, "--no-jit");
285     } else {
286         if ($enableFTL) {
287             push(@jscStressDriverCmd, "--ftl-jit");
288         }
289     }
290     if ($createTarball) {
291         push(@jscStressDriverCmd, "--tarball");
292     }
293
294     if ($remoteHost) {
295         push(@jscStressDriverCmd, "--remote");
296         push(@jscStressDriverCmd, $remoteHost);
297     }
298
299     if ($remoteConfigFile) {
300         push(@jscStressDriverCmd, "--remote-config-file");
301         push(@jscStressDriverCmd, $remoteConfigFile);
302     }
303
304     if ($childProcesses) {
305         push(@jscStressDriverCmd, "--child-processes");
306         push(@jscStressDriverCmd, $childProcesses);
307     }
308
309     if ($shellRunner) {
310         push(@jscStressDriverCmd, "--shell-runner");
311     }
312
313     if ($makeRunner) {
314         push(@jscStressDriverCmd, "--make-runner");
315     }
316
317     if ($filter) {
318         push(@jscStressDriverCmd, "--filter");
319         push(@jscStressDriverCmd, $filter);
320     }
321
322     # End option processing, the rest of the arguments are tests
323     push(@jscStressDriverCmd, "--");
324
325     if (defined($extraTests)) {
326         push(@jscStressDriverCmd, $extraTests);
327     }
328     if (defined($ENV{"EXTRA_JSC_TESTS"})) {
329         push(@jscStressDriverCmd, $ENV{"EXTRA_JSC_TESTS"});
330     }
331     print "Running: " . join(" ", @jscStressDriverCmd) . "\n";
332     my $result = system(@jscStressDriverCmd);
333     exit exitStatus($result) if $result;
334
335     my @jscStressFailList = readAllLines($jscStressResultsDir . "/failed");
336     @jscStressFailList = sort @jscStressFailList;
337     my $numJSCStressFailures = @jscStressFailList;
338
339     if ($numJSCStressFailures) {
340         print "\n** The following JSC stress test failures have been introduced:\n";
341         foreach my $testFailure (@jscStressFailList) {
342             print "\t$testFailure\n";
343         }
344     }
345     print "\n";
346
347     print "Results for JSC stress tests:\n";
348     printThingsFound($numJSCStressFailures, "failure", "failures", "found");
349     print "    OK.\n" if $numJSCStressFailures == 0;
350
351     print "\n";
352
353     if (defined($jsonFileName)) {
354         $jsonData{'stressTestFailures'} = \@jscStressFailList;
355     }
356
357     writeJsonDataIfApplicable();
358     exit(1) if $numJSCStressFailures;
359 }
360
361 sub readAllLines
362 {
363     my ($filename) = @_;
364     my @array = ();
365     eval {
366         open FILE, $filename or die;
367         while (<FILE>) {
368             chomp;
369             push @array, $_;
370         }
371         close FILE;
372     };
373     return @array;
374 }
375
376 sub printThingsFound
377 {
378     my ($number, $label, $pluralLabel, $verb) = @_;
379     print "    $number ";
380     if ($number == 1) {
381         print $label;
382     } else {
383         print $pluralLabel;
384     }
385     print " $verb.\n";
386 }
387
388 sub writeJsonDataIfApplicable
389 {
390     if (defined($jsonFileName)) {
391         open(my $fileHandler, ">", $jsonFileName) or die;
392         print $fileHandler "${\encode_json(\%jsonData)}\n";
393         close($fileHandler);
394     }
395 }