Wed, 31 Dec 2014 06:55:50 +0100
Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2
michael@0 | 1 | # This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 3 | # file, You can obtain one at http://mozilla.org/MPL/2.0/. |
michael@0 | 4 | |
michael@0 | 5 | from __future__ import unicode_literals |
michael@0 | 6 | |
michael@0 | 7 | import mozpack.path |
michael@0 | 8 | import os |
michael@0 | 9 | import re |
michael@0 | 10 | import sys |
michael@0 | 11 | import warnings |
michael@0 | 12 | import which |
michael@0 | 13 | |
michael@0 | 14 | from mozbuild.base import ( |
michael@0 | 15 | MachCommandBase, |
michael@0 | 16 | MachCommandConditions as conditions, |
michael@0 | 17 | MozbuildObject, |
michael@0 | 18 | ) |
michael@0 | 19 | |
michael@0 | 20 | from mach.decorators import ( |
michael@0 | 21 | CommandArgument, |
michael@0 | 22 | CommandProvider, |
michael@0 | 23 | Command, |
michael@0 | 24 | ) |
michael@0 | 25 | |
michael@0 | 26 | |
michael@0 | 27 | DEBUGGER_HELP = 'Debugger binary to run test in. Program name or path.' |
michael@0 | 28 | |
michael@0 | 29 | ADB_NOT_FOUND = ''' |
michael@0 | 30 | The %s command requires the adb binary to be on your path. |
michael@0 | 31 | |
michael@0 | 32 | If you have a B2G build, this can be found in |
michael@0 | 33 | '%s/out/host/<platform>/bin'. |
michael@0 | 34 | '''.lstrip() |
michael@0 | 35 | |
michael@0 | 36 | GAIA_PROFILE_NOT_FOUND = ''' |
michael@0 | 37 | The %s command requires a non-debug gaia profile. Either pass in --profile, |
michael@0 | 38 | or set the GAIA_PROFILE environment variable. |
michael@0 | 39 | |
michael@0 | 40 | If you do not have a non-debug gaia profile, you can build one: |
michael@0 | 41 | $ git clone https://github.com/mozilla-b2g/gaia |
michael@0 | 42 | $ cd gaia |
michael@0 | 43 | $ make |
michael@0 | 44 | |
michael@0 | 45 | The profile should be generated in a directory called 'profile'. |
michael@0 | 46 | '''.lstrip() |
michael@0 | 47 | |
michael@0 | 48 | GAIA_PROFILE_IS_DEBUG = ''' |
michael@0 | 49 | The %s command requires a non-debug gaia profile. The specified profile, |
michael@0 | 50 | %s, is a debug profile. |
michael@0 | 51 | |
michael@0 | 52 | If you do not have a non-debug gaia profile, you can build one: |
michael@0 | 53 | $ git clone https://github.com/mozilla-b2g/gaia |
michael@0 | 54 | $ cd gaia |
michael@0 | 55 | $ make |
michael@0 | 56 | |
michael@0 | 57 | The profile should be generated in a directory called 'profile'. |
michael@0 | 58 | '''.lstrip() |
michael@0 | 59 | |
michael@0 | 60 | MARIONETTE_DISABLED = ''' |
michael@0 | 61 | The %s command requires a marionette enabled build. |
michael@0 | 62 | |
michael@0 | 63 | Add 'ENABLE_MARIONETTE=1' to your mozconfig file and re-build the application. |
michael@0 | 64 | Your currently active mozconfig is %s. |
michael@0 | 65 | '''.lstrip() |
michael@0 | 66 | |
michael@0 | 67 | class ReftestRunner(MozbuildObject): |
michael@0 | 68 | """Easily run reftests. |
michael@0 | 69 | |
michael@0 | 70 | This currently contains just the basics for running reftests. We may want |
michael@0 | 71 | to hook up result parsing, etc. |
michael@0 | 72 | """ |
michael@0 | 73 | def __init__(self, *args, **kwargs): |
michael@0 | 74 | MozbuildObject.__init__(self, *args, **kwargs) |
michael@0 | 75 | |
michael@0 | 76 | # TODO Bug 794506 remove once mach integrates with virtualenv. |
michael@0 | 77 | build_path = os.path.join(self.topobjdir, 'build') |
michael@0 | 78 | if build_path not in sys.path: |
michael@0 | 79 | sys.path.append(build_path) |
michael@0 | 80 | |
michael@0 | 81 | self.tests_dir = os.path.join(self.topobjdir, '_tests') |
michael@0 | 82 | self.reftest_dir = os.path.join(self.tests_dir, 'reftest') |
michael@0 | 83 | |
michael@0 | 84 | def _manifest_file(self, suite): |
michael@0 | 85 | """Returns the manifest file used for a given test suite.""" |
michael@0 | 86 | files = { |
michael@0 | 87 | 'reftest': 'reftest.list', |
michael@0 | 88 | 'reftest-ipc': 'reftest.list', |
michael@0 | 89 | 'crashtest': 'crashtests.list', |
michael@0 | 90 | 'crashtest-ipc': 'crashtests.list', |
michael@0 | 91 | } |
michael@0 | 92 | assert suite in files |
michael@0 | 93 | return files[suite] |
michael@0 | 94 | |
michael@0 | 95 | def _find_manifest(self, suite, test_file): |
michael@0 | 96 | assert test_file |
michael@0 | 97 | path_arg = self._wrap_path_argument(test_file) |
michael@0 | 98 | relpath = path_arg.relpath() |
michael@0 | 99 | |
michael@0 | 100 | if os.path.isdir(path_arg.srcdir_path()): |
michael@0 | 101 | return mozpack.path.join(relpath, self._manifest_file(suite)) |
michael@0 | 102 | |
michael@0 | 103 | if relpath.endswith('.list'): |
michael@0 | 104 | return relpath |
michael@0 | 105 | |
michael@0 | 106 | raise Exception('Running a single test is not currently supported') |
michael@0 | 107 | |
michael@0 | 108 | def _make_shell_string(self, s): |
michael@0 | 109 | return "'%s'" % re.sub("'", r"'\''", s) |
michael@0 | 110 | |
michael@0 | 111 | def run_b2g_test(self, b2g_home=None, xre_path=None, test_file=None, |
michael@0 | 112 | suite=None, **kwargs): |
michael@0 | 113 | """Runs a b2g reftest. |
michael@0 | 114 | |
michael@0 | 115 | test_file is a path to a test file. It can be a relative path from the |
michael@0 | 116 | top source directory, an absolute filename, or a directory containing |
michael@0 | 117 | test files. |
michael@0 | 118 | |
michael@0 | 119 | suite is the type of reftest to run. It can be one of ('reftest', |
michael@0 | 120 | 'crashtest'). |
michael@0 | 121 | """ |
michael@0 | 122 | if suite not in ('reftest', 'crashtest'): |
michael@0 | 123 | raise Exception('None or unrecognized reftest suite type.') |
michael@0 | 124 | |
michael@0 | 125 | # Find the manifest file |
michael@0 | 126 | if not test_file: |
michael@0 | 127 | if suite == 'reftest': |
michael@0 | 128 | test_file = mozpack.path.join('layout', 'reftests') |
michael@0 | 129 | elif suite == 'crashtest': |
michael@0 | 130 | test_file = mozpack.path.join('testing', 'crashtest') |
michael@0 | 131 | |
michael@0 | 132 | if not os.path.exists(os.path.join(self.topsrcdir, test_file)): |
michael@0 | 133 | test_file = mozpack.path.relpath(os.path.abspath(test_file), |
michael@0 | 134 | self.topsrcdir) |
michael@0 | 135 | |
michael@0 | 136 | manifest = self._find_manifest(suite, test_file) |
michael@0 | 137 | if not os.path.exists(mozpack.path.join(self.topsrcdir, manifest)): |
michael@0 | 138 | raise Exception('No manifest file was found at %s.' % manifest) |
michael@0 | 139 | |
michael@0 | 140 | # Need to chdir to reftest_dir otherwise imports fail below. |
michael@0 | 141 | os.chdir(self.reftest_dir) |
michael@0 | 142 | |
michael@0 | 143 | # The imp module can spew warnings if the modules below have |
michael@0 | 144 | # already been imported, ignore them. |
michael@0 | 145 | with warnings.catch_warnings(): |
michael@0 | 146 | warnings.simplefilter('ignore') |
michael@0 | 147 | |
michael@0 | 148 | import imp |
michael@0 | 149 | path = os.path.join(self.reftest_dir, 'runreftestb2g.py') |
michael@0 | 150 | with open(path, 'r') as fh: |
michael@0 | 151 | imp.load_module('reftest', fh, path, ('.py', 'r', imp.PY_SOURCE)) |
michael@0 | 152 | import reftest |
michael@0 | 153 | |
michael@0 | 154 | # Set up the reftest options. |
michael@0 | 155 | parser = reftest.B2GOptions() |
michael@0 | 156 | options, args = parser.parse_args([]) |
michael@0 | 157 | |
michael@0 | 158 | # Tests need to be served from a subdirectory of the server. Symlink |
michael@0 | 159 | # topsrcdir here to get around this. |
michael@0 | 160 | tests = os.path.join(self.reftest_dir, 'tests') |
michael@0 | 161 | if not os.path.isdir(tests): |
michael@0 | 162 | os.symlink(self.topsrcdir, tests) |
michael@0 | 163 | args.insert(0, os.path.join('tests', manifest)) |
michael@0 | 164 | |
michael@0 | 165 | for k, v in kwargs.iteritems(): |
michael@0 | 166 | setattr(options, k, v) |
michael@0 | 167 | |
michael@0 | 168 | if conditions.is_b2g_desktop(self): |
michael@0 | 169 | if self.substs.get('ENABLE_MARIONETTE') != '1': |
michael@0 | 170 | print(MARIONETTE_DISABLED % ('mochitest-b2g-desktop', |
michael@0 | 171 | self.mozconfig['path'])) |
michael@0 | 172 | return 1 |
michael@0 | 173 | |
michael@0 | 174 | options.profile = options.profile or os.environ.get('GAIA_PROFILE') |
michael@0 | 175 | if not options.profile: |
michael@0 | 176 | print(GAIA_PROFILE_NOT_FOUND % 'reftest-b2g-desktop') |
michael@0 | 177 | return 1 |
michael@0 | 178 | |
michael@0 | 179 | if os.path.isfile(os.path.join(options.profile, 'extensions', \ |
michael@0 | 180 | 'httpd@gaiamobile.org')): |
michael@0 | 181 | print(GAIA_PROFILE_IS_DEBUG % ('mochitest-b2g-desktop', |
michael@0 | 182 | options.profile)) |
michael@0 | 183 | return 1 |
michael@0 | 184 | |
michael@0 | 185 | options.desktop = True |
michael@0 | 186 | options.app = self.get_binary_path() |
michael@0 | 187 | if not options.app.endswith('-bin'): |
michael@0 | 188 | options.app = '%s-bin' % options.app |
michael@0 | 189 | if not os.path.isfile(options.app): |
michael@0 | 190 | options.app = options.app[:-len('-bin')] |
michael@0 | 191 | |
michael@0 | 192 | return reftest.run_desktop_reftests(parser, options, args) |
michael@0 | 193 | |
michael@0 | 194 | |
michael@0 | 195 | try: |
michael@0 | 196 | which.which('adb') |
michael@0 | 197 | except which.WhichError: |
michael@0 | 198 | # TODO Find adb automatically if it isn't on the path |
michael@0 | 199 | raise Exception(ADB_NOT_FOUND % ('%s-remote' % suite, b2g_home)) |
michael@0 | 200 | |
michael@0 | 201 | options.b2gPath = b2g_home |
michael@0 | 202 | options.logcat_dir = self.reftest_dir |
michael@0 | 203 | options.httpdPath = os.path.join(self.topsrcdir, 'netwerk', 'test', 'httpserver') |
michael@0 | 204 | options.xrePath = xre_path |
michael@0 | 205 | options.ignoreWindowSize = True |
michael@0 | 206 | return reftest.run_remote_reftests(parser, options, args) |
michael@0 | 207 | |
michael@0 | 208 | def run_desktop_test(self, test_file=None, filter=None, suite=None, |
michael@0 | 209 | debugger=None, parallel=False, shuffle=False, |
michael@0 | 210 | e10s=False, this_chunk=None, total_chunks=None): |
michael@0 | 211 | """Runs a reftest. |
michael@0 | 212 | |
michael@0 | 213 | test_file is a path to a test file. It can be a relative path from the |
michael@0 | 214 | top source directory, an absolute filename, or a directory containing |
michael@0 | 215 | test files. |
michael@0 | 216 | |
michael@0 | 217 | filter is a regular expression (in JS syntax, as could be passed to the |
michael@0 | 218 | RegExp constructor) to select which reftests to run from the manifest. |
michael@0 | 219 | |
michael@0 | 220 | suite is the type of reftest to run. It can be one of ('reftest', |
michael@0 | 221 | 'crashtest'). |
michael@0 | 222 | |
michael@0 | 223 | debugger is the program name (in $PATH) or the full path of the |
michael@0 | 224 | debugger to run. |
michael@0 | 225 | |
michael@0 | 226 | parallel indicates whether tests should be run in parallel or not. |
michael@0 | 227 | |
michael@0 | 228 | shuffle indicates whether to run tests in random order. |
michael@0 | 229 | """ |
michael@0 | 230 | |
michael@0 | 231 | if suite not in ('reftest', 'reftest-ipc', 'crashtest', 'crashtest-ipc'): |
michael@0 | 232 | raise Exception('None or unrecognized reftest suite type.') |
michael@0 | 233 | |
michael@0 | 234 | env = {} |
michael@0 | 235 | extra_args = [] |
michael@0 | 236 | |
michael@0 | 237 | if test_file: |
michael@0 | 238 | path = self._find_manifest(suite, test_file) |
michael@0 | 239 | if not os.path.exists(mozpack.path.join(self.topsrcdir, path)): |
michael@0 | 240 | raise Exception('No manifest file was found at %s.' % path) |
michael@0 | 241 | env[b'TEST_PATH'] = path |
michael@0 | 242 | if filter: |
michael@0 | 243 | extra_args.extend(['--filter', self._make_shell_string(filter)]) |
michael@0 | 244 | |
michael@0 | 245 | pass_thru = False |
michael@0 | 246 | |
michael@0 | 247 | if debugger: |
michael@0 | 248 | extra_args.append('--debugger=%s' % debugger) |
michael@0 | 249 | pass_thru = True |
michael@0 | 250 | |
michael@0 | 251 | if parallel: |
michael@0 | 252 | extra_args.append('--run-tests-in-parallel') |
michael@0 | 253 | |
michael@0 | 254 | if shuffle: |
michael@0 | 255 | extra_args.append('--shuffle') |
michael@0 | 256 | |
michael@0 | 257 | if e10s: |
michael@0 | 258 | extra_args.append('--e10s') |
michael@0 | 259 | |
michael@0 | 260 | if this_chunk: |
michael@0 | 261 | extra_args.append('--this-chunk=%s' % this_chunk) |
michael@0 | 262 | |
michael@0 | 263 | if total_chunks: |
michael@0 | 264 | extra_args.append('--total-chunks=%s' % total_chunks) |
michael@0 | 265 | |
michael@0 | 266 | if extra_args: |
michael@0 | 267 | args = [os.environ.get(b'EXTRA_TEST_ARGS', '')] |
michael@0 | 268 | args.extend(extra_args) |
michael@0 | 269 | env[b'EXTRA_TEST_ARGS'] = ' '.join(args) |
michael@0 | 270 | |
michael@0 | 271 | # TODO hook up harness via native Python |
michael@0 | 272 | return self._run_make(directory='.', target=suite, append_env=env, |
michael@0 | 273 | pass_thru=pass_thru, ensure_exit_code=False) |
michael@0 | 274 | |
michael@0 | 275 | |
michael@0 | 276 | def ReftestCommand(func): |
michael@0 | 277 | """Decorator that adds shared command arguments to reftest commands.""" |
michael@0 | 278 | |
michael@0 | 279 | debugger = CommandArgument('--debugger', metavar='DEBUGGER', |
michael@0 | 280 | help=DEBUGGER_HELP) |
michael@0 | 281 | func = debugger(func) |
michael@0 | 282 | |
michael@0 | 283 | flter = CommandArgument('--filter', metavar='REGEX', |
michael@0 | 284 | help='A JS regular expression to match test URLs against, to select ' |
michael@0 | 285 | 'a subset of tests to run.') |
michael@0 | 286 | func = flter(func) |
michael@0 | 287 | |
michael@0 | 288 | path = CommandArgument('test_file', nargs='?', metavar='MANIFEST', |
michael@0 | 289 | help='Reftest manifest file, or a directory in which to select ' |
michael@0 | 290 | 'reftest.list. If omitted, the entire test suite is executed.') |
michael@0 | 291 | func = path(func) |
michael@0 | 292 | |
michael@0 | 293 | parallel = CommandArgument('--parallel', action='store_true', |
michael@0 | 294 | help='Run tests in parallel.') |
michael@0 | 295 | func = parallel(func) |
michael@0 | 296 | |
michael@0 | 297 | shuffle = CommandArgument('--shuffle', action='store_true', |
michael@0 | 298 | help='Run tests in random order.') |
michael@0 | 299 | func = shuffle(func) |
michael@0 | 300 | |
michael@0 | 301 | e10s = CommandArgument('--e10s', action='store_true', |
michael@0 | 302 | help='Use content processes.') |
michael@0 | 303 | func = e10s(func) |
michael@0 | 304 | |
michael@0 | 305 | totalChunks = CommandArgument('--total-chunks', |
michael@0 | 306 | help = 'How many chunks to split the tests up into.') |
michael@0 | 307 | func = totalChunks(func) |
michael@0 | 308 | |
michael@0 | 309 | thisChunk = CommandArgument('--this-chunk', |
michael@0 | 310 | help = 'Which chunk to run between 1 and --total-chunks.') |
michael@0 | 311 | func = thisChunk(func) |
michael@0 | 312 | |
michael@0 | 313 | return func |
michael@0 | 314 | |
michael@0 | 315 | def B2GCommand(func): |
michael@0 | 316 | """Decorator that adds shared command arguments to b2g mochitest commands.""" |
michael@0 | 317 | |
michael@0 | 318 | busybox = CommandArgument('--busybox', default=None, |
michael@0 | 319 | help='Path to busybox binary to install on device') |
michael@0 | 320 | func = busybox(func) |
michael@0 | 321 | |
michael@0 | 322 | logcatdir = CommandArgument('--logcat-dir', default=None, |
michael@0 | 323 | help='directory to store logcat dump files') |
michael@0 | 324 | func = logcatdir(func) |
michael@0 | 325 | |
michael@0 | 326 | geckopath = CommandArgument('--gecko-path', default=None, |
michael@0 | 327 | help='the path to a gecko distribution that should \ |
michael@0 | 328 | be installed on the emulator prior to test') |
michael@0 | 329 | func = geckopath(func) |
michael@0 | 330 | |
michael@0 | 331 | sdcard = CommandArgument('--sdcard', default="10MB", |
michael@0 | 332 | help='Define size of sdcard: 1MB, 50MB...etc') |
michael@0 | 333 | func = sdcard(func) |
michael@0 | 334 | |
michael@0 | 335 | emulator_res = CommandArgument('--emulator-res', default='800x1000', |
michael@0 | 336 | help='Emulator resolution of the format \'<width>x<height>\'') |
michael@0 | 337 | func = emulator_res(func) |
michael@0 | 338 | |
michael@0 | 339 | emulator = CommandArgument('--emulator', default='arm', |
michael@0 | 340 | help='Architecture of emulator to use: x86 or arm') |
michael@0 | 341 | func = emulator(func) |
michael@0 | 342 | |
michael@0 | 343 | marionette = CommandArgument('--marionette', default=None, |
michael@0 | 344 | help='host:port to use when connecting to Marionette') |
michael@0 | 345 | func = marionette(func) |
michael@0 | 346 | |
michael@0 | 347 | totalChunks = CommandArgument('--total-chunks', dest='totalChunks', |
michael@0 | 348 | help = 'How many chunks to split the tests up into.') |
michael@0 | 349 | func = totalChunks(func) |
michael@0 | 350 | |
michael@0 | 351 | thisChunk = CommandArgument('--this-chunk', dest='thisChunk', |
michael@0 | 352 | help = 'Which chunk to run between 1 and --total-chunks.') |
michael@0 | 353 | func = thisChunk(func) |
michael@0 | 354 | |
michael@0 | 355 | path = CommandArgument('test_file', default=None, nargs='?', |
michael@0 | 356 | metavar='TEST', |
michael@0 | 357 | help='Test to run. Can be specified as a single file, a ' \ |
michael@0 | 358 | 'directory, or omitted. If omitted, the entire test suite is ' \ |
michael@0 | 359 | 'executed.') |
michael@0 | 360 | func = path(func) |
michael@0 | 361 | |
michael@0 | 362 | return func |
michael@0 | 363 | |
michael@0 | 364 | |
michael@0 | 365 | @CommandProvider |
michael@0 | 366 | class MachCommands(MachCommandBase): |
michael@0 | 367 | @Command('reftest', category='testing', description='Run reftests.') |
michael@0 | 368 | @ReftestCommand |
michael@0 | 369 | def run_reftest(self, test_file, **kwargs): |
michael@0 | 370 | return self._run_reftest(test_file, suite='reftest', **kwargs) |
michael@0 | 371 | |
michael@0 | 372 | @Command('reftest-ipc', category='testing', |
michael@0 | 373 | description='Run IPC reftests.') |
michael@0 | 374 | @ReftestCommand |
michael@0 | 375 | def run_ipc(self, test_file, **kwargs): |
michael@0 | 376 | return self._run_reftest(test_file, suite='reftest-ipc', **kwargs) |
michael@0 | 377 | |
michael@0 | 378 | @Command('crashtest', category='testing', |
michael@0 | 379 | description='Run crashtests.') |
michael@0 | 380 | @ReftestCommand |
michael@0 | 381 | def run_crashtest(self, test_file, **kwargs): |
michael@0 | 382 | return self._run_reftest(test_file, suite='crashtest', **kwargs) |
michael@0 | 383 | |
michael@0 | 384 | @Command('crashtest-ipc', category='testing', |
michael@0 | 385 | description='Run IPC crashtests.') |
michael@0 | 386 | @ReftestCommand |
michael@0 | 387 | def run_crashtest_ipc(self, test_file, **kwargs): |
michael@0 | 388 | return self._run_reftest(test_file, suite='crashtest-ipc', **kwargs) |
michael@0 | 389 | |
michael@0 | 390 | def _run_reftest(self, test_file=None, suite=None, **kwargs): |
michael@0 | 391 | reftest = self._spawn(ReftestRunner) |
michael@0 | 392 | return reftest.run_desktop_test(test_file, suite=suite, **kwargs) |
michael@0 | 393 | |
michael@0 | 394 | |
michael@0 | 395 | # TODO For now b2g commands will only work with the emulator, |
michael@0 | 396 | # they should be modified to work with all devices. |
michael@0 | 397 | def is_emulator(cls): |
michael@0 | 398 | """Emulator needs to be configured.""" |
michael@0 | 399 | return cls.device_name.find('emulator') == 0 |
michael@0 | 400 | |
michael@0 | 401 | |
michael@0 | 402 | @CommandProvider |
michael@0 | 403 | class B2GCommands(MachCommandBase): |
michael@0 | 404 | def __init__(self, context): |
michael@0 | 405 | MachCommandBase.__init__(self, context) |
michael@0 | 406 | |
michael@0 | 407 | for attr in ('b2g_home', 'xre_path', 'device_name'): |
michael@0 | 408 | setattr(self, attr, getattr(context, attr, None)) |
michael@0 | 409 | |
michael@0 | 410 | @Command('reftest-remote', category='testing', |
michael@0 | 411 | description='Run a remote reftest.', |
michael@0 | 412 | conditions=[conditions.is_b2g, is_emulator]) |
michael@0 | 413 | @B2GCommand |
michael@0 | 414 | def run_reftest_remote(self, test_file, **kwargs): |
michael@0 | 415 | return self._run_reftest(test_file, suite='reftest', **kwargs) |
michael@0 | 416 | |
michael@0 | 417 | @Command('reftest-b2g-desktop', category='testing', |
michael@0 | 418 | description='Run a b2g desktop reftest.', |
michael@0 | 419 | conditions=[conditions.is_b2g_desktop]) |
michael@0 | 420 | @B2GCommand |
michael@0 | 421 | def run_reftest_b2g_desktop(self, test_file, **kwargs): |
michael@0 | 422 | return self._run_reftest(test_file, suite='reftest', **kwargs) |
michael@0 | 423 | |
michael@0 | 424 | @Command('crashtest-remote', category='testing', |
michael@0 | 425 | description='Run a remote crashtest.', |
michael@0 | 426 | conditions=[conditions.is_b2g, is_emulator]) |
michael@0 | 427 | @B2GCommand |
michael@0 | 428 | def run_crashtest_remote(self, test_file, **kwargs): |
michael@0 | 429 | return self._run_reftest(test_file, suite='crashtest', **kwargs) |
michael@0 | 430 | |
michael@0 | 431 | def _run_reftest(self, test_file=None, suite=None, **kwargs): |
michael@0 | 432 | reftest = self._spawn(ReftestRunner) |
michael@0 | 433 | return reftest.run_b2g_test(self.b2g_home, self.xre_path, |
michael@0 | 434 | test_file, suite=suite, **kwargs) |