Instead of providing setup_logging functions that return a logger but don't handle any cleanup, provide context managers that clean up the logging configuration. In particular wptlogging.LoggingManager will call shutdown on the logger iff it created the logger in the first place. Where we store the logger as a global variable we wrap in a GlobalLogger class that knows how to set the global state and unsets it at the end. Rather inelegantly, the interaction with globals means we end up copying a lot of code around. Differential Revision: https://phabricator.services.mozilla.com/D306960
131 lines
3.9 KiB
Python
131 lines
3.9 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/.
|
|
|
|
import os
|
|
import sys
|
|
|
|
from mozlog import handlers
|
|
from mozlog.structuredlog import log_levels
|
|
|
|
here = os.path.abspath(os.path.dirname(__file__))
|
|
|
|
|
|
def setup_environment(tests_root=None):
|
|
if tests_root is None:
|
|
tests_root = os.path.join(here, "tests")
|
|
if tests_root not in sys.path:
|
|
sys.path.insert(0, tests_root)
|
|
from tools import localpaths # noqa: F401
|
|
|
|
|
|
def create_parser_wpt():
|
|
setup_environment()
|
|
|
|
from wptrunner import wptcommandline
|
|
|
|
result = wptcommandline.create_parser()
|
|
|
|
result.add_argument(
|
|
"--no-install",
|
|
action="store_true",
|
|
default=False,
|
|
help="Do not install test runner application",
|
|
)
|
|
return result
|
|
|
|
|
|
class CriticalLogBuffer(handlers.BaseHandler):
|
|
"""
|
|
Buffer critical log entries
|
|
"""
|
|
|
|
def __init__(self):
|
|
self.log_entries = []
|
|
|
|
def __call__(self, data):
|
|
if (
|
|
data["action"] == "log"
|
|
and log_levels[data["level"]] <= log_levels["CRITICAL"]
|
|
):
|
|
self.log_entries.append(data)
|
|
|
|
|
|
class WebPlatformTestsRunner:
|
|
"""Run web platform tests."""
|
|
|
|
def __init__(self, setup):
|
|
self.setup = setup
|
|
|
|
def logging_manager(self, **kwargs):
|
|
from tools.wpt import run
|
|
|
|
return run.GlobalLogger(
|
|
kwargs,
|
|
{self.setup.default_log_type: sys.stdout},
|
|
formatter_defaults={"screenshot": True},
|
|
)
|
|
|
|
def run(self, logger, **kwargs):
|
|
from mozbuild.base import BinaryNotFoundException
|
|
from wptrunner import wptrunner
|
|
|
|
if kwargs["manifest_update"] is not False:
|
|
self.update_manifest(logger)
|
|
kwargs["manifest_update"] = False
|
|
|
|
if kwargs["product"] == "firefox":
|
|
try:
|
|
kwargs = self.setup.kwargs_firefox(kwargs)
|
|
except BinaryNotFoundException as e:
|
|
logger.error(e)
|
|
logger.info(e.help())
|
|
return 1
|
|
elif kwargs["product"] == "firefox_android":
|
|
kwargs = self.setup.kwargs_firefox_android(kwargs)
|
|
else:
|
|
kwargs = self.setup.kwargs_wptrun(kwargs)
|
|
|
|
log_buffer = CriticalLogBuffer()
|
|
logger.add_handler(log_buffer)
|
|
|
|
# wptrunner.start() unconditionally calls logger.shutdown() in its
|
|
# finally block. When invoked from `mach test`, the logger is shared
|
|
# across multiple WPT invocations (one per subsuite bucket), so
|
|
# shutting it down after the first run kills it for all subsequent
|
|
# runs. Temporarily replace shutdown with a no-op so the caller
|
|
# retains control over the logger lifetime.
|
|
original_shutdown = logger.shutdown
|
|
logger.shutdown = lambda *args, **kwargs: None
|
|
|
|
result = 1
|
|
try:
|
|
result = wptrunner.start(**kwargs)
|
|
finally:
|
|
logger.shutdown = original_shutdown
|
|
if int(result) != 0:
|
|
self._process_log_errors(logger, log_buffer, kwargs)
|
|
logger.remove_handler(log_buffer)
|
|
return int(result)
|
|
|
|
def _process_log_errors(self, logger, log_buffer, kwargs):
|
|
for item in log_buffer.log_entries:
|
|
if (
|
|
kwargs["webdriver_binary"] is None
|
|
and "webdriver" in item["message"]
|
|
and self.setup.topobjdir
|
|
):
|
|
print(
|
|
"ERROR: Couldn't find geckodriver binary required to run wdspec tests, consider `ac_add_options --enable-geckodriver` in your build configuration"
|
|
)
|
|
|
|
def update_manifest(self, logger, **kwargs):
|
|
import manifestupdate
|
|
|
|
return manifestupdate.run(
|
|
logger=logger,
|
|
src_root=self.setup.topsrcdir,
|
|
obj_root=self.setup.topobjdir,
|
|
**kwargs,
|
|
)
|