Bug 1225903 - Drop support for b2g desktop in mochitest, r=jgriffin

Mochitests on b2g desktop are no longer being run on any trunk branches, including
b2g-inbound. Dropping support for it significantly reduces complexity
in the mochitest harness.

--HG--
extra : commitid : jAe5IJxAQp
extra : rebase_source : 5f163aea70fb99a95667fdafeb7b3361bed1f82d
This commit is contained in:
Andrew Halberstadt 2015-11-18 13:35:38 -05:00
parent 161662dac8
commit 629335ccca
6 changed files with 348 additions and 526 deletions

View File

@ -30,30 +30,6 @@ import mozpack.path as mozpath
here = os.path.abspath(os.path.dirname(__file__)) here = os.path.abspath(os.path.dirname(__file__))
GAIA_PROFILE_NOT_FOUND = '''
The mochitest command requires a non-debug gaia profile. Either
pass in --profile, or set the GAIA_PROFILE environment variable.
If you do not have a non-debug gaia profile, you can build one:
$ git clone https://github.com/mozilla-b2g/gaia
$ cd gaia
$ make
The profile should be generated in a directory called 'profile'.
'''.lstrip()
GAIA_PROFILE_IS_DEBUG = '''
The mochitest command requires a non-debug gaia profile. The
specified profile, {}, is a debug profile.
If you do not have a non-debug gaia profile, you can build one:
$ git clone https://github.com/mozilla-b2g/gaia
$ cd gaia
$ make
The profile should be generated in a directory called 'profile'.
'''.lstrip()
ENG_BUILD_REQUIRED = ''' ENG_BUILD_REQUIRED = '''
The mochitest command requires an engineering build. It may be the case that The mochitest command requires an engineering build. It may be the case that
VARIANT=user or PRODUCTION=1 were set. Try re-building with VARIANT=eng: VARIANT=user or PRODUCTION=1 were set. Try re-building with VARIANT=eng:
@ -99,7 +75,7 @@ ALL_FLAVORS = {
'mochitest': { 'mochitest': {
'suite': 'plain', 'suite': 'plain',
'aliases': ('plain', 'mochitest'), 'aliases': ('plain', 'mochitest'),
'enabled_apps': ('firefox', 'b2g', 'android', 'mulet', 'b2g_desktop'), 'enabled_apps': ('firefox', 'b2g', 'android', 'mulet'),
}, },
'chrome': { 'chrome': {
'suite': 'chrome', 'suite': 'chrome',
@ -159,7 +135,7 @@ ALL_FLAVORS = {
}, },
} }
SUPPORTED_APPS = ['firefox', 'b2g', 'android', 'mulet', 'b2g_desktop'] SUPPORTED_APPS = ['firefox', 'b2g', 'android', 'mulet']
SUPPORTED_FLAVORS = list(chain.from_iterable([f['aliases'] for f in ALL_FLAVORS.values()])) SUPPORTED_FLAVORS = list(chain.from_iterable([f['aliases'] for f in ALL_FLAVORS.values()]))
CANONICAL_FLAVORS = sorted([f['aliases'][0] for f in ALL_FLAVORS.values()]) CANONICAL_FLAVORS = sorted([f['aliases'][0] for f in ALL_FLAVORS.values()])
@ -236,17 +212,7 @@ class MochitestRunner(MozbuildObject):
def run_b2g_test(self, context, tests=None, suite='mochitest', **kwargs): def run_b2g_test(self, context, tests=None, suite='mochitest', **kwargs):
"""Runs a b2g mochitest.""" """Runs a b2g mochitest."""
if kwargs.get('desktop'): if context.target_out:
kwargs['profile'] = kwargs.get('profile') or os.environ.get('GAIA_PROFILE')
if not kwargs['profile'] or not os.path.isdir(kwargs['profile']):
print(GAIA_PROFILE_NOT_FOUND)
sys.exit(1)
if os.path.isfile(os.path.join(kwargs['profile'], 'extensions',
'httpd@gaiamobile.org')):
print(GAIA_PROFILE_IS_DEBUG.format(kwargs['profile']))
sys.exit(1)
elif context.target_out:
host_webapps_dir = os.path.join(context.target_out, 'data', 'local', 'webapps') host_webapps_dir = os.path.join(context.target_out, 'data', 'local', 'webapps')
if not os.path.isdir(os.path.join( if not os.path.isdir(os.path.join(
host_webapps_dir, 'test-container.gaiamobile.org')): host_webapps_dir, 'test-container.gaiamobile.org')):
@ -277,10 +243,7 @@ class MochitestRunner(MozbuildObject):
manifest.tests.extend(tests) manifest.tests.extend(tests)
options.manifestFile = manifest options.manifestFile = manifest
if options.desktop: return mochitest.run_test_harness(options)
return mochitest.run_desktop_mochitests(options)
return mochitest.run_remote_mochitests(options)
def run_desktop_test(self, context, tests=None, suite=None, **kwargs): def run_desktop_test(self, context, tests=None, suite=None, **kwargs):
"""Runs a mochitest. """Runs a mochitest.
@ -562,7 +525,7 @@ class MachCommands(MachCommandBase):
buildapp, '\n'.join(sorted(msg)))) buildapp, '\n'.join(sorted(msg))))
return 1 return 1
if buildapp in ('b2g', 'b2g_desktop'): if buildapp in ('b2g',):
run_mochitest = mochitest.run_b2g_test run_mochitest = mochitest.run_b2g_test
elif buildapp == 'android': elif buildapp == 'android':
run_mochitest = mochitest.run_android_test run_mochitest = mochitest.run_android_test

View File

@ -596,7 +596,7 @@ class MochitestArguments(ArgumentContainer):
if options.extra_mozinfo_json: if options.extra_mozinfo_json:
if not os.path.isfile(options.extra_mozinfo_json): if not os.path.isfile(options.extra_mozinfo_json):
parser.error("Error: couldn't find mozinfo.json at '%s'."\ parser.error("Error: couldn't find mozinfo.json at '%s'."
% options.extra_mozinfo_json) % options.extra_mozinfo_json)
options.extra_mozinfo_json = json.load(open(options.extra_mozinfo_json)) options.extra_mozinfo_json = json.load(open(options.extra_mozinfo_json))
@ -794,12 +794,6 @@ class B2GArguments(ArgumentContainer):
"help": "Path to B2G repo or QEMU directory.", "help": "Path to B2G repo or QEMU directory.",
"suppress": True, "suppress": True,
}], }],
[["--desktop"],
{"action": "store_true",
"default": False,
"help": "Run the tests on a B2G desktop build.",
"suppress": True,
}],
[["--marionette"], [["--marionette"],
{"default": None, {"default": None,
"help": "host:port to use when connecting to Marionette", "help": "host:port to use when connecting to Marionette",
@ -873,11 +867,6 @@ class B2GArguments(ArgumentContainer):
"prior to test.", "prior to test.",
"suppress": True, "suppress": True,
}], }],
[["--profile"],
{"dest": "profile",
"default": None,
"help": "For desktop testing, the path to the gaia profile to use.",
}],
[["--logdir"], [["--logdir"],
{"dest": "logdir", {"dest": "logdir",
"default": None, "default": None,
@ -909,20 +898,6 @@ class B2GArguments(ArgumentContainer):
def validate(self, parser, options, context): def validate(self, parser, options, context):
"""Validate b2g options.""" """Validate b2g options."""
if options.desktop and not options.app:
if not (build_obj and conditions.is_b2g_desktop(build_obj)):
parser.error(
"--desktop specified, but no b2g desktop build detected! Either "
"build for b2g desktop, or point --appname to a b2g desktop binary.")
elif build_obj and conditions.is_b2g_desktop(build_obj):
options.desktop = True
if not options.app:
options.app = build_obj.get_binary_path()
if not options.app.endswith('-bin'):
options.app = '%s-bin' % options.app
if not os.path.isfile(options.app):
options.app = options.app[:-len('-bin')]
if options.remoteWebServer is None: if options.remoteWebServer is None:
if os.name != "nt": if os.name != "nt":
options.remoteWebServer = moznetwork.get_ip() options.remoteWebServer = moznetwork.get_ip()
@ -1193,7 +1168,7 @@ class MochitestArgumentParser(ArgumentParser):
if not self.app and build_obj: if not self.app and build_obj:
if conditions.is_android(build_obj): if conditions.is_android(build_obj):
self.app = 'android' self.app = 'android'
elif conditions.is_b2g(build_obj) or conditions.is_b2g_desktop(build_obj): elif conditions.is_b2g(build_obj):
self.app = 'b2g' self.app = 'b2g'
if not self.app: if not self.app:
# platform can't be determined and app wasn't specified explicitly, # platform can't be determined and app wasn't specified explicitly,

View File

@ -16,7 +16,7 @@ sys.path.insert(
from automation import Automation from automation import Automation
from remoteautomation import RemoteAutomation, fennecLogcatFilters from remoteautomation import RemoteAutomation, fennecLogcatFilters
from runtests import Mochitest, MessageLogger from runtests import MochitestDesktop, MessageLogger
from mochitest_options import MochitestArgumentParser from mochitest_options import MochitestArgumentParser
from manifestparser import TestManifest from manifestparser import TestManifest
@ -27,7 +27,8 @@ import mozinfo
SCRIPT_DIR = os.path.abspath(os.path.realpath(os.path.dirname(__file__))) SCRIPT_DIR = os.path.abspath(os.path.realpath(os.path.dirname(__file__)))
class RobocopTestRunner(Mochitest): # TODO inherit from MochitestBase instead
class RobocopTestRunner(MochitestDesktop):
""" """
A test harness for Robocop. Robocop tests are UI tests for Firefox for Android, A test harness for Robocop. Robocop tests are UI tests for Firefox for Android,
based on the Robotium test framework. This harness leverages some functionality based on the Robotium test framework. This harness leverages some functionality
@ -42,7 +43,7 @@ class RobocopTestRunner(Mochitest):
""" """
Simple one-time initialization. Simple one-time initialization.
""" """
Mochitest.__init__(self, options) MochitestDesktop.__init__(self, options)
self.auto = automation self.auto = automation
self.dm = devmgr self.dm = devmgr
@ -131,7 +132,7 @@ class RobocopTestRunner(Mochitest):
blobberUploadDir) blobberUploadDir)
self.dm.getDirectory(self.remoteNSPR, blobberUploadDir) self.dm.getDirectory(self.remoteNSPR, blobberUploadDir)
self.dm.getDirectory(self.remoteScreenshots, blobberUploadDir) self.dm.getDirectory(self.remoteScreenshots, blobberUploadDir)
Mochitest.cleanup(self, self.options) MochitestDesktop.cleanup(self, self.options)
if self.localProfile: if self.localProfile:
os.system("rm -Rf %s" % self.localProfile) os.system("rm -Rf %s" % self.localProfile)
self.dm.removeDir(self.remoteProfile) self.dm.removeDir(self.remoteProfile)
@ -225,7 +226,7 @@ class RobocopTestRunner(Mochitest):
self.options.extraPrefs.append('browser.snippets.enabled=false') self.options.extraPrefs.append('browser.snippets.enabled=false')
self.options.extraPrefs.append('browser.casting.enabled=true') self.options.extraPrefs.append('browser.casting.enabled=true')
self.options.extraPrefs.append('extensions.autoupdate.enabled=false') self.options.extraPrefs.append('extensions.autoupdate.enabled=false')
manifest = Mochitest.buildProfile(self, self.options) manifest = MochitestDesktop.buildProfile(self, self.options)
self.localProfile = self.options.profilePath self.localProfile = self.options.profilePath
self.log.debug("Profile created at %s" % self.localProfile) self.log.debug("Profile created at %s" % self.localProfile)
# some files are not needed for robocop; save time by not pushing # some files are not needed for robocop; save time by not pushing

View File

@ -492,18 +492,11 @@ class WebSocketServer(object):
self._process.kill() self._process.kill()
class MochitestUtilsMixin(object): class MochitestBase(object):
""" """
Class containing some utility functions common to both local and remote Base mochitest class for both desktop and b2g.
mochitest runners
""" """
# TODO Utility classes are a code smell. This class is temporary
# and should be removed when desktop mochitests are refactored
# on top of mozbase. Each of the functions in here should
# probably live somewhere in mozbase
oldcwd = os.getcwd() oldcwd = os.getcwd()
jarDir = 'mochijar' jarDir = 'mochijar'
@ -519,6 +512,7 @@ class MochitestUtilsMixin(object):
self.server = None self.server = None
self.wsserver = None self.wsserver = None
self.sslTunnel = None self.sslTunnel = None
self._active_tests = None
self._locations = None self._locations = None
if self.log is None: if self.log is None:
@ -530,7 +524,7 @@ class MochitestUtilsMixin(object):
{ {
"tbpl": sys.stdout "tbpl": sys.stdout
}) })
MochitestUtilsMixin.log = self.log MochitestBase.log = self.log
self.message_logger = MessageLogger(logger=self.log) self.message_logger = MessageLogger(logger=self.log)
@ -548,6 +542,10 @@ class MochitestUtilsMixin(object):
mozinfo.find_and_update_from_json(*dirs) mozinfo.find_and_update_from_json(*dirs)
def environment(self, **kwargs):
kwargs['log'] = self.log
return test_environment(**kwargs)
def getFullPath(self, path): def getFullPath(self, path):
" Get an absolute path relative to self.oldcwd." " Get an absolute path relative to self.oldcwd."
return os.path.normpath( return os.path.normpath(
@ -994,6 +992,273 @@ overlay chrome://browser/content/browser.xul chrome://mochikit/content/jetpack-a
extensions.append(os.path.join(SCRIPT_DIR, self.jarDir)) extensions.append(os.path.join(SCRIPT_DIR, self.jarDir))
return extensions return extensions
def logPreamble(self, tests):
"""Logs a suite_start message and test_start/test_end at the beginning of a run.
"""
self.log.suite_start([t['path'] for t in tests])
for test in tests:
if 'disabled' in test:
self.log.test_start(test['path'])
self.log.test_end(
test['path'],
'SKIP',
message=test['disabled'])
def getActiveTests(self, options, disabled=True):
"""
This method is used to parse the manifest and return active filtered tests.
"""
if self._active_tests:
return self._active_tests
manifest = self.getTestManifest(options)
if manifest:
if options.extra_mozinfo_json:
mozinfo.update(options.extra_mozinfo_json)
info = mozinfo.info
# Bug 1089034 - imptest failure expectations are encoded as
# test manifests, even though they aren't tests. This gross
# hack causes several problems in automation including
# throwing off the chunking numbers. Remove them manually
# until bug 1089034 is fixed.
def remove_imptest_failure_expectations(tests, values):
return (t for t in tests
if 'imptests/failures' not in t['path'])
filters = [
remove_imptest_failure_expectations,
subsuite(options.subsuite),
]
if options.test_tags:
filters.append(tags(options.test_tags))
if options.test_paths:
options.test_paths = self.normalize_paths(options.test_paths)
filters.append(pathprefix(options.test_paths))
# Add chunking filters if specified
if options.totalChunks:
if options.chunkByRuntime:
runtime_file = self.resolve_runtime_file(options)
if not os.path.exists(runtime_file):
self.log.warning("runtime file %s not found; defaulting to chunk-by-dir" %
runtime_file)
options.chunkByRuntime = None
flavor = self.getTestFlavor(options)
if flavor in ('browser-chrome', 'devtools-chrome'):
# these values match current mozharness configs
options.chunkbyDir = 5
else:
options.chunkByDir = 4
if options.chunkByDir:
filters.append(chunk_by_dir(options.thisChunk,
options.totalChunks,
options.chunkByDir))
elif options.chunkByRuntime:
with open(runtime_file, 'r') as f:
runtime_data = json.loads(f.read())
runtimes = runtime_data['runtimes']
default = runtime_data['excluded_test_average']
filters.append(
chunk_by_runtime(options.thisChunk,
options.totalChunks,
runtimes,
default_runtime=default))
else:
filters.append(chunk_by_slice(options.thisChunk,
options.totalChunks))
tests = manifest.active_tests(
exists=False, disabled=disabled, filters=filters, **info)
if len(tests) == 0:
self.log.error("no tests to run using specified "
"combination of filters: {}".format(
manifest.fmt_filters()))
paths = []
for test in tests:
if len(tests) == 1 and 'disabled' in test:
del test['disabled']
pathAbs = os.path.abspath(test['path'])
assert pathAbs.startswith(self.testRootAbs)
tp = pathAbs[len(self.testRootAbs):].replace('\\', '/').strip('/')
if not self.isTest(options, tp):
self.log.warning(
'Warning: %s from manifest %s is not a valid test' %
(test['name'], test['manifest']))
continue
testob = {'path': tp}
if 'disabled' in test:
testob['disabled'] = test['disabled']
if 'expected' in test:
testob['expected'] = test['expected']
paths.append(testob)
def path_sort(ob1, ob2):
path1 = ob1['path'].split('/')
path2 = ob2['path'].split('/')
return cmp(path1, path2)
paths.sort(path_sort)
self._active_tests = paths
if options.dump_tests:
options.dump_tests = os.path.expanduser(options.dump_tests)
assert os.path.exists(os.path.dirname(options.dump_tests))
with open(options.dump_tests, 'w') as dumpFile:
dumpFile.write(json.dumps({'active_tests': self._active_tests}))
self.log.info("Dumping active_tests to %s file." % options.dump_tests)
sys.exit()
return self._active_tests
def getTestManifest(self, options):
if isinstance(options.manifestFile, TestManifest):
manifest = options.manifestFile
elif options.manifestFile and os.path.isfile(options.manifestFile):
manifestFileAbs = os.path.abspath(options.manifestFile)
assert manifestFileAbs.startswith(SCRIPT_DIR)
manifest = TestManifest([options.manifestFile], strict=False)
elif options.manifestFile and os.path.isfile(os.path.join(SCRIPT_DIR, options.manifestFile)):
manifestFileAbs = os.path.abspath(
os.path.join(
SCRIPT_DIR,
options.manifestFile))
assert manifestFileAbs.startswith(SCRIPT_DIR)
manifest = TestManifest([manifestFileAbs], strict=False)
else:
masterName = self.getTestFlavor(options) + '.ini'
masterPath = os.path.join(SCRIPT_DIR, self.testRoot, masterName)
if os.path.exists(masterPath):
manifest = TestManifest([masterPath], strict=False)
else:
self._log.warning(
'TestManifest masterPath %s does not exist' %
masterPath)
return manifest
def makeTestConfig(self, options):
"Creates a test configuration file for customizing test execution."
options.logFile = options.logFile.replace("\\", "\\\\")
if "MOZ_HIDE_RESULTS_TABLE" in os.environ and os.environ[
"MOZ_HIDE_RESULTS_TABLE"] == "1":
options.hideResultsTable = True
# strip certain unnecessary items to avoid serialization errors in json.dumps()
d = dict((k, v) for k, v in options.__dict__.items() if (v is None) or
isinstance(v, (basestring, numbers.Number)))
d['testRoot'] = self.testRoot
if not options.keep_open:
d['closeWhenDone'] = '1'
content = json.dumps(d)
with open(os.path.join(options.profilePath, "testConfig.js"), "w") as config:
config.write(content)
def buildBrowserEnv(self, options, debugger=False, env=None):
"""build the environment variables for the specific test and operating system"""
if mozinfo.info["asan"]:
lsanPath = SCRIPT_DIR
else:
lsanPath = None
browserEnv = self.environment(
xrePath=options.xrePath,
env=env,
debugger=debugger,
dmdPath=options.dmdPath,
lsanPath=lsanPath)
# These variables are necessary for correct application startup; change
# via the commandline at your own risk.
browserEnv["XPCOM_DEBUG_BREAK"] = "stack"
# When creating child processes on Windows pre-Vista (e.g. Windows XP) we
# don't normally inherit stdout/err handles, because you can only do it by
# inheriting all other inheritable handles as well.
# We need to inherit them for plain mochitests for test logging purposes, so
# we do so on the basis of a specific environment variable.
if self.getTestFlavor(options) == "mochitest":
browserEnv["MOZ_WIN_INHERIT_STD_HANDLES_PRE_VISTA"] = "1"
# interpolate environment passed with options
try:
browserEnv.update(
dict(
parseKeyValue(
options.environment,
context='--setenv')))
except KeyValueParseError as e:
self.log.error(str(e))
return None
browserEnv["XPCOM_MEM_BLOAT_LOG"] = self.leak_report_file
try:
gmp_path = self.getGMPPluginPath(options)
if gmp_path is not None:
browserEnv["MOZ_GMP_PATH"] = gmp_path
except EnvironmentError:
self.log.error('Could not find path to gmp-fake plugin!')
return None
if options.fatalAssertions:
browserEnv["XPCOM_DEBUG_BREAK"] = "stack-and-abort"
# Produce an NSPR log, is setup (see NSPR_LOG_MODULES global at the top of
# this script).
self.nsprLogs = NSPR_LOG_MODULES and "MOZ_UPLOAD_DIR" in os.environ
if self.nsprLogs:
browserEnv["NSPR_LOG_MODULES"] = NSPR_LOG_MODULES
browserEnv["NSPR_LOG_FILE"] = "%s/nspr.log" % tempfile.gettempdir()
browserEnv["GECKO_SEPARATE_NSPR_LOGS"] = "1"
if debugger and not options.slowscript:
browserEnv["JS_DISABLE_SLOW_SCRIPT_SIGNALS"] = "1"
# For e10s, our tests default to suppressing the "unsafe CPOW usage"
# warnings that can plague test logs.
if not options.enableCPOWWarnings:
browserEnv["DISABLE_UNSAFE_CPOW_WARNINGS"] = "1"
return browserEnv
def killNamedOrphans(self, pname):
""" Kill orphan processes matching the given command name """
self.log.info("Checking for orphan %s processes..." % pname)
def _psInfo(line):
if pname in line:
self.log.info(line)
process = mozprocess.ProcessHandler(['ps', '-f'],
processOutputLine=_psInfo)
process.run()
process.wait()
def _psKill(line):
parts = line.split()
if len(parts) == 3 and parts[0].isdigit():
pid = int(parts[0])
if parts[2] == pname and parts[1] == '1':
self.log.info("killing %s orphan with pid %d" % (pname, pid))
killPid(pid, self.log)
process = mozprocess.ProcessHandler(['ps', '-o', 'pid,ppid,comm'],
processOutputLine=_psKill)
process.run()
process.wait()
class SSLTunnel: class SSLTunnel:
@ -1225,8 +1490,10 @@ def parseKeyValue(strings, separator='=', context='key, value: '):
return [string.split(separator, 1) for string in strings] return [string.split(separator, 1) for string in strings]
class Mochitest(MochitestUtilsMixin): class MochitestDesktop(MochitestBase):
_active_tests = None """
Mochitest class for desktop firefox and mulet.
"""
certdbNew = False certdbNew = False
sslTunnel = None sslTunnel = None
DEFAULT_TIMEOUT = 60.0 DEFAULT_TIMEOUT = 60.0
@ -1237,7 +1504,7 @@ class Mochitest(MochitestUtilsMixin):
test_name = 'automation.py' test_name = 'automation.py'
def __init__(self, logger_options): def __init__(self, logger_options):
super(Mochitest, self).__init__(logger_options) MochitestBase.__init__(self, logger_options)
# Max time in seconds to wait for server startup before tests will fail -- if # Max time in seconds to wait for server startup before tests will fail -- if
# this seems big, it's mostly for debug machines where cold startup # this seems big, it's mostly for debug machines where cold startup
@ -1256,10 +1523,6 @@ class Mochitest(MochitestUtilsMixin):
self.expectedError = {} self.expectedError = {}
self.result = {} self.result = {}
def environment(self, **kwargs):
kwargs['log'] = self.log
return test_environment(**kwargs)
def extraPrefs(self, extraPrefs): def extraPrefs(self, extraPrefs):
"""interpolate extra preferences from option strings""" """interpolate extra preferences from option strings"""
@ -1467,75 +1730,6 @@ class Mochitest(MochitestUtilsMixin):
return os.pathsep.join(gmp_paths) return os.pathsep.join(gmp_paths)
def buildBrowserEnv(self, options, debugger=False, env=None):
"""build the environment variables for the specific test and operating system"""
if mozinfo.info["asan"]:
lsanPath = SCRIPT_DIR
else:
lsanPath = None
browserEnv = self.environment(
xrePath=options.xrePath,
env=env,
debugger=debugger,
dmdPath=options.dmdPath,
lsanPath=lsanPath)
# These variables are necessary for correct application startup; change
# via the commandline at your own risk.
browserEnv["XPCOM_DEBUG_BREAK"] = "stack"
# When creating child processes on Windows pre-Vista (e.g. Windows XP) we
# don't normally inherit stdout/err handles, because you can only do it by
# inheriting all other inheritable handles as well.
# We need to inherit them for plain mochitests for test logging purposes, so
# we do so on the basis of a specific environment variable.
if self.getTestFlavor(options) == "mochitest":
browserEnv["MOZ_WIN_INHERIT_STD_HANDLES_PRE_VISTA"] = "1"
# interpolate environment passed with options
try:
browserEnv.update(
dict(
parseKeyValue(
options.environment,
context='--setenv')))
except KeyValueParseError as e:
self.log.error(str(e))
return None
browserEnv["XPCOM_MEM_BLOAT_LOG"] = self.leak_report_file
try:
gmp_path = self.getGMPPluginPath(options)
if gmp_path is not None:
browserEnv["MOZ_GMP_PATH"] = gmp_path
except EnvironmentError:
self.log.error('Could not find path to gmp-fake plugin!')
return None
if options.fatalAssertions:
browserEnv["XPCOM_DEBUG_BREAK"] = "stack-and-abort"
# Produce an NSPR log, is setup (see NSPR_LOG_MODULES global at the top of
# this script).
self.nsprLogs = NSPR_LOG_MODULES and "MOZ_UPLOAD_DIR" in os.environ
if self.nsprLogs:
browserEnv["NSPR_LOG_MODULES"] = NSPR_LOG_MODULES
browserEnv["NSPR_LOG_FILE"] = "%s/nspr.log" % tempfile.gettempdir()
browserEnv["GECKO_SEPARATE_NSPR_LOGS"] = "1"
if debugger and not options.slowscript:
browserEnv["JS_DISABLE_SLOW_SCRIPT_SIGNALS"] = "1"
# For e10s, our tests default to suppressing the "unsafe CPOW usage"
# warnings that can plague test logs.
if not options.enableCPOWWarnings:
browserEnv["DISABLE_UNSAFE_CPOW_WARNINGS"] = "1"
return browserEnv
def cleanup(self, options): def cleanup(self, options):
""" remove temporary files and profile """ """ remove temporary files and profile """
if hasattr(self, 'manifest') and self.manifest is not None: if hasattr(self, 'manifest') and self.manifest is not None:
@ -1673,8 +1867,6 @@ class Mochitest(MochitestUtilsMixin):
interactive = False interactive = False
valgrindArgs_split = ([] if valgrindArgs is None valgrindArgs_split = ([] if valgrindArgs is None
else valgrindArgs.split()) else valgrindArgs.split())
valgrindSuppFiles_split = ([] if valgrindSuppFiles is None
else valgrindSuppFiles.split(","))
valgrindSuppFiles_final = [] valgrindSuppFiles_final = []
if valgrindSuppFiles is not None: if valgrindSuppFiles is not None:
@ -1877,133 +2069,6 @@ class Mochitest(MochitestUtilsMixin):
norm_paths.append(p) norm_paths.append(p)
return norm_paths return norm_paths
def getActiveTests(self, options, disabled=True):
"""
This method is used to parse the manifest and return active filtered tests.
"""
if self._active_tests:
return self._active_tests
manifest = self.getTestManifest(options)
if manifest:
if options.extra_mozinfo_json:
mozinfo.update(options.extra_mozinfo_json)
info = mozinfo.info
# Bug 1089034 - imptest failure expectations are encoded as
# test manifests, even though they aren't tests. This gross
# hack causes several problems in automation including
# throwing off the chunking numbers. Remove them manually
# until bug 1089034 is fixed.
def remove_imptest_failure_expectations(tests, values):
return (t for t in tests
if 'imptests/failures' not in t['path'])
filters = [
remove_imptest_failure_expectations,
subsuite(options.subsuite),
]
if options.test_tags:
filters.append(tags(options.test_tags))
if options.test_paths:
options.test_paths = self.normalize_paths(options.test_paths)
filters.append(pathprefix(options.test_paths))
# Add chunking filters if specified
if options.totalChunks:
if options.chunkByRuntime:
runtime_file = self.resolve_runtime_file(options)
if not os.path.exists(runtime_file):
self.log.warning("runtime file %s not found; defaulting to chunk-by-dir" %
runtime_file)
options.chunkByRuntime = None
flavor = self.getTestFlavor(options)
if flavor in ('browser-chrome', 'devtools-chrome'):
# these values match current mozharness configs
options.chunkbyDir = 5
else:
options.chunkByDir = 4
if options.chunkByDir:
filters.append(chunk_by_dir(options.thisChunk,
options.totalChunks,
options.chunkByDir))
elif options.chunkByRuntime:
with open(runtime_file, 'r') as f:
runtime_data = json.loads(f.read())
runtimes = runtime_data['runtimes']
default = runtime_data['excluded_test_average']
filters.append(
chunk_by_runtime(options.thisChunk,
options.totalChunks,
runtimes,
default_runtime=default))
else:
filters.append(chunk_by_slice(options.thisChunk,
options.totalChunks))
tests = manifest.active_tests(
exists=False, disabled=disabled, filters=filters, **info)
if len(tests) == 0:
self.log.error("no tests to run using specified "
"combination of filters: {}".format(
manifest.fmt_filters()))
paths = []
for test in tests:
if len(tests) == 1 and 'disabled' in test:
del test['disabled']
pathAbs = os.path.abspath(test['path'])
assert pathAbs.startswith(self.testRootAbs)
tp = pathAbs[len(self.testRootAbs):].replace('\\', '/').strip('/')
if not self.isTest(options, tp):
self.log.warning(
'Warning: %s from manifest %s is not a valid test' %
(test['name'], test['manifest']))
continue
testob = {'path': tp}
if 'disabled' in test:
testob['disabled'] = test['disabled']
if 'expected' in test:
testob['expected'] = test['expected']
paths.append(testob)
def path_sort(ob1, ob2):
path1 = ob1['path'].split('/')
path2 = ob2['path'].split('/')
return cmp(path1, path2)
paths.sort(path_sort)
self._active_tests = paths
if options.dump_tests:
options.dump_tests = os.path.expanduser(options.dump_tests)
assert os.path.exists(os.path.dirname(options.dump_tests))
with open(options.dump_tests, 'w') as dumpFile:
dumpFile.write(json.dumps({'active_tests': self._active_tests}))
self.log.info("Dumping active_tests to %s file." % options.dump_tests)
sys.exit()
return self._active_tests
def logPreamble(self, tests):
"""Logs a suite_start message and test_start/test_end at the beginning of a run.
"""
self.log.suite_start([t['path'] for t in tests])
for test in tests:
if 'disabled' in test:
self.log.test_start(test['path'])
self.log.test_end(
test['path'],
'SKIP',
message=test['disabled'])
def getTestsToRun(self, options): def getTestsToRun(self, options):
""" """
This method makes a list of tests that are to be run. Required mainly for --bisect-chunk. This method makes a list of tests that are to be run. Required mainly for --bisect-chunk.
@ -2056,29 +2121,6 @@ class Mochitest(MochitestUtilsMixin):
return result return result
def killNamedOrphans(self, pname):
""" Kill orphan processes matching the given command name """
self.log.info("Checking for orphan %s processes..." % pname)
def _psInfo(line):
if pname in line:
self.log.info(line)
process = mozprocess.ProcessHandler(['ps', '-f'],
processOutputLine=_psInfo)
process.run()
process.wait()
def _psKill(line):
parts = line.split()
if len(parts) == 3 and parts[0].isdigit():
pid = int(parts[0])
if parts[2] == pname and parts[1] == '1':
self.log.info("killing %s orphan with pid %d" % (pname, pid))
killPid(pid, self.log)
process = mozprocess.ProcessHandler(['ps', '-o', 'pid,ppid,comm'],
processOutputLine=_psKill)
process.run()
process.wait()
def runTests(self, options, onLaunch=None): def runTests(self, options, onLaunch=None):
""" Prepare, configure, run tests and cleanup """ """ Prepare, configure, run tests and cleanup """
@ -2200,7 +2242,6 @@ class Mochitest(MochitestUtilsMixin):
options, options,
debuggerInfo is not None) debuggerInfo is not None)
# If there are any Mulet-specific tests doing remote network access, # If there are any Mulet-specific tests doing remote network access,
# we will not be aware since we are explicitely allowing this, as for # we will not be aware since we are explicitely allowing this, as for
# B2G # B2G
@ -2514,52 +2555,6 @@ class Mochitest(MochitestUtilsMixin):
self.shutdownLeaks.log(message) self.shutdownLeaks.log(message)
return message return message
def makeTestConfig(self, options):
"Creates a test configuration file for customizing test execution."
options.logFile = options.logFile.replace("\\", "\\\\")
if "MOZ_HIDE_RESULTS_TABLE" in os.environ and os.environ[
"MOZ_HIDE_RESULTS_TABLE"] == "1":
options.hideResultsTable = True
# strip certain unnecessary items to avoid serialization errors in json.dumps()
d = dict((k, v) for k, v in options.__dict__.items() if (v is None) or
isinstance(v,(basestring,numbers.Number)))
d['testRoot'] = self.testRoot
if not options.keep_open:
d['closeWhenDone'] = '1'
content = json.dumps(d)
with open(os.path.join(options.profilePath, "testConfig.js"), "w") as config:
config.write(content)
def getTestManifest(self, options):
if isinstance(options.manifestFile, TestManifest):
manifest = options.manifestFile
elif options.manifestFile and os.path.isfile(options.manifestFile):
manifestFileAbs = os.path.abspath(options.manifestFile)
assert manifestFileAbs.startswith(SCRIPT_DIR)
manifest = TestManifest([options.manifestFile], strict=False)
elif options.manifestFile and os.path.isfile(os.path.join(SCRIPT_DIR, options.manifestFile)):
manifestFileAbs = os.path.abspath(
os.path.join(
SCRIPT_DIR,
options.manifestFile))
assert manifestFileAbs.startswith(SCRIPT_DIR)
manifest = TestManifest([manifestFileAbs], strict=False)
else:
masterName = self.getTestFlavor(options) + '.ini'
masterPath = os.path.join(SCRIPT_DIR, self.testRoot, masterName)
if os.path.exists(masterPath):
manifest = TestManifest([masterPath], strict=False)
else:
self._log.warning(
'TestManifest masterPath %s does not exist' %
masterPath)
return manifest
def getDirectories(self, options): def getDirectories(self, options):
""" """
Make the list of directories by parsing manifests Make the list of directories by parsing manifests
@ -2581,7 +2576,7 @@ def run_test_harness(options):
logger_options = { logger_options = {
key: value for key, value in vars(options).iteritems() key: value for key, value in vars(options).iteritems()
if key.startswith('log') or key == 'valgrind'} if key.startswith('log') or key == 'valgrind'}
runner = Mochitest(logger_options) runner = MochitestDesktop(logger_options)
options.runByDir = False options.runByDir = False

View File

@ -5,17 +5,14 @@
import json import json
import os import os
import posixpath import posixpath
import shutil
import sys import sys
import tempfile import tempfile
import threading
import traceback import traceback
here = os.path.abspath(os.path.dirname(__file__)) here = os.path.abspath(os.path.dirname(__file__))
sys.path.insert(0, here) sys.path.insert(0, here)
from runtests import Mochitest from runtests import MochitestBase
from runtests import MochitestUtilsMixin
from mochitest_options import MochitestArgumentParser from mochitest_options import MochitestArgumentParser
from marionette import Marionette from marionette import Marionette
from mozprofile import Profile, Preferences from mozprofile import Profile, Preferences
@ -24,15 +21,22 @@ import mozinfo
import mozleak import mozleak
class B2GMochitest(MochitestUtilsMixin): class MochitestB2G(MochitestBase):
"""
Mochitest class for b2g emulators and devices.
"""
marionette = None marionette = None
remote_log = None
def __init__(self, marionette_args, def __init__(self, marionette_args,
logger_options, logger_options,
profile_data_dir,
local_binary_dir,
locations=os.path.join(here, 'server-locations.txt'),
out_of_process=True, out_of_process=True,
profile_data_dir=None, remote_test_root=None,
locations=os.path.join(here, 'server-locations.txt')): remote_log_file=None):
super(B2GMochitest, self).__init__(logger_options) MochitestBase.__init__(self, logger_options)
self.marionette_args = marionette_args self.marionette_args = marionette_args
self.out_of_process = out_of_process self.out_of_process = out_of_process
self.locations_file = locations self.locations_file = locations
@ -42,8 +46,9 @@ class B2GMochitest(MochitestUtilsMixin):
self.test_script_args = [self.out_of_process] self.test_script_args = [self.out_of_process]
self.product = 'b2g' self.product = 'b2g'
self.remote_chrome_test_dir = None self.remote_chrome_test_dir = None
self.local_log = None
self.local_binary_dir = local_binary_dir
if profile_data_dir:
self.preferences = [ self.preferences = [
os.path.join( os.path.join(
profile_data_dir, profile_data_dir,
@ -59,21 +64,9 @@ class B2GMochitest(MochitestUtilsMixin):
else: else:
self.SERVER_STARTUP_TIMEOUT = 90 self.SERVER_STARTUP_TIMEOUT = 90
def setup_common_options(self, options):
test_url = self.buildTestPath(options)
# For B2G emulators buildURLOptions has been called
# without calling buildTestPath first and that
# causes manifestFile not to be set
if not "manifestFile=tests.json" in self.urlOpts:
self.urlOpts.append("manifestFile=%s" % options.manifestFile)
if len(self.urlOpts) > 0:
test_url += "?" + "&".join(self.urlOpts)
self.test_script_args.append(test_url)
def buildTestPath(self, options, testsToFilter=None): def buildTestPath(self, options, testsToFilter=None):
if options.manifestFile != 'tests.json': if options.manifestFile != 'tests.json':
super(B2GMochitest, self).buildTestPath(options, testsToFilter, disabled=False) MochitestBase.buildTestPath(self, options, testsToFilter, disabled=False)
return self.buildTestURL(options) return self.buildTestURL(options)
def build_profile(self, options): def build_profile(self, options):
@ -107,11 +100,7 @@ class B2GMochitest(MochitestUtilsMixin):
'proxy': {"remote": options.webServer} 'proxy': {"remote": options.webServer}
} }
if options.profile:
self.profile = Profile.clone(options.profile, **kwargs)
else:
self.profile = Profile(**kwargs) self.profile = Profile(**kwargs)
options.profilePath = self.profile.profile options.profilePath = self.profile.profile
# TODO bug 839108 - mozprofile should probably handle this # TODO bug 839108 - mozprofile should probably handle this
manifest = self.addChromeToProfile(options) manifest = self.addChromeToProfile(options)
@ -244,7 +233,7 @@ class B2GMochitest(MochitestUtilsMixin):
if options.chrome: if options.chrome:
self.app_ctx.dm.removeDir(self.remote_chrome_test_dir) self.app_ctx.dm.removeDir(self.remote_chrome_test_dir)
self.app_ctx.dm.mkDir(self.remote_chrome_test_dir) self.app_ctx.dm.mkDir(self.remote_chrome_test_dir)
local = super(B2GMochitest, self).getChromeTestDir(options) local = MochitestBase.getChromeTestDir(self, options)
local = os.path.join(local, "chrome") local = os.path.join(local, "chrome")
remote = self.remote_chrome_test_dir remote = self.remote_chrome_test_dir
self.log.info( self.log.info(
@ -319,27 +308,6 @@ class B2GMochitest(MochitestUtilsMixin):
return self.remote_chrome_test_dir return self.remote_chrome_test_dir
return 'dummy-chrome-test-dir' return 'dummy-chrome-test-dir'
class B2GDeviceMochitest(B2GMochitest, Mochitest):
remote_log = None
def __init__(
self,
marionette_args,
logger_options,
profile_data_dir,
local_binary_dir,
remote_test_root=None,
remote_log_file=None):
B2GMochitest.__init__(
self,
marionette_args,
logger_options,
out_of_process=True,
profile_data_dir=profile_data_dir)
self.local_log = None
self.local_binary_dir = local_binary_dir
def cleanup(self, manifest, options): def cleanup(self, manifest, options):
if self.local_log: if self.local_log:
self.app_ctx.dm.getFile(self.remote_log, self.local_log) self.app_ctx.dm.getFile(self.remote_log, self.local_log)
@ -370,7 +338,7 @@ class B2GDeviceMochitest(B2GMochitest, Mochitest):
options.utilityPath = self.local_binary_dir options.utilityPath = self.local_binary_dir
options.profilePath = tempfile.mkdtemp() options.profilePath = tempfile.mkdtemp()
MochitestUtilsMixin.startServers(self, options, debuggerInfo) MochitestBase.startServers(self, options, debuggerInfo)
options.xrePath = savedXre options.xrePath = savedXre
options.utilityPath = savedUtility options.utilityPath = savedUtility
@ -380,72 +348,26 @@ class B2GDeviceMochitest(B2GMochitest, Mochitest):
self.local_log = options.logFile self.local_log = options.logFile
options.logFile = self.remote_log options.logFile = self.remote_log
options.profilePath = self.profile.profile options.profilePath = self.profile.profile
super(B2GDeviceMochitest, self).buildURLOptions(options, env) MochitestBase.buildURLOptions(self, options, env)
test_url = self.buildTestPath(options)
# For B2G emulators buildURLOptions has been called
# without calling buildTestPath first and that
# causes manifestFile not to be set
if "manifestFile=tests.json" not in self.urlOpts:
self.urlOpts.append("manifestFile=%s" % options.manifestFile)
if len(self.urlOpts) > 0:
test_url += "?" + "&".join(self.urlOpts)
self.test_script_args.append(test_url)
self.setup_common_options(options)
options.profilePath = self.app_ctx.remote_profile options.profilePath = self.app_ctx.remote_profile
options.logFile = self.local_log options.logFile = self.local_log
class B2GDesktopMochitest(B2GMochitest, Mochitest): def run_test_harness(options):
def __init__(self, marionette_args, logger_options, profile_data_dir):
B2GMochitest.__init__(
self,
marionette_args,
logger_options,
out_of_process=False,
profile_data_dir=profile_data_dir)
Mochitest.__init__(self, logger_options)
self.certdbNew = True
def runMarionetteScript(self, marionette, test_script, test_script_args):
assert(marionette.wait_for_port())
marionette.start_session()
marionette.set_context(marionette.CONTEXT_CHROME)
if os.path.isfile(test_script):
f = open(test_script, 'r')
test_script = f.read()
f.close()
self.marionette.execute_script(test_script,
script_args=test_script_args)
def startTests(self):
# This is run in a separate thread because otherwise, the app's
# stdout buffer gets filled (which gets drained only after this
# function returns, by waitForFinish), which causes the app to hang.
self.marionette = Marionette(**self.marionette_args)
thread = threading.Thread(target=self.runMarionetteScript,
args=(self.marionette,
self.test_script,
self.test_script_args))
thread.start()
def buildURLOptions(self, options, env):
super(B2GDesktopMochitest, self).buildURLOptions(options, env)
self.setup_common_options(options)
# Copy the extensions to the B2G bundles dir.
extensionDir = os.path.join(
options.profilePath,
'extensions',
'staged')
bundlesDir = os.path.join(os.path.dirname(options.app),
'distribution', 'bundles')
for filename in os.listdir(extensionDir):
shutil.rmtree(os.path.join(bundlesDir, filename), True)
shutil.copytree(os.path.join(extensionDir, filename),
os.path.join(bundlesDir, filename))
def buildProfile(self, options):
return self.build_profile(options)
def run_remote_mochitests(options):
# create our Marionette instance # create our Marionette instance
marionette_args = { marionette_args = {
'adb_path': options.adbPath, 'adb_path': options.adbPath,
@ -466,7 +388,7 @@ def run_remote_mochitests(options):
print "ERROR: Invalid options specified, use --help for a list of valid options" print "ERROR: Invalid options specified, use --help for a list of valid options"
sys.exit(1) sys.exit(1)
mochitest = B2GDeviceMochitest( mochitest = MochitestB2G(
marionette_args, marionette_args,
options, options,
options.profile_data_dir, options.profile_data_dir,
@ -495,45 +417,10 @@ def run_remote_mochitests(options):
return retVal return retVal
def run_desktop_mochitests(options):
# create our Marionette instance
marionette_args = {}
if options.marionette:
host, port = options.marionette.split(':')
marionette_args['host'] = host
marionette_args['port'] = int(port)
# add a -bin suffix if b2g-bin exists, but just b2g was specified
if options.app[-4:] != '-bin':
if os.path.isfile("%s-bin" % options.app):
options.app = "%s-bin" % options.app
mochitest = B2GDesktopMochitest(
marionette_args,
options,
options.profile_data_dir)
if options is None:
sys.exit(1)
if options.desktop and not options.profile:
raise Exception("must specify --profile when specifying --desktop")
options.browserArgs += ['-marionette']
options.runByDir = False
retVal = mochitest.runTests(options, onLaunch=mochitest.startTests)
mochitest.message_logger.finish()
return retVal
def main(): def main():
parser = MochitestArgumentParser(app='b2g') parser = MochitestArgumentParser(app='b2g')
options = parser.parse_args() options = parser.parse_args()
return run_test_harness(options)
if options.desktop:
return run_desktop_mochitests(options)
else:
return run_remote_mochitests(options)
if __name__ == "__main__": if __name__ == "__main__":
sys.exit(main()) sys.exit(main())

View File

@ -13,7 +13,7 @@ sys.path.insert(
from automation import Automation from automation import Automation
from remoteautomation import RemoteAutomation, fennecLogcatFilters from remoteautomation import RemoteAutomation, fennecLogcatFilters
from runtests import Mochitest, MessageLogger from runtests import MochitestDesktop, MessageLogger
from mochitest_options import MochitestArgumentParser from mochitest_options import MochitestArgumentParser
import devicemanager import devicemanager
@ -22,14 +22,15 @@ import mozinfo
SCRIPT_DIR = os.path.abspath(os.path.realpath(os.path.dirname(__file__))) SCRIPT_DIR = os.path.abspath(os.path.realpath(os.path.dirname(__file__)))
class MochiRemote(Mochitest): # TODO inherit from MochitestBase instead
class MochiRemote(MochitestDesktop):
_automation = None _automation = None
_dm = None _dm = None
localProfile = None localProfile = None
logMessages = [] logMessages = []
def __init__(self, automation, devmgr, options): def __init__(self, automation, devmgr, options):
Mochitest.__init__(self, options) MochitestDesktop.__init__(self, options)
self._automation = automation self._automation = automation
self._dm = devmgr self._dm = devmgr
@ -63,7 +64,7 @@ class MochiRemote(Mochitest):
blobberUploadDir = os.environ.get('MOZ_UPLOAD_DIR', None) blobberUploadDir = os.environ.get('MOZ_UPLOAD_DIR', None)
if blobberUploadDir: if blobberUploadDir:
self._dm.getDirectory(self.remoteNSPR, blobberUploadDir) self._dm.getDirectory(self.remoteNSPR, blobberUploadDir)
Mochitest.cleanup(self, options) MochitestDesktop.cleanup(self, options)
def findPath(self, paths, filename=None): def findPath(self, paths, filename=None):
for path in paths: for path in paths:
@ -155,7 +156,7 @@ class MochiRemote(Mochitest):
""" Create the servers on the host and start them up """ """ Create the servers on the host and start them up """
restoreRemotePaths = self.switchToLocalPaths(options) restoreRemotePaths = self.switchToLocalPaths(options)
# ignoreSSLTunnelExts is a workaround for bug 1109310 # ignoreSSLTunnelExts is a workaround for bug 1109310
Mochitest.startServers( MochitestDesktop.startServers(
self, self,
options, options,
debuggerInfo, debuggerInfo,
@ -164,7 +165,7 @@ class MochiRemote(Mochitest):
def buildProfile(self, options): def buildProfile(self, options):
restoreRemotePaths = self.switchToLocalPaths(options) restoreRemotePaths = self.switchToLocalPaths(options)
manifest = Mochitest.buildProfile(self, options) manifest = MochitestDesktop.buildProfile(self, options)
self.localProfile = options.profilePath self.localProfile = options.profilePath
self._dm.removeDir(self.remoteProfile) self._dm.removeDir(self.remoteProfile)
@ -185,7 +186,7 @@ class MochiRemote(Mochitest):
options.fileLevel = 'INFO' options.fileLevel = 'INFO'
options.profilePath = self.localProfile options.profilePath = self.localProfile
env["MOZ_HIDE_RESULTS_TABLE"] = "1" env["MOZ_HIDE_RESULTS_TABLE"] = "1"
retVal = Mochitest.buildURLOptions(self, options, env) retVal = MochitestDesktop.buildURLOptions(self, options, env)
# we really need testConfig.js (for browser chrome) # we really need testConfig.js (for browser chrome)
try: try:
@ -239,7 +240,7 @@ class MochiRemote(Mochitest):
return None return None
def buildBrowserEnv(self, options, debugger=False): def buildBrowserEnv(self, options, debugger=False):
browserEnv = Mochitest.buildBrowserEnv( browserEnv = MochitestDesktop.buildBrowserEnv(
self, self,
options, options,
debugger=debugger) debugger=debugger)
@ -248,7 +249,7 @@ class MochiRemote(Mochitest):
del browserEnv["MOZ_WIN_INHERIT_STD_HANDLES_PRE_VISTA"] del browserEnv["MOZ_WIN_INHERIT_STD_HANDLES_PRE_VISTA"]
if "XPCOM_MEM_BLOAT_LOG" in browserEnv: if "XPCOM_MEM_BLOAT_LOG" in browserEnv:
del browserEnv["XPCOM_MEM_BLOAT_LOG"] del browserEnv["XPCOM_MEM_BLOAT_LOG"]
# override nsprLogs to avoid processing in Mochitest base class # override nsprLogs to avoid processing in MochitestDesktop base class
self.nsprLogs = None self.nsprLogs = None
browserEnv["NSPR_LOG_FILE"] = os.path.join( browserEnv["NSPR_LOG_FILE"] = os.path.join(
self.remoteNSPR, self.remoteNSPR,