172 lines
7.4 KiB
Python
Executable File
172 lines
7.4 KiB
Python
Executable File
#!/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 = [variable for variable in JSCTestModifier.variables if variable in self._conditions]
|
|
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())
|