conftest.py (5324B)
1 # This Source Code Form is subject to the terms of the Mozilla Public 2 # License, v. 2.0. If a copy of the MPL was not distributed with this 3 # file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 5 import io 6 import json 7 import os 8 from argparse import Namespace 9 10 import mozinfo 11 import pytest 12 from manifestparser import TestManifest, expression 13 from moztest.selftest.fixtures import binary_fixture, setup_test_harness # noqa 14 15 here = os.path.abspath(os.path.dirname(__file__)) 16 setup_args = [os.path.join(here, "files"), "mochitest", "testing/mochitest"] 17 18 19 @pytest.fixture 20 def create_manifest(tmpdir, build_obj): 21 def inner(string, name="manifest.ini"): 22 manifest = tmpdir.join(name) 23 manifest.write(string, ensure=True) 24 path = str(manifest) 25 return TestManifest(manifests=(path,), strict=False, rootdir=tmpdir.strpath) 26 27 return inner 28 29 30 @pytest.fixture(scope="function") 31 def parser(request): 32 parser = pytest.importorskip("mochitest_options") 33 34 app = getattr(request.module, "APP", "generic") 35 return parser.MochitestArgumentParser(app=app) 36 37 38 @pytest.fixture(scope="function") 39 def runtests(setup_test_harness, binary, parser, request): 40 """Creates an easy to use entry point into the mochitest harness. 41 42 :returns: A function with the signature `*tests, **opts`. Each test is a file name 43 (relative to the `files` dir). At least one is required. The opts are 44 used to override the default mochitest options, they are optional. 45 """ 46 flavor = "plain" 47 if "flavor" in request.fixturenames: 48 flavor = request.getfixturevalue("flavor") 49 50 runFailures = "" 51 if "runFailures" in request.fixturenames: 52 runFailures = request.getfixturevalue("runFailures") 53 54 restartAfterFailure = False 55 if "restartAfterFailure" in request.fixturenames: 56 restartAfterFailure = request.getfixturevalue("restartAfterFailure") 57 58 setup_test_harness(*setup_args, flavor=flavor) 59 60 runtests = pytest.importorskip("runtests") 61 62 mochitest_root = runtests.SCRIPT_DIR 63 if flavor == "plain": 64 test_root = os.path.join(mochitest_root, "tests", "selftests") 65 manifest_name = "mochitest.ini" 66 elif flavor == "browser-chrome": 67 test_root = os.path.join(mochitest_root, "browser", "tests", "selftests") 68 manifest_name = "browser.ini" 69 else: 70 raise Exception(f"Invalid flavor {flavor}!") 71 72 buf = io.StringIO() 73 options = vars(parser.parse_args([])) 74 options.update({ 75 "app": binary, 76 "flavor": flavor, 77 "runFailures": runFailures, 78 "restartAfterFailure": restartAfterFailure, 79 "keep_open": False, 80 "log_raw": [buf], 81 }) 82 83 if runFailures == "selftest": 84 options["crashAsPass"] = True 85 options["timeoutAsPass"] = True 86 runtests.mozinfo.update({"selftest": True}) 87 88 if not os.path.isdir(runtests.build_obj.bindir): 89 package_root = os.path.dirname(mochitest_root) 90 options.update({ 91 "certPath": os.path.join(package_root, "certs"), 92 "utilityPath": os.path.join(package_root, "bin"), 93 }) 94 options["extraProfileFiles"].append( 95 os.path.join(package_root, "bin", "plugins") 96 ) 97 98 options.update(getattr(request.module, "OPTIONS", {})) 99 100 def normalize(test): 101 if isinstance(test, str): 102 test = [test] 103 return [ 104 { 105 "name": t, 106 "relpath": t, 107 "path": os.path.join(test_root, t), 108 # add a dummy manifest file because mochitest expects it 109 "manifest": os.path.join(test_root, manifest_name), 110 "manifest_relpath": manifest_name, 111 "skip-if": runFailures, 112 } 113 for t in test 114 ] 115 116 def inner(*tests, **opts): 117 assert len(tests) > 0 118 119 # Inject a TestManifest in the runtests option if one 120 # has not been already included by the caller. 121 if not isinstance(options["manifestFile"], TestManifest): 122 manifest = TestManifest() 123 options["manifestFile"] = manifest 124 # pylint --py3k: W1636 125 manifest.tests.extend(list(map(normalize, tests))[0]) 126 options.update(opts) 127 128 result = runtests.run_test_harness(parser, Namespace(**options)) 129 out = json.loads("[" + ",".join(buf.getvalue().splitlines()) + "]") 130 buf.close() 131 return result, out 132 133 return inner 134 135 136 @pytest.fixture 137 def build_obj(setup_test_harness): 138 setup_test_harness(*setup_args) 139 mochitest_options = pytest.importorskip("mochitest_options") 140 return mochitest_options.build_obj 141 142 143 @pytest.fixture(autouse=True) 144 def skip_using_mozinfo(request, setup_test_harness): 145 """Gives tests the ability to skip based on values from mozinfo. 146 147 Example: 148 @pytest.mark.skip_mozinfo("!e10s || os == 'linux'") 149 def test_foo(): 150 pass 151 """ 152 153 setup_test_harness(*setup_args) 154 runtests = pytest.importorskip("runtests") 155 runtests.update_mozinfo() 156 157 skip_mozinfo = request.node.get_closest_marker("skip_mozinfo") 158 if skip_mozinfo: 159 value = skip_mozinfo.args[0] 160 if expression.parse(value, **mozinfo.info): 161 pytest.skip(f"skipped due to mozinfo match: \n{value}")