# 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 argparse import json import os import platform import re import shutil import subprocess import sys import tempfile from collections import OrderedDict
import mozlog import mozprofile from mach.decorators import Command, CommandArgument, SubCommand from mozbuild import nodeutil from mozbuild.base import BinaryNotFoundException, MozbuildObject
EX_CONFIG = 78
EX_SOFTWARE = 70
EX_USAGE = 64
def setup(): # add node and npm from mozbuild to front of system path
npm, _ = nodeutil.find_npm_executable() ifnot npm:
exit(EX_CONFIG, "could not find npm executable")
path = os.path.abspath(os.path.join(npm, os.pardir))
os.environ["PATH"] = "{}{}{}".format(path, os.pathsep, os.environ["PATH"])
print("Removing folders for current Puppeteer version…")
shutil.rmtree(puppeteer_dir, ignore_errors=True)
os.makedirs(puppeteer_dir)
with TemporaryDirectory() as tmpdir:
print(f'Fetching commitish "{commitish}" from {repository}…')
git("clone", "--depth", "1", "--branch", commitish, repository, tmpdir)
git( "checkout-index", "-a", "-f", "--prefix", "{}/".format(puppeteer_dir),
worktree=tmpdir,
)
# remove files which may interfere with git checkout of central try:
os.remove(os.path.join(puppeteer_dir, ".gitattributes"))
os.remove(os.path.join(puppeteer_dir, ".gitignore")) except OSError: pass
unwanted_dirs = ["experimental", "docs"]
for dir in unwanted_dirs:
dir_path = os.path.join(puppeteer_dir, dir) if os.path.isdir(dir_path):
shutil.rmtree(dir_path)
if install:
env = { "CI": "1", # Force the quiet logger of wireit "HUSKY": "0", # Disable any hook checks "PUPPETEER_SKIP_DOWNLOAD": "1", # Don't download any build
}
print("Cleaning up and installing new version of Puppeteer…")
run_npm( "run", "clean",
cwd=puppeteer_dir,
env=env,
exit_on_fail=False,
)
if pipe:
_, pipe_err = pipe_p.communicate()
out, git_err = git_p.communicate()
# use error from first program that failed if git_p.returncode > 0:
exit(EX_SOFTWARE, git_err) if pipe and pipe_p.returncode > 0:
exit(EX_SOFTWARE, pipe_err)
return out
def run_npm(*args, **kwargs): from mozprocess import run_and_wait
def output_timeout_handler(proc): # In some cases, we wait longer for a mocha timeout
print( "Timed out after {} seconds of no output".format(kwargs["output_timeout"])
)
env = os.environ.copy()
npm, _ = nodeutil.find_npm_executable() if kwargs.get("env"):
env.update(kwargs["env"])
proc_kwargs = {"output_timeout_handler": output_timeout_handler} for kw in ["output_line_handler", "output_timeout"]: if kw in kwargs:
proc_kwargs[kw] = kwargs[kw]
def process_event(self, event): if isinstance(event, list) and len(event) > 1:
status = self.status_map.get(event[0])
test_start = event[0] == "test-start" ifnot status andnot test_start: return
test_info = event[1]
test_full_title = test_info.get("fullTitle", "")
test_name = test_full_title
test_path = test_info.get("file", "")
test_file_name = os.path.basename(test_path).replace(".js", "")
test_err = test_info.get("err") if status == "FAIL"and test_err: if"timeout"in test_err.lower():
status = "TIMEOUT" if test_name and test_path:
test_name = "{} ({})".format(test_name, os.path.basename(test_path)) # mocha hook failures are not tracked in metadata if status != "PASS"and self.hook_re.search(test_name):
self.logger.error("TEST-UNEXPECTED-ERROR %s" % (test_name,)) return if test_start:
self.logger.test_start(test_name) return
expected_name = "[{}] {}".format(test_file_name, test_full_title)
expected_item = next(
(
expectation for expectation in reversed(list(self.expected)) if self.testExpectation(expectation["testIdPattern"], expected_name)
), None,
) if expected_item isNone:
expected = ["PASS"] else:
expected = expected_item["expectations"] # mozlog doesn't really allow unexpected skip, # so if a test is disabled just expect that and note the unexpected skip # Also, mocha doesn't log test-start for skipped tests if status == "SKIP":
self.logger.test_start(test_name) if self.expected and status notin expected:
self.unexpected_skips.add(test_name)
expected = ["SKIP"]
known_intermittent = expected[1:]
expected_status = expected[0]
# check if we've seen a result for this test before this log line
result_recorded = self.test_results.get(test_name) if result_recorded:
self.logger.warning( "Received a second status for {}: " "first {}, now {}".format(test_name, result_recorded, status)
) # mocha intermittently logs an additional test result after the # test has already timed out. Avoid recording this second status. if result_recorded != "TIMEOUT":
self.test_results[test_name] = status if status notin expected:
self.has_unexpected = True
self.logger.test_end(
test_name,
status=status,
expected=expected_status,
known_intermittent=known_intermittent,
)
def after_end(self): if self.unexpected_skips:
self.has_unexpected = True for test_name in self.unexpected_skips:
self.logger.error( "TEST-UNEXPECTED-MISSING Unexpected skipped %s" % (test_name,)
)
self.logger.suite_end()
# tempfile.TemporaryDirectory missing from Python 2.7 class TemporaryDirectory(object): def __init__(self):
self.path = tempfile.mkdtemp()
self._closed = False
def run_test(self, logger, *tests, **params): """
Runs Puppeteer unit tests with npm.
Possible optional test parameters:
`binary`:
Path for the browser binary to use. Defaults to the local
build.
`headless`:
Boolean to indicate whether to activate Firefox' headless mode.
`extra_prefs`:
Dictionary of extra preferences to write to the profile,
before invoking npm. Overrides default preferences.
`enable_webrender`:
Boolean to indicate whether to enable WebRender compositor in Gecko. """
setup()
env = { # Checked by Puppeteer's custom mocha config "CI": "1", # Print browser process ouptut "DUMPIO": "1", # Run in headless mode if trueish, otherwise use headful "HEADLESS": str(headless), # Causes some tests to be skipped due to assumptions about install "PUPPETEER_ALT_INSTALL": "1",
}
prefs = {} for k, v in params.get("extra_prefs", {}).items():
print("Using extra preference: {}={}".format(k, v))
prefs[k] = mozprofile.Preferences.cast(v)
if prefs:
extra_options["extraPrefsFirefox"] = prefs
if extra_options:
env["EXTRA_LAUNCH_OPTIONS"] = json.dumps(extra_options)
expected_path = os.path.join(
os.path.dirname(__file__), "test", "puppeteer", "test", "TestExpectations.json",
) if os.path.exists(expected_path): with open(expected_path) as f:
expected_data = json.load(f) else:
expected_data = []
expected_platform = platform.uname().system.lower() if expected_platform == "windows":
expected_platform = "win32"
# Filter expectation data for the selected browser, # headless or headful mode, the operating system, # run in BiDi mode or not.
expectations = [
expectation for expectation in expected_data if is_relevant_expectation(
expectation, product, env["HEADLESS"], expected_platform
)
]
output_handler = MochaOutputHandler(logger, expectations)
run_npm(
*command,
cwd=self.puppeteer_dir,
env=env,
output_line_handler=output_handler, # Puppeteer unit tests don't always clean-up child processes in case of # failure, so use an output_timeout as a fallback
output_timeout=60,
exit_on_fail=True,
)
output_handler.after_end()
if output_handler.has_unexpected:
logger.error("Got unexpected results")
exit(1)
def create_parser_puppeteer():
p = argparse.ArgumentParser()
p.add_argument( "--product", type=str, default="firefox", choices=["chrome", "firefox"]
)
p.add_argument( "--binary",
type=str,
help="Path to browser binary. Defaults to local Firefox build.",
)
p.add_argument( "--ci",
action="store_true",
help="Flag that indicates that tests run in a CI environment.",
)
p.add_argument( "--disable-fission",
action="store_true",
default=False,
dest="disable_fission",
help="Disable Fission (site isolation) in Gecko.",
)
p.add_argument( "--enable-webrender",
action="store_true",
help="Enable the WebRender compositor in Gecko.",
)
p.add_argument( "-z", "--headless", action="store_true", help="Run browser in headless mode."
)
p.add_argument( "--setpref",
action="append",
dest="extra_prefs",
metavar="=",
help="Defines additional user preferences.",
)
p.add_argument( "--setopt",
action="append",
dest="extra_options",
metavar=",
help="Defines additional options for `puppeteer.launch`.",
)
p.add_argument( "--this-chunk",
type=str,
default="1",
help="Defines a current chunk to run.",
)
p.add_argument( "--total-chunks",
type=str,
default="1",
help="Defines a total amount of chunks to run.",
)
p.add_argument( "-v",
dest="verbosity",
action="count",
default=0,
help="Increase remote agent logging verbosity to include " "debug level messages with -v, trace messages with -vv," "and to not truncate long trace messages with -vvv",
)
p.add_argument("tests", nargs="*")
mozlog.commandline.add_logging_group(p) return p
# moztest calls this programmatically with test objects or manifests if"test_objects"in kwargs and tests isnotNone:
logger.error("Expected either 'test_objects' or 'tests'")
exit(1)
if product != "firefox"and extra_prefs isnotNone:
logger.error("User preferences are not recognized by %s" % product)
exit(1)
if"test_objects"in kwargs:
tests = [] for test in kwargs["test_objects"]:
tests.append(test["path"])
prefs = {} for s in extra_prefs or []:
kv = s.split("=") if len(kv) != 2:
logger.error("syntax error in --setpref={}".format(s))
exit(EX_USAGE)
prefs[kv[0]] = kv[1].strip()
options = {} for s in extra_options or []:
kv = s.split("=") if len(kv) != 2:
logger.error("syntax error in --setopt={}".format(s))
exit(EX_USAGE)
options[kv[0]] = kv[1].strip()
prefs.update({"fission.autostart": True}) if disable_fission:
prefs.update({"fission.autostart": False})
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.