Tool to mark jsc test skip/enable
https://bugs.webkit.org/show_bug.cgi?id=202063
Reviewed by Keith Miller.
* Scripts/run-javascriptcore-tests:
(runJSCStressTests):
* Scripts/run-jsc-stress-tests:
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@251161 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Tools/ChangeLog b/Tools/ChangeLog
index bbd51bf..ea397bc 100644
--- a/Tools/ChangeLog
+++ b/Tools/ChangeLog
@@ -1,3 +1,14 @@
+2019-10-15 Zhifei Fang <zhifei_fang@apple.com>
+
+ Tool to mark jsc test skip/enable
+ https://bugs.webkit.org/show_bug.cgi?id=202063
+
+ Reviewed by Keith Miller.
+
+ * Scripts/run-javascriptcore-tests:
+ (runJSCStressTests):
+ * Scripts/run-jsc-stress-tests:
+
2019-10-15 Peng Liu <peng.liu6@apple.com>
[Picture-in-Picture Web API] Implement HTMLVideoElement.requestPictureInPicture() / Document.exitPictureInPicture()
diff --git a/Tools/Scripts/mark-jsc-stress-test b/Tools/Scripts/mark-jsc-stress-test
new file mode 100755
index 0000000..43e01b3
--- /dev/null
+++ b/Tools/Scripts/mark-jsc-stress-test
@@ -0,0 +1,171 @@
+#!/usr/bin/env python -u
+import os
+import sys
+import getopt
+import argparse
+import re
+import logging
+import json
+
+logger = logging.getLogger()
+handler = logging.StreamHandler(sys.stdout)
+formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
+handler.setFormatter(formatter)
+logger.setLevel(logging.INFO)
+logger.addHandler(handler)
+
+def iter_dir_recusive(path, callback):
+ if os.path.isfile(path) and os.path.splitext(path)[1] == '.js':
+ logger.info("Processing {} ...".format(path))
+ callback(path)
+ else:
+ for root, dirs, files in os.walk(path):
+ for name in files:
+ iter_dir_recusive(os.path.join(root, name), callback)
+ logger.info("Done.")
+
+
+class JSCTestModifier(object):
+ variables = [
+ "$hostOs", "$model", "$architecture"
+ ]
+ def __init__(self, test_pathes, conditions={}, match="all"):
+ self._conditions = conditions
+ self._test_pathes = test_pathes
+ self._match = match
+ self._skip_line_postfix = "# added by mark-jsc-stress-test.py"
+
+ def skip(self):
+ for path in self._test_pathes:
+ logger.info("Mark {} skip".format(path))
+ iter_dir_recusive(path, lambda file_path: self._skip_test_file(file_path))
+
+ def enable(self):
+ for path in self._test_pathes:
+ logger.info("Mark {} enable".format(path))
+ iter_dir_recusive(path, lambda file_path: self._enable_test_file(file_path))
+
+ def _generate_condition_op(self, value):
+ op = "=="
+ if ("!" == value[0]):
+ op = "!="
+ value = value[1:]
+ return op, value
+
+ # Condition grammer is like !A or B or C and D
+ # Translate it to ruby: $hostOs != A or $hostOs == B or $hostOs == C and $hostOs == D
+ def _parse_condition(self, variable, condition):
+ res = []
+ values = []
+ for word in re.split(r'\s+', condition):
+ if word == "or" or word == "and":
+ value = " ".join(values).strip()
+ values = []
+ res.append('{} {} "{}"'.format(variable, *self._generate_condition_op(value)))
+ res.append(word)
+ else:
+ values.append(word)
+ if values:
+ value = " ".join(values).strip()
+ res.append('{} {} "{}"'.format(variable, *self._generate_condition_op(value)))
+ return " ".join(res)
+
+ def _generate_skip_annotation_line(self):
+ skip_line_prefix = "//@ skip if"
+ skip_conditions = []
+ skip_line = "{} {} {}"
+ supported_variables = filter(lambda variable: variable in self._conditions, JSCTestModifier.variables)
+ condition_template = "{}" if len(supported_variables) == 1 else "({})"
+ for variable in supported_variables:
+ skip_conditions.append(condition_template.format(self._parse_condition(variable, self._conditions[variable])))
+ if not skip_conditions:
+ # No conditions, always skip
+ skip_conditions = ["true"]
+ if self._match == "any":
+ skip_line = skip_line.format(skip_line_prefix, " or ".join(skip_conditions), self._skip_line_postfix)
+ elif self._match == "all":
+ skip_line = skip_line.format(skip_line_prefix, " and ".join(skip_conditions), self._skip_line_postfix)
+ return skip_line
+
+ # This can only remove the skip annotation generated by this script
+ def _enable_test_file(self, test_file):
+ with open(test_file, 'r+') as f:
+ lines = f.readlines()
+ f.seek(0)
+ for line in lines:
+ if not self._skip_line_postfix in line:
+ f.write(line)
+ f.truncate()
+
+
+ def _skip_test_file(self, test_file):
+ # remove the exisiting skip line, so that we can apply the new one
+ self._enable_test_file(test_file)
+ skip_line = self._generate_skip_annotation_line()
+ with open(test_file, 'r+') as f:
+ original_content = f.read()
+ f.seek(0)
+ f.write("{}\n{}".format(skip_line, original_content))
+
+opensource_root = os.path.join(os.path.dirname(os.path.realpath(__file__)), "../../")
+jsc_test_search_path = [
+ os.path.join(opensource_root, "JSTests"),
+ os.path.join(opensource_root, "LayoutTests")
+]
+def main():
+ parser = argparse.ArgumentParser()
+ subparsers = parser.add_subparsers(dest="action")
+ file_list_help = "Files/directories list; use ',' to separate each item. Example: a.js, b.js, c.js Use '-' if you are using --jsc-json-output argument"
+ parser_enable = subparsers.add_parser("enable", help="Enable the tests which are marked as skipped by this script")
+ parser_enable.add_argument("files", help=file_list_help)
+ parser_enable.add_argument("--jsc-json-output", help="Pass the json output of run-javascriptcore-tests to unskip all failed tests")
+
+ parser_skip = subparsers.add_parser("skip", help="Insert skip condition to given files/directories")
+ parser_skip.add_argument("files", help=file_list_help)
+ parser_skip.add_argument("--jsc-json-output", help="Pass the json output of run-javascriptcore-tests to skip all failed tests")
+ parser_skip.add_argument("--platform", "--host-os", help="Skip if host os matches given value, Examples: 'windows or linux' '!windows and !linux'")
+ parser_skip.add_argument("--model", help="Skip if hardware model matches given value, Examples: 'Apple Watch Series 3 or Apple Watch Series 4' '!Apple Watch Series 3 and !Apple Watch Series 4'")
+ parser_skip.add_argument("--architecture", help="Skip if architecture matches given value, Examples: 'arm or x86' '!arm and !x86'")
+ parser_skip.add_argument("--match", default="all", help="Match all or any above conditions")
+
+ args = vars(parser.parse_args())
+ conditions = {}
+ files = []
+ if not args["files"] and not args["--log-file"]:
+ logger.error("Please speicify a list of file, or use --log-file to give a JSC test log")
+ return 1
+ if args["files"] and not args["files"] == "-":
+ files += args["files"].split(",")
+ if args["jsc_json_output"]:
+ with open(args["jsc_json_output"]) as f:
+ jsc_json_output = json.load(f)
+ failures = jsc_json_output["stressTestFailures"]
+ failure_test_files_set = set()
+ for failure_test in failures:
+ path_parts = failure_test.split(os.path.sep)
+ if 'yaml' in path_parts[0]:
+ failure_test_path = os.path.join(*path_parts[1:])
+ else:
+ failure_test_path = failure_test
+ failure_test_file = os.path.splitext(failure_test_path)[0]
+ for search_path in jsc_test_search_path:
+ whole_path = os.path.join(search_path, failure_test_file)
+ if failure_test_file not in failure_test_files_set and os.path.isfile(whole_path):
+ files.append(whole_path)
+ failure_test_files_set.add(failure_test_file)
+
+ if "host_os" in args and args["host_os"]:
+ conditions["$hostOs"] = args["host_os"]
+ if "platform" in args and args["platform"]:
+ conditions["$hostOs"] = args["platform"]
+ if "architecture" in args and args["architecture"]:
+ conditions["$architecture"] = args["architecture"]
+ if "model" in args and args["model"]:
+ conditions["$model"] = args["model"]
+
+ modifer = JSCTestModifier(files, conditions, args["match"] if "match" in args else None)
+ getattr(modifer, args["action"])()
+ return 0
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/Tools/Scripts/run-javascriptcore-tests b/Tools/Scripts/run-javascriptcore-tests
index 8fcac48..f3bba60 100755
--- a/Tools/Scripts/run-javascriptcore-tests
+++ b/Tools/Scripts/run-javascriptcore-tests
@@ -90,6 +90,7 @@
my $createTarball = 0;
my $remoteHost = 0;
+my $model = 0;
my $failFast = 1;
my %jsonData = ();
my @testResults = ();
@@ -229,6 +230,7 @@
--tarball Create a tarball of the bundle produced by running the JSC stress tests.
--remote= Run the JSC stress tests on the specified remote host. Implies --tarball.
--remote-config-file= Same as remote, but read config from JSON file.
+ --model= Specify remote hardware model, this info used for determine what jsc tests should run on remote
--extra-tests= Path to a file containing extra tests
--child-processes= Specify the number of child processes.
--shell-runner Uses the shell-based test runner instead of the default make-based runner.
@@ -286,6 +288,7 @@
'json-output=s' => \$jsonFileName,
'tarball!' => \$createTarball,
'remote=s' => \$remoteHost,
+ 'model=s' => \$model,
'remote-config-file=s' => \$remoteConfigFile,
'child-processes=s' => \$childProcesses,
'shell-runner' => \$shellRunner,
@@ -536,6 +539,11 @@
push(@jscStressDriverCmd, "--remote-config-file");
push(@jscStressDriverCmd, $remoteConfigFile);
}
+
+ if ($model) {
+ push(@jscStressDriverCmd, "--model");
+ push(@jscStressDriverCmd, $model);
+ }
if ($childProcesses) {
push(@jscStressDriverCmd, "--child-processes");
diff --git a/Tools/Scripts/run-jsc-stress-tests b/Tools/Scripts/run-jsc-stress-tests
index 54dfc0b..85c7bcd 100755
--- a/Tools/Scripts/run-jsc-stress-tests
+++ b/Tools/Scripts/run-jsc-stress-tests
@@ -114,6 +114,7 @@
$remoteHosts = []
$architecture = nil
$hostOS = nil
+$model = nil
$filter = nil
$envVars = []
$mode = "full"
@@ -183,6 +184,7 @@
['--test-writer', GetoptLong::REQUIRED_ARGUMENT],
['--remote', GetoptLong::REQUIRED_ARGUMENT],
['--remote-config-file', GetoptLong::REQUIRED_ARGUMENT],
+ ['--model', GetoptLong::REQUIRED_ARGUMENT],
['--child-processes', '-c', GetoptLong::REQUIRED_ARGUMENT],
['--filter', GetoptLong::REQUIRED_ARGUMENT],
['--verbose', '-v', GetoptLong::NO_ARGUMENT],
@@ -241,6 +243,8 @@
$architecture = arg
when '--os'
$hostOS = arg
+ when '--model'
+ $model = arg
when '--env-vars'
$envVars = arg.gsub(/\s+/, ' ').split(' ')
when '--quick'