Skip to content

Commit

Permalink
Merge pull request #162 from w3c/jgraham/update_properties
Browse files Browse the repository at this point in the history
Allow per-product configuration of properties to use in metadata conditionals.
  • Loading branch information
jgraham committed Nov 20, 2015
2 parents 24eddf3 + 2a1cff9 commit 045e705
Show file tree
Hide file tree
Showing 9 changed files with 163 additions and 40 deletions.
8 changes: 7 additions & 1 deletion wptrunner/browsers/firefox.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -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()

Expand Down
14 changes: 12 additions & 2 deletions wptrunner/browsers/servo.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -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):
Expand Down
12 changes: 11 additions & 1 deletion wptrunner/browsers/servodriver.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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:
Expand Down
71 changes: 52 additions & 19 deletions wptrunner/manifestupdate.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,18 @@ 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,
a new AST is created to associate with this manifest.
:param test_path: Path of the test file associated with this manifest.
:param url_base: Base url for serving the tests in this manifest
:param url_base: Base url for serving the tests in this manifest.
:param property_order: List of properties to use in expectation metadata
from most to least significant.
:param boolean_properties: Set of properties in property_order that should
be treated as boolean.
"""
if node is None:
node = DataNode(None)
Expand All @@ -65,6 +70,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)
Expand Down Expand Up @@ -229,7 +236,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])
Expand Down Expand Up @@ -308,18 +318,30 @@ 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
:param values: List of Results"""
:param values: List of Results
:param property_order: List of properties to use in expectation metadata
from most to least significant.
:param boolean_properties: Set of properties in property_order that should
be treated as boolean."""

by_property = defaultdict(set)
for run_info, status in 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:
Expand All @@ -328,11 +350,9 @@ def group_conditionals(values):
del by_property[key]

properties = set(item[0] for item in by_property.iterkeys())

prop_order = ["debug", "e10s", "os", "version", "processor", "bits"]
include_props = []

for prop in prop_order:
for prop in property_order:
if prop in properties:
include_props.append(prop)

Expand All @@ -343,28 +363,33 @@ 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."""
properties in prop_set match.
:param prop_set: tuple of (property name, value) pairs for each
property in this expression and the value it must match
:param status: Status on RHS when all the given properties match
:param boolean_properties: Set of properties in property_order that should
be treated as boolean.
"""
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("=="),
Expand Down Expand Up @@ -397,24 +422,32 @@ 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.
:param metadata_root: Absolute path to the root of the metadata directory
:param test_path: Path to the test(s) relative to the test root
:param url_base: Base url for serving the tests in this manifest
"""
:param property_order: List of properties to use in expectation metadata
from most to least significant.
:param boolean_properties: Set of properties in property_order that should
be treated as boolean."""
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)
44 changes: 32 additions & 12 deletions wptrunner/metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"""

Expand All @@ -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"]
Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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)
Expand All @@ -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

Expand Down
15 changes: 15 additions & 0 deletions wptrunner/products.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,18 @@ def load_product(config, product):
browser_cls, browser_kwargs,
executor_classes, executor_kwargs,
env_options, run_info_extras)


def load_product_update(config, product):
"""Return tuple of (property_order, boolean_properties) indicating the
run_info properties to use when constructing the expectation data for
this product. None for either key indicates that the default keys
appropriate for distinguishing based on platform will be used."""

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
Loading

0 comments on commit 045e705

Please sign in to comment.