unittestrunner.py (4340B)
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 argparse 6 import configparser 7 import os 8 import re 9 import subprocess 10 import sys 11 12 here = os.path.abspath(os.path.dirname(__file__)) 13 14 local_requirements = { 15 b"mozinfo": "testing/mozbase/mozinfo", 16 b"mozlog": "testing/mozbase/mozlog", 17 b"mozdebug": "testing/mozbase/mozdebug", 18 b"marionette_driver": "testing/marionette/client/", 19 b"mozprofile": "testing/mozbase/mozprofile", 20 b"mozprocess": "testing/mozbase/mozprocess", 21 b"mozcrash": "testing/mozbase/mozcrash", 22 b"mozrunner": "testing/mozbase/mozrunner", 23 b"mozleak": "testing/mozbase/mozleak", 24 b"mozversion": "testing/mozbase/mozversion", 25 } 26 27 requirements_re = re.compile(rb"(%s)[^\w]" % b"|".join(local_requirements.keys())) 28 29 30 class ReplaceRequirements: 31 def __init__(self, top_src_path, tox_path): 32 self.top_src_path = top_src_path 33 self.tox_path = tox_path 34 self.file_cache = {} 35 36 def __enter__(self): 37 self.file_cache = {} 38 deps = self.read_deps() 39 for dep in deps: 40 self.replace_path(dep) 41 42 def __exit__(self, *args, **kwargs): 43 for path, data in self.file_cache.items(): 44 with open(path, "wb") as f: 45 f.write(data) 46 47 def read_deps(self): 48 rv = [] 49 parser = configparser.ConfigParser() 50 path = os.path.join(self.tox_path, "tox.ini") 51 with open(path) as f: 52 parser.read_file(f) 53 deps = parser.get("testenv", "deps") 54 dep_re = re.compile(r"(?:.*:\s*)?-r(.*)") 55 56 # This can break if we start using more features of tox 57 for dep in deps.splitlines(): 58 m = dep_re.match(dep) 59 if m: 60 rv.append(m.group(1).replace("{toxinidir}", self.tox_path)) 61 return rv 62 63 def replace_path(self, requirements_path): 64 lines = [] 65 with open(requirements_path, "rb") as f: 66 self.file_cache[requirements_path] = f.read() 67 f.seek(0) 68 for line in f: 69 m = requirements_re.match(line) 70 if not m: 71 lines.append(line) 72 else: 73 key = m.group(1) 74 path = local_requirements[key] 75 lines.append( 76 b"-e %s\n" 77 % (os.path.join(self.top_src_path, path).encode("utf8"),) 78 ) 79 80 with open(requirements_path, "wb") as f: 81 for line in lines: 82 f.write(line) 83 84 with open(requirements_path, "rb") as f: 85 print(f.read()) 86 87 88 def get_parser(): 89 parser = argparse.ArgumentParser() 90 parser.add_argument( 91 "--no-tools", 92 dest="tools", 93 action="store_false", 94 default=True, 95 help="Don't run the tools unittests", 96 ) 97 parser.add_argument( 98 "--no-wptrunner", 99 dest="wptrunner", 100 action="store_false", 101 default=True, 102 help="Don't run the wptrunner unittests", 103 ) 104 parser.add_argument( 105 "tox_kwargs", nargs=argparse.REMAINDER, help="Arguments to pass through to tox" 106 ) 107 return parser 108 109 110 def run(top_src_dir, tools=True, wptrunner=True, tox_kwargs=None, **kwargs): 111 tox_paths = [] 112 if tox_kwargs is None: 113 tox_kwargs = [] 114 if tools: 115 tox_paths.append( 116 os.path.join(top_src_dir, "testing", "web-platform", "tests", "tools") 117 ) 118 if wptrunner: 119 tox_paths.append( 120 os.path.join( 121 top_src_dir, "testing", "web-platform", "tests", "tools", "wptrunner" 122 ) 123 ) 124 125 success = True 126 127 for tox_path in tox_paths: 128 with ReplaceRequirements(top_src_dir, tox_path): 129 cmd = ["tox"] + tox_kwargs 130 try: 131 subprocess.check_call(cmd, cwd=tox_path) 132 except subprocess.CalledProcessError: 133 success = False 134 return success 135 136 137 def main(): 138 kwargs = vars(get_parser().parse_args()) 139 top_src_path = os.path.abspath(os.path.join(here, os.pardir, os.pardir)) 140 return run(top_src_path, **kwargs) 141 142 143 if __name__ == "__main__": 144 if not main(): 145 sys.exit(1)