diff options
Diffstat (limited to 'testing/mozbase/moztest/moztest/selftest')
-rw-r--r-- | testing/mozbase/moztest/moztest/selftest/__init__.py | 0 | ||||
-rw-r--r-- | testing/mozbase/moztest/moztest/selftest/fixtures.py | 116 | ||||
-rw-r--r-- | testing/mozbase/moztest/moztest/selftest/output.py | 52 |
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)) |