mach_commands.py (10780B)
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 logging 7 import os 8 import sys 9 10 import mozinfo 11 from mach.decorators import Command, CommandArgument, CommandArgumentGroup 12 from mozbuild.base import BinaryNotFoundException 13 from mozbuild.base import MachCommandConditions as conditions 14 15 16 def setup_awsy_argument_parser(): 17 from marionette_harness.runtests import MarionetteArguments 18 from mozlog.structured import commandline 19 20 parser = MarionetteArguments() 21 commandline.add_logging_group(parser) 22 23 return parser 24 25 26 from awsy import ITERATIONS, MAX_TABS, PER_TAB_PAUSE, SETTLE_WAIT_TIME 27 28 29 def run_awsy(command_context, tests, binary=None, **kwargs): 30 import json 31 32 from marionette_harness.runtests import MarionetteHarness, MarionetteTestRunner 33 from mozlog.structured import commandline 34 35 parser = setup_awsy_argument_parser() 36 37 awsy_source_dir = os.path.join(command_context.topsrcdir, "testing", "awsy") 38 if not tests: 39 if kwargs["base"]: 40 filename = "test_base_memory_usage.py" 41 else: 42 filename = "test_memory_usage.py" 43 tests = [os.path.join(awsy_source_dir, "awsy", filename)] 44 45 args = argparse.Namespace(tests=tests) 46 47 args.binary = binary 48 49 if kwargs["quick"]: 50 kwargs["entities"] = 3 51 kwargs["iterations"] = 1 52 kwargs["perTabPause"] = 1 53 kwargs["settleWaitTime"] = 1 54 55 runtime_testvars = {} 56 for arg in ( 57 "webRootDir", 58 "pageManifest", 59 "resultsDir", 60 "entities", 61 "iterations", 62 "perTabPause", 63 "settleWaitTime", 64 "maxTabs", 65 "dmd", 66 "tp5", 67 ): 68 if arg in kwargs and kwargs[arg] is not None: 69 runtime_testvars[arg] = kwargs[arg] 70 71 if "webRootDir" not in runtime_testvars: 72 awsy_tests_dir = os.path.join(command_context.topobjdir, "_tests", "awsy") 73 web_root_dir = os.path.join(awsy_tests_dir, "html") 74 runtime_testvars["webRootDir"] = web_root_dir 75 else: 76 web_root_dir = runtime_testvars["webRootDir"] 77 awsy_tests_dir = os.path.dirname(web_root_dir) 78 79 if "resultsDir" not in runtime_testvars: 80 runtime_testvars["resultsDir"] = os.path.join(awsy_tests_dir, "results") 81 82 runtime_testvars["bin"] = binary 83 runtime_testvars["run_local"] = True 84 85 page_load_test_dir = os.path.join(web_root_dir, "page_load_test") 86 if not os.path.isdir(page_load_test_dir): 87 os.makedirs(page_load_test_dir) 88 89 if not os.path.isdir(runtime_testvars["resultsDir"]): 90 os.makedirs(runtime_testvars["resultsDir"]) 91 92 runtime_testvars_path = os.path.join(awsy_tests_dir, "runtime-testvars.json") 93 if kwargs["testvars"]: 94 kwargs["testvars"].append(runtime_testvars_path) 95 else: 96 kwargs["testvars"] = [runtime_testvars_path] 97 98 runtime_testvars_file = open(runtime_testvars_path, "w") 99 runtime_testvars_file.write(json.dumps(runtime_testvars, indent=2)) 100 runtime_testvars_file.close() 101 102 manifest_file = os.path.join(awsy_source_dir, "tp5n-pageset.manifest") 103 tooltool_args = { 104 "args": [ 105 sys.executable, 106 os.path.join(command_context.topsrcdir, "mach"), 107 "artifact", 108 "toolchain", 109 "-v", 110 "--tooltool-manifest=%s" % manifest_file, 111 "--cache-dir=%s" 112 % os.path.join(command_context._mach_context.state_dir, "tooltool-cache"), 113 ] 114 } 115 command_context.run_process(cwd=page_load_test_dir, **tooltool_args) 116 tp5nzip = os.path.join(page_load_test_dir, "tp5n.zip") 117 tp5nmanifest = os.path.join(page_load_test_dir, "tp5n", "tp5n.manifest") 118 if not os.path.exists(tp5nmanifest): 119 unzip_args = {"args": ["unzip", "-q", "-o", tp5nzip, "-d", page_load_test_dir]} 120 try: 121 command_context.run_process(**unzip_args) 122 except Exception as exc: 123 troubleshoot = "" 124 if mozinfo.os == "win": 125 troubleshoot = ( 126 " Try using --web-root to specify a " 127 "directory closer to the drive root." 128 ) 129 130 command_context.log( 131 logging.ERROR, 132 "awsy", 133 {"directory": page_load_test_dir, "exception": exc}, 134 "Failed to unzip `tp5n.zip` into " 135 "`{directory}` with `{exception}`." + troubleshoot, 136 ) 137 raise exc 138 139 # If '--preferences' was not specified supply our default set. 140 if not kwargs["prefs_files"]: 141 kwargs["prefs_files"] = [os.path.join(awsy_source_dir, "conf", "prefs.json")] 142 143 # Setup DMD env vars if necessary. 144 if kwargs["dmd"]: 145 bin_dir = os.path.dirname(binary) 146 147 if "DMD" not in os.environ: 148 os.environ["DMD"] = "1" 149 150 # Work around a startup crash with DMD on windows 151 if mozinfo.os == "win": 152 kwargs["pref"] = "security.sandbox.content.level:0" 153 command_context.log( 154 logging.WARNING, 155 "awsy", 156 {}, 157 "Forcing 'security.sandbox.content.level' = 0 because DMD is enabled.", 158 ) 159 elif mozinfo.os == "mac": 160 # On mac binary is in MacOS and dmd.py is in Resources, ie: 161 # Name.app/Contents/MacOS/libdmd.dylib 162 # Name.app/Contents/Resources/dmd.py 163 bin_dir = os.path.join(bin_dir, "../Resources/") 164 165 # Also add the bin dir to the python path so we can use dmd.py 166 if bin_dir not in sys.path: 167 sys.path.append(bin_dir) 168 169 for k, v in kwargs.items(): 170 setattr(args, k, v) 171 172 parser.verify_usage(args) 173 174 args.logger = commandline.setup_logging( 175 "Are We Slim Yet Tests", args, {"mach": sys.stdout} 176 ) 177 failed = MarionetteHarness(MarionetteTestRunner, args=vars(args)).run() 178 if failed > 0: 179 return 1 180 else: 181 return 0 182 183 184 @Command( 185 "awsy-test", 186 category="testing", 187 description="Run Are We Slim Yet (AWSY) memory usage testing using marionette.", 188 parser=setup_awsy_argument_parser, 189 ) 190 @CommandArgumentGroup("AWSY") 191 @CommandArgument( 192 "--web-root", 193 group="AWSY", 194 action="store", 195 type=str, 196 dest="webRootDir", 197 help="Path to web server root directory. If not specified, " 198 "defaults to topobjdir/_tests/awsy/html.", 199 ) 200 @CommandArgument( 201 "--page-manifest", 202 group="AWSY", 203 action="store", 204 type=str, 205 dest="pageManifest", 206 help="Path to page manifest text file containing a list " 207 "of urls to test. The urls must be served from localhost. If not " 208 "specified, defaults to page_load_test/tp5n/tp5n.manifest under " 209 "the web root.", 210 ) 211 @CommandArgument( 212 "--results", 213 group="AWSY", 214 action="store", 215 type=str, 216 dest="resultsDir", 217 help="Path to results directory. If not specified, defaults " 218 "to the parent directory of the web root.", 219 ) 220 @CommandArgument( 221 "--quick", 222 group="AWSY", 223 action="store_true", 224 dest="quick", 225 default=False, 226 help="Set --entities=3, --iterations=1, --per-tab-pause=1, " 227 "--settle-wait-time=1 for a quick test. Overrides any explicit " 228 "argument settings.", 229 ) 230 @CommandArgument( 231 "--entities", 232 group="AWSY", 233 action="store", 234 type=int, 235 dest="entities", 236 help="Number of urls to load. Defaults to the total number of urls.", 237 ) 238 @CommandArgument( 239 "--max-tabs", 240 group="AWSY", 241 action="store", 242 type=int, 243 dest="maxTabs", 244 help="Maximum number of tabs to open. Defaults to %s." % MAX_TABS, 245 ) 246 @CommandArgument( 247 "--iterations", 248 group="AWSY", 249 action="store", 250 type=int, 251 dest="iterations", 252 help="Number of times to run through the test suite. Defaults to %s." % ITERATIONS, 253 ) 254 @CommandArgument( 255 "--per-tab-pause", 256 group="AWSY", 257 action="store", 258 type=int, 259 dest="perTabPause", 260 help="Seconds to wait in between opening tabs. Defaults to %s." % PER_TAB_PAUSE, 261 ) 262 @CommandArgument( 263 "--settle-wait-time", 264 group="AWSY", 265 action="store", 266 type=int, 267 dest="settleWaitTime", 268 help="Seconds to wait for things to settled down. " 269 "Defaults to %s." % SETTLE_WAIT_TIME, 270 ) 271 @CommandArgument( 272 "--dmd", 273 group="AWSY", 274 action="store_true", 275 dest="dmd", 276 default=False, 277 help="Enable DMD during testing. Requires a DMD-enabled build.", 278 ) 279 @CommandArgument( 280 "--tp5", 281 group="AWSY", 282 action="store_true", 283 dest="tp5", 284 default=False, 285 help="Use the tp5 pageset during testing.", 286 ) 287 @CommandArgument( 288 "--base", 289 group="AWSY", 290 action="store_true", 291 dest="base", 292 default=False, 293 help="Run base memory usage tests.", 294 ) 295 def run_awsy_test(command_context, tests, **kwargs): 296 """mach awsy-test runs the in-tree version of the Are We Slim Yet 297 (AWSY) tests. 298 299 awsy-test is implemented as a marionette test and marionette 300 test arguments also apply although they are not necessary 301 since reasonable defaults will be chosen. 302 303 The AWSY specific arguments can be found in the Command 304 Arguments for AWSY section below. 305 306 awsy-test will automatically download the tp5n.zip talos 307 pageset from tooltool and install it under 308 topobjdir/_tests/awsy/html. You can specify your own page set 309 by specifying --web-root and --page-manifest. 310 311 The results of the test will be placed in the results 312 directory specified by the --results argument. 313 314 On Windows, you may experience problems due to path length 315 errors when extracting the tp5n.zip file containing the 316 test pages or when attempting to write checkpoints to the 317 results directory. In that case, you should specify both 318 the --web-root and --results arguments pointing to a location 319 with a short path. For example: 320 321 --web-root=c:\\\\tmp\\\\html --results=c:\\\\tmp\\\\results 322 323 Note that the double backslashes are required. 324 """ 325 kwargs["logger_name"] = "Awsy Tests" 326 if "test_objects" in kwargs: 327 tests = [] 328 for obj in kwargs["test_objects"]: 329 tests.append(obj["file_relpath"]) 330 del kwargs["test_objects"] 331 332 if not kwargs.get("binary") and conditions.is_firefox(command_context): 333 try: 334 kwargs["binary"] = command_context.get_binary_path("app") 335 except BinaryNotFoundException as e: 336 command_context.log( 337 logging.ERROR, "awsy", {"error": str(e)}, "ERROR: {error}" 338 ) 339 command_context.log(logging.INFO, "awsy", {"help": e.help()}, "{help}") 340 return 1 341 return run_awsy(command_context, tests, **kwargs)