Update web-platform-tests to revision ddfc95cf0493ae147a4f6a4d7be8eff1a0c23098

This commit is contained in:
Anthony Ramine 2018-01-18 10:15:04 +01:00
parent 1f6a864ab5
commit 7e6290451f
832 changed files with 16026 additions and 2649 deletions

View file

@ -132,11 +132,6 @@ def get_sha1():
return git("rev-parse", "HEAD").strip()
def install_wptrunner():
"""Install wptrunner."""
call("pip", "install", wptrunner_root)
def deepen_checkout(user):
"""Convert from a shallow checkout to a full one"""
fetch_args = [user, "+refs/heads/*:refs/remotes/origin/*"]

View file

@ -16,6 +16,7 @@ fi
if [[ $(./wpt test-jobs --includes wptrunner_unittest; echo $?) -eq 0 ]]; then
if [ $TOXENV == "py27" ] || [ $TOXENV == "pypy" ]; then
TOXENV="$TOXENV,py27-flake8"
cd tools/wptrunner
tox
fi

View file

@ -70,8 +70,8 @@ class XMLParser(object):
def _end(self, tag):
return self._target.end(_fixname(tag))
def _external(self, context, base, systemId, publicId):
if publicId in {
def _external(self, context, base, system_id, public_id):
if public_id in {
"-//W3C//DTD XHTML 1.0 Transitional//EN",
"-//W3C//DTD XHTML 1.1//EN",
"-//W3C//DTD XHTML 1.0 Strict//EN",

View file

@ -2,7 +2,7 @@ import json
import os
import re
from collections import defaultdict
from six import iteritems, itervalues, viewkeys
from six import iteritems, itervalues, viewkeys, string_types
from .item import ManualTest, WebdriverSpecTest, Stub, RefTestNode, RefTest, TestharnessTest, SupportFile, ConformanceCheckerTest, VisualTest
from .log import get_logger
@ -20,14 +20,6 @@ class ManifestVersionMismatch(ManifestError):
pass
def sourcefile_items(args):
tests_root, url_base, rel_path, status = args
source_file = SourceFile(tests_root,
rel_path,
url_base)
return rel_path, source_file.manifest_items()
class Manifest(object):
def __init__(self, url_base="/"):
assert url_base is not None
@ -221,7 +213,7 @@ def load(tests_root, manifest):
logger = get_logger()
# "manifest" is a path or file-like object.
if isinstance(manifest, basestring):
if isinstance(manifest, string_types):
if os.path.exists(manifest):
logger.debug("Opening manifest at %s" % manifest)
else:

View file

@ -1,3 +1,5 @@
# flake8: noqa
from __future__ import print_function
import argparse

View file

@ -1,9 +1,3 @@
def get_logger(name="ssl"):
logger = structured.get_default_logger(name)
if logger is None:
logger = structured.structuredlog.StructuredLogger(name)
return logger
class NoSSLEnvironment(object):
ssl_enabled = False

View file

@ -3,8 +3,12 @@ envlist = py27,py36,pypy
skipsdist=True
[testenv]
# flake8 versions should be kept in sync across tools/tox.ini, tools/wpt/tox.ini, and tools/wptrunner/tox.ini
deps =
flake8
flake8==3.5.0
pycodestyle==2.3.1
pyflakes==1.6.0
pep8-naming==0.4.1
pytest
pytest-cov
mock
@ -19,6 +23,28 @@ passenv =
HYPOTHESIS_PROFILE
[flake8]
ignore = E128,E129,E221,E226,E231,E251,E265,E302,E303,E305,E402,E901,F401,F821,F841
# flake8 config should be kept in sync across tools/tox.ini, tools/wpt/tox.ini, and tools/wptrunner/tox.ini
select = E,W,F,N
# E128: continuation line under-indented for visual indent
# E129: visually indented line with same indent as next logical line
# E221: multiple spaces before operator
# E226: missing whitespace around arithmetic operator
# E231: missing whitespace after ,, ;, or :
# E251: unexpected spaces around keyword / parameter equals
# E265: block comment should start with #
# E302: expected 2 blank lines, found 0
# E303: too many blank lines (3)
# E305: expected 2 blank lines after end of function or class
# E402: module level import not at top of file
# E731: do not assign a lambda expression, use a def
# E901: SyntaxError or IndentationError
# W601: .has_key() is deprecated, use in
# F401: module imported but unused
# F403: from module import * used; unable to detect undefined names
# F405: name may be undefined, or defined from star imports: module
# F841: local variable name is assigned to but never used
# N801: class names should use CapWords convention
# N802: function name should be lowercase
ignore = E128,E129,E221,E226,E231,E251,E265,E302,E303,E305,E402,E731,E901,W601,F401,F403,F405,F841,N801,N802
max-line-length = 141
exclude = .tox,html5lib,third_party/py,third_party/pytest,third_party/funcsigs,third_party/attrs,third_party/pluggy/,pywebsocket,six,_venv,webencodings,wptserve/docs,wptserve/tests/functional/docroot/,wpt,wptrunner

View file

@ -4,6 +4,8 @@ import error
import protocol
import transport
from six import string_types
from mozlog import get_default_logger
logger = get_default_logger()
@ -313,7 +315,7 @@ class Cookies(object):
cookie = {"name": name,
"value": None}
if isinstance(name, (str, unicode)):
if isinstance(name, string_types):
cookie["value"] = value
elif hasattr(value, "value"):
cookie["value"] = value.value

View file

@ -16,7 +16,7 @@ class Encoder(json.JSONEncoder):
return [self.default(x) for x in obj]
elif isinstance(obj, webdriver.Element):
return {webdriver.Element.identifier: obj.id}
return super(ProtocolEncoder, self).default(obj)
return super(Encoder, self).default(obj)
class Decoder(json.JSONDecoder):

View file

@ -1,18 +0,0 @@
class ServoExtensionCommands(object):
def __init__(self, session):
self.session = session
@command
def get_prefs(self, *prefs):
body = {"prefs": list(prefs)}
return self.session.send_command("POST", "servo/prefs/get", body)
@command
def set_prefs(self, prefs):
body = {"prefs": prefs}
return self.session.send_command("POST", "servo/prefs/set", body)
@command
def reset_prefs(self, *prefs):
body = {"prefs": list(prefs)}
return self.session.send_command("POST", "servo/prefs/reset", body)

View file

@ -4,6 +4,7 @@ import urlparse
import error
from six import text_type
"""Implements HTTP transport for the WebDriver wire protocol."""
@ -135,7 +136,7 @@ class HTTPWireProtocol(object):
except ValueError:
raise ValueError("Failed to encode request body as JSON:\n"
"%s" % json.dumps(body, indent=2))
if isinstance(payload, unicode):
if isinstance(payload, text_type):
payload = body.encode("utf-8")
if headers is None:

View file

@ -4,9 +4,12 @@ import platform
import re
import shutil
import stat
import subprocess
import sys
from abc import ABCMeta, abstractmethod
from ConfigParser import RawConfigParser
from distutils.spawn import find_executable
from io import BytesIO
from utils import call, get, untar, unzip
@ -278,6 +281,61 @@ class Chrome(Browser):
logger.critical("dbus not running and can't be started")
sys.exit(1)
class ChromeAndroid(Browser):
"""Chrome-specific interface for android.
Includes installation, webdriver installation, and wptrunner setup methods.
"""
product = "chrome_android"
requirements = "requirements_chrome_android.txt"
def install(self, dest=None):
raise NotImplementedError
def platform_string(self):
raise NotImplementedError
def find_webdriver(self):
return find_executable("chromedriver")
def install_webdriver(self, dest=None):
"""Install latest Webdriver."""
if dest is None:
dest = os.pwd
latest = get("http://chromedriver.storage.googleapis.com/LATEST_RELEASE").text.strip()
url = "http://chromedriver.storage.googleapis.com/%s/chromedriver_%s.zip" % (latest,
self.platform_string())
unzip(get(url).raw, dest)
path = find_executable("chromedriver", dest)
st = os.stat(path)
os.chmod(path, st.st_mode | stat.S_IEXEC)
return path
def version(self, root):
raise NotImplementedError
def prepare_environment(self):
# https://bugs.chromium.org/p/chromium/issues/detail?id=713947
logger.debug("DBUS_SESSION_BUS_ADDRESS %s" % os.environ.get("DBUS_SESSION_BUS_ADDRESS"))
if "DBUS_SESSION_BUS_ADDRESS" not in os.environ:
if find_executable("dbus-launch"):
logger.debug("Attempting to start dbus")
dbus_conf = subprocess.check_output(["dbus-launch"])
logger.debug(dbus_conf)
# From dbus-launch(1):
#
# > When dbus-launch prints bus information to standard output,
# > by default it is in a simple key-value pairs format.
for line in dbus_conf.strip().split("\n"):
key, _, value = line.partition("=")
os.environ[key] = value
else:
logger.critical("dbus not running and can't be started")
sys.exit(1)
class Opera(Browser):
"""Opera-specific interface.

View file

@ -39,8 +39,3 @@ def install(name, component, destination):
subclass = getattr(browser, name.title())
sys.stdout.write('Now installing %s %s...\n' % (name, component))
getattr(subclass(), method)(dest=destination)
if __name__ == '__main__':
args = parser.parse_args()
run(None, **vars(args))

View file

@ -38,18 +38,3 @@ def table(headings, data, log):
for row in data:
log("|%s|" % "|".join(" %s" % row[i].ljust(max_widths[i] - 1) for i in cols))
log("")
def err_string(results_dict, iterations):
"""Create and return string with errors from test run."""
rv = []
total_results = sum(results_dict.values())
for key, value in sorted(results_dict.items()):
rv.append("%s%s" %
(key, ": %s/%s" % (value, iterations) if value != iterations else ""))
if total_results < iterations:
rv.append("MISSING: %s/%s" % (iterations - total_results, iterations))
rv = ", ".join(rv)
if is_inconsistent(results_dict, iterations):
rv = "**%s**" % rv
return rv

View file

@ -223,6 +223,28 @@ class Chrome(BrowserSetup):
else:
raise WptrunError("Unable to locate or install chromedriver binary")
class ChromeAndroid(BrowserSetup):
name = "chrome_android"
browser_cls = browser.ChromeAndroid
def setup_kwargs(self, kwargs):
if kwargs["webdriver_binary"] is None:
webdriver_binary = self.browser.find_webdriver()
if webdriver_binary is None:
install = self.prompt_install("chromedriver")
if install:
print("Downloading chromedriver")
webdriver_binary = self.browser.install_webdriver(dest=self.venv.bin_path)
else:
print("Using webdriver binary %s" % webdriver_binary)
if webdriver_binary:
kwargs["webdriver_binary"] = webdriver_binary
else:
raise WptrunError("Unable to locate or install chromedriver binary")
class Opera(BrowserSetup):
name = "opera"
@ -321,6 +343,7 @@ class Servo(BrowserSetup):
product_setup = {
"firefox": Firefox,
"chrome": Chrome,
"chrome_android": ChromeAndroid,
"edge": Edge,
"ie": InternetExplorer,
"servo": Servo,

View file

@ -0,0 +1,7 @@
from tools.wpt import stability
def test_is_inconsistent():
assert stability.is_inconsistent({"PASS": 10}, 10) is False
assert stability.is_inconsistent({"PASS": 9}, 10) is True
assert stability.is_inconsistent({"PASS": 9, "FAIL": 1}, 10) is True
assert stability.is_inconsistent({"PASS": 8, "FAIL": 1}, 10) is True

View file

@ -10,7 +10,8 @@ import pytest
from tools.wpt import wpt
# Tests currently don't work on Windows for path reasons
pytestmark = pytest.mark.skipif(os.name == "nt",
reason="Tests currently don't work on Windows for path reasons")
def test_missing():
with pytest.raises(SystemExit):
@ -25,6 +26,9 @@ def test_help():
assert excinfo.value.code == 0
@pytest.mark.slow
@pytest.mark.system_dependent
@pytest.mark.remote_network
def test_run_firefox():
# TODO: It seems like there's a bug in argparse that makes this argument order required
# should try to work around that
@ -44,6 +48,8 @@ def test_run_firefox():
del os.environ["MOZ_HEADLESS"]
@pytest.mark.slow
@pytest.mark.system_dependent
def test_run_chrome():
with pytest.raises(SystemExit) as excinfo:
wpt.main(argv=["run", "--yes", "--no-pause", "--binary-arg", "headless",
@ -52,6 +58,8 @@ def test_run_chrome():
assert excinfo.value.code == 0
@pytest.mark.slow
@pytest.mark.remote_network
def test_install_chromedriver():
chromedriver_path = os.path.join(wpt.localpaths.repo_root, "_venv", "bin", "chromedriver")
if os.path.exists(chromedriver_path):
@ -63,6 +71,8 @@ def test_install_chromedriver():
os.unlink(chromedriver_path)
@pytest.mark.slow
@pytest.mark.remote_network
def test_install_firefox():
fx_path = os.path.join(wpt.localpaths.repo_root, "_venv", "firefox")
if os.path.exists(fx_path):
@ -109,6 +119,8 @@ def test_files_changed_ignore_rules():
assert compile_ignore_rule("foobar/baz/**").pattern == "^foobar/baz/.*$"
@pytest.mark.slow # this updates the manifest
@pytest.mark.system_dependent
def test_tests_affected(capsys):
# This doesn't really work properly for random commits because we test the files in
# the current working directory for references to the changed files, not the ones at
@ -121,6 +133,8 @@ def test_tests_affected(capsys):
assert "html/browsers/offline/appcache/workers/appcache-worker.html" in out
@pytest.mark.slow
@pytest.mark.system_dependent
def test_serve():
def test():
s = socket.socket()

View file

@ -1,10 +1,9 @@
[tox]
envlist = py27
envlist = py27,py27-flake8
skipsdist=True
[testenv]
deps =
flake8
pytest
pytest-cov
hypothesis
@ -13,9 +12,41 @@ deps =
-r{toxinidir}/../wptrunner/requirements_firefox.txt
commands =
pytest --cov
flake8
pytest --cov {posargs}
[testenv:py27-flake8]
# flake8 versions should be kept in sync across tools/tox.ini, tools/wpt/tox.ini, and tools/wptrunner/tox.ini
deps =
flake8==3.5.0
pycodestyle==2.3.1
pyflakes==1.6.0
pep8-naming==0.4.1
commands =
flake8 {posargs}
[flake8]
ignore = E128,E129,E221,E226,E231,E251,E265,E302,E303,E305,E402,E901,F401,F821,F841
# flake8 config should be kept in sync across tools/tox.ini, tools/wpt/tox.ini, and tools/wptrunner/tox.ini
select = E,W,F,N
# E128: continuation line under-indented for visual indent
# E129: visually indented line with same indent as next logical line
# E221: multiple spaces before operator
# E226: missing whitespace around arithmetic operator
# E231: missing whitespace after ,, ;, or :
# E251: unexpected spaces around keyword / parameter equals
# E265: block comment should start with #
# E302: expected 2 blank lines, found 0
# E303: too many blank lines (3)
# E305: expected 2 blank lines after end of function or class
# E402: module level import not at top of file
# E731: do not assign a lambda expression, use a def
# E901: SyntaxError or IndentationError
# W601: .has_key() is deprecated, use in
# F401: module imported but unused
# F403: from module import * used; unable to detect undefined names
# F405: name may be undefined, or defined from star imports: module
# F841: local variable name is assigned to but never used
# N801: class names should use CapWords convention
# N802: function name should be lowercase
ignore = E128,E129,E221,E226,E231,E251,E265,E302,E303,E305,E402,E731,E901,W601,F401,F403,F405,F841,N801,N802
max-line-length = 141

View file

@ -27,7 +27,7 @@ class Kwargs(dict):
value = value()
if not value:
if err_fn is not None:
return err_fn(kwargs, "Failed to find %s" % desc)
return err_fn(self, "Failed to find %s" % desc)
else:
return
self[name] = value

View file

@ -1,4 +1,5 @@
import os
import shutil
import sys
import logging
from distutils.spawn import find_executable
@ -21,7 +22,7 @@ class Virtualenv(object):
def create(self):
if os.path.exists(self.path):
shutil.rmtree(self.path)
call(self.virtualenv, self.path)
call(self.virtualenv, self.path, "-p", sys.executable)
@property
def bin_path(self):

View file

@ -1,6 +1,5 @@
exclude MANIFEST.in
include requirements.txt
include wptrunner/browsers/b2g_setup/*
include wptrunner.default.ini
include wptrunner/testharness_runner.html
include wptrunner/*.js

View file

@ -23,7 +23,7 @@ The ``wptrunner`` command takes multiple options, of which the
following are most significant:
``--product`` (defaults to `firefox`)
The product to test against: `b2g`, `chrome`, `firefox`, or `servo`.
The product to test against: `chrome`, `firefox`, or `servo`.
``--binary`` (required if product is `firefox` or `servo`)
The path to a binary file for the product (browser) to test against.

View file

@ -186,22 +186,22 @@ htmlhelp_basename = 'wptrunnerdoc'
# -- Options for LaTeX output ---------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#'preamble': '',
# Additional stuff for the LaTeX preamble.
#'preamble': '',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
('index', 'wptrunner.tex', u'wptrunner Documentation',
u'James Graham', 'manual'),
('index', 'wptrunner.tex', u'wptrunner Documentation',
u'James Graham', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
@ -244,9 +244,9 @@ man_pages = [
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
('index', 'wptrunner', u'wptrunner Documentation',
u'James Graham', 'wptrunner', 'One line description of project.',
'Miscellaneous'),
('index', 'wptrunner', u'wptrunner Documentation',
u'James Graham', 'wptrunner', 'One line description of project.',
'Miscellaneous'),
]
# Documents to append as an appendix to all manuals.

View file

@ -54,7 +54,7 @@ A test run is started using the ``wptrunner`` command. The command
takes multiple options, of which the following are most significant:
``--product`` (defaults to `firefox`)
The product to test against: `b2g`, `chrome`, `firefox`, or `servo`.
The product to test against: `chrome`, `firefox`, or `servo`.
``--binary`` (required if product is `firefox` or `servo`)
The path to a binary file for the product (browser) to test against.

View file

@ -0,0 +1,2 @@
mozprocess >= 0.19
selenium >= 2.41.0

View file

@ -53,13 +53,12 @@ setup(name=PACKAGE_NAME,
"config.json",
"wptrunner.default.ini",
"browsers/server-locations.txt",
"browsers/b2g_setup/*",
"browsers/sauce_setup/*",
"prefs/*"]},
include_package_data=True,
data_files=[("requirements", requirements_files)],
install_requires=deps
)
)
if "install" in sys.argv:
path = os.path.relpath(os.path.join(sys.prefix, "requirements"), os.curdir)

View file

@ -156,7 +156,8 @@ def main():
run(config, args)
except Exception:
if args.pdb:
import pdb, traceback
import pdb
import traceback
print traceback.format_exc()
pdb.post_mortem()
else:

View file

@ -2,7 +2,7 @@
xfail_strict=true
[tox]
envlist = {py27,pypy}-{base,b2g,chrome,firefox,servo}
envlist = {py27,pypy}-{base,chrome,firefox,servo},py27-flake8
[testenv]
deps =
@ -15,3 +15,40 @@ deps =
servo: -r{toxinidir}/requirements_servo.txt
commands = pytest --cov
[testenv:py27-flake8]
# flake8 versions should be kept in sync across tools/tox.ini, tools/wpt/tox.ini, and tools/wptrunner/tox.ini
deps =
flake8==3.5.0
pycodestyle==2.3.1
pyflakes==1.6.0
pep8-naming==0.4.1
commands =
flake8
[flake8]
# flake8 config should be kept in sync across tools/tox.ini, tools/wpt/tox.ini, and tools/wptrunner/tox.ini
select = E,W,F,N
# E128: continuation line under-indented for visual indent
# E129: visually indented line with same indent as next logical line
# E221: multiple spaces before operator
# E226: missing whitespace around arithmetic operator
# E231: missing whitespace after ,, ;, or :
# E251: unexpected spaces around keyword / parameter equals
# E265: block comment should start with #
# E302: expected 2 blank lines, found 0
# E303: too many blank lines (3)
# E305: expected 2 blank lines after end of function or class
# E402: module level import not at top of file
# E731: do not assign a lambda expression, use a def
# E901: SyntaxError or IndentationError
# W601: .has_key() is deprecated, use in
# F401: module imported but unused
# F403: from module import * used; unable to detect undefined names
# F405: name may be undefined, or defined from star imports: module
# F841: local variable name is assigned to but never used
# N801: class names should use CapWords convention
# N802: function name should be lowercase
ignore = E128,E129,E221,E226,E231,E251,E265,E302,E303,E305,E402,E731,E901,W601,F401,F403,F405,F841,N801,N802
max-line-length = 141

View file

@ -23,6 +23,7 @@ module global scope.
"""
product_list = ["chrome",
"chrome_android",
"edge",
"firefox",
"ie",

View file

@ -0,0 +1,98 @@
from .base import Browser, ExecutorBrowser, require_arg
from ..webdriver_server import ChromeDriverServer
from ..executors import executor_kwargs as base_executor_kwargs
from ..executors.executorselenium import (SeleniumTestharnessExecutor,
SeleniumRefTestExecutor)
from ..executors.executorchrome import ChromeDriverWdspecExecutor
__wptrunner__ = {"product": "chrome_android",
"check_args": "check_args",
"browser": "ChromeAndroidBrowser",
"executor": {"testharness": "SeleniumTestharnessExecutor",
"reftest": "SeleniumRefTestExecutor",
"wdspec": "ChromeDriverWdspecExecutor"},
"browser_kwargs": "browser_kwargs",
"executor_kwargs": "executor_kwargs",
"env_extras": "env_extras",
"env_options": "env_options"}
def check_args(**kwargs):
require_arg(kwargs, "webdriver_binary")
def browser_kwargs(test_type, run_info_data, **kwargs):
return {"binary": kwargs["binary"],
"webdriver_binary": kwargs["webdriver_binary"],
"webdriver_args": kwargs.get("webdriver_args")}
def executor_kwargs(test_type, server_config, cache_manager, run_info_data,
**kwargs):
from selenium.webdriver import DesiredCapabilities
executor_kwargs = base_executor_kwargs(test_type, server_config,
cache_manager, **kwargs)
executor_kwargs["close_after_done"] = True
capabilities = dict(DesiredCapabilities.CHROME.items())
capabilities["chromeOptions"] = {}
# required to start on mobile
capabilities["chromeOptions"]["androidPackage"] = "com.android.chrome"
for (kwarg, capability) in [("binary", "binary"), ("binary_args", "args")]:
if kwargs[kwarg] is not None:
capabilities["chromeOptions"][capability] = kwargs[kwarg]
if test_type == "testharness":
capabilities["useAutomationExtension"] = False
capabilities["excludeSwitches"] = ["enable-automation"]
if test_type == "wdspec":
capabilities["chromeOptions"]["w3c"] = True
executor_kwargs["capabilities"] = capabilities
return executor_kwargs
def env_extras(**kwargs):
return []
def env_options():
return {"host": "web-platform.test",
"bind_hostname": "true"}
class ChromeAndroidBrowser(Browser):
"""Chrome is backed by chromedriver, which is supplied through
``wptrunner.webdriver.ChromeDriverServer``.
"""
def __init__(self, logger, binary, webdriver_binary="chromedriver",
webdriver_args=None):
"""Creates a new representation of Chrome. The `binary` argument gives
the browser binary to use for testing."""
Browser.__init__(self, logger)
self.binary = binary
self.server = ChromeDriverServer(self.logger,
binary=webdriver_binary,
args=webdriver_args)
def start(self, **kwargs):
self.server.start(block=False)
def stop(self, force=False):
self.server.stop(force=force)
def pid(self):
return self.server.pid
def is_alive(self):
# TODO(ato): This only indicates the driver is alive,
# and doesn't say anything about whether a browser session
# is active.
return self.server.is_alive()
def cleanup(self):
self.stop()
def executor_browser(self):
return ExecutorBrowser, {"webdriver_url": self.server.url}

View file

@ -96,15 +96,15 @@ def executor_kwargs(test_type, server_config, cache_manager, run_info_data,
executor_kwargs["reftest_internal"] = kwargs["reftest_internal"]
executor_kwargs["reftest_screenshot"] = kwargs["reftest_screenshot"]
if test_type == "wdspec":
fxOptions = {}
options = {}
if kwargs["binary"]:
fxOptions["binary"] = kwargs["binary"]
options["binary"] = kwargs["binary"]
if kwargs["binary_args"]:
fxOptions["args"] = kwargs["binary_args"]
fxOptions["prefs"] = {
options["args"] = kwargs["binary_args"]
options["prefs"] = {
"network.dns.localDomains": ",".join(hostnames)
}
capabilities["moz:firefoxOptions"] = fxOptions
capabilities["moz:firefoxOptions"] = options
if kwargs["certutil_binary"] is None:
capabilities["acceptInsecureCerts"] = True
if capabilities:
@ -364,7 +364,7 @@ class FirefoxBrowser(Browser):
env[env_var] = (os.path.pathsep.join([certutil_dir, env[env_var]])
if env_var in env else certutil_dir).encode(
sys.getfilesystemencoding() or 'utf-8', 'replace')
sys.getfilesystemencoding() or 'utf-8', 'replace')
def certutil(*args):
cmd = [self.certutil_binary] + list(args)

View file

@ -28,10 +28,10 @@ def executor_kwargs(test_type, server_config, cache_manager, run_info_data,
**kwargs):
from selenium.webdriver import DesiredCapabilities
ieOptions = {}
ieOptions["requireWindowFocus"] = True
options = {}
options["requireWindowFocus"] = True
capabilities = {}
capabilities["se:ieOptions"] = ieOptions
capabilities["se:ieOptions"] = options
executor_kwargs = base_executor_kwargs(test_type, server_config,
cache_manager, **kwargs)
executor_kwargs["close_after_done"] = True
@ -51,7 +51,7 @@ class InternetExplorerBrowser(Browser):
def __init__(self, logger, webdriver_binary, webdriver_args=None):
Browser.__init__(self, logger)
self.server = InterentExplorerDriverServer(self.logger,
self.server = InternetExplorerDriverServer(self.logger,
binary=webdriver_binary,
args=webdriver_args)
self.webdriver_host = "localhost"

View file

@ -61,7 +61,7 @@ def get_ssl_kwargs(**kwargs):
elif kwargs["ssl_type"] == "pregenerated":
args = {"host_key_path": kwargs["host_key_path"],
"host_cert_path": kwargs["host_cert_path"],
"ca_cert_path": kwargs["ca_cert_path"]}
"ca_cert_path": kwargs["ca_cert_path"]}
else:
args = {}
return args

View file

@ -13,7 +13,7 @@ here = os.path.split(__file__)[0]
# Extra timeout to use after internal test timeout at which the harness
# should force a timeout
extra_timeout = 5 # seconds
extra_timeout = 5 # seconds
def executor_kwargs(test_type, server_config, cache_manager, **kwargs):
@ -67,8 +67,8 @@ class TestharnessResultConverter(object):
(result_url, test.url))
harness_result = test.result_cls(self.harness_codes[status], message)
return (harness_result,
[test.subtest_result_cls(name, self.test_codes[status], message, stack)
for name, status, message, stack in subtest_results])
[test.subtest_result_cls(st_name, self.test_codes[st_status], st_message, st_stack)
for st_name, st_status, st_message, st_stack in subtest_results])
testharness_result_converter = TestharnessResultConverter()
@ -124,7 +124,7 @@ class TestExecutor(object):
self.debug_info = debug_info
self.last_environment = {"protocol": "http",
"prefs": {}}
self.protocol = None # This must be set in subclasses
self.protocol = None # This must be set in subclasses
@property
def logger(self):

View file

@ -304,7 +304,7 @@ class ExecuteAsyncScriptRun(object):
self.result_flag = threading.Event()
def run(self):
index = self.url.rfind("/storage/");
index = self.url.rfind("/storage/")
if index != -1:
# Clear storage
self.protocol.clear_origin(self.url)
@ -503,7 +503,7 @@ class MarionetteRefTestExecutor(RefTestExecutor):
assert viewport_size is None
assert dpi is None
timeout = self.timeout_multiplier * test.timeout if self.debug_info is None else None
timeout = self.timeout_multiplier * test.timeout if self.debug_info is None else None
test_url = self.test_url(test)

View file

@ -51,7 +51,7 @@ class SeleniumProtocol(Protocol):
self.webdriver = webdriver.Remote(command_executor=RemoteConnection(self.url.strip("/"),
resolve_ip=False),
desired_capabilities=self.capabilities)
except:
except Exception:
self.logger.warning(
"Connecting to Selenium failed:\n%s" % traceback.format_exc())
else:
@ -64,7 +64,7 @@ class SeleniumProtocol(Protocol):
else:
try:
self.after_connect()
except:
except Exception:
print >> sys.stderr, traceback.format_exc()
self.logger.warning(
"Failed to connect to navigate initial page")
@ -76,7 +76,7 @@ class SeleniumProtocol(Protocol):
self.logger.debug("Hanging up on Selenium session")
try:
self.webdriver.quit()
except:
except Exception:
pass
del self.webdriver
@ -103,7 +103,7 @@ class SeleniumProtocol(Protocol):
def wait(self):
while True:
try:
self.webdriver.execute_async_script("");
self.webdriver.execute_async_script("")
except exceptions.TimeoutException:
pass
except (socket.timeout, exceptions.NoSuchWindowException,
@ -220,7 +220,7 @@ class SeleniumTestharnessExecutor(TestharnessExecutor):
win_s = webdriver.execute_script("return window['%s'];" % self.window_id)
win_obj = json.loads(win_s)
test_window = win_obj["window-fcc6-11e5-b4f8-330a88ab9d7f"]
except:
except Exception:
after = webdriver.window_handles
if len(after) == 2:
test_window = next(iter(set(after) - set([parent])))

View file

@ -28,7 +28,7 @@ from .executormarionette import WdspecRun
pytestrunner = None
webdriver = None
extra_timeout = 5 # seconds
extra_timeout = 5 # seconds
hosts_text = """127.0.0.1 web-platform.test
127.0.0.1 www.web-platform.test

View file

@ -43,7 +43,7 @@ class ServoWebDriverProtocol(Protocol):
self.session = webdriver.Session(self.host, self.port,
extension=webdriver.servo.ServoCommandExtensions)
self.session.start()
except:
except Exception:
self.logger.warning(
"Connecting with WebDriver failed:\n%s" % traceback.format_exc())
else:
@ -60,7 +60,7 @@ class ServoWebDriverProtocol(Protocol):
self.logger.debug("Hanging up on WebDriver session")
try:
self.session.end()
except:
except Exception:
pass
def is_alive(self):

View file

@ -247,8 +247,8 @@ class TestNode(ManifestItem):
boolean_properties=self.root.boolean_properties)
except ConditionError as e:
if stability is not None:
self.set("disabled", stability or "unstable", e.cond.children[0])
self.new_disabled = True
self.set("disabled", stability or "unstable", e.cond.children[0])
self.new_disabled = True
else:
print "Conflicting test results for %s, cannot update" % self.root.test_path
return

View file

@ -355,7 +355,7 @@ def load_expected(test_manifest, metadata_path, test_path, tests, property_order
# Remove expected data for tests that no longer exist
for test in expected_manifest.iterchildren():
if not test.id in tests_by_id:
if test.id not in tests_by_id:
test.remove()
# Add tests that don't have expected data

View file

@ -274,6 +274,6 @@ def check_stability(logger, repeat_loop=10, repeat_restart=5, chaos_mode=True, m
write_summary(logger, step_results, "FAIL")
return 1
step_results.append((desc, "PASS"))
step_results.append((desc, "PASS"))
write_summary(logger, step_results, "PASS")

View file

@ -93,7 +93,7 @@ class EqualTimeChunker(TestChunker):
for i, (test_type, test_path, tests) in enumerate(manifest_items):
test_dir = tuple(os.path.split(test_path)[0].split(os.path.sep)[:3])
if not test_dir in by_dir:
if test_dir not in by_dir:
by_dir[test_dir] = PathData(test_dir)
data = by_dir[test_dir]
@ -261,7 +261,7 @@ class EqualTimeChunker(TestChunker):
return self.paths.popleft()
@property
def badness(self_):
def badness(self_): # noqa: N805
"""Badness metric for this chunk"""
return self._badness(self_.time)
@ -587,6 +587,7 @@ class TestSource(object):
self.current_metadata = None
@abstractmethod
# noqa: N805
#@classmethod (doesn't compose with @abstractmethod)
def make_queue(cls, tests, **kwargs):
pass

View file

@ -195,7 +195,7 @@ class BrowserManager(object):
self.logger.debug("Starting browser with settings %r" % self.browser_settings)
self.browser.start(**self.browser_settings)
self.browser_pid = self.browser.pid()
except:
except Exception:
self.logger.warning("Failure during init %s" % traceback.format_exc())
if self.init_timer is not None:
self.init_timer.cancel()
@ -566,7 +566,7 @@ class TestRunnerManager(threading.Thread):
expected = test.expected()
status = file_result.status if file_result.status != "EXTERNAL-TIMEOUT" else "TIMEOUT"
if file_result.status in ("TIMEOUT", "EXTERNAL-TIMEOUT"):
if file_result.status in ("TIMEOUT", "EXTERNAL-TIMEOUT"):
if self.browser.check_for_crashes():
status = "CRASH"
@ -585,8 +585,8 @@ class TestRunnerManager(threading.Thread):
restart_before_next = (test.restart_after or
file_result.status in ("CRASH", "EXTERNAL-TIMEOUT") or
((subtest_unexpected or is_unexpected)
and self.restart_on_unexpected))
((subtest_unexpected or is_unexpected) and
self.restart_on_unexpected))
if (self.pause_after_test or
(self.pause_on_unexpected and (subtest_unexpected or is_unexpected))):
@ -689,7 +689,7 @@ class TestRunnerManager(threading.Thread):
break
else:
if cmd == "log":
self.log(*data)
self.log(*data)
else:
self.logger.warning("%r: %r" % (cmd, data))
while True:

View file

@ -42,15 +42,13 @@ class HostsTest(unittest.TestCase):
192.168.1.1 another_host another_alias
""","""127.0.0.1 localhost alias
192.168.1.1 another_host another_alias
"""
)
""")
def test_multiple_same_name(self):
# The semantics are that we overwrite earlier entries with the same name
self.do_test("""127.0.0.1 \tlocalhost alias
192.168.1.1 localhost another_alias""","""192.168.1.1 localhost another_alias
"""
)
""")
if __name__ == "__main__":
unittest.main()

View file

@ -44,4 +44,3 @@ def main():
assert structuredlog.get_default_logger() is not None
success = run_update(logger, **args)
sys.exit(0 if success else 1)

View file

@ -109,7 +109,7 @@ class UpdateCheckout(Step):
state.sync["branch"],
state.local_branch)
sync_path = os.path.abspath(sync_tree.root)
if not sync_path in sys.path:
if sync_path not in sys.path:
from update import setup_paths
setup_paths(sync_path)

View file

@ -75,7 +75,7 @@ class HgTree(object):
kwargs["repo"] = path
try:
hg("root", **kwargs)
except:
except Exception:
return False
return True
@ -155,7 +155,7 @@ class GitTree(object):
kwargs["repo"] = path
try:
git("rev-parse", "--show-toplevel", **kwargs)
except:
except Exception:
return False
return True
@ -305,8 +305,8 @@ class GitTree(object):
def paths(self):
"""List paths in the tree"""
repo_paths = [self.root] + [os.path.join(self.root, path)
for path in self.submodules()]
repo_paths = [self.root] + [os.path.join(self.root, path)
for path in self.submodules()]
rv = []

View file

@ -15,7 +15,7 @@ def vcs(bin_name):
repo = kwargs.pop("repo", None)
log_error = kwargs.pop("log_error", True)
if kwargs:
raise TypeError, kwargs
raise TypeError(kwargs)
args = list(args)

View file

@ -72,7 +72,7 @@ class WebDriverServer(object):
"Waiting for server to become accessible: %s" % self.url)
try:
wait_for_service((self.host, self.port))
except:
except Exception:
self.logger.error(
"WebDriver HTTP server was not accessible "
"within the timeout:\n%s" % traceback.format_exc())
@ -125,8 +125,6 @@ class SeleniumServer(WebDriverServer):
class ChromeDriverServer(WebDriverServer):
default_base_path = "/"
def __init__(self, logger, binary="chromedriver", port=None,
base_path="", args=None):
WebDriverServer.__init__(
@ -138,8 +136,6 @@ class ChromeDriverServer(WebDriverServer):
cmd_arg("url-base", self.base_path) if self.base_path else ""] + self._args
class EdgeDriverServer(WebDriverServer):
default_base_path = "/"
def __init__(self, logger, binary="microsoftwebdriver.exe", port=None,
base_path="", args=None):
WebDriverServer.__init__(
@ -147,8 +143,7 @@ class EdgeDriverServer(WebDriverServer):
def make_command(self):
return [self.binary,
cmd_arg("port", str(self.port)),
cmd_arg("url-base", self.base_path) if self.base_path else ""] + self._args
"--port=%s" % str(self.port)] + self._args
class OperaDriverServer(ChromeDriverServer):
def __init__(self, logger, binary="operadriver", port=None,
@ -157,17 +152,6 @@ class OperaDriverServer(ChromeDriverServer):
self, logger, binary, port=port, base_path=base_path, args=args)
class EdgeDriverServer(WebDriverServer):
def __init__(self, logger, binary="MicrosoftWebDriver.exe", port=None,
base_path="", host="localhost", args=None):
WebDriverServer.__init__(
self, logger, binary, host=host, port=port, args=args)
def make_command(self):
return [self.binary,
"--port=%s" % str(self.port)] + self._args
class InternetExplorerDriverServer(WebDriverServer):
def __init__(self, logger, binary="IEDriverServer.exe", port=None,
base_path="", host="localhost", args=None):

View file

@ -28,7 +28,7 @@ def require_arg(kwargs, name, value_func=None):
if value_func is None:
value_func = lambda x: x is not None
if not name in kwargs or not value_func(kwargs[name]):
if name not in kwargs or not value_func(kwargs[name]):
print >> sys.stderr, "Missing required argument %s" % name
sys.exit(1)
@ -97,7 +97,8 @@ scheme host and port.""")
test_selection_group.add_argument("--skip-timeout", action="store_true",
help="Skip tests that are expected to time out")
test_selection_group.add_argument("--tag", action="append", dest="tags",
help="Labels applied to tests to include in the run. Labels starting dir: are equivalent to top-level directories.")
help="Labels applied to tests to include in the run. "
"Labels starting dir: are equivalent to top-level directories.")
debugging_group = parser.add_argument_group("Debugging")
debugging_group.add_argument('--debugger', const="__default__", nargs="?",
@ -479,7 +480,8 @@ def create_parser_update(product_choices=None):
help="Don't create a VCS commit containing the changes.")
parser.add_argument("--sync", dest="sync", action="store_true", default=False,
help="Sync the tests with the latest from upstream (implies --patch)")
parser.add_argument("--ignore-existing", action="store_true", help="When updating test results only consider results from the logfiles provided, not existing expectations.")
parser.add_argument("--ignore-existing", action="store_true",
help="When updating test results only consider results from the logfiles provided, not existing expectations.")
parser.add_argument("--stability", nargs="?", action="store", const="unstable", default=None,
help=("Reason for disabling tests. When updating test results, disable tests that have "
"inconsistent results across many runs with the given reason."))

View file

@ -211,15 +211,15 @@ class TokenizerTest(unittest.TestCase):
""")
def test_atom_1(self):
self.compare(r"""key: @True
self.compare(r"""key: @True
""")
def test_atom_2(self):
self.compare(r"""key: @False
self.compare(r"""key: @False
""")
def test_atom_3(self):
self.compare(r"""key: @Reset
self.compare(r"""key: @Reset
""")
def test_atom_4(self):

View file

@ -145,8 +145,7 @@ class TokenizerTest(unittest.TestCase):
(token_types.string, r"\nb")])
def test_list_0(self):
self.compare(
"""
self.compare("""
key: []""",
[(token_types.string, "key"),
(token_types.separator, ":"),
@ -154,8 +153,7 @@ key: []""",
(token_types.list_end, "]")])
def test_list_1(self):
self.compare(
"""
self.compare("""
key: [a, "b"]""",
[(token_types.string, "key"),
(token_types.separator, ":"),
@ -165,8 +163,7 @@ key: [a, "b"]""",
(token_types.list_end, "]")])
def test_list_2(self):
self.compare(
"""
self.compare("""
key: [a,
b]""",
[(token_types.string, "key"),
@ -177,8 +174,7 @@ key: [a,
(token_types.list_end, "]")])
def test_list_3(self):
self.compare(
"""
self.compare("""
key: [a, #b]
c]""",
[(token_types.string, "key"),
@ -199,18 +195,16 @@ key: [a, #b]
c]""")
def test_list_6(self):
self.compare(
"""key: [a , b]""",
[(token_types.string, "key"),
(token_types.separator, ":"),
(token_types.list_start, "["),
(token_types.string, "a"),
(token_types.string, "b"),
(token_types.list_end, "]")])
self.compare("""key: [a , b]""",
[(token_types.string, "key"),
(token_types.separator, ":"),
(token_types.list_start, "["),
(token_types.string, "a"),
(token_types.string, "b"),
(token_types.list_end, "]")])
def test_expr_0(self):
self.compare(
"""
self.compare("""
key:
if cond == 1: value""",
[(token_types.string, "key"),
@ -224,8 +218,7 @@ key:
(token_types.string, "value")])
def test_expr_1(self):
self.compare(
"""
self.compare("""
key:
if cond == 1: value1
value2""",
@ -241,8 +234,7 @@ key:
(token_types.string, "value2")])
def test_expr_2(self):
self.compare(
"""
self.compare("""
key:
if cond=="1": value""",
[(token_types.string, "key"),
@ -256,8 +248,7 @@ key:
(token_types.string, "value")])
def test_expr_3(self):
self.compare(
"""
self.compare("""
key:
if cond==1.1: value""",
[(token_types.string, "key"),
@ -271,8 +262,7 @@ key:
(token_types.string, "value")])
def test_expr_4(self):
self.compare(
"""
self.compare("""
key:
if cond==1.1 and cond2 == "a": value""",
[(token_types.string, "key"),
@ -290,8 +280,7 @@ key:
(token_types.string, "value")])
def test_expr_5(self):
self.compare(
"""
self.compare("""
key:
if (cond==1.1 ): value""",
[(token_types.string, "key"),
@ -307,8 +296,7 @@ key:
(token_types.string, "value")])
def test_expr_6(self):
self.compare(
"""
self.compare("""
key:
if "\\ttest": value""",
[(token_types.string, "key"),
@ -322,27 +310,26 @@ key:
def test_expr_7(self):
with self.assertRaises(parser.ParseError):
self.tokenize(
"""
"""
key:
if 1A: value""")
def test_expr_8(self):
with self.assertRaises(parser.ParseError):
self.tokenize(
"""
"""
key:
if 1a: value""")
def test_expr_9(self):
with self.assertRaises(parser.ParseError):
self.tokenize(
"""
"""
key:
if 1.1.1: value""")
def test_expr_10(self):
self.compare(
"""
self.compare("""
key:
if 1.: value""",
[(token_types.string, "key"),

View file

@ -307,7 +307,8 @@ def main():
return start(**kwargs)
except Exception:
if kwargs["pdb"]:
import pdb, traceback
import pdb
import traceback
print traceback.format_exc()
pdb.post_mortem()
else:

View file

@ -356,7 +356,7 @@ class ReftestTest(Test):
return node
def update_metadata(self, metadata):
if not "url_count" in metadata:
if "url_count" not in metadata:
metadata["url_count"] = defaultdict(int)
for reference, _ in self.references:
# We assume a naive implementation in which a url with multiple

View file

@ -12,8 +12,8 @@ This would serve bytes 1 to 199, inclusive, of foo.txt with the HTTP status
code 404.
.. note::
Pipes are only applied to static files, and will not work if applied to
other types of handlers, such as Python File Handlers.
If you write directly to the response socket using ResponseWriter,
or when using the asis handler, only the trickle pipe will affect the response.
There are several built-in pipe functions, and it is possible to add
more using the `@pipe` decorator on a function, if required.

View file

@ -1,9 +1,11 @@
import os
import unittest
import time
import json
import pytest
wptserve = pytest.importorskip("wptserve")
from .base import TestUsingServer, doc_root
@ -82,5 +84,72 @@ class TestTrickle(TestUsingServer):
self.assertEqual(resp.info()["Pragma"], "no-cache")
self.assertEqual(resp.info()["Expires"], "0")
class TestPipesWithVariousHandlers(TestUsingServer):
def test_with_python_file_handler(self):
resp = self.request("/test_string.py", query="pipe=slice(null,2)")
self.assertEqual(resp.read(), "PA")
def test_with_python_func_handler(self):
@wptserve.handlers.handler
def handler(request, response):
return "PASS"
route = ("GET", "/test/test_pipes_1/", handler)
self.server.router.register(*route)
resp = self.request(route[1], query="pipe=slice(null,2)")
self.assertEqual(resp.read(), "PA")
def test_with_python_func_handler_using_response_writer(self):
@wptserve.handlers.handler
def handler(request, response):
response.writer.write_content("PASS")
route = ("GET", "/test/test_pipes_1/", handler)
self.server.router.register(*route)
resp = self.request(route[1], query="pipe=slice(null,2)")
# slice has not been applied to the response, because response.writer was used.
self.assertEqual(resp.read(), "PASS")
def test_header_pipe_with_python_func_using_response_writer(self):
@wptserve.handlers.handler
def handler(request, response):
response.writer.write_content("CONTENT")
route = ("GET", "/test/test_pipes_1/", handler)
self.server.router.register(*route)
resp = self.request(route[1], query="pipe=header(X-TEST,FAIL)")
# header pipe was ignored, because response.writer was used.
self.assertFalse(resp.info().get("X-TEST"))
self.assertEqual(resp.read(), "CONTENT")
def test_with_json_handler(self):
@wptserve.handlers.json_handler
def handler(request, response):
return json.dumps({'data': 'PASS'})
route = ("GET", "/test/test_pipes_2/", handler)
self.server.router.register(*route)
resp = self.request(route[1], query="pipe=slice(null,2)")
self.assertEqual(resp.read(), '"{')
def test_slice_with_as_is_handler(self):
resp = self.request("/test.asis", query="pipe=slice(null,2)")
self.assertEqual(202, resp.getcode())
self.assertEqual("Giraffe", resp.msg)
self.assertEqual("PASS", resp.info()["X-Test"])
# slice has not been applied to the response, because response.writer was used.
self.assertEqual("Content", resp.read())
def test_headers_with_as_is_handler(self):
resp = self.request("/test.asis", query="pipe=header(X-TEST,FAIL)")
self.assertEqual(202, resp.getcode())
self.assertEqual("Giraffe", resp.msg)
# header pipe was ignored.
self.assertEqual("PASS", resp.info()["X-TEST"])
self.assertEqual("Content", resp.read())
def test_trickle_with_as_is_handler(self):
t0 = time.time()
resp = self.request("/test.asis", query="pipe=trickle(1:d2:5:d1:r2)")
t1 = time.time()
self.assertTrue('Content' in resp.read())
self.assertGreater(6, t1-t0)
if __name__ == '__main__':
unittest.main()

View file

@ -237,6 +237,7 @@ class PythonScriptHandler(object):
if "main" in environ:
handler = FunctionHandler(environ["main"])
handler(request, response)
wrap_pipeline(path, request, response)
else:
raise HTTPException(500, "No main function in script %s" % path)
except IOError:
@ -267,6 +268,7 @@ class FunctionHandler(object):
else:
content = rv
response.content = content
wrap_pipeline('', request, response)
#The generic name here is so that this can be used as a decorator
@ -309,6 +311,7 @@ class AsIsHandler(object):
try:
with open(path) as f:
response.writer.write_content(f.read())
wrap_pipeline(path, request, response)
response.close_connection = True
except IOError:
raise HTTPException(404)

View file

@ -6,6 +6,7 @@ import types
import uuid
from cStringIO import StringIO
from six import text_type
def resolve_content(response):
return b"".join(item for item in response.iter_content(read_file=True))
@ -276,18 +277,18 @@ def slice(request, response, start, end=None):
class ReplacementTokenizer(object):
def ident(scanner, token):
def ident(self, token):
return ("ident", token)
def index(scanner, token):
def index(self, token):
token = token[1:-1]
try:
token = int(token)
except ValueError:
token = unicode(token, "utf8")
token = token.decode('utf8')
return ("index", token)
def var(scanner, token):
def var(self, token):
token = token[:-1]
return ("var", token)
@ -425,7 +426,7 @@ def template(request, content, escape_type="html"):
#Should possibly support escaping for other contexts e.g. script
#TODO: read the encoding of the response
return escape_func(unicode(value)).encode("utf-8")
return escape_func(text_type(value)).encode("utf-8")
template_regexp = re.compile(r"{{([^}]*)}}")
new_content = template_regexp.sub(config_replacement, content)

View file

@ -9,6 +9,8 @@ import socket
from .constants import response_codes
from .logger import get_logger
from six import string_types, binary_type, text_type
missing = object()
class Response(object):
@ -400,7 +402,7 @@ class ResponseWriter(object):
if name.lower() not in self._headers_seen:
self.write_header(name, f())
if (type(self._response.content) in (str, unicode) and
if (isinstance(self._response.content, string_types) and
"content-length" not in self._headers_seen):
#Would be nice to avoid double-encoding here
self.write_header("Content-Length", len(self.encode(self._response.content)))
@ -457,9 +459,9 @@ class ResponseWriter(object):
def encode(self, data):
"""Convert unicode to bytes according to response.encoding."""
if isinstance(data, str):
if isinstance(data, binary_type):
return data
elif isinstance(data, unicode):
elif isinstance(data, text_type):
return data.encode(self._response.encoding)
else:
raise ValueError

View file

@ -110,14 +110,15 @@ class WebTestServer(ThreadingMixIn, BaseHTTPServer.HTTPServer):
# Ensure that we don't hang on shutdown waiting for requests
daemon_threads = True
def __init__(self, server_address, RequestHandlerClass, router, rewriter, bind_hostname,
def __init__(self, server_address, request_handler_cls,
router, rewriter, bind_hostname,
config=None, use_ssl=False, key_file=None, certificate=None,
encrypt_after_connect=False, latency=None, **kwargs):
"""Server for HTTP(s) Requests
:param server_address: tuple of (server_name, port)
:param RequestHandlerClass: BaseHTTPRequestHandler-like class to use for
:param request_handler_cls: BaseHTTPRequestHandler-like class to use for
handling requests.
:param router: Router instance to use for matching requests to handler
@ -161,7 +162,7 @@ class WebTestServer(ThreadingMixIn, BaseHTTPServer.HTTPServer):
hostname_port = ("",server_address[1])
#super doesn't work here because BaseHTTPServer.HTTPServer is old-style
BaseHTTPServer.HTTPServer.__init__(self, hostname_port, RequestHandlerClass, **kwargs)
BaseHTTPServer.HTTPServer.__init__(self, hostname_port, request_handler_cls, **kwargs)
if config is not None:
Server.config = config

View file

@ -2,7 +2,8 @@ import base64
import json
import os
import uuid
from multiprocessing.managers import BaseManager, DictProxy
import threading
from multiprocessing.managers import AcquirerProxy, BaseManager, DictProxy
class ServerDictManager(BaseManager):
shared_data = {}
@ -13,11 +14,13 @@ def _get_shared():
ServerDictManager.register("get_dict",
callable=_get_shared,
proxytype=DictProxy)
ServerDictManager.register('Lock', threading.Lock, AcquirerProxy)
class ClientDictManager(BaseManager):
pass
ClientDictManager.register("get_dict")
ClientDictManager.register("Lock")
class StashServer(object):
def __init__(self, address=None, authkey=None):
@ -53,6 +56,22 @@ def start_server(address=None, authkey=None):
return (manager, manager._address, manager._authkey)
class LockWrapper(object):
def __init__(self, lock):
self.lock = lock
def acquire(self):
self.lock.acquire()
def release(self):
self.lock.release()
def __enter__(self):
self.acquire()
def __exit__(self, *args, **kwargs):
self.release()
#TODO: Consider expiring values after some fixed time for long-running
#servers
@ -81,21 +100,23 @@ class Stash(object):
"""
_proxy = None
lock = None
def __init__(self, default_path, address=None, authkey=None):
self.default_path = default_path
self.data = self._get_proxy(address, authkey)
self._get_proxy(address, authkey)
self.data = Stash._proxy
def _get_proxy(self, address=None, authkey=None):
if address is None and authkey is None:
Stash._proxy = {}
Stash.lock = threading.Lock()
if Stash._proxy is None:
manager = ClientDictManager(address, authkey)
manager.connect()
Stash._proxy = manager.get_dict()
return Stash._proxy
Stash.lock = LockWrapper(manager.Lock())
def _wrap_key(self, key, path):
if path is None: