172 lines
6.0 KiB
Python
172 lines
6.0 KiB
Python
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
"""
|
|
Set up a browser environment before running a test.
|
|
"""
|
|
|
|
import os
|
|
import re
|
|
import tempfile
|
|
import mozfile
|
|
from mozprocess import ProcessHandler
|
|
from mozprofile.profile import Profile
|
|
|
|
from mozlog import get_proxy_logger
|
|
|
|
from talos import utils
|
|
from talos.utils import TalosError
|
|
from talos.sps_profile import SpsProfile
|
|
|
|
|
|
LOG = get_proxy_logger()
|
|
|
|
|
|
class FFSetup(object):
|
|
"""
|
|
Initialize the browser environment before running a test.
|
|
|
|
This prepares:
|
|
- the environment vars for running the test in the browser,
|
|
available via the instance member *env*.
|
|
- the profile used to run the test, available via the
|
|
instance member *profile_dir*.
|
|
- sps profiling, available via the instance member *sps_profile*
|
|
of type :class:`SpsProfile` or None if not used.
|
|
|
|
Note that the browser will be run once with the profile, to ensure
|
|
this is basically working and negate any performance noise with the
|
|
real test run (installing the profile the first time takes time).
|
|
|
|
This class should be used as a context manager::
|
|
|
|
with FFSetup(browser_config, test_config) as setup:
|
|
# setup.env is initialized, and setup.profile_dir created
|
|
pass
|
|
# here the profile is removed
|
|
"""
|
|
|
|
PROFILE_REGEX = re.compile('__metrics(.*)__metrics',
|
|
re.DOTALL | re.MULTILINE)
|
|
|
|
def __init__(self, browser_config, test_config):
|
|
self.browser_config, self.test_config = browser_config, test_config
|
|
self._tmp_dir = tempfile.mkdtemp()
|
|
self.env = None
|
|
# The profile dir must be named 'profile' because of xperf analysis
|
|
# (in etlparser.py). TODO fix that ?
|
|
self.profile_dir = os.path.join(self._tmp_dir, 'profile')
|
|
self.sps_profile = None
|
|
|
|
def _init_env(self):
|
|
self.env = dict(os.environ)
|
|
for k, v in self.browser_config['env'].iteritems():
|
|
self.env[k] = str(v)
|
|
self.env['MOZ_CRASHREPORTER_NO_REPORT'] = '1'
|
|
# for winxp e10s logging:
|
|
# https://bugzilla.mozilla.org/show_bug.cgi?id=1037445
|
|
self.env['MOZ_WIN_INHERIT_STD_HANDLES_PRE_VISTA'] = '1'
|
|
self.env['MOZ_CRASHREPORTER_DISABLE'] = '1'
|
|
|
|
self.env['MOZ_DISABLE_NONLOCAL_CONNECTIONS'] = '1'
|
|
|
|
self.env["LD_LIBRARY_PATH"] = \
|
|
os.path.dirname(self.browser_config['browser_path'])
|
|
|
|
def _init_profile(self):
|
|
preferences = dict(self.browser_config['preferences'])
|
|
if self.test_config.get('preferences'):
|
|
test_prefs = dict(
|
|
[(i, utils.parse_pref(j))
|
|
for i, j in self.test_config['preferences'].items()]
|
|
)
|
|
preferences.update(test_prefs)
|
|
# interpolate webserver value in prefs
|
|
webserver = self.browser_config['webserver']
|
|
if '://' not in webserver:
|
|
webserver = 'http://' + webserver
|
|
for name, value in preferences.items():
|
|
if type(value) is str:
|
|
value = utils.interpolate(value, webserver=webserver)
|
|
preferences[name] = value
|
|
|
|
extensions = self.browser_config['extensions'][:]
|
|
if self.test_config.get('extensions'):
|
|
extensions.append(self.test_config['extensions'])
|
|
|
|
if self.browser_config['develop'] or \
|
|
self.browser_config['branch_name'] == 'Try':
|
|
extensions = [os.path.dirname(i) for i in extensions]
|
|
|
|
profile = Profile.clone(
|
|
os.path.normpath(self.test_config['profile_path']),
|
|
self.profile_dir,
|
|
restore=False)
|
|
|
|
profile.set_preferences(preferences)
|
|
profile.addon_manager.install_addons(extensions)
|
|
|
|
def _run_profile(self):
|
|
command_args = utils.GenerateBrowserCommandLine(
|
|
self.browser_config["browser_path"],
|
|
self.browser_config["extra_args"],
|
|
self.profile_dir,
|
|
self.browser_config["init_url"]
|
|
)
|
|
|
|
def browser_log(line):
|
|
LOG.process_output(browser.pid, line)
|
|
|
|
browser = ProcessHandler(command_args, env=self.env,
|
|
processOutputLine=browser_log)
|
|
browser.run()
|
|
LOG.process_start(browser.pid, ' '.join(command_args))
|
|
try:
|
|
exit_code = browser.wait()
|
|
except KeyboardInterrupt:
|
|
browser.kill()
|
|
raise
|
|
|
|
LOG.process_exit(browser.pid, exit_code)
|
|
results_raw = '\n'.join(browser.output)
|
|
|
|
if not self.PROFILE_REGEX.search(results_raw):
|
|
LOG.info("Could not find %s in browser output"
|
|
% self.PROFILE_REGEX.pattern)
|
|
LOG.info("Raw results:%s" % results_raw)
|
|
raise TalosError("browser failed to close after being initialized")
|
|
|
|
def _init_sps_profile(self):
|
|
upload_dir = os.getenv('MOZ_UPLOAD_DIR')
|
|
if self.test_config.get('sps_profile') and not upload_dir:
|
|
LOG.critical("Profiling ignored because MOZ_UPLOAD_DIR was not"
|
|
" set")
|
|
if upload_dir and self.test_config.get('sps_profile'):
|
|
self.sps_profile = SpsProfile(upload_dir,
|
|
self.browser_config,
|
|
self.test_config)
|
|
self.sps_profile.update_env(self.env)
|
|
|
|
def clean(self):
|
|
mozfile.remove(self._tmp_dir)
|
|
if self.sps_profile:
|
|
self.sps_profile.clean()
|
|
|
|
def __enter__(self):
|
|
LOG.info('Initialising browser for %s test...'
|
|
% self.test_config['name'])
|
|
self._init_env()
|
|
self._init_profile()
|
|
try:
|
|
self._run_profile()
|
|
except:
|
|
self.clean()
|
|
raise
|
|
self._init_sps_profile()
|
|
LOG.info('Browser initialized.')
|
|
return self
|
|
|
|
def __exit__(self, type, value, tb):
|
|
self.clean()
|