diff --git a/wptrunner/browsers/firefox.py b/wptrunner/browsers/firefox.py index cf4defa..675fde6 100644 --- a/wptrunner/browsers/firefox.py +++ b/wptrunner/browsers/firefox.py @@ -28,7 +28,8 @@ "browser_kwargs": "browser_kwargs", "executor_kwargs": "executor_kwargs", "env_options": "env_options", - "run_info_extras": "run_info_extras"} + "run_info_extras": "run_info_extras", + "update_properties": "update_properties"} def check_args(**kwargs): @@ -73,9 +74,14 @@ def env_options(): "certificate_domain": "web-platform.test", "supports_debugger": True} + def run_info_extras(**kwargs): return {"e10s": kwargs["gecko_e10s"]} + +def update_properties(): + return ["debug", "e10s", "os", "version", "processor", "bits"], {"debug", "e10s"} + class FirefoxBrowser(Browser): used_ports = set() diff --git a/wptrunner/browsers/servo.py b/wptrunner/browsers/servo.py index dce012d..0f6e11f 100644 --- a/wptrunner/browsers/servo.py +++ b/wptrunner/browsers/servo.py @@ -17,7 +17,9 @@ "reftest": "ServoRefTestExecutor"}, "browser_kwargs": "browser_kwargs", "executor_kwargs": "executor_kwargs", - "env_options": "env_options"} + "env_options": "env_options", + "run_info_extras": "run_info_extras", + "update_properties": "update_properties"} def check_args(**kwargs): @@ -47,8 +49,16 @@ def env_options(): "supports_debugger": True} +def run_info_extras(**kwargs): + return {"backend": kwargs["servo_backend"]} + + +def update_properties(): + return ["debug", "os", "version", "processor", "bits", "backend"], None + + def render_arg(render_backend): - return {"cpu": "--cpu"}[render_backend] + return {"cpu": "--cpu", "webrender": "--webrender"}[render_backend] class ServoBrowser(NullBrowser): diff --git a/wptrunner/browsers/servodriver.py b/wptrunner/browsers/servodriver.py index 9a7dd4e..2c05a4d 100644 --- a/wptrunner/browsers/servodriver.py +++ b/wptrunner/browsers/servodriver.py @@ -23,7 +23,9 @@ "reftest": "ServoWebDriverRefTestExecutor"}, "browser_kwargs": "browser_kwargs", "executor_kwargs": "executor_kwargs", - "env_options": "env_options"} + "env_options": "env_options", + "run_info_extras": "run_info_extras", + "update_properties": "update_properties"} hosts_text = """127.0.0.1 web-platform.test 127.0.0.1 www.web-platform.test @@ -59,6 +61,14 @@ def env_options(): "supports_debugger": True} +def run_info_extras(**kwargs): + return {"backend": kwargs["servo_backend"]} + + +def update_properties(): + return ["debug", "os", "version", "processor", "bits", "backend"], None + + def make_hosts_file(): hosts_fd, hosts_path = tempfile.mkstemp() with os.fdopen(hosts_fd, "w") as f: diff --git a/wptrunner/manifestupdate.py b/wptrunner/manifestupdate.py index 0a5d46c..db5502b 100644 --- a/wptrunner/manifestupdate.py +++ b/wptrunner/manifestupdate.py @@ -49,7 +49,8 @@ def data_cls_getter(output_node, visited_node): class ExpectedManifest(ManifestItem): - def __init__(self, node, test_path=None, url_base=None): + def __init__(self, node, test_path=None, url_base=None, property_order=None, + boolean_properties=None): """Object representing all the tests in a particular manifest :param node: AST Node associated with this object. If this is None, @@ -65,6 +66,8 @@ def __init__(self, node, test_path=None, url_base=None): self.url_base = url_base assert self.url_base is not None self.modified = False + self.boolean_properties = boolean_properties + self.property_order = property_order def append(self, child): ManifestItem.append(self, child) @@ -229,7 +232,10 @@ def coalesce_expected(self): self.set("expected", status, condition=None) final_conditionals.append(self._data["expected"][-1]) else: - for conditional_node, status in group_conditionals(self.new_expected): + for conditional_node, status in group_conditionals( + self.new_expected, + property_order=self.root.property_order, + boolean_properties=self.root.boolean_properties): if status != unconditional_status: self.set("expected", status, condition=conditional_node.children[0]) final_conditionals.append(self._data["expected"][-1]) @@ -308,7 +314,7 @@ def is_empty(self): return True -def group_conditionals(values): +def group_conditionals(values, property_order=None, boolean_properties=None): """Given a list of Result objects, return a list of (conditional_node, status) pairs representing the conditional expressions that are required to match each status @@ -320,6 +326,14 @@ def group_conditionals(values): for prop_name, prop_value in run_info.iteritems(): by_property[(prop_name, prop_value)].add(status) + if property_order is None: + property_order = ["debug", "os", "version", "processor", "bits"] + + if boolean_properties is None: + boolean_properties = set(["debug"]) + else: + boolean_properties = set(boolean_properties) + # If we have more than one value, remove any properties that are common # for all the values if len(values) > 1: @@ -329,10 +343,11 @@ def group_conditionals(values): properties = set(item[0] for item in by_property.iterkeys()) - prop_order = ["debug", "e10s", "os", "version", "processor", "bits"] + if property_order is None: + property_order = ["debug", "os", "version", "processor", "bits"] include_props = [] - for prop in prop_order: + for prop in property_order: if prop in properties: include_props.append(prop) @@ -343,28 +358,26 @@ def group_conditionals(values): if prop_set in conditions: continue - expr = make_expr(prop_set, status) + expr = make_expr(prop_set, status, boolean_properties=boolean_properties) conditions[prop_set] = (expr, status) return conditions.values() -def make_expr(prop_set, status): +def make_expr(prop_set, status, boolean_properties=None): """Create an AST that returns the value ``status`` given all the properties in prop_set match.""" root = ConditionalNode() assert len(prop_set) > 0 - no_value_props = set(["debug", "e10s"]) - expressions = [] for prop, value in prop_set: number_types = (int, float, long) value_cls = (NumberNode if type(value) in number_types else StringNode) - if prop not in no_value_props: + if prop not in boolean_properties: expressions.append( BinaryExpressionNode( BinaryOperatorNode("=="), @@ -397,7 +410,8 @@ def make_expr(prop_set, status): return root -def get_manifest(metadata_root, test_path, url_base): +def get_manifest(metadata_root, test_path, url_base, property_order=None, + boolean_properties=None): """Get the ExpectedManifest for a particular test path, or None if there is no metadata stored for that test path. @@ -408,13 +422,17 @@ def get_manifest(metadata_root, test_path, url_base): manifest_path = expected.expected_path(metadata_root, test_path) try: with open(manifest_path) as f: - return compile(f, test_path, url_base) + return compile(f, test_path, url_base, property_order=property_order, + boolean_properties=boolean_properties) except IOError: return None -def compile(manifest_file, test_path, url_base): +def compile(manifest_file, test_path, url_base, property_order=None, + boolean_properties=None): return conditional.compile(manifest_file, data_cls_getter=data_cls_getter, test_path=test_path, - url_base=url_base) + url_base=url_base, + property_order=property_order, + boolean_properties=boolean_properties) diff --git a/wptrunner/metadata.py b/wptrunner/metadata.py index 7f03034..1a25898 100644 --- a/wptrunner/metadata.py +++ b/wptrunner/metadata.py @@ -32,7 +32,7 @@ def load_test_manifests(serve_root, test_paths): def update_expected(test_paths, serve_root, log_file_names, rev_old=None, rev_new="HEAD", ignore_existing=False, - sync_root=None): + sync_root=None, property_order=None, boolean_properties=None): """Update the metadata files for web-platform-tests based on the results obtained in a previous run""" @@ -51,7 +51,9 @@ def update_expected(test_paths, serve_root, log_file_names, expected_map_by_manifest = update_from_logs(manifests, *log_file_names, - ignore_existing=ignore_existing) + ignore_existing=ignore_existing, + property_order=property_order, + boolean_properties=boolean_properties) for test_manifest, expected_map in expected_map_by_manifest.iteritems(): url_base = manifests[test_manifest]["url_base"] @@ -127,14 +129,19 @@ def unexpected_changes(manifests, change_data, files_changed): def update_from_logs(manifests, *log_filenames, **kwargs): - ignore_existing = kwargs.pop("ignore_existing", False) + ignore_existing = kwargs.get("ignore_existing", False) + property_order = kwargs.get("property_order") + boolean_properties = kwargs.get("boolean_properties") expected_map = {} id_test_map = {} for test_manifest, paths in manifests.iteritems(): - expected_map_manifest, id_path_map_manifest = create_test_tree(paths["metadata_path"], - test_manifest) + expected_map_manifest, id_path_map_manifest = create_test_tree( + paths["metadata_path"], + test_manifest, + property_order=property_order, + boolean_properties=boolean_properties) expected_map[test_manifest] = expected_map_manifest id_test_map.update(id_path_map_manifest) @@ -284,15 +291,22 @@ def test_end(self, data): del self.test_cache[test_id] -def create_test_tree(metadata_path, test_manifest): +def create_test_tree(metadata_path, test_manifest, property_order=None, + boolean_properties=None): expected_map = {} id_test_map = {} exclude_types = frozenset(["stub", "helper", "manual"]) include_types = set(manifest.item_types) - exclude_types for test_path, tests in test_manifest.itertypes(*include_types): - expected_data = load_expected(test_manifest, metadata_path, test_path, tests) + expected_data = load_expected(test_manifest, metadata_path, test_path, tests, + property_order=property_order, + boolean_properties=boolean_properties) if expected_data is None: - expected_data = create_expected(test_manifest, test_path, tests) + expected_data = create_expected(test_manifest, + test_path, + tests, + property_order=property_order, + boolean_properties=boolean_properties) for test in tests: id_test_map[test.id] = (test_manifest, test) @@ -301,17 +315,23 @@ def create_test_tree(metadata_path, test_manifest): return expected_map, id_test_map -def create_expected(test_manifest, test_path, tests): - expected = manifestupdate.ExpectedManifest(None, test_path, test_manifest.url_base) +def create_expected(test_manifest, test_path, tests, property_order=None, + boolean_properties=None): + expected = manifestupdate.ExpectedManifest(None, test_path, test_manifest.url_base, + property_order=property_order, + boolean_properties=boolean_properties) for test in tests: expected.append(manifestupdate.TestNode.create(test.item_type, test.id)) return expected -def load_expected(test_manifest, metadata_path, test_path, tests): +def load_expected(test_manifest, metadata_path, test_path, tests, property_order=None, + boolean_properties=None): expected_manifest = manifestupdate.get_manifest(metadata_path, test_path, - test_manifest.url_base) + test_manifest.url_base, + property_order=property_order, + boolean_properties=boolean_properties) if expected_manifest is None: return diff --git a/wptrunner/products.py b/wptrunner/products.py index f67a51c..5bf0079 100644 --- a/wptrunner/products.py +++ b/wptrunner/products.py @@ -55,3 +55,13 @@ def load_product(config, product): browser_cls, browser_kwargs, executor_classes, executor_kwargs, env_options, run_info_extras) + + +def load_product_update(config, product): + module = product_module(config, product) + data = module.__wptrunner__ + + update_properties = (getattr(module, data["update_properties"])() + if "update_properties" in data else (None, None)) + + return update_properties diff --git a/wptrunner/update/metadata.py b/wptrunner/update/metadata.py index dbcc9f9..c62dfec 100644 --- a/wptrunner/update/metadata.py +++ b/wptrunner/update/metadata.py @@ -4,10 +4,21 @@ import os -from .. import metadata +from .. import metadata, products from base import Step, StepRunner +class GetUpdatePropertyList(Step): + provides = ["property_order", "boolean_properties"] + + + def create(self, state): + property_order, boolean_properties = products.load_product_update( + state.config, state.product) + state.property_order = property_order + state.boolean_properties = boolean_properties + + class UpdateExpected(Step): """Do the metadata update on the local checkout""" @@ -24,7 +35,9 @@ def create(self, state): state.run_log, rev_old=None, ignore_existing=state.ignore_existing, - sync_root=sync_root) + sync_root=sync_root, + property_order=state.property_order, + boolean_properties=state.boolean_properties) class CreateMetadataPatch(Step): @@ -57,5 +70,6 @@ def create(self, state): class MetadataUpdateRunner(StepRunner): """(Sub)Runner for updating metadata""" - steps = [UpdateExpected, + steps = [GetUpdatePropertyList, + UpdateExpected, CreateMetadataPatch] diff --git a/wptrunner/update/update.py b/wptrunner/update/update.py index 2fb9443..213622c 100644 --- a/wptrunner/update/update.py +++ b/wptrunner/update/update.py @@ -91,6 +91,8 @@ def create(self, state): state.ignore_existing = kwargs["ignore_existing"] state.no_patch = kwargs["no_patch"] state.suite_name = kwargs["suite_name"] + state.product = kwargs["product"] + state.config = kwargs["config"] runner = MetadataUpdateRunner(self.logger, state) runner.run() diff --git a/wptrunner/wptcommandline.py b/wptrunner/wptcommandline.py index 9e84d11..96b6906 100644 --- a/wptrunner/wptcommandline.py +++ b/wptrunner/wptcommandline.py @@ -338,12 +338,25 @@ def check_args(kwargs): return kwargs +def check_args_update(kwargs): + set_from_config(kwargs) + + if kwargs["product"] is None: + kwargs["product"] = "firefox" -def create_parser_update(): +def create_parser_update(product_choices=None): from mozlog.structured import commandline + import products + + if product_choices is None: + config_data = config.load() + product_choices = products.products_enabled(config_data) + parser = argparse.ArgumentParser("web-platform-tests-update", description="Update script for web-platform-tests tests.") + parser.add_argument("--product", action="store", choices=product_choices, + default=None, help="Browser for which metadata is being updated") parser.add_argument("--config", action="store", type=abs_path, help="Path to config file") parser.add_argument("--metadata", action="store", type=abs_path, dest="metadata_root", help="Path to the folder containing test metadata"), @@ -386,7 +399,7 @@ def parse_args(): def parse_args_update(): parser = create_parser_update() rv = vars(parser.parse_args()) - set_from_config(rv) + check_args_update(rv) return rv