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