|
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 mozinfo |
|
6 import moznetwork |
|
7 import optparse |
|
8 import os |
|
9 import tempfile |
|
10 |
|
11 from automationutils import addCommonOptions, isURL |
|
12 from mozprofile import DEFAULT_PORTS |
|
13 |
|
14 here = os.path.abspath(os.path.dirname(__file__)) |
|
15 |
|
16 try: |
|
17 from mozbuild.base import MozbuildObject |
|
18 build_obj = MozbuildObject.from_environment(cwd=here) |
|
19 except ImportError: |
|
20 build_obj = None |
|
21 |
|
22 __all__ = ["MochitestOptions", "B2GOptions"] |
|
23 |
|
24 VMWARE_RECORDING_HELPER_BASENAME = "vmwarerecordinghelper" |
|
25 |
|
26 class MochitestOptions(optparse.OptionParser): |
|
27 """Usage instructions for runtests.py. |
|
28 All arguments are optional. |
|
29 If --chrome is specified, chrome tests will be run instead of web content tests. |
|
30 If --browser-chrome is specified, browser-chrome tests will be run instead of web content tests. |
|
31 See <http://mochikit.com/doc/html/MochiKit/Logging.html> for details on the logging levels. |
|
32 """ |
|
33 |
|
34 LOG_LEVELS = ("DEBUG", "INFO", "WARNING", "ERROR", "FATAL") |
|
35 LEVEL_STRING = ", ".join(LOG_LEVELS) |
|
36 mochitest_options = [ |
|
37 [["--close-when-done"], |
|
38 { "action": "store_true", |
|
39 "dest": "closeWhenDone", |
|
40 "default": False, |
|
41 "help": "close the application when tests are done running", |
|
42 }], |
|
43 [["--appname"], |
|
44 { "action": "store", |
|
45 "type": "string", |
|
46 "dest": "app", |
|
47 "default": None, |
|
48 "help": "absolute path to application, overriding default", |
|
49 }], |
|
50 [["--utility-path"], |
|
51 { "action": "store", |
|
52 "type": "string", |
|
53 "dest": "utilityPath", |
|
54 "default": build_obj.bindir if build_obj is not None else None, |
|
55 "help": "absolute path to directory containing utility programs (xpcshell, ssltunnel, certutil)", |
|
56 }], |
|
57 [["--certificate-path"], |
|
58 { "action": "store", |
|
59 "type": "string", |
|
60 "dest": "certPath", |
|
61 "help": "absolute path to directory containing certificate store to use testing profile", |
|
62 "default": os.path.join(build_obj.topsrcdir, 'build', 'pgo', 'certs') if build_obj is not None else None, |
|
63 }], |
|
64 [["--log-file"], |
|
65 { "action": "store", |
|
66 "type": "string", |
|
67 "dest": "logFile", |
|
68 "metavar": "FILE", |
|
69 "help": "file to which logging occurs", |
|
70 "default": "", |
|
71 }], |
|
72 [["--hide-subtests"], |
|
73 { "action": "store_true", |
|
74 "dest": "hide_subtests", |
|
75 "help": "only show subtest log output if there was a failure", |
|
76 "default": False, |
|
77 }], |
|
78 [["--autorun"], |
|
79 { "action": "store_true", |
|
80 "dest": "autorun", |
|
81 "help": "start running tests when the application starts", |
|
82 "default": False, |
|
83 }], |
|
84 [["--timeout"], |
|
85 { "type": "int", |
|
86 "dest": "timeout", |
|
87 "help": "per-test timeout in seconds", |
|
88 "default": None, |
|
89 }], |
|
90 [["--total-chunks"], |
|
91 { "type": "int", |
|
92 "dest": "totalChunks", |
|
93 "help": "how many chunks to split the tests up into", |
|
94 "default": None, |
|
95 }], |
|
96 [["--this-chunk"], |
|
97 { "type": "int", |
|
98 "dest": "thisChunk", |
|
99 "help": "which chunk to run", |
|
100 "default": None, |
|
101 }], |
|
102 [["--chunk-by-dir"], |
|
103 { "type": "int", |
|
104 "dest": "chunkByDir", |
|
105 "help": "group tests together in the same chunk that are in the same top chunkByDir directories", |
|
106 "default": 0, |
|
107 }], |
|
108 [["--shuffle"], |
|
109 { "dest": "shuffle", |
|
110 "action": "store_true", |
|
111 "help": "randomize test order", |
|
112 "default": False, |
|
113 }], |
|
114 [["--console-level"], |
|
115 { "action": "store", |
|
116 "type": "choice", |
|
117 "dest": "consoleLevel", |
|
118 "choices": LOG_LEVELS, |
|
119 "metavar": "LEVEL", |
|
120 "help": "one of %s to determine the level of console " |
|
121 "logging" % LEVEL_STRING, |
|
122 "default": None, |
|
123 }], |
|
124 [["--file-level"], |
|
125 { "action": "store", |
|
126 "type": "choice", |
|
127 "dest": "fileLevel", |
|
128 "choices": LOG_LEVELS, |
|
129 "metavar": "LEVEL", |
|
130 "help": "one of %s to determine the level of file " |
|
131 "logging if a file has been specified, defaulting " |
|
132 "to INFO" % LEVEL_STRING, |
|
133 "default": "INFO", |
|
134 }], |
|
135 [["--chrome"], |
|
136 { "action": "store_true", |
|
137 "dest": "chrome", |
|
138 "help": "run chrome Mochitests", |
|
139 "default": False, |
|
140 }], |
|
141 [["--ipcplugins"], |
|
142 { "action": "store_true", |
|
143 "dest": "ipcplugins", |
|
144 "help": "run ipcplugins Mochitests", |
|
145 "default": False, |
|
146 }], |
|
147 [["--test-path"], |
|
148 { "action": "store", |
|
149 "type": "string", |
|
150 "dest": "testPath", |
|
151 "help": "start in the given directory's tests", |
|
152 "default": "", |
|
153 }], |
|
154 [["--start-at"], |
|
155 { "action": "store", |
|
156 "type": "string", |
|
157 "dest": "startAt", |
|
158 "help": "skip over tests until reaching the given test", |
|
159 "default": "", |
|
160 }], |
|
161 [["--end-at"], |
|
162 { "action": "store", |
|
163 "type": "string", |
|
164 "dest": "endAt", |
|
165 "help": "don't run any tests after the given one", |
|
166 "default": "", |
|
167 }], |
|
168 [["--browser-chrome"], |
|
169 { "action": "store_true", |
|
170 "dest": "browserChrome", |
|
171 "help": "run browser chrome Mochitests", |
|
172 "default": False, |
|
173 }], |
|
174 [["--subsuite"], |
|
175 { "action": "store", |
|
176 "dest": "subsuite", |
|
177 "help": "subsuite of tests to run", |
|
178 "default": "", |
|
179 }], |
|
180 [["--webapprt-content"], |
|
181 { "action": "store_true", |
|
182 "dest": "webapprtContent", |
|
183 "help": "run WebappRT content tests", |
|
184 "default": False, |
|
185 }], |
|
186 [["--webapprt-chrome"], |
|
187 { "action": "store_true", |
|
188 "dest": "webapprtChrome", |
|
189 "help": "run WebappRT chrome tests", |
|
190 "default": False, |
|
191 }], |
|
192 [["--a11y"], |
|
193 { "action": "store_true", |
|
194 "dest": "a11y", |
|
195 "help": "run accessibility Mochitests", |
|
196 "default": False, |
|
197 }], |
|
198 [["--setenv"], |
|
199 { "action": "append", |
|
200 "type": "string", |
|
201 "dest": "environment", |
|
202 "metavar": "NAME=VALUE", |
|
203 "help": "sets the given variable in the application's " |
|
204 "environment", |
|
205 "default": [], |
|
206 }], |
|
207 [["--exclude-extension"], |
|
208 { "action": "append", |
|
209 "type": "string", |
|
210 "dest": "extensionsToExclude", |
|
211 "help": "excludes the given extension from being installed " |
|
212 "in the test profile", |
|
213 "default": [], |
|
214 }], |
|
215 [["--browser-arg"], |
|
216 { "action": "append", |
|
217 "type": "string", |
|
218 "dest": "browserArgs", |
|
219 "metavar": "ARG", |
|
220 "help": "provides an argument to the test application", |
|
221 "default": [], |
|
222 }], |
|
223 [["--leak-threshold"], |
|
224 { "action": "store", |
|
225 "type": "int", |
|
226 "dest": "leakThreshold", |
|
227 "metavar": "THRESHOLD", |
|
228 "help": "fail if the number of bytes leaked through " |
|
229 "refcounted objects (or bytes in classes with " |
|
230 "MOZ_COUNT_CTOR and MOZ_COUNT_DTOR) is greater " |
|
231 "than the given number", |
|
232 "default": 0, |
|
233 }], |
|
234 [["--fatal-assertions"], |
|
235 { "action": "store_true", |
|
236 "dest": "fatalAssertions", |
|
237 "help": "abort testing whenever an assertion is hit " |
|
238 "(requires a debug build to be effective)", |
|
239 "default": False, |
|
240 }], |
|
241 [["--extra-profile-file"], |
|
242 { "action": "append", |
|
243 "dest": "extraProfileFiles", |
|
244 "help": "copy specified files/dirs to testing profile", |
|
245 "default": [], |
|
246 }], |
|
247 [["--install-extension"], |
|
248 { "action": "append", |
|
249 "dest": "extensionsToInstall", |
|
250 "help": "install the specified extension in the testing profile." |
|
251 "The extension file's name should be <id>.xpi where <id> is" |
|
252 "the extension's id as indicated in its install.rdf." |
|
253 "An optional path can be specified too.", |
|
254 "default": [], |
|
255 }], |
|
256 [["--profile-path"], |
|
257 { "action": "store", |
|
258 "type": "string", |
|
259 "dest": "profilePath", |
|
260 "help": "Directory where the profile will be stored." |
|
261 "This directory will be deleted after the tests are finished", |
|
262 "default": tempfile.mkdtemp(), |
|
263 }], |
|
264 [["--testing-modules-dir"], |
|
265 { "action": "store", |
|
266 "type": "string", |
|
267 "dest": "testingModulesDir", |
|
268 "help": "Directory where testing-only JS modules are located.", |
|
269 "default": None, |
|
270 }], |
|
271 [["--use-vmware-recording"], |
|
272 { "action": "store_true", |
|
273 "dest": "vmwareRecording", |
|
274 "help": "enables recording while the application is running " |
|
275 "inside a VMware Workstation 7.0 or later VM", |
|
276 "default": False, |
|
277 }], |
|
278 [["--repeat"], |
|
279 { "action": "store", |
|
280 "type": "int", |
|
281 "dest": "repeat", |
|
282 "metavar": "REPEAT", |
|
283 "help": "repeats the test or set of tests the given number of times, ie: repeat: 1 will run the test twice.", |
|
284 "default": 0, |
|
285 }], |
|
286 [["--run-until-failure"], |
|
287 { "action": "store_true", |
|
288 "dest": "runUntilFailure", |
|
289 "help": "Run tests repeatedly and stops on the first time a test fails. " |
|
290 "Default cap is 30 runs, which can be overwritten with the --repeat parameter.", |
|
291 "default": False, |
|
292 }], |
|
293 [["--run-only-tests"], |
|
294 { "action": "store", |
|
295 "type": "string", |
|
296 "dest": "runOnlyTests", |
|
297 "help": "JSON list of tests that we only want to run. [DEPRECATED- please use --test-manifest]", |
|
298 "default": None, |
|
299 }], |
|
300 [["--test-manifest"], |
|
301 { "action": "store", |
|
302 "type": "string", |
|
303 "dest": "testManifest", |
|
304 "help": "JSON list of tests to specify 'runtests'. Old format for mobile specific tests", |
|
305 "default": None, |
|
306 }], |
|
307 [["--manifest"], |
|
308 { "action": "store", |
|
309 "type": "string", |
|
310 "dest": "manifestFile", |
|
311 "help": ".ini format of tests to run.", |
|
312 "default": None, |
|
313 }], |
|
314 [["--failure-file"], |
|
315 { "action": "store", |
|
316 "type": "string", |
|
317 "dest": "failureFile", |
|
318 "help": "Filename of the output file where we can store a .json list of failures to be run in the future with --run-only-tests.", |
|
319 "default": None, |
|
320 }], |
|
321 [["--run-slower"], |
|
322 { "action": "store_true", |
|
323 "dest": "runSlower", |
|
324 "help": "Delay execution between test files.", |
|
325 "default": False, |
|
326 }], |
|
327 [["--metro-immersive"], |
|
328 { "action": "store_true", |
|
329 "dest": "immersiveMode", |
|
330 "help": "launches tests in immersive browser", |
|
331 "default": False, |
|
332 }], |
|
333 [["--httpd-path"], |
|
334 { "action": "store", |
|
335 "type": "string", |
|
336 "dest": "httpdPath", |
|
337 "default": None, |
|
338 "help": "path to the httpd.js file", |
|
339 }], |
|
340 [["--setpref"], |
|
341 { "action": "append", |
|
342 "type": "string", |
|
343 "default": [], |
|
344 "dest": "extraPrefs", |
|
345 "metavar": "PREF=VALUE", |
|
346 "help": "defines an extra user preference", |
|
347 }], |
|
348 [["--jsdebugger"], |
|
349 { "action": "store_true", |
|
350 "default": False, |
|
351 "dest": "jsdebugger", |
|
352 "help": "open the browser debugger", |
|
353 }], |
|
354 [["--debug-on-failure"], |
|
355 { "action": "store_true", |
|
356 "default": False, |
|
357 "dest": "debugOnFailure", |
|
358 "help": "breaks execution and enters the JS debugger on a test failure. Should be used together with --jsdebugger." |
|
359 }], |
|
360 [["--e10s"], |
|
361 { "action": "store_true", |
|
362 "default": False, |
|
363 "dest": "e10s", |
|
364 "help": "Run tests with electrolysis preferences and test filtering enabled.", |
|
365 }], |
|
366 [["--dmd-path"], |
|
367 { "action": "store", |
|
368 "default": None, |
|
369 "dest": "dmdPath", |
|
370 "help": "Specifies the path to the directory containing the shared library for DMD.", |
|
371 }], |
|
372 [["--dump-output-directory"], |
|
373 { "action": "store", |
|
374 "default": None, |
|
375 "dest": "dumpOutputDirectory", |
|
376 "help": "Specifies the directory in which to place dumped memory reports.", |
|
377 }], |
|
378 [["--dump-about-memory-after-test"], |
|
379 { "action": "store_true", |
|
380 "default": False, |
|
381 "dest": "dumpAboutMemoryAfterTest", |
|
382 "help": "Produce an about:memory dump after each test in the directory specified " |
|
383 "by --dump-output-directory." |
|
384 }], |
|
385 [["--dump-dmd-after-test"], |
|
386 { "action": "store_true", |
|
387 "default": False, |
|
388 "dest": "dumpDMDAfterTest", |
|
389 "help": "Produce a DMD dump after each test in the directory specified " |
|
390 "by --dump-output-directory." |
|
391 }], |
|
392 [["--slowscript"], |
|
393 { "action": "store_true", |
|
394 "default": False, |
|
395 "dest": "slowscript", |
|
396 "help": "Do not set the JS_DISABLE_SLOW_SCRIPT_SIGNALS env variable; " |
|
397 "when not set, recoverable but misleading SIGSEGV instances " |
|
398 "may occur in Ion/Odin JIT code." |
|
399 }], |
|
400 [["--screenshot-on-fail"], |
|
401 { "action": "store_true", |
|
402 "default": False, |
|
403 "dest": "screenshotOnFail", |
|
404 "help": "Take screenshots on all test failures. Set $MOZ_UPLOAD_DIR to a directory for storing the screenshots." |
|
405 }], |
|
406 [["--quiet"], |
|
407 { "action": "store_true", |
|
408 "default": False, |
|
409 "dest": "quiet", |
|
410 "help": "Do not print test log lines unless a failure occurs." |
|
411 }], |
|
412 [["--pidfile"], |
|
413 { "action": "store", |
|
414 "type": "string", |
|
415 "dest": "pidFile", |
|
416 "help": "name of the pidfile to generate", |
|
417 "default": "", |
|
418 }], |
|
419 ] |
|
420 |
|
421 def __init__(self, **kwargs): |
|
422 |
|
423 optparse.OptionParser.__init__(self, **kwargs) |
|
424 for option, value in self.mochitest_options: |
|
425 self.add_option(*option, **value) |
|
426 addCommonOptions(self) |
|
427 self.set_usage(self.__doc__) |
|
428 |
|
429 def verifyOptions(self, options, mochitest): |
|
430 """ verify correct options and cleanup paths """ |
|
431 |
|
432 mozinfo.update({"e10s": options.e10s}) # for test manifest parsing. |
|
433 |
|
434 if options.app is None: |
|
435 if build_obj is not None: |
|
436 options.app = build_obj.get_binary_path() |
|
437 else: |
|
438 self.error("could not find the application path, --appname must be specified") |
|
439 |
|
440 if options.totalChunks is not None and options.thisChunk is None: |
|
441 self.error("thisChunk must be specified when totalChunks is specified") |
|
442 |
|
443 if options.totalChunks: |
|
444 if not 1 <= options.thisChunk <= options.totalChunks: |
|
445 self.error("thisChunk must be between 1 and totalChunks") |
|
446 |
|
447 if options.xrePath is None: |
|
448 # default xrePath to the app path if not provided |
|
449 # but only if an app path was explicitly provided |
|
450 if options.app != self.defaults['app']: |
|
451 options.xrePath = os.path.dirname(options.app) |
|
452 elif build_obj is not None: |
|
453 # otherwise default to dist/bin |
|
454 options.xrePath = build_obj.bindir |
|
455 else: |
|
456 self.error("could not find xre directory, --xre-path must be specified") |
|
457 |
|
458 # allow relative paths |
|
459 options.xrePath = mochitest.getFullPath(options.xrePath) |
|
460 options.profilePath = mochitest.getFullPath(options.profilePath) |
|
461 options.app = mochitest.getFullPath(options.app) |
|
462 if options.dmdPath is not None: |
|
463 options.dmdPath = mochitest.getFullPath(options.dmdPath) |
|
464 |
|
465 if not os.path.exists(options.app): |
|
466 msg = """\ |
|
467 Error: Path %(app)s doesn't exist. |
|
468 Are you executing $objdir/_tests/testing/mochitest/runtests.py?""" |
|
469 self.error(msg % {"app": options.app}) |
|
470 return None |
|
471 |
|
472 if options.utilityPath: |
|
473 options.utilityPath = mochitest.getFullPath(options.utilityPath) |
|
474 |
|
475 if options.certPath: |
|
476 options.certPath = mochitest.getFullPath(options.certPath) |
|
477 |
|
478 if options.symbolsPath and not isURL(options.symbolsPath): |
|
479 options.symbolsPath = mochitest.getFullPath(options.symbolsPath) |
|
480 |
|
481 # Set server information on the options object |
|
482 options.webServer = '127.0.0.1' |
|
483 options.httpPort = DEFAULT_PORTS['http'] |
|
484 options.sslPort = DEFAULT_PORTS['https'] |
|
485 # options.webSocketPort = DEFAULT_PORTS['ws'] |
|
486 options.webSocketPort = str(9988) # <- http://hg.mozilla.org/mozilla-central/file/b871dfb2186f/build/automation.py.in#l30 |
|
487 # The default websocket port is incorrect in mozprofile; it is |
|
488 # set to the SSL proxy setting. See: |
|
489 # see https://bugzilla.mozilla.org/show_bug.cgi?id=916517 |
|
490 |
|
491 if options.vmwareRecording: |
|
492 if not mozinfo.isWin: |
|
493 self.error("use-vmware-recording is only supported on Windows.") |
|
494 mochitest.vmwareHelperPath = os.path.join( |
|
495 options.utilityPath, VMWARE_RECORDING_HELPER_BASENAME + ".dll") |
|
496 if not os.path.exists(mochitest.vmwareHelperPath): |
|
497 self.error("%s not found, cannot automate VMware recording." % |
|
498 mochitest.vmwareHelperPath) |
|
499 |
|
500 if options.testManifest and options.runOnlyTests: |
|
501 self.error("Please use --test-manifest only and not --run-only-tests") |
|
502 |
|
503 if options.runOnlyTests: |
|
504 if not os.path.exists(os.path.abspath(os.path.join(here, options.runOnlyTests))): |
|
505 self.error("unable to find --run-only-tests file '%s'" % options.runOnlyTests) |
|
506 options.runOnly = True |
|
507 options.testManifest = options.runOnlyTests |
|
508 options.runOnlyTests = None |
|
509 |
|
510 if options.manifestFile and options.testManifest: |
|
511 self.error("Unable to support both --manifest and --test-manifest/--run-only-tests at the same time") |
|
512 |
|
513 if options.webapprtContent and options.webapprtChrome: |
|
514 self.error("Only one of --webapprt-content and --webapprt-chrome may be given.") |
|
515 |
|
516 if options.jsdebugger: |
|
517 options.extraPrefs += [ |
|
518 "devtools.debugger.remote-enabled=true", |
|
519 "devtools.debugger.chrome-enabled=true", |
|
520 "devtools.chrome.enabled=true", |
|
521 "devtools.debugger.prompt-connection=false" |
|
522 ] |
|
523 options.autorun = False |
|
524 |
|
525 if options.debugOnFailure and not options.jsdebugger: |
|
526 self.error("--debug-on-failure should be used together with --jsdebugger.") |
|
527 |
|
528 # Try to guess the testing modules directory. |
|
529 # This somewhat grotesque hack allows the buildbot machines to find the |
|
530 # modules directory without having to configure the buildbot hosts. This |
|
531 # code should never be executed in local runs because the build system |
|
532 # should always set the flag that populates this variable. If buildbot ever |
|
533 # passes this argument, this code can be deleted. |
|
534 if options.testingModulesDir is None: |
|
535 possible = os.path.join(here, os.path.pardir, 'modules') |
|
536 |
|
537 if os.path.isdir(possible): |
|
538 options.testingModulesDir = possible |
|
539 |
|
540 # Even if buildbot is updated, we still want this, as the path we pass in |
|
541 # to the app must be absolute and have proper slashes. |
|
542 if options.testingModulesDir is not None: |
|
543 options.testingModulesDir = os.path.normpath(options.testingModulesDir) |
|
544 |
|
545 if not os.path.isabs(options.testingModulesDir): |
|
546 options.testingModulesDir = os.path.abspath(options.testingModulesDir) |
|
547 |
|
548 if not os.path.isdir(options.testingModulesDir): |
|
549 self.error('--testing-modules-dir not a directory: %s' % |
|
550 options.testingModulesDir) |
|
551 |
|
552 options.testingModulesDir = options.testingModulesDir.replace('\\', '/') |
|
553 if options.testingModulesDir[-1] != '/': |
|
554 options.testingModulesDir += '/' |
|
555 |
|
556 if options.immersiveMode: |
|
557 if not mozinfo.isWin: |
|
558 self.error("immersive is only supported on Windows 8 and up.") |
|
559 mochitest.immersiveHelperPath = os.path.join( |
|
560 options.utilityPath, "metrotestharness.exe") |
|
561 if not os.path.exists(mochitest.immersiveHelperPath): |
|
562 self.error("%s not found, cannot launch immersive tests." % |
|
563 mochitest.immersiveHelperPath) |
|
564 |
|
565 if options.runUntilFailure: |
|
566 if not options.repeat: |
|
567 options.repeat = 29 |
|
568 |
|
569 if options.dumpOutputDirectory is None: |
|
570 options.dumpOutputDirectory = tempfile.gettempdir() |
|
571 |
|
572 if options.dumpAboutMemoryAfterTest or options.dumpDMDAfterTest: |
|
573 if not os.path.isdir(options.dumpOutputDirectory): |
|
574 self.error('--dump-output-directory not a directory: %s' % |
|
575 options.dumpOutputDirectory) |
|
576 |
|
577 return options |
|
578 |
|
579 |
|
580 class B2GOptions(MochitestOptions): |
|
581 b2g_options = [ |
|
582 [["--b2gpath"], |
|
583 { "action": "store", |
|
584 "type": "string", |
|
585 "dest": "b2gPath", |
|
586 "help": "path to B2G repo or qemu dir", |
|
587 "default": None, |
|
588 }], |
|
589 [["--desktop"], |
|
590 { "action": "store_true", |
|
591 "dest": "desktop", |
|
592 "help": "Run the tests on a B2G desktop build", |
|
593 "default": False, |
|
594 }], |
|
595 [["--marionette"], |
|
596 { "action": "store", |
|
597 "type": "string", |
|
598 "dest": "marionette", |
|
599 "help": "host:port to use when connecting to Marionette", |
|
600 "default": None, |
|
601 }], |
|
602 [["--emulator"], |
|
603 { "action": "store", |
|
604 "type": "string", |
|
605 "dest": "emulator", |
|
606 "help": "Architecture of emulator to use: x86 or arm", |
|
607 "default": None, |
|
608 }], |
|
609 [["--wifi"], |
|
610 { "action": "store", |
|
611 "type": "string", |
|
612 "dest": "wifi", |
|
613 "help": "Devine wifi configuration for on device mochitest", |
|
614 "default": False, |
|
615 }], |
|
616 [["--sdcard"], |
|
617 { "action": "store", |
|
618 "type": "string", |
|
619 "dest": "sdcard", |
|
620 "help": "Define size of sdcard: 1MB, 50MB...etc", |
|
621 "default": "10MB", |
|
622 }], |
|
623 [["--no-window"], |
|
624 { "action": "store_true", |
|
625 "dest": "noWindow", |
|
626 "help": "Pass --no-window to the emulator", |
|
627 "default": False, |
|
628 }], |
|
629 [["--adbpath"], |
|
630 { "action": "store", |
|
631 "type": "string", |
|
632 "dest": "adbPath", |
|
633 "help": "path to adb", |
|
634 "default": "adb", |
|
635 }], |
|
636 [["--deviceIP"], |
|
637 { "action": "store", |
|
638 "type": "string", |
|
639 "dest": "deviceIP", |
|
640 "help": "ip address of remote device to test", |
|
641 "default": None, |
|
642 }], |
|
643 [["--devicePort"], |
|
644 { "action": "store", |
|
645 "type": "string", |
|
646 "dest": "devicePort", |
|
647 "help": "port of remote device to test", |
|
648 "default": 20701, |
|
649 }], |
|
650 [["--remote-logfile"], |
|
651 { "action": "store", |
|
652 "type": "string", |
|
653 "dest": "remoteLogFile", |
|
654 "help": "Name of log file on the device relative to the device root. \ |
|
655 PLEASE ONLY USE A FILENAME.", |
|
656 "default" : None, |
|
657 }], |
|
658 [["--remote-webserver"], |
|
659 { "action": "store", |
|
660 "type": "string", |
|
661 "dest": "remoteWebServer", |
|
662 "help": "ip address where the remote web server is hosted at", |
|
663 "default": None, |
|
664 }], |
|
665 [["--http-port"], |
|
666 { "action": "store", |
|
667 "type": "string", |
|
668 "dest": "httpPort", |
|
669 "help": "ip address where the remote web server is hosted at", |
|
670 "default": None, |
|
671 }], |
|
672 [["--ssl-port"], |
|
673 { "action": "store", |
|
674 "type": "string", |
|
675 "dest": "sslPort", |
|
676 "help": "ip address where the remote web server is hosted at", |
|
677 "default": None, |
|
678 }], |
|
679 [["--gecko-path"], |
|
680 { "action": "store", |
|
681 "type": "string", |
|
682 "dest": "geckoPath", |
|
683 "help": "the path to a gecko distribution that should \ |
|
684 be installed on the emulator prior to test", |
|
685 "default": None, |
|
686 }], |
|
687 [["--profile"], |
|
688 { "action": "store", |
|
689 "type": "string", |
|
690 "dest": "profile", |
|
691 "help": "for desktop testing, the path to the \ |
|
692 gaia profile to use", |
|
693 "default": None, |
|
694 }], |
|
695 [["--logcat-dir"], |
|
696 { "action": "store", |
|
697 "type": "string", |
|
698 "dest": "logcat_dir", |
|
699 "help": "directory to store logcat dump files", |
|
700 "default": None, |
|
701 }], |
|
702 [['--busybox'], |
|
703 { "action": 'store', |
|
704 "type": 'string', |
|
705 "dest": 'busybox', |
|
706 "help": "Path to busybox binary to install on device", |
|
707 "default": None, |
|
708 }], |
|
709 [['--profile-data-dir'], |
|
710 { "action": 'store', |
|
711 "type": 'string', |
|
712 "dest": 'profile_data_dir', |
|
713 "help": "Path to a directory containing preference and other \ |
|
714 data to be installed into the profile", |
|
715 "default": os.path.join(here, 'profile_data'), |
|
716 }], |
|
717 ] |
|
718 |
|
719 def __init__(self): |
|
720 MochitestOptions.__init__(self) |
|
721 |
|
722 for option in self.b2g_options: |
|
723 self.add_option(*option[0], **option[1]) |
|
724 |
|
725 defaults = {} |
|
726 defaults["httpPort"] = DEFAULT_PORTS['http'] |
|
727 defaults["sslPort"] = DEFAULT_PORTS['https'] |
|
728 defaults["remoteTestRoot"] = "/data/local/tests" |
|
729 defaults["logFile"] = "mochitest.log" |
|
730 defaults["autorun"] = True |
|
731 defaults["closeWhenDone"] = True |
|
732 defaults["testPath"] = "" |
|
733 defaults["extensionsToExclude"] = ["specialpowers"] |
|
734 self.set_defaults(**defaults) |
|
735 |
|
736 def verifyRemoteOptions(self, options): |
|
737 if options.remoteWebServer == None: |
|
738 if os.name != "nt": |
|
739 options.remoteWebServer = moznetwork.get_ip() |
|
740 else: |
|
741 self.error("You must specify a --remote-webserver=<ip address>") |
|
742 options.webServer = options.remoteWebServer |
|
743 |
|
744 if options.geckoPath and not options.emulator: |
|
745 self.error("You must specify --emulator if you specify --gecko-path") |
|
746 |
|
747 if options.logcat_dir and not options.emulator: |
|
748 self.error("You must specify --emulator if you specify --logcat-dir") |
|
749 |
|
750 if not os.path.isdir(options.xrePath): |
|
751 self.error("--xre-path '%s' is not a directory" % options.xrePath) |
|
752 xpcshell = os.path.join(options.xrePath, 'xpcshell') |
|
753 if not os.access(xpcshell, os.F_OK): |
|
754 self.error('xpcshell not found at %s' % xpcshell) |
|
755 if self.elf_arm(xpcshell): |
|
756 self.error('--xre-path points to an ARM version of xpcshell; it ' |
|
757 'should instead point to a version that can run on ' |
|
758 'your desktop') |
|
759 |
|
760 if options.pidFile != "": |
|
761 f = open(options.pidFile, 'w') |
|
762 f.write("%s" % os.getpid()) |
|
763 f.close() |
|
764 |
|
765 return options |
|
766 |
|
767 def verifyOptions(self, options, mochitest): |
|
768 # since we are reusing verifyOptions, it will exit if App is not found |
|
769 temp = options.app |
|
770 options.app = __file__ |
|
771 tempPort = options.httpPort |
|
772 tempSSL = options.sslPort |
|
773 tempIP = options.webServer |
|
774 options = MochitestOptions.verifyOptions(self, options, mochitest) |
|
775 options.webServer = tempIP |
|
776 options.app = temp |
|
777 options.sslPort = tempSSL |
|
778 options.httpPort = tempPort |
|
779 |
|
780 return options |
|
781 |
|
782 def elf_arm(self, filename): |
|
783 data = open(filename, 'rb').read(20) |
|
784 return data[:4] == "\x7fELF" and ord(data[18]) == 40 # EM_ARM |