summaryrefslogtreecommitdiffstats
path: root/testing/mozbase/moztest/moztest/selftest
diff options
context:
space:
mode:
Diffstat (limited to 'testing/mozbase/moztest/moztest/selftest')
-rw-r--r--testing/mozbase/moztest/moztest/selftest/__init__.py0
-rw-r--r--testing/mozbase/moztest/moztest/selftest/fixtures.py116
-rw-r--r--testing/mozbase/moztest/moztest/selftest/output.py52
3 files changed, 168 insertions, 0 deletions
diff --git a/testing/mozbase/moztest/moztest/selftest/__init__.py b/testing/mozbase/moztest/moztest/selftest/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/testing/mozbase/moztest/moztest/selftest/__init__.py
diff --git a/testing/mozbase/moztest/moztest/selftest/fixtures.py b/testing/mozbase/moztest/moztest/selftest/fixtures.py
new file mode 100644
index 0000000000..5d21e7aa63
--- /dev/null
+++ b/testing/mozbase/moztest/moztest/selftest/fixtures.py
@@ -0,0 +1,116 @@
+# 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/.
+"""Pytest fixtures to help set up Firefox and a tests archive
+in test harness selftests.
+"""
+
+import os
+import shutil
+import sys
+
+import mozinstall
+import pytest
+
+here = os.path.abspath(os.path.dirname(__file__))
+
+try:
+ from mozbuild.base import MozbuildObject
+
+ build = MozbuildObject.from_environment(cwd=here)
+except ImportError:
+ build = None
+
+
+HARNESS_ROOT_NOT_FOUND = """
+Could not find test harness root. Either a build or the 'GECKO_INSTALLER_URL'
+environment variable is required.
+""".lstrip()
+
+
+def _get_test_harness(suite, install_dir, flavor="plain"):
+ # Check if there is a local build
+ if build:
+ harness_root = os.path.join(build.topobjdir, "_tests", install_dir)
+ if os.path.isdir(harness_root):
+ return harness_root
+
+ if "TEST_HARNESS_ROOT" in os.environ:
+ harness_root = os.path.join(os.environ["TEST_HARNESS_ROOT"], suite)
+ if os.path.isdir(harness_root):
+ return harness_root
+
+ # Couldn't find a harness root, let caller do error handling.
+ return None
+
+
+@pytest.fixture(scope="session")
+def setup_test_harness(request, flavor="plain"):
+ """Fixture for setting up a mozharness-based test harness like
+ mochitest or reftest"""
+
+ def inner(files_dir, *args, **kwargs):
+ harness_root = _get_test_harness(*args, **kwargs)
+ test_root = None
+ if harness_root:
+ sys.path.insert(0, harness_root)
+
+ # Link the test files to the test package so updates are automatically
+ # picked up. Fallback to copy on Windows.
+ if files_dir:
+ test_root = os.path.join(harness_root, "tests", "selftests")
+ if kwargs.get("flavor") == "browser-chrome":
+ test_root = os.path.join(
+ harness_root, "browser", "tests", "selftests"
+ )
+ if not os.path.exists(test_root):
+ if os.path.lexists(test_root):
+ os.remove(test_root)
+
+ if hasattr(os, "symlink"):
+ if not os.path.isdir(os.path.dirname(test_root)):
+ os.makedirs(os.path.dirname(test_root))
+ try:
+ os.symlink(files_dir, test_root)
+ except FileExistsError:
+ # another pytest job set up the symlink - no problem
+ pass
+ else:
+ shutil.copytree(files_dir, test_root)
+ elif "TEST_HARNESS_ROOT" in os.environ:
+ # The mochitest tests will run regardless of whether a build exists or not.
+ # In a local environment, they should simply be skipped if setup fails. But
+ # in automation, we'll need to make sure an error is propagated up.
+ pytest.fail(HARNESS_ROOT_NOT_FOUND)
+ else:
+ # Tests will be marked skipped by the calls to pytest.importorskip() below.
+ # We are purposefully not failing here because running |mach python-test|
+ # without a build is a perfectly valid use case.
+ pass
+ return test_root
+
+ return inner
+
+
+def binary():
+ """Return a Firefox binary"""
+ try:
+ return build.get_binary_path()
+ except Exception:
+ pass
+
+ app = "firefox"
+ bindir = os.path.join(os.environ["PYTHON_TEST_TMP"], app)
+ if os.path.isdir(bindir):
+ try:
+ return mozinstall.get_binary(bindir, app_name=app)
+ except Exception:
+ pass
+
+ if "GECKO_BINARY_PATH" in os.environ:
+ return os.environ["GECKO_BINARY_PATH"]
+
+
+@pytest.fixture(name="binary", scope="session")
+def binary_fixture():
+ return binary()
diff --git a/testing/mozbase/moztest/moztest/selftest/output.py b/testing/mozbase/moztest/moztest/selftest/output.py
new file mode 100644
index 0000000000..cdc6600f41
--- /dev/null
+++ b/testing/mozbase/moztest/moztest/selftest/output.py
@@ -0,0 +1,52 @@
+# 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/.
+
+"""Methods for testing interactions with mozharness."""
+
+import json
+import os
+import sys
+
+from mozbuild.base import MozbuildObject
+from six import string_types
+
+here = os.path.abspath(os.path.dirname(__file__))
+build = MozbuildObject.from_environment(cwd=here)
+
+sys.path.insert(0, os.path.join(build.topsrcdir, "testing", "mozharness"))
+from mozharness.base.errors import BaseErrorList
+from mozharness.base.log import INFO
+from mozharness.mozilla.structuredlog import StructuredOutputParser
+from mozharness.mozilla.testing.errors import HarnessErrorList
+
+
+def get_mozharness_status(suite, lines, status, formatter=None, buf=None):
+ """Given list of log lines, determine what the mozharness status would be."""
+ parser = StructuredOutputParser(
+ config={"log_level": INFO},
+ error_list=BaseErrorList + HarnessErrorList,
+ strict=False,
+ suite_category=suite,
+ )
+
+ if formatter:
+ parser.formatter = formatter
+
+ # Processing the log with mozharness will re-print all the output to stdout
+ # Since this exact same output has already been printed by the actual test
+ # run, temporarily redirect stdout to devnull.
+ buf = buf or open(os.devnull, "w")
+ orig = sys.stdout
+ sys.stdout = buf
+ for line in lines:
+ parser.parse_single_line(json.dumps(line))
+ sys.stdout = orig
+ return parser.evaluate_parser(status)
+
+
+def filter_action(actions, lines):
+ if isinstance(actions, string_types):
+ actions = (actions,)
+ # pylint --py3k: W1639
+ return list(filter(lambda x: x["action"] in actions, lines))