summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/harness/wptrunner/manifestexpected.py
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/harness/wptrunner/manifestexpected.py')
-rw-r--r--testing/web-platform/harness/wptrunner/manifestexpected.py256
1 files changed, 256 insertions, 0 deletions
diff --git a/testing/web-platform/harness/wptrunner/manifestexpected.py b/testing/web-platform/harness/wptrunner/manifestexpected.py
new file mode 100644
index 000000000..c0e22a843
--- /dev/null
+++ b/testing/web-platform/harness/wptrunner/manifestexpected.py
@@ -0,0 +1,256 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this file,
+# You can obtain one at http://mozilla.org/MPL/2.0/.
+
+import os
+import urlparse
+
+from wptmanifest.backends import static
+from wptmanifest.backends.static import ManifestItem
+
+import expected
+
+"""Manifest structure used to store expected results of a test.
+
+Each manifest file is represented by an ExpectedManifest that
+has one or more TestNode children, one per test in the manifest.
+Each TestNode has zero or more SubtestNode children, one for each
+known subtest of the test.
+"""
+
+def data_cls_getter(output_node, visited_node):
+ # visited_node is intentionally unused
+ if output_node is None:
+ return ExpectedManifest
+ if isinstance(output_node, ExpectedManifest):
+ return TestNode
+ if isinstance(output_node, TestNode):
+ return SubtestNode
+ raise ValueError
+
+
+def bool_prop(name, node):
+ """Boolean property"""
+ try:
+ return node.get(name)
+ except KeyError:
+ return None
+
+
+def tags(node):
+ """Set of tags that have been applied to the test"""
+ try:
+ value = node.get("tags")
+ if isinstance(value, (str, unicode)):
+ return {value}
+ return set(value)
+ except KeyError:
+ return set()
+
+
+def prefs(node):
+ def value(ini_value):
+ if isinstance(ini_value, (str, unicode)):
+ return tuple(ini_value.split(":", 1))
+ else:
+ return (ini_value, None)
+
+ try:
+ node_prefs = node.get("prefs")
+ if type(node_prefs) in (str, unicode):
+ prefs = {value(node_prefs)}
+ rv = dict(value(item) for item in node_prefs)
+ except KeyError:
+ rv = {}
+ return rv
+
+
+class ExpectedManifest(ManifestItem):
+ def __init__(self, name, test_path, url_base):
+ """Object representing all the tests in a particular manifest
+
+ :param name: Name of the AST Node associated with this object.
+ Should always be None since this should always be associated with
+ the root node of the AST.
+ :param test_path: Path of the test file associated with this manifest.
+ :param url_base: Base url for serving the tests in this manifest
+ """
+ if name is not None:
+ raise ValueError("ExpectedManifest should represent the root node")
+ if test_path is None:
+ raise ValueError("ExpectedManifest requires a test path")
+ if url_base is None:
+ raise ValueError("ExpectedManifest requires a base url")
+ ManifestItem.__init__(self, name)
+ self.child_map = {}
+ self.test_path = test_path
+ self.url_base = url_base
+
+ def append(self, child):
+ """Add a test to the manifest"""
+ ManifestItem.append(self, child)
+ self.child_map[child.id] = child
+
+ def _remove_child(self, child):
+ del self.child_map[child.id]
+ ManifestItem.remove_child(self, child)
+ assert len(self.child_map) == len(self.children)
+
+ def get_test(self, test_id):
+ """Get a test from the manifest by ID
+
+ :param test_id: ID of the test to return."""
+ return self.child_map.get(test_id)
+
+ @property
+ def url(self):
+ return urlparse.urljoin(self.url_base,
+ "/".join(self.test_path.split(os.path.sep)))
+
+ @property
+ def disabled(self):
+ return bool_prop("disabled", self)
+
+ @property
+ def restart_after(self):
+ return bool_prop("restart-after", self)
+
+ @property
+ def tags(self):
+ return tags(self)
+
+ @property
+ def prefs(self):
+ return prefs(self)
+
+
+class DirectoryManifest(ManifestItem):
+ @property
+ def disabled(self):
+ return bool_prop("disabled", self)
+
+ @property
+ def restart_after(self):
+ return bool_prop("restart-after", self)
+
+ @property
+ def tags(self):
+ return tags(self)
+
+ @property
+ def prefs(self):
+ return prefs(self)
+
+
+class TestNode(ManifestItem):
+ def __init__(self, name):
+ """Tree node associated with a particular test in a manifest
+
+ :param name: name of the test"""
+ assert name is not None
+ ManifestItem.__init__(self, name)
+ self.updated_expected = []
+ self.new_expected = []
+ self.subtests = {}
+ self.default_status = None
+ self._from_file = True
+
+ @property
+ def is_empty(self):
+ required_keys = set(["type"])
+ if set(self._data.keys()) != required_keys:
+ return False
+ return all(child.is_empty for child in self.children)
+
+ @property
+ def test_type(self):
+ return self.get("type")
+
+ @property
+ def id(self):
+ return urlparse.urljoin(self.parent.url, self.name)
+
+ @property
+ def disabled(self):
+ return bool_prop("disabled", self)
+
+ @property
+ def restart_after(self):
+ return bool_prop("restart-after", self)
+
+ @property
+ def tags(self):
+ return tags(self)
+
+ @property
+ def prefs(self):
+ return prefs(self)
+
+ def append(self, node):
+ """Add a subtest to the current test
+
+ :param node: AST Node associated with the subtest"""
+ child = ManifestItem.append(self, node)
+ self.subtests[child.name] = child
+
+ def get_subtest(self, name):
+ """Get the SubtestNode corresponding to a particular subtest, by name
+
+ :param name: Name of the node to return"""
+ if name in self.subtests:
+ return self.subtests[name]
+ return None
+
+
+class SubtestNode(TestNode):
+ def __init__(self, name):
+ """Tree node associated with a particular subtest in a manifest
+
+ :param name: name of the subtest"""
+ TestNode.__init__(self, name)
+
+ @property
+ def is_empty(self):
+ if self._data:
+ return False
+ return True
+
+
+def get_manifest(metadata_root, test_path, url_base, run_info):
+ """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 run_info: Dictionary of properties of the test run for which the expectation
+ values should be computed.
+ """
+ manifest_path = expected.expected_path(metadata_root, test_path)
+ try:
+ with open(manifest_path) as f:
+ return static.compile(f,
+ run_info,
+ data_cls_getter=data_cls_getter,
+ test_path=test_path,
+ url_base=url_base)
+ except IOError:
+ return None
+
+def get_dir_manifest(metadata_root, path, run_info):
+ """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 path: Path to the ini file relative to the metadata root
+ :param run_info: Dictionary of properties of the test run for which the expectation
+ values should be computed.
+ """
+ full_path = os.path.join(metadata_root, path)
+ try:
+ with open(full_path) as f:
+ return static.compile(f,
+ run_info,
+ data_cls_getter=lambda x,y: DirectoryManifest)
+ except IOError:
+ return None