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 5from __future__ import absolute_import, unicode_literals 6 7import argparse 8import os 9import sys 10 11from mozbuild.base import ( 12 MachCommandBase, 13 MachCommandConditions as conditions, 14) 15 16from mach.decorators import ( 17 CommandArgument, 18 CommandArgumentGroup, 19 CommandProvider, 20 Command, 21) 22 23def setup_awsy_argument_parser(): 24 from marionette_harness.runtests import MarionetteArguments 25 from mozlog.structured import commandline 26 27 parser = MarionetteArguments() 28 commandline.add_logging_group(parser) 29 30 return parser 31 32 33@CommandProvider 34class MachCommands(MachCommandBase): 35 AWSY_PATH = os.path.dirname(os.path.realpath(__file__)) 36 if AWSY_PATH not in sys.path: 37 sys.path.append(AWSY_PATH) 38 from awsy import ITERATIONS, PER_TAB_PAUSE, SETTLE_WAIT_TIME, MAX_TABS 39 40 def run_awsy(self, tests, binary=None, **kwargs): 41 import json 42 from mozlog.structured import commandline 43 44 from marionette_harness.runtests import ( 45 MarionetteTestRunner, 46 MarionetteHarness 47 ) 48 49 parser = setup_awsy_argument_parser() 50 51 awsy_source_dir = os.path.join(self.topsrcdir, 'testing', 'awsy') 52 if not tests: 53 tests = [os.path.join(awsy_source_dir, 54 'awsy', 55 'test_memory_usage.py')] 56 57 args = argparse.Namespace(tests=tests) 58 59 args.binary = binary 60 61 if kwargs['quick']: 62 kwargs['entities'] = 3 63 kwargs['iterations'] = 1 64 kwargs['perTabPause'] = 1 65 kwargs['settleWaitTime'] = 1 66 67 if 'disable_stylo' in kwargs and kwargs['disable_stylo']: 68 if 'single_stylo_traversal' in kwargs and kwargs['single_stylo_traversal']: 69 print("--disable-stylo conflicts with --single-stylo-traversal") 70 return 1 71 if 'enable_stylo' in kwargs and kwargs['enable_stylo']: 72 print("--disable-stylo conflicts with --enable-stylo") 73 return 1 74 75 if 'single_stylo_traversal' in kwargs and kwargs['single_stylo_traversal']: 76 os.environ['STYLO_THREADS'] = '1' 77 else: 78 os.environ['STYLO_THREADS'] = '4' 79 80 if 'enable_stylo' in kwargs and kwargs['enable_stylo']: 81 os.environ['STYLO_FORCE_ENABLED'] = '1' 82 if 'disable_stylo' in kwargs and kwargs['disable_stylo']: 83 os.environ['STYLO_FORCE_DISABLED'] = '1' 84 85 if 'enable_webrender' in kwargs and kwargs['enable_webrender']: 86 os.environ['MOZ_WEBRENDER'] = '1' 87 os.environ['MOZ_ACCELERATED'] = '1' 88 89 runtime_testvars = {} 90 for arg in ('webRootDir', 'pageManifest', 'resultsDir', 'entities', 'iterations', 91 'perTabPause', 'settleWaitTime', 'maxTabs', 'dmd'): 92 if kwargs[arg]: 93 runtime_testvars[arg] = kwargs[arg] 94 95 if 'webRootDir' not in runtime_testvars: 96 awsy_tests_dir = os.path.join(self.topobjdir, '_tests', 'awsy') 97 web_root_dir = os.path.join(awsy_tests_dir, 'html') 98 runtime_testvars['webRootDir'] = web_root_dir 99 else: 100 web_root_dir = runtime_testvars['webRootDir'] 101 awsy_tests_dir = os.path.dirname(web_root_dir) 102 103 if 'resultsDir' not in runtime_testvars: 104 runtime_testvars['resultsDir'] = os.path.join(awsy_tests_dir, 105 'results') 106 page_load_test_dir = os.path.join(web_root_dir, 'page_load_test') 107 if not os.path.isdir(page_load_test_dir): 108 os.makedirs(page_load_test_dir) 109 110 if not os.path.isdir(runtime_testvars['resultsDir']): 111 os.makedirs(runtime_testvars['resultsDir']) 112 113 runtime_testvars_path = os.path.join(awsy_tests_dir, 'runtime-testvars.json') 114 if kwargs['testvars']: 115 kwargs['testvars'].append(runtime_testvars_path) 116 else: 117 kwargs['testvars'] = [runtime_testvars_path] 118 119 runtime_testvars_file = open(runtime_testvars_path, 'wb') 120 runtime_testvars_file.write(json.dumps(runtime_testvars, indent=2)) 121 runtime_testvars_file.close() 122 123 manifest_file = os.path.join(awsy_source_dir, 124 'tp5n-pageset.manifest') 125 tooltool_args = {'args': [ 126 sys.executable, 127 os.path.join(self.topsrcdir, 'mach'), 128 'artifact', 'toolchain', '-v', 129 '--tooltool-manifest=%s' % manifest_file, 130 '--cache-dir=%s' % os.path.join(self.topsrcdir, 'tooltool-cache'), 131 ]} 132 self.run_process(cwd=page_load_test_dir, **tooltool_args) 133 tp5nzip = os.path.join(page_load_test_dir, 'tp5n.zip') 134 tp5nmanifest = os.path.join(page_load_test_dir, 'tp5n', 'tp5n.manifest') 135 if not os.path.exists(tp5nmanifest): 136 unzip_args = {'args': [ 137 'unzip', 138 '-q', 139 '-o', 140 tp5nzip, 141 '-d', 142 page_load_test_dir]} 143 self.run_process(**unzip_args) 144 145 # If '--preferences' was not specified supply our default set. 146 if not kwargs['prefs_files']: 147 kwargs['prefs_files'] = [os.path.join(awsy_source_dir, 'conf', 'prefs.json')] 148 149 # Setup DMD env vars if necessary. 150 if kwargs['dmd']: 151 bin_dir = os.path.dirname(binary) 152 153 if 'DMD' not in os.environ: 154 os.environ['DMD'] = '1' 155 156 # Also add the bin dir to the python path so we can use dmd.py 157 if bin_dir not in sys.path: 158 sys.path.append(bin_dir) 159 160 for k, v in kwargs.iteritems(): 161 setattr(args, k, v) 162 163 parser.verify_usage(args) 164 165 args.logger = commandline.setup_logging('Are We Slim Yet Tests', 166 args, 167 {'mach': sys.stdout}) 168 failed = MarionetteHarness(MarionetteTestRunner, args=vars(args)).run() 169 if failed > 0: 170 return 1 171 else: 172 return 0 173 174 @Command('awsy-test', category='testing', 175 description='Run Are We Slim Yet (AWSY) memory usage testing using marionette.', 176 parser=setup_awsy_argument_parser, 177 ) 178 @CommandArgumentGroup('AWSY') 179 @CommandArgument('--web-root', group='AWSY', action='store', type=str, 180 dest='webRootDir', 181 help='Path to web server root directory. If not specified, ' 182 'defaults to topobjdir/_tests/awsy/html.') 183 @CommandArgument('--page-manifest', group='AWSY', action='store', type=str, 184 dest='pageManifest', 185 help='Path to page manifest text file containing a list ' 186 'of urls to test. The urls must be served from localhost. If not ' 187 'specified, defaults to page_load_test/tp5n/tp5n.manifest under ' 188 'the web root.') 189 @CommandArgument('--results', group='AWSY', action='store', type=str, 190 dest='resultsDir', 191 help='Path to results directory. If not specified, defaults ' 192 'to the parent directory of the web root.') 193 @CommandArgument('--quick', group='AWSY', action='store_true', 194 dest='quick', default=False, 195 help='Set --entities=3, --iterations=1, --per-tab-pause=1, ' 196 '--settle-wait-time=1 for a quick test. Overrides any explicit ' 197 'argument settings.') 198 @CommandArgument('--entities', group='AWSY', action='store', type=int, 199 dest='entities', 200 help='Number of urls to load. Defaults to the total number of ' 201 'urls.') 202 @CommandArgument('--max-tabs', group='AWSY', action='store', type=int, 203 dest='maxTabs', 204 help='Maximum number of tabs to open. ' 205 'Defaults to %s.' % MAX_TABS) 206 @CommandArgument('--iterations', group='AWSY', action='store', type=int, 207 dest='iterations', 208 help='Number of times to run through the test suite. ' 209 'Defaults to %s.' % ITERATIONS) 210 @CommandArgument('--per-tab-pause', group='AWSY', action='store', type=int, 211 dest='perTabPause', 212 help='Seconds to wait in between opening tabs. ' 213 'Defaults to %s.' % PER_TAB_PAUSE) 214 @CommandArgument('--settle-wait-time', group='AWSY', action='store', type=int, 215 dest='settleWaitTime', 216 help='Seconds to wait for things to settled down. ' 217 'Defaults to %s.' % SETTLE_WAIT_TIME) 218 @CommandArgument('--enable-stylo', group='AWSY', action='store_true', 219 dest='enable_stylo', default=False, 220 help='Enable Stylo.') 221 @CommandArgument('--disable-stylo', group='AWSY', action='store_true', 222 dest='disable_stylo', default=False, 223 help='Disable Stylo.') 224 @CommandArgument('--single-stylo-traversal', group='AWSY', action='store_true', 225 dest='single_stylo_traversal', default=False, 226 help='Set STYLO_THREADS=1.') 227 @CommandArgument('--enable-webrender', group='AWSY', action='store_true', 228 dest='enable_webrender', default=False, 229 help='Enable WebRender.') 230 @CommandArgument('--dmd', group='AWSY', action='store_true', 231 dest='dmd', default=False, 232 help='Enable DMD during testing. Requires a DMD-enabled build.') 233 def run_awsy_test(self, tests, **kwargs): 234 """mach awsy-test runs the in-tree version of the Are We Slim Yet 235 (AWSY) tests. 236 237 awsy-test is implemented as a marionette test and marionette 238 test arguments also apply although they are not necessary 239 since reasonable defaults will be chosen. 240 241 The AWSY specific arguments can be found in the Command 242 Arguments for AWSY section below. 243 244 awsy-test will automatically download the tp5n.zip talos 245 pageset from tooltool and install it under 246 topobjdir/_tests/awsy/html. You can specify your own page set 247 by specifying --web-root and --page-manifest. 248 249 The results of the test will be placed in the results 250 directory specified by the --results argument. 251 252 On Windows, you may experience problems due to path length 253 errors when extracting the tp5n.zip file containing the 254 test pages or when attempting to write checkpoints to the 255 results directory. In that case, you should specify both 256 the --web-root and --results arguments pointing to a location 257 with a short path. For example: 258 259 --web-root=c:\\\\tmp\\\\html --results=c:\\\\tmp\\\\results 260 261 Note that the double backslashes are required. 262 """ 263 kwargs['logger_name'] = 'Awsy Tests' 264 if 'test_objects' in kwargs: 265 tests = [] 266 for obj in kwargs['test_objects']: 267 tests.append(obj['file_relpath']) 268 del kwargs['test_objects'] 269 270 if not kwargs.get('binary') and conditions.is_firefox(self): 271 kwargs['binary'] = self.get_binary_path('app') 272 return self.run_awsy(tests, **kwargs) 273