2 # ***** BEGIN LICENSE BLOCK *****
3 # Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 # The contents of this file are subject to the Mozilla Public License Version
6 # 1.1 (the "License"); you may not use this file except in compliance with
7 # the License. You may obtain a copy of the License at
8 # http://www.mozilla.org/MPL/
10 # Software distributed under the License is distributed on an "AS IS" basis,
11 # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 # for the specific language governing rights and limitations under the
15 # The Original Code is mozilla.org code.
17 # The Initial Developer of the Original Code is
18 # the Mozilla Foundation.
19 # Portions created by the Initial Developer are Copyright (C) 1998
20 # the Initial Developer. All Rights Reserved.
23 # Robert Sayre <sayrer@gmail.com>
24 # Jeff Walden <jwalden+bmo@mit.edu>
25 # Serge Gautherie <sgautherie.bz@free.fr>
27 # Alternatively, the contents of this file may be used under the terms of
28 # either the GNU General Public License Version 2 or later (the "GPL"), or
29 # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 # in which case the provisions of the GPL or the LGPL are applicable instead
31 # of those above. If you wish to allow use of your version of this file only
32 # under the terms of either the GPL or the LGPL, and not to allow others to
33 # use your version of this file under the terms of the MPL, indicate your
34 # decision by deleting the provisions above and replace them with the notice
35 # and other provisions required by the GPL or the LGPL. If you do not delete
36 # the provisions above, a recipient may use your version of this file under
37 # the terms of any one of the MPL, the GPL or the LGPL.
39 # ***** END LICENSE BLOCK *****
42 Runs the Mochitest test harness.
45 from __future__
import with_statement
46 from datetime
import datetime
53 SCRIPT_DIR
= os
.path
.abspath(os
.path
.realpath(os
.path
.dirname(sys
.argv
[0])))
54 sys
.path
.insert(0, SCRIPT_DIR
);
57 from urllib
import quote_plus
as encodeURIComponent
60 from automation
import Automation
61 from automationutils
import *
64 VMWARE_RECORDING_HELPER_BASENAME
= "vmwarerecordinghelper"
66 #######################
67 # COMMANDLINE OPTIONS #
68 #######################
70 class MochitestOptions(optparse
.OptionParser
):
71 """Parses Mochitest commandline options."""
72 def __init__(self
, automation
, scriptdir
, **kwargs
):
73 self
._automation
= automation
74 optparse
.OptionParser
.__init
__(self
, **kwargs
)
77 # we want to pass down everything from self._automation.__all__
78 addCommonOptions(self
, defaults
=dict(zip(self
._automation
.__all
__,
79 [getattr(self
._automation
, x
) for x
in self
._automation
.__all
__])))
80 self
._automation
.addCommonOptions(self
)
82 self
.add_option("--close-when-done",
83 action
= "store_true", dest
= "closeWhenDone",
84 help = "close the application when tests are done running")
85 defaults
["closeWhenDone"] = False
87 self
.add_option("--appname",
88 action
= "store", type = "string", dest
= "app",
89 help = "absolute path to application, overriding default")
90 defaults
["app"] = os
.path
.join(scriptdir
, self
._automation
.DEFAULT_APP
)
92 self
.add_option("--utility-path",
93 action
= "store", type = "string", dest
= "utilityPath",
94 help = "absolute path to directory containing utility programs (xpcshell, ssltunnel, certutil)")
95 defaults
["utilityPath"] = self
._automation
.DIST_BIN
97 self
.add_option("--certificate-path",
98 action
= "store", type = "string", dest
= "certPath",
99 help = "absolute path to directory containing certificate store to use testing profile")
100 defaults
["certPath"] = self
._automation
.CERTS_SRC_DIR
102 self
.add_option("--log-file",
103 action
= "store", type = "string",
104 dest
= "logFile", metavar
= "FILE",
105 help = "file to which logging occurs")
106 defaults
["logFile"] = ""
108 self
.add_option("--autorun",
109 action
= "store_true", dest
= "autorun",
110 help = "start running tests when the application starts")
111 defaults
["autorun"] = False
113 self
.add_option("--timeout",
114 type = "int", dest
= "timeout",
115 help = "per-test timeout in seconds")
116 defaults
["timeout"] = None
118 self
.add_option("--total-chunks",
119 type = "int", dest
= "totalChunks",
120 help = "how many chunks to split the tests up into")
121 defaults
["totalChunks"] = None
123 self
.add_option("--this-chunk",
124 type = "int", dest
= "thisChunk",
125 help = "which chunk to run")
126 defaults
["thisChunk"] = None
128 self
.add_option("--chunk-by-dir",
129 type = "int", dest
= "chunkByDir",
130 help = "group tests together in the same chunk that are in the same top chunkByDir directories")
131 defaults
["chunkByDir"] = 0
133 self
.add_option("--shuffle",
135 action
= "store_true",
136 help = "randomize test order")
137 defaults
["shuffle"] = False
139 LOG_LEVELS
= ("DEBUG", "INFO", "WARNING", "ERROR", "FATAL")
140 LEVEL_STRING
= ", ".join(LOG_LEVELS
)
142 self
.add_option("--console-level",
143 action
= "store", type = "choice", dest
= "consoleLevel",
144 choices
= LOG_LEVELS
, metavar
= "LEVEL",
145 help = "one of %s to determine the level of console "
146 "logging" % LEVEL_STRING
)
147 defaults
["consoleLevel"] = None
149 self
.add_option("--file-level",
150 action
= "store", type = "choice", dest
= "fileLevel",
151 choices
= LOG_LEVELS
, metavar
= "LEVEL",
152 help = "one of %s to determine the level of file "
153 "logging if a file has been specified, defaulting "
154 "to INFO" % LEVEL_STRING
)
155 defaults
["fileLevel"] = "INFO"
157 self
.add_option("--chrome",
158 action
= "store_true", dest
= "chrome",
159 help = "run chrome Mochitests")
160 defaults
["chrome"] = False
162 self
.add_option("--test-path",
163 action
= "store", type = "string", dest
= "testPath",
164 help = "start in the given directory's tests")
165 defaults
["testPath"] = ""
167 self
.add_option("--browser-chrome",
168 action
= "store_true", dest
= "browserChrome",
169 help = "run browser chrome Mochitests")
170 defaults
["browserChrome"] = False
172 self
.add_option("--a11y",
173 action
= "store_true", dest
= "a11y",
174 help = "run accessibility Mochitests");
175 defaults
["a11y"] = False
177 self
.add_option("--setenv",
178 action
= "append", type = "string",
179 dest
= "environment", metavar
= "NAME=VALUE",
180 help = "sets the given variable in the application's "
182 defaults
["environment"] = []
184 self
.add_option("--browser-arg",
185 action
= "append", type = "string",
186 dest
= "browserArgs", metavar
= "ARG",
187 help = "provides an argument to the test application")
188 defaults
["browserArgs"] = []
190 self
.add_option("--leak-threshold",
191 action
= "store", type = "int",
192 dest
= "leakThreshold", metavar
= "THRESHOLD",
193 help = "fail if the number of bytes leaked through "
194 "refcounted objects (or bytes in classes with "
195 "MOZ_COUNT_CTOR and MOZ_COUNT_DTOR) is greater "
196 "than the given number")
197 defaults
["leakThreshold"] = 0
199 self
.add_option("--fatal-assertions",
200 action
= "store_true", dest
= "fatalAssertions",
201 help = "abort testing whenever an assertion is hit "
202 "(requires a debug build to be effective)")
203 defaults
["fatalAssertions"] = False
205 self
.add_option("--extra-profile-file",
206 action
= "append", dest
= "extraProfileFiles",
207 help = "copy specified files/dirs to testing profile")
208 defaults
["extraProfileFiles"] = []
210 self
.add_option("--profile-path", action
= "store",
211 type = "string", dest
= "profilePath",
212 help = "Directory where the profile will be stored."
213 "This directory will be deleted after the tests are finished")
214 defaults
["profilePath"] = tempfile
.mkdtemp()
216 self
.add_option("--use-vmware-recording",
217 action
= "store_true", dest
= "vmwareRecording",
218 help = "enables recording while the application is running "
219 "inside a VMware Workstation 7.0 or later VM")
220 defaults
["vmwareRecording"] = False
222 # -h, --help are automatically handled by OptionParser
224 self
.set_defaults(**defaults
)
227 Usage instructions for runtests.py.
228 All arguments are optional.
229 If --chrome is specified, chrome tests will be run instead of web content tests.
230 If --browser-chrome is specified, browser-chrome tests will be run instead of web content tests.
231 See <http://mochikit.com/doc/html/MochiKit/Logging.html> for details on the logging levels."""
232 self
.set_usage(usage
)
234 def verifyOptions(self
, options
, mochitest
):
235 """ verify correct options and cleanup paths """
237 if options
.totalChunks
is not None and options
.thisChunk
is None:
238 self
.error("thisChunk must be specified when totalChunks is specified")
240 if options
.totalChunks
:
241 if not 1 <= options
.thisChunk
<= options
.totalChunks
:
242 self
.error("thisChunk must be between 1 and totalChunks")
244 if options
.xrePath
is None:
245 # default xrePath to the app path if not provided
246 # but only if an app path was explicitly provided
247 if options
.app
!= self
.defaults
['app']:
248 options
.xrePath
= os
.path
.dirname(options
.app
)
250 # otherwise default to dist/bin
251 options
.xrePath
= self
._automation
.DIST_BIN
253 # allow relative paths
254 options
.xrePath
= mochitest
.getFullPath(options
.xrePath
)
256 options
.profilePath
= mochitest
.getFullPath(options
.profilePath
)
258 options
.app
= mochitest
.getFullPath(options
.app
)
259 if not os
.path
.exists(options
.app
):
261 Error: Path %(app)s doesn't exist.
262 Are you executing $objdir/_tests/testing/mochitest/runtests.py?"""
263 print msg
% {"app": options
.app
}
266 options
.utilityPath
= mochitest
.getFullPath(options
.utilityPath
)
267 options
.certPath
= mochitest
.getFullPath(options
.certPath
)
268 if options
.symbolsPath
and not isURL(options
.symbolsPath
):
269 options
.symbolsPath
= mochitest
.getFullPath(options
.symbolsPath
)
271 options
.webServer
= self
._automation
.DEFAULT_WEB_SERVER
272 options
.httpPort
= self
._automation
.DEFAULT_HTTP_PORT
273 options
.sslPort
= self
._automation
.DEFAULT_SSL_PORT
274 options
.webSocketPort
= self
._automation
.DEFAULT_WEBSOCKET_PORT
276 if options
.vmwareRecording
:
277 if not self
._automation
.IS_WIN32
:
278 self
.error("use-vmware-recording is only supported on Windows.")
279 mochitest
.vmwareHelperPath
= os
.path
.join(
280 options
.utilityPath
, VMWARE_RECORDING_HELPER_BASENAME
+ ".dll")
281 if not os
.path
.exists(mochitest
.vmwareHelperPath
):
282 self
.error("%s not found, cannot automate VMware recording." %
283 mochitest
.vmwareHelperPath
)
288 #######################
289 # HTTP SERVER SUPPORT #
290 #######################
292 class MochitestServer
:
293 "Web server used to serve Mochitests, for closer fidelity to the real web."
295 def __init__(self
, automation
, options
):
296 self
._automation
= automation
297 self
._closeWhenDone
= options
.closeWhenDone
298 self
._utilityPath
= options
.utilityPath
299 self
._xrePath
= options
.xrePath
300 self
._profileDir
= options
.profilePath
301 self
.webServer
= options
.webServer
302 self
.httpPort
= options
.httpPort
303 self
.shutdownURL
= "http://%(server)s:%(port)s/server/shutdown" % { "server" : self
.webServer
, "port" : self
.httpPort
}
306 "Run the Mochitest server, returning the process ID of the server."
308 env
= self
._automation
.environment(xrePath
= self
._xrePath
)
309 env
["XPCOM_DEBUG_BREAK"] = "warn"
310 if self
._automation
.IS_WIN32
:
311 env
["PATH"] = env
["PATH"] + ";" + self
._xrePath
313 args
= ["-g", self
._xrePath
,
315 "-f", "./" + "httpd.js",
316 "-e", "const _PROFILE_PATH = '%(profile)s';const _SERVER_PORT = '%(port)s'; const _SERVER_ADDR ='%(server)s';" %
317 {"profile" : self
._profileDir
.replace('\\', '\\\\'), "port" : self
.httpPort
, "server" : self
.webServer
},
318 "-f", "./" + "server.js"]
320 xpcshell
= os
.path
.join(self
._utilityPath
,
321 "xpcshell" + self
._automation
.BIN_SUFFIX
)
322 self
._process
= self
._automation
.Process([xpcshell
] + args
, env
= env
)
323 pid
= self
._process
.pid
325 print "Error starting server."
327 self
._automation
.log
.info("INFO | runtests.py | Server pid: %d", pid
)
329 def ensureReady(self
, timeout
):
332 aliveFile
= os
.path
.join(self
._profileDir
, "server_alive.txt")
335 if os
.path
.exists(aliveFile
):
340 print "Timed out while waiting for server startup."
346 c
= urllib2
.urlopen(self
.shutdownURL
)
350 rtncode
= self
._process
.poll()
352 self
._process
.terminate()
356 class WebSocketServer(object):
357 "Class which encapsulates the mod_pywebsocket server"
359 def __init__(self
, automation
, options
, scriptdir
):
360 self
.port
= options
.webSocketPort
361 self
._automation
= automation
362 self
._scriptdir
= scriptdir
365 script
= os
.path
.join(self
._scriptdir
, 'pywebsocket/standalone.py')
366 cmd
= [sys
.executable
, script
, '-p', str(self
.port
), '-w', self
._scriptdir
, '-l', os
.path
.join(self
._scriptdir
, "websock.log"), '--log-level=debug']
368 self
._process
= self
._automation
.Process(cmd
)
369 pid
= self
._process
.pid
371 print "Error starting websocket server."
373 self
._automation
.log
.info("INFO | runtests.py | Websocket server pid: %d", pid
)
378 class Mochitest(object):
379 # Path to the test script on the server
380 TEST_PATH
= "/tests/"
381 CHROME_PATH
= "/redirect.html";
382 A11Y_PATH
= "/redirect-a11y.html"
389 def __init__(self
, automation
):
390 self
.automation
= automation
392 # Max time in seconds to wait for server startup before tests will fail -- if
393 # this seems big, it's mostly for debug machines where cold startup
394 # (particularly after a build) takes forever.
395 if self
.automation
.IS_DEBUG_BUILD
:
396 self
.SERVER_STARTUP_TIMEOUT
= 180
398 self
.SERVER_STARTUP_TIMEOUT
= 90
400 self
.SCRIPT_DIRECTORY
= os
.path
.abspath(os
.path
.realpath(os
.path
.dirname(__file__
)))
401 os
.chdir(self
.SCRIPT_DIRECTORY
)
403 def getFullPath(self
, path
):
404 " Get an absolute path relative to self.oldcwd."
405 return os
.path
.normpath(os
.path
.join(self
.oldcwd
, os
.path
.expanduser(path
)))
407 def buildTestPath(self
, options
):
408 """ Build the url path to the specific test harness and test file or directory """
409 testHost
= "http://mochi.test:8888"
410 testURL
= testHost
+ self
.TEST_PATH
+ options
.testPath
412 testURL
= testHost
+ self
.CHROME_PATH
414 self
.urlOpts
.append("testPath=" + encodeURIComponent(options
.testPath
))
416 testURL
= testHost
+ self
.A11Y_PATH
418 self
.urlOpts
.append("testPath=" + encodeURIComponent(options
.testPath
))
419 elif options
.browserChrome
:
420 testURL
= "about:blank"
423 def startWebSocketServer(self
, options
):
424 """ Launch the websocket server """
425 if options
.webServer
!= '127.0.0.1':
428 self
.wsserver
= WebSocketServer(self
.automation
, options
, self
.SCRIPT_DIRECTORY
)
429 self
.wsserver
.start()
431 def stopWebSocketServer(self
, options
):
432 if options
.webServer
!= '127.0.0.1':
437 def startWebServer(self
, options
):
438 if options
.webServer
!= '127.0.0.1':
441 """ Create the webserver and start it up """
442 self
.server
= MochitestServer(self
.automation
, options
)
445 # If we're lucky, the server has fully started by now, and all paths are
446 # ready, etc. However, xpcshell cold start times suck, at least for debug
447 # builds. We'll try to connect to the server for awhile, and if we fail,
448 # we'll try to kill the server and exit with an error.
449 self
.server
.ensureReady(self
.SERVER_STARTUP_TIMEOUT
)
451 def stopWebServer(self
, options
):
452 """ Server's no longer needed, and perhaps more importantly, anything it might
453 spew to console shouldn't disrupt the leak information table we print next.
455 if options
.webServer
!= '127.0.0.1':
460 def getLogFilePath(self
, logFile
):
461 """ return the log file path relative to the device we are testing on, in most cases
462 it will be the full path on the local system
464 return self
.getFullPath(logFile
)
466 def buildProfile(self
, options
):
467 """ create the profile and add optional chrome bits and files if requested """
468 self
.automation
.initializeProfile(options
.profilePath
, options
.extraPrefs
, useServerLocations
= True)
469 manifest
= self
.addChromeToProfile(options
)
470 self
.copyExtraFilesToProfile(options
)
473 def buildBrowserEnv(self
, options
):
474 """ build the environment variables for the specific test and operating system """
475 browserEnv
= self
.automation
.environment(xrePath
= options
.xrePath
)
477 # These variables are necessary for correct application startup; change
478 # via the commandline at your own risk.
479 browserEnv
["XPCOM_DEBUG_BREAK"] = "stack"
481 for v
in options
.environment
:
484 print "Error: syntax error in --setenv=" + v
486 browserEnv
[v
[:ix
]] = v
[ix
+ 1:]
488 browserEnv
["XPCOM_MEM_BLOAT_LOG"] = self
.leak_report_file
490 if options
.fatalAssertions
:
491 browserEnv
["XPCOM_DEBUG_BREAK"] = "stack-and-abort"
495 def buildURLOptions(self
, options
):
496 """ Add test control options from the command line to the url
498 URL parameters to test URL:
500 autorun -- kick off tests automatically
501 closeWhenDone -- runs quit.js after tests
502 logFile -- logs test run to an absolute path
503 totalChunks -- how many chunks to split tests into
504 thisChunk -- which chunk to run
505 timeout -- per-test timeout in seconds
508 # allow relative paths for logFile
510 options
.logFile
= self
.getLogFilePath(options
.logFile
)
511 if options
.browserChrome
:
512 self
.makeTestConfig(options
)
515 self
.urlOpts
.append("autorun=1")
517 self
.urlOpts
.append("timeout=%d" % options
.timeout
)
518 if options
.closeWhenDone
:
519 self
.urlOpts
.append("closeWhenDone=1")
521 self
.urlOpts
.append("logFile=" + encodeURIComponent(options
.logFile
))
522 self
.urlOpts
.append("fileLevel=" + encodeURIComponent(options
.fileLevel
))
523 if options
.consoleLevel
:
524 self
.urlOpts
.append("consoleLevel=" + encodeURIComponent(options
.consoleLevel
))
525 if options
.totalChunks
:
526 self
.urlOpts
.append("totalChunks=%d" % options
.totalChunks
)
527 self
.urlOpts
.append("thisChunk=%d" % options
.thisChunk
)
528 if options
.chunkByDir
:
529 self
.urlOpts
.append("chunkByDir=%d" % options
.chunkByDir
)
531 self
.urlOpts
.append("shuffle=1")
533 def cleanup(self
, manifest
, options
):
534 """ remove temporary files and profile """
536 shutil
.rmtree(options
.profilePath
)
538 def startVMwareRecording(self
, options
):
539 """ starts recording inside VMware VM using the recording helper dll """
540 assert(self
.automation
.IS_WIN32
)
541 from ctypes
import cdll
542 self
.vmwareHelper
= cdll
.LoadLibrary(self
.vmwareHelperPath
)
543 if self
.vmwareHelper
is None:
544 self
.automation
.log
.warning("WARNING | runtests.py | Failed to load "
545 "VMware recording helper")
547 self
.automation
.log
.info("INFO | runtests.py | Starting VMware recording.")
549 self
.vmwareHelper
.StartRecording()
551 self
.automation
.log
.warning("WARNING | runtests.py | Failed to start "
552 "VMware recording: (%s)" % str(e
))
553 self
.vmwareHelper
= None
555 def stopVMwareRecording(self
):
556 """ stops recording inside VMware VM using the recording helper dll """
557 assert(self
.automation
.IS_WIN32
)
558 if self
.vmwareHelper
is not None:
559 self
.automation
.log
.info("INFO | runtests.py | Stopping VMware "
562 self
.vmwareHelper
.StopRecording()
564 self
.automation
.log
.warning("WARNING | runtests.py | Failed to stop "
565 "VMware recording: (%s)" % str(e
))
566 self
.vmwareHelper
= None
568 def runTests(self
, options
):
569 """ Prepare, configure, run tests and cleanup """
570 debuggerInfo
= getDebuggerInfo(self
.oldcwd
, options
.debugger
, options
.debuggerArgs
,
571 options
.debuggerInteractive
);
573 self
.leak_report_file
= os
.path
.join(options
.profilePath
, "runtests_leaks.log")
575 browserEnv
= self
.buildBrowserEnv(options
)
576 if browserEnv
is None:
579 manifest
= self
.buildProfile(options
)
582 self
.startWebServer(options
)
583 self
.startWebSocketServer(options
)
585 testURL
= self
.buildTestPath(options
)
586 self
.buildURLOptions(options
)
587 if len(self
.urlOpts
) > 0:
588 testURL
+= "?" + "&".join(self
.urlOpts
)
590 # Remove the leak detection file so it can't "leak" to the tests run.
591 # The file is not there if leak logging was not enabled in the application build.
592 if os
.path
.exists(self
.leak_report_file
):
593 os
.remove(self
.leak_report_file
)
595 # then again to actually run mochitest
597 timeout
= options
.timeout
+ 30
598 elif not options
.autorun
:
601 timeout
= 330.0 # default JS harness timeout is 300 seconds
603 if options
.vmwareRecording
:
604 self
.startVMwareRecording(options
);
606 self
.automation
.log
.info("INFO | runtests.py | Running tests: start.\n")
607 status
= self
.automation
.runApp(testURL
, browserEnv
, options
.app
,
608 options
.profilePath
, options
.browserArgs
,
609 runSSLTunnel
= self
.runSSLTunnel
,
610 utilityPath
= options
.utilityPath
,
611 xrePath
= options
.xrePath
,
612 certPath
=options
.certPath
,
613 debuggerInfo
=debuggerInfo
,
614 symbolsPath
=options
.symbolsPath
,
617 if options
.vmwareRecording
:
618 self
.stopVMwareRecording();
620 self
.stopWebServer(options
)
621 self
.stopWebSocketServer(options
)
622 processLeakLog(self
.leak_report_file
, options
.leakThreshold
)
623 self
.automation
.log
.info("\nINFO | runtests.py | Running tests: end.")
625 if manifest
is not None:
626 self
.cleanup(manifest
, options
)
629 def makeTestConfig(self
, options
):
630 "Creates a test configuration file for customizing test execution."
636 logFile
= options
.logFile
.replace("\\", "\\\\")
637 testPath
= options
.testPath
.replace("\\", "\\\\")
640 autoRun: %(autorun)s,
641 closeWhenDone: %(closeWhenDone)s,
642 logPath: "%(logPath)s",
643 testPath: "%(testPath)s"
644 })""" % {"autorun": boolString(options
.autorun
),
645 "closeWhenDone": boolString(options
.closeWhenDone
),
647 "testPath": testPath
}
649 config
= open(os
.path
.join(options
.profilePath
, "testConfig.js"), "w")
650 config
.write(content
)
654 def addChromeToProfile(self
, options
):
655 "Adds MochiKit chrome tests to the profile."
657 chromedir
= os
.path
.join(options
.profilePath
, "chrome")
661 @namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); /* set default namespace to XUL */
664 background-color: rgb(235, 235, 235) !important;
667 background-image: none !important;
671 # write userChrome.css
672 chromeFile
= open(os
.path
.join(options
.profilePath
, "userChrome.css"), "a")
673 chromeFile
.write(chrome
)
677 # register our chrome dir
678 chrometestDir
= os
.path
.abspath(".") + "/"
679 if self
.automation
.IS_WIN32
:
680 chrometestDir
= "file:///" + chrometestDir
.replace("\\", "/")
682 manifest
= os
.path
.join(options
.profilePath
, 'tests.manifest')
685 if options
.browserChrome
:
686 browser_chrome
= """overlay chrome://navigator/content/navigator.xul chrome://mochikit/content/browser-test-overlay.xul
687 overlay chrome://browser/content/browser.xul chrome://mochikit/content/browser-test-overlay.xul
689 elif (options
.chrome
== False) and (options
.a11y
== False):
690 #only do the ipc-overlay.xul for mochitest-plain.
691 #Currently there are focus issues in chrome tests and issues with new windows and dialogs when using ipc
692 browser_chrome
+= "overlay chrome://browser/content/browser.xul chrome://mochikit/content/ipc-overlay.xul\n"
695 if not os
.path
.exists(os
.path
.join(self
.SCRIPT_DIRECTORY
, jarDir
)):
696 print "TEST-UNEXPECTED-FAIL | invalid setup: missing mochikit extension"
699 manifestFile
= open(manifest
, "w")
700 if self
.installTestsJar(options
):
701 manifestFile
.write("content mochitests jar:tests.jar!/content/\n");
703 manifestFile
.write("content mochitests %s contentaccessible=yes\n" % chrometestDir
)
706 self
.installChromeJar(jarDir
, browser_chrome
, options
)
709 def installChromeJar(self
, jarDirName
, browser_chrome
, options
):
711 copy mochijar directory to profile as an extension so we have chrome://mochikit for all harness code
713 jarDir
= os
.path
.join(options
.profilePath
, 'extensions', 'mochikit@mozilla.org')
714 shutil
.copytree(os
.path
.join(self
.SCRIPT_DIRECTORY
, jarDirName
), jarDir
)
715 with
open(os
.path
.join(jarDir
, "chrome.manifest"), 'a') as mfile
:
716 mfile
.write(browser_chrome
)
720 def installTestsJar(self
, options
):
721 """ copy tests.jar to the profile directory so we can auto register it in the .xul harness """
722 if os
.path
.exists(os
.path
.join(self
.SCRIPT_DIRECTORY
, 'tests.jar')):
723 shutil
.copy(os
.path
.join(self
.SCRIPT_DIRECTORY
, 'tests.jar'), options
.profilePath
)
727 def copyExtraFilesToProfile(self
, options
):
728 "Copy extra files or dirs specified on the command line to the testing profile."
729 for f
in options
.extraProfileFiles
:
730 abspath
= self
.getFullPath(f
)
731 dest
= os
.path
.join(options
.profilePath
, os
.path
.basename(abspath
))
732 if os
.path
.isdir(abspath
):
733 shutil
.copytree(abspath
, dest
)
735 shutil
.copy(abspath
, dest
)
738 automation
= Automation()
739 mochitest
= Mochitest(automation
)
740 parser
= MochitestOptions(automation
, mochitest
.SCRIPT_DIRECTORY
)
741 options
, args
= parser
.parse_args()
743 options
= parser
.verifyOptions(options
, mochitest
)
747 options
.utilityPath
= mochitest
.getFullPath(options
.utilityPath
)
748 options
.certPath
= mochitest
.getFullPath(options
.certPath
)
749 if options
.symbolsPath
and not isURL(options
.symbolsPath
):
750 options
.symbolsPath
= mochitest
.getFullPath(options
.symbolsPath
)
752 automation
.setServerInfo(options
.webServer
,
755 options
.webSocketPort
)
756 sys
.exit(mochitest
.runTests(options
))
758 if __name__
== "__main__":