d072a861c64488460f6fd2805e8f9e2317320d92
[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 my $memoryLimited;
56
57 my $buildJSC = 1;
58
59 my $runTestAPI = 1;
60
61 my $runJSCStress = 1;
62 my $runJITStressTests = 1;
63 my $runMozillaTests = 1;
64 my $runQuickMode = 0;
65 my $forceCollectContinuously = 0;
66 my $envVars = "";
67 my $gmallocPath = undef;
68 my $gmallocDefaultPath = "/usr/lib/libgmalloc.dylib";
69
70 my $createTarball = 0;
71 my $remoteHost = 0;
72 my $failFast = 1;
73 my %jsonData = ();
74 my $remoteConfigFile;
75 my $jsonFileName;
76
77 if ($ENV{RUN_JAVASCRIPTCORE_TESTS_TESTAPI}) {
78     if ($ENV{RUN_JAVASCRIPTCORE_TESTS_TESTAPI} eq "true") {
79         $runTestAPI = 1;
80     } elsif ($ENV{RUN_JAVASCRIPTCORE_TESTS_TESTAPI} eq "false") {
81         $runTestAPI = 0;
82     } else {
83         print "Don't recognize value for RUN_JAVASCRIPTCORE_TESTS_TESTAPI environment variable: '"
84             . $ENV{RUN_JAVASCRIPTCORE_TESTS_TESTAPI} . "'. Should be set to 'true' or 'false'.\n";
85     }
86 }
87
88 if ($ENV{RUN_JAVASCRIPTCORE_TESTS_BUILD}) {
89     if ($ENV{RUN_JAVASCRIPTCORE_TESTS_BUILD} eq "true") {
90         $buildJSC = 1;
91     } elsif ($ENV{RUN_JAVASCRIPTCORE_TESTS_BUILD} eq "false") {
92         $buildJSC = 0;
93     } else {
94         print "Don't recognize value for RUN_JAVASCRIPTCORE_TESTS_BUILD environment variable: '"
95             . $ENV{RUN_JAVASCRIPTCORE_TESTS_BUILD} . "'. Should be set to 'true' or 'false'.\n";
96     }
97 }
98
99 if ($ENV{RUN_JAVASCRIPTCORE_TESTS_EXTRA_TESTS}) {
100     push @extraTests, $ENV{RUN_JAVASCRIPTCORE_TESTS_EXTRA_TESTS};
101 }
102
103 my $programName = basename($0);
104 my $buildJSCDefault = $buildJSC ? "will check" : "will not check";
105 my $testapiDefault = $runTestAPI ? "will run" : "will not run";
106 my $jscStressDefault = $runJSCStress ? "will run" : " will not run";
107 my $jitStressTestsDefault = $runJITStressTests ? "will run" : " will not run";
108 my $mozillaTestsDefault = $runMozillaTests ? "will run" : " will not run";
109 my $quickModeDefault = $runQuickMode ? "some" : "all";
110 my $failFastDefault = $failFast ? "fail fast" : "don't fail fast";
111 my $filter;
112 my $usage = <<EOF;
113 Usage: $programName [options] [options to pass to build system]
114   --help                        Show this help message
115   --root=                       Path to pre-built root containing jsc
116   --[no-]ftl-jit                Turn the FTL JIT on or off
117   --[no-]build                  Check (or don't check) to see if the jsc build is up-to-date (default: $buildJSCDefault)
118   --[no-]testapi                Run (or don't run) testapi (default: $testapiDefault)
119   --[no-]jsc-stress             Run (or don't run) the JSC stress tests (default: $jscStressDefault)
120   --[no-]jit-stress-tests       Run (or don't run) the JIT stress tests (default: $jitStressTestsDefault)
121   --[no-]mozilla-tests          Run (or don't run) the Mozilla tests (default: $mozillaTestsDefault)
122   --[no-]quick                  Run some (or all) of the regular testing modes (default: $quickModeDefault)
123                                 If the runner only runs some it will run the default and no-cjit-validate modes.
124                                 Note, this will not change the behavior of tests that specify their own modes.
125
126   --[no-]fail-fast              Stop this script when a test family reports an error or failure (default: $failFastDefault)
127   --[no-]force-collectContinuously Enable the collectContinuously mode even if it was disabled on this platform.
128   --json-output=                Create a file at specified path, listing failed stress tests in JSON format.
129   --tarball                     Create a tarball of the bundle produced by running the JSC stress tests.
130   --remote=                     Run the JSC stress tests on the specified remote host. Implies --tarball.
131   --remote-config-file=         Same as remote, but read config from JSON file.
132   --extra-tests=                Path to a file containing extra tests
133   --child-processes=            Specify the number of child processes.
134   --shell-runner                Uses the shell-based test runner instead of the default make-based runner.
135                                 In general the shell runner is slower than the make runner.
136   --make-runner                 Uses the faster make-based runner.
137
138   --memory-limited              Indicate that we are targeting the test for a memory limited device.
139                                 Skip tests tagged with //\@skip if \$memoryLimited
140
141   --filter                      Only run tests whose name matches the given regular expression.
142   --env-vars                    Pass a list of environment variables to set before running tests.
143                                 Each environment variable should be separated by a space.
144                                 e.g. \"foo=bar x=y\" (no quotes).
145   --gmalloc:                    Run tests with Guard Malloc enabled (if no path is given: $gmallocDefaultPath is used)
146
147 Environment Variables:
148   - set RUN_JAVASCRIPTCORE_TESTS_TESTAPI to "true" or "false" (no quotes) to determine if we run the testapi tests.
149   - set RUN_JAVASCRIPTCORE_TESTS_BUILD to "true" or "false" (no quotes) to set the should-we-build-before-running-tests setting.
150   - set RUN_JAVASCRIPTCORE_TESTS_EXTRA_TESTS to the path of a yaml file or a directory of JS files to be run as part of run-javascriptcore-tests.
151 EOF
152
153 GetOptions(
154     'root=s' => \$root,
155     'extra-tests=s' => \@extraTests,
156     'build!' => \$buildJSC,
157     'testapi!' => \$runTestAPI,
158     'jsc-stress!' => \$runJSCStress,
159     'jit-stress-tests!' => \$runJITStressTests,
160     'mozilla-tests!' => \$runMozillaTests,
161     'quick!' => \$runQuickMode,
162     'fail-fast!' => \$failFast,
163     'force-collectContinuously!' => \$forceCollectContinuously,
164     'json-output=s' => \$jsonFileName,
165     'tarball!' => \$createTarball,
166     'remote=s' => \$remoteHost,
167     'remote-config-file=s' => \$remoteConfigFile,
168     'child-processes=s' => \$childProcesses,
169     'shell-runner' => \$shellRunner,
170     'make-runner' => \$makeRunner,
171     'memory-limited' => \$memoryLimited,
172     'filter=s' => \$filter,
173     'help' => \$showHelp,
174     'env-vars=s' => \$envVars,
175     'gmalloc:s' => \$gmallocPath,
176 );
177
178 # Assume any arguments left over from GetOptions are assumed to be build arguments
179 my @buildArgs = @ARGV;
180
181 if ($showHelp) {
182    print STDERR $usage;
183    exit 1;
184 }
185
186 setConfigurationProductDir(Cwd::abs_path($root)) if (defined($root));
187
188 if (defined($jsonFileName)) {
189     $jsonFileName = File::Spec->rel2abs($jsonFileName);
190 }
191
192 if (!defined($root) && $buildJSC) {
193     chdirWebKit();
194
195     push(@buildArgs, argumentsForConfiguration());
196
197     print "Running: build-jsc " . join(" ", @buildArgs) . "\n";
198     my $buildResult = system "perl", File::Spec->catfile("Tools", "Scripts", "build-jsc"), @buildArgs;
199     if ($buildResult) {
200         print STDERR "Compiling jsc failed!\n";
201         exit exitStatus($buildResult);
202     }
203 }
204
205 if (defined($gmallocPath)) {
206     if ($gmallocPath eq "") {
207         $envVars .= " DYLD_INSERT_LIBRARIES=" . $gmallocDefaultPath;
208     } else {
209         $envVars .= " DYLD_INSERT_LIBRARIES=" . $gmallocPath;
210     }
211 }
212
213 my $productDir = jscProductDir();
214 $ENV{DYLD_FRAMEWORK_PATH} = $productDir;
215 $ENV{JSCTEST_timeout} = 120 unless $ENV{JSCTEST_timeout}; # Set a 120 second timeout on all jsc tests (if environment variable not defined already).
216 $ENV{TZ}="US/Pacific"; # Some tests fail if the time zone is not set to US/Pacific (<https://webkit.org/b/136363>)
217 setPathForRunningWebKitApp(\%ENV) if isCygwin();
218
219 sub testapiPath($)
220 {
221     my ($productDir) = @_;
222     my $jscName = "testapi";
223     $jscName .= "_debug" if configuration() eq "Debug_All";
224     return File::Spec->catfile($productDir, $jscName);
225 }
226
227 #run api tests
228 if ($runTestAPI) {
229     chdirWebKit();
230     chdir($productDir) or die "Failed to switch directory to '$productDir'\n";
231     my @command = (testapiPath($productDir));
232     unshift @command, ("xcrun", "-sdk", xcodeSDK(), "sim") if willUseIOSSimulatorSDK();
233     unshift @command, wrapperPrefixIfNeeded() if shouldUseJhbuild();
234
235     if ($envVars ne "") {
236         foreach my $var (split(/\s+/, $envVars)) {
237             if ($var =~ /([^=]*)=(.*)/) {
238                 $ENV{$1} = $2;
239             }
240         }
241     }
242
243     # Use an "indirect object" so that system() won't get confused if the path
244     # contains spaces (see perldoc -f exec).
245     my $testapiResult = system { $command[0] } @command;
246     my $exitStatus = exitStatus($testapiResult);
247     print "testAPI completed with rc=$testapiResult ($exitStatus)\n";
248
249     if (defined($jsonFileName)) {
250         my $apiStatus = ($exitStatus == 0)? JSON::PP::true: JSON::PP::false;
251         $jsonData{'allApiTestsPassed'} = $apiStatus;
252     }
253
254     if ($testapiResult && $failFast) {
255         writeJsonDataIfApplicable();
256         exit exitStatus($testapiResult);
257     }
258 }
259
260 # Find JavaScriptCore directory
261 chdirWebKit();
262
263 runJSCStressTests();
264
265 sub runJSCStressTests
266 {
267     my $jscStressResultsDir = $productDir . "/jsc-stress-results";
268
269     my @testList;
270     if ($runJSCStress) {
271         @testList = (
272             "PerformanceTests/SunSpider/tests/sunspider-1.0",
273             "PerformanceTests/JetStream/cdjs/cdjs-tests.yaml",
274             "PerformanceTests/ARES-6/Air/airjs-tests.yaml",
275             "PerformanceTests/ARES-6/Basic/basic-tests.yaml",
276             "JSTests/executableAllocationFuzz.yaml",
277             "JSTests/exceptionFuzz.yaml",
278             "PerformanceTests/SunSpider/no-architecture-specific-optimizations.yaml",
279             "PerformanceTests/SunSpider/shadow-chicken.yaml",
280             "PerformanceTests/SunSpider/tests/v8-v6",
281             "JSTests/stress",
282             "JSTests/microbenchmarks",
283             "JSTests/slowMicrobenchmarks.yaml",
284             "PerformanceTests/SunSpider/profiler-test.yaml",
285             "LayoutTests/jsc-layout-tests.yaml",
286             "JSTests/typeProfiler.yaml",
287             "JSTests/controlFlowProfiler.yaml",
288             "JSTests/es6.yaml",
289             "JSTests/modules.yaml",
290             "JSTests/ChakraCore.yaml",
291             "JSTests/wasm.yaml");
292     }
293
294     if ($runMozillaTests) {
295         push(@testList, "JSTests/mozilla/mozilla-tests.yaml");
296     }
297
298     # Set LANG environment variable so the stress tests will work with newer ruby (<rdar://problem/15010705>)
299     $ENV{LANG}="en_US.UTF-8";
300     my @jscStressDriverCmd = (
301         "/usr/bin/env", "ruby", "Tools/Scripts/run-jsc-stress-tests",
302         "-j", jscPath($productDir), "-o", $jscStressResultsDir);
303
304     push(@jscStressDriverCmd, @testList);
305
306     if (isWindows() && !isCygwin()) {
307         shift @jscStressDriverCmd; # Remove /usr/bin/env
308     }
309
310     if (configuration() eq "Debug") {
311         push(@jscStressDriverCmd, "--debug");
312     }
313     
314     if ($forceCollectContinuously) {
315         push(@jscStressDriverCmd, "--force-collectContinuously");
316     }
317
318     if ($envVars ne "") {
319             push(@jscStressDriverCmd, "--env-vars");
320             push(@jscStressDriverCmd, $envVars);
321     }
322
323     if ($runQuickMode) {
324         push(@jscStressDriverCmd, "--quick");
325     }
326
327     if (!$runJITStressTests) {
328         push(@jscStressDriverCmd, "--no-jit");
329     }
330     if ($createTarball) {
331         push(@jscStressDriverCmd, "--tarball");
332     }
333
334     if ($remoteHost) {
335         push(@jscStressDriverCmd, "--remote");
336         push(@jscStressDriverCmd, $remoteHost);
337     }
338
339     if ($remoteConfigFile) {
340         push(@jscStressDriverCmd, "--remote-config-file");
341         push(@jscStressDriverCmd, $remoteConfigFile);
342     }
343
344     if ($childProcesses) {
345         push(@jscStressDriverCmd, "--child-processes");
346         push(@jscStressDriverCmd, $childProcesses);
347     }
348
349     if ($shellRunner) {
350         push(@jscStressDriverCmd, "--shell-runner");
351     }
352
353     if ($makeRunner) {
354         push(@jscStressDriverCmd, "--make-runner");
355     }
356
357     if ($memoryLimited) {
358         push(@jscStressDriverCmd, "--memory-limited");
359     }
360
361     if ($filter) {
362         push(@jscStressDriverCmd, "--filter");
363         push(@jscStressDriverCmd, $filter);
364     }
365
366     unshift @jscStressDriverCmd, wrapperPrefixIfNeeded() if shouldUseJhbuild();
367
368     # End option processing, the rest of the arguments are tests
369     push(@jscStressDriverCmd, "--");
370
371     for my $testSuite (@extraTests) {
372         push(@jscStressDriverCmd, $testSuite);
373     }
374     if (defined($ENV{"EXTRA_JSC_TESTS"})) {
375         push(@jscStressDriverCmd, $ENV{"EXTRA_JSC_TESTS"});
376     }
377     print "Running: " . join(" ", @jscStressDriverCmd) . "\n";
378     my $result = system(@jscStressDriverCmd);
379     exit exitStatus($result) if $result;
380
381     my @jscStressFailList = readAllLines($jscStressResultsDir . "/failed");
382     @jscStressFailList = sort @jscStressFailList;
383     my $numJSCStressFailures = @jscStressFailList;
384
385     if ($numJSCStressFailures) {
386         print "\n** The following JSC stress test failures have been introduced:\n";
387         foreach my $testFailure (@jscStressFailList) {
388             print "\t$testFailure\n";
389         }
390     }
391     print "\n";
392
393     print "Results for JSC stress tests:\n";
394     printThingsFound($numJSCStressFailures, "failure", "failures", "found");
395     print "    OK.\n" if $numJSCStressFailures == 0;
396
397     print "\n";
398
399     if (defined($jsonFileName)) {
400         $jsonData{'stressTestFailures'} = \@jscStressFailList;
401     }
402
403     writeJsonDataIfApplicable();
404     exit(1) if $numJSCStressFailures;
405 }
406
407 sub readAllLines
408 {
409     my ($filename) = @_;
410     my @array = ();
411     eval {
412         open FILE, $filename or die;
413         while (<FILE>) {
414             chomp;
415             push @array, $_;
416         }
417         close FILE;
418     };
419     return @array;
420 }
421
422 sub printThingsFound
423 {
424     my ($number, $label, $pluralLabel, $verb) = @_;
425     print "    $number ";
426     if ($number == 1) {
427         print $label;
428     } else {
429         print $pluralLabel;
430     }
431     print " $verb.\n";
432 }
433
434 sub writeJsonDataIfApplicable
435 {
436     if (defined($jsonFileName)) {
437         open(my $fileHandler, ">", $jsonFileName) or die;
438         print $fileHandler "${\encode_json(\%jsonData)}\n";
439         close($fileHandler);
440     }
441 }