aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--python/mach_bootstrap.py2
-rw-r--r--python/servo/devenv_commands.py26
-rw-r--r--tests/wpt/README.md14
-rw-r--r--tests/wpt/harness/.gitignore7
-rw-r--r--tests/wpt/harness/.travis.yml20
-rw-r--r--tests/wpt/harness/MANIFEST.in13
-rw-r--r--tests/wpt/harness/README.rst242
-rw-r--r--tests/wpt/harness/docs/Makefile177
-rw-r--r--tests/wpt/harness/docs/architecture.svg1
-rw-r--r--tests/wpt/harness/docs/conf.py267
-rw-r--r--tests/wpt/harness/docs/design.rst106
-rw-r--r--tests/wpt/harness/docs/expectation.rst248
-rw-r--r--tests/wpt/harness/docs/index.rst24
-rw-r--r--tests/wpt/harness/docs/make.bat242
-rw-r--r--tests/wpt/harness/docs/usage.rst238
-rw-r--r--tests/wpt/harness/requirements.txt4
-rw-r--r--tests/wpt/harness/requirements_b2g.txt7
-rw-r--r--tests/wpt/harness/requirements_chrome.txt2
-rw-r--r--tests/wpt/harness/requirements_firefox.txt5
-rw-r--r--tests/wpt/harness/requirements_servo.txt1
-rw-r--r--tests/wpt/harness/setup.py73
-rw-r--r--tests/wpt/harness/test/metadata/reftest/reftest_and_fail.html.ini3
-rw-r--r--tests/wpt/harness/test/metadata/reftest/reftest_cycle_fail.html.ini3
-rw-r--r--tests/wpt/harness/test/metadata/reftest/reftest_match_fail.html.ini3
-rw-r--r--tests/wpt/harness/test/metadata/reftest/reftest_mismatch_fail.html.ini3
-rw-r--r--tests/wpt/harness/test/metadata/reftest/reftest_ref_timeout.html.ini3
-rw-r--r--tests/wpt/harness/test/metadata/reftest/reftest_timeout.html.ini3
-rw-r--r--tests/wpt/harness/test/metadata/testharness/firefox/__dir__.ini2
-rw-r--r--tests/wpt/harness/test/metadata/testharness/firefox/subdir/test_pref_reset.html.ini3
-rw-r--r--tests/wpt/harness/test/metadata/testharness/firefox/test_pref_set.html.ini4
-rw-r--r--tests/wpt/harness/test/metadata/testharness/subdir/__dir__.ini1
-rw-r--r--tests/wpt/harness/test/metadata/testharness/subdir/testharness_1.html.ini3
-rw-r--r--tests/wpt/harness/test/metadata/testharness/tags/__dir__.ini1
-rw-r--r--tests/wpt/harness/test/metadata/testharness/tags/testharness_0.html.ini5
-rw-r--r--tests/wpt/harness/test/metadata/testharness/tags/testharness_1.html.ini3
-rw-r--r--tests/wpt/harness/test/metadata/testharness/tags/testharness_2.html.ini5
-rw-r--r--tests/wpt/harness/test/metadata/testharness/testharness_0.html.ini4
-rw-r--r--tests/wpt/harness/test/metadata/testharness/testharness_error.html.ini3
-rw-r--r--tests/wpt/harness/test/metadata/testharness/testharness_timeout.html.ini3
-rw-r--r--tests/wpt/harness/test/test.cfg.example20
-rw-r--r--tests/wpt/harness/test/test.py166
-rw-r--r--tests/wpt/harness/test/testdata/reftest/green-ref.html4
-rw-r--r--tests/wpt/harness/test/testdata/reftest/green.html3
-rw-r--r--tests/wpt/harness/test/testdata/reftest/red.html3
-rw-r--r--tests/wpt/harness/test/testdata/reftest/reftest.https.html9
-rw-r--r--tests/wpt/harness/test/testdata/reftest/reftest_and_fail.html5
-rw-r--r--tests/wpt/harness/test/testdata/reftest/reftest_and_fail_0-ref.html5
-rw-r--r--tests/wpt/harness/test/testdata/reftest/reftest_cycle.html5
-rw-r--r--tests/wpt/harness/test/testdata/reftest/reftest_cycle_0-ref.html5
-rw-r--r--tests/wpt/harness/test/testdata/reftest/reftest_cycle_1-ref.html5
-rw-r--r--tests/wpt/harness/test/testdata/reftest/reftest_cycle_fail.html5
-rw-r--r--tests/wpt/harness/test/testdata/reftest/reftest_cycle_fail_0-ref.html5
-rw-r--r--tests/wpt/harness/test/testdata/reftest/reftest_match.html5
-rw-r--r--tests/wpt/harness/test/testdata/reftest/reftest_match_fail.html5
-rw-r--r--tests/wpt/harness/test/testdata/reftest/reftest_mismatch.html5
-rw-r--r--tests/wpt/harness/test/testdata/reftest/reftest_mismatch_fail.html5
-rw-r--r--tests/wpt/harness/test/testdata/reftest/reftest_or_0.html6
-rw-r--r--tests/wpt/harness/test/testdata/reftest/reftest_ref_timeout-ref.html6
-rw-r--r--tests/wpt/harness/test/testdata/reftest/reftest_ref_timeout.html6
-rw-r--r--tests/wpt/harness/test/testdata/reftest/reftest_timeout.html6
-rw-r--r--tests/wpt/harness/test/testdata/reftest/reftest_wait_0.html11
-rw-r--r--tests/wpt/harness/test/testdata/testharness/firefox/subdir/test_pref_inherit.html10
-rw-r--r--tests/wpt/harness/test/testdata/testharness/firefox/subdir/test_pref_reset.html10
-rw-r--r--tests/wpt/harness/test/testdata/testharness/firefox/test_pref_dir.html10
-rw-r--r--tests/wpt/harness/test/testdata/testharness/firefox/test_pref_set.html10
-rw-r--r--tests/wpt/harness/test/testdata/testharness/subdir/testharness_1.html9
-rw-r--r--tests/wpt/harness/test/testdata/testharness/tags/testharness_0.html9
-rw-r--r--tests/wpt/harness/test/testdata/testharness/tags/testharness_1.html9
-rw-r--r--tests/wpt/harness/test/testdata/testharness/tags/testharness_2.html9
-rw-r--r--tests/wpt/harness/test/testdata/testharness/testharness.https.html10
-rw-r--r--tests/wpt/harness/test/testdata/testharness/testharness_0.html9
-rw-r--r--tests/wpt/harness/test/testdata/testharness/testharness_error.html7
-rw-r--r--tests/wpt/harness/test/testdata/testharness/testharness_long_timeout.html9
-rw-r--r--tests/wpt/harness/test/testdata/testharness/testharness_timeout.html6
-rw-r--r--tests/wpt/harness/tox.ini15
-rw-r--r--tests/wpt/harness/wptrunner.default.ini11
-rw-r--r--tests/wpt/harness/wptrunner/__init__.py3
-rw-r--r--tests/wpt/harness/wptrunner/browsers/__init__.py33
-rw-r--r--tests/wpt/harness/wptrunner/browsers/b2g.py243
-rw-r--r--tests/wpt/harness/wptrunner/browsers/b2g_setup/certtest_app.zipbin1237 -> 0 bytes
-rw-r--r--tests/wpt/harness/wptrunner/browsers/base.py160
-rw-r--r--tests/wpt/harness/wptrunner/browsers/chrome.py81
-rw-r--r--tests/wpt/harness/wptrunner/browsers/edge.py71
-rw-r--r--tests/wpt/harness/wptrunner/browsers/firefox.py264
-rw-r--r--tests/wpt/harness/wptrunner/browsers/server-locations.txt38
-rw-r--r--tests/wpt/harness/wptrunner/browsers/servo.py84
-rw-r--r--tests/wpt/harness/wptrunner/browsers/servodriver.py162
-rw-r--r--tests/wpt/harness/wptrunner/browsers/webdriver.py137
-rw-r--r--tests/wpt/harness/wptrunner/config.json7
-rw-r--r--tests/wpt/harness/wptrunner/config.py64
-rw-r--r--tests/wpt/harness/wptrunner/environment.py212
-rw-r--r--tests/wpt/harness/wptrunner/executors/__init__.py8
-rw-r--r--tests/wpt/harness/wptrunner/executors/base.py329
-rw-r--r--tests/wpt/harness/wptrunner/executors/executormarionette.py561
-rw-r--r--tests/wpt/harness/wptrunner/executors/executorselenium.py263
-rw-r--r--tests/wpt/harness/wptrunner/executors/executorservo.py372
-rw-r--r--tests/wpt/harness/wptrunner/executors/executorservodriver.py261
-rw-r--r--tests/wpt/harness/wptrunner/executors/process.py24
-rw-r--r--tests/wpt/harness/wptrunner/executors/pytestrunner/__init__.py6
-rw-r--r--tests/wpt/harness/wptrunner/executors/pytestrunner/fixtures.py136
-rw-r--r--tests/wpt/harness/wptrunner/executors/pytestrunner/runner.py114
-rw-r--r--tests/wpt/harness/wptrunner/executors/reftest-wait.js22
-rw-r--r--tests/wpt/harness/wptrunner/executors/reftest-wait_servodriver.js20
-rw-r--r--tests/wpt/harness/wptrunner/executors/reftest-wait_webdriver.js23
-rw-r--r--tests/wpt/harness/wptrunner/executors/reftest.js5
-rw-r--r--tests/wpt/harness/wptrunner/executors/testharness_marionette.js36
-rw-r--r--tests/wpt/harness/wptrunner/executors/testharness_servodriver.js6
-rw-r--r--tests/wpt/harness/wptrunner/executors/testharness_webdriver.js33
-rw-r--r--tests/wpt/harness/wptrunner/executors/webdriver.py642
-rw-r--r--tests/wpt/harness/wptrunner/expected.py18
-rw-r--r--tests/wpt/harness/wptrunner/hosts.py104
-rw-r--r--tests/wpt/harness/wptrunner/manifestexpected.py256
-rw-r--r--tests/wpt/harness/wptrunner/manifestinclude.py144
-rw-r--r--tests/wpt/harness/wptrunner/manifestupdate.py453
-rw-r--r--tests/wpt/harness/wptrunner/metadata.py353
-rw-r--r--tests/wpt/harness/wptrunner/products.py72
-rw-r--r--tests/wpt/harness/wptrunner/reduce.py197
-rw-r--r--tests/wpt/harness/wptrunner/testharness_runner.html6
-rw-r--r--tests/wpt/harness/wptrunner/testharnessreport-servo.js21
-rw-r--r--tests/wpt/harness/wptrunner/testharnessreport-servodriver.js27
-rw-r--r--tests/wpt/harness/wptrunner/testharnessreport.js17
-rw-r--r--tests/wpt/harness/wptrunner/testloader.py621
-rw-r--r--tests/wpt/harness/wptrunner/testrunner.py672
-rw-r--r--tests/wpt/harness/wptrunner/tests/__init__.py3
-rw-r--r--tests/wpt/harness/wptrunner/tests/test_chunker.py86
-rw-r--r--tests/wpt/harness/wptrunner/tests/test_hosts.py60
-rw-r--r--tests/wpt/harness/wptrunner/tests/test_update.py332
-rw-r--r--tests/wpt/harness/wptrunner/update/__init__.py51
-rw-r--r--tests/wpt/harness/wptrunner/update/base.py69
-rw-r--r--tests/wpt/harness/wptrunner/update/metadata.py75
-rw-r--r--tests/wpt/harness/wptrunner/update/state.py137
-rw-r--r--tests/wpt/harness/wptrunner/update/sync.py181
-rw-r--r--tests/wpt/harness/wptrunner/update/tree.py387
-rw-r--r--tests/wpt/harness/wptrunner/update/update.py158
-rw-r--r--tests/wpt/harness/wptrunner/vcs.py53
-rw-r--r--tests/wpt/harness/wptrunner/webdriver_server.py238
-rw-r--r--tests/wpt/harness/wptrunner/wptcommandline.py427
-rw-r--r--tests/wpt/harness/wptrunner/wptlogging.py125
-rw-r--r--tests/wpt/harness/wptrunner/wptmanifest/__init__.py8
-rw-r--r--tests/wpt/harness/wptrunner/wptmanifest/backends/__init__.py3
-rw-r--r--tests/wpt/harness/wptrunner/wptmanifest/backends/conditional.py331
-rw-r--r--tests/wpt/harness/wptrunner/wptmanifest/backends/static.py224
-rw-r--r--tests/wpt/harness/wptrunner/wptmanifest/node.py161
-rw-r--r--tests/wpt/harness/wptrunner/wptmanifest/parser.py750
-rw-r--r--tests/wpt/harness/wptrunner/wptmanifest/serializer.py140
-rw-r--r--tests/wpt/harness/wptrunner/wptmanifest/tests/__init__.py3
-rw-r--r--tests/wpt/harness/wptrunner/wptmanifest/tests/test_conditional.py147
-rw-r--r--tests/wpt/harness/wptrunner/wptmanifest/tests/test_parser.py79
-rw-r--r--tests/wpt/harness/wptrunner/wptmanifest/tests/test_serializer.py231
-rw-r--r--tests/wpt/harness/wptrunner/wptmanifest/tests/test_static.py102
-rw-r--r--tests/wpt/harness/wptrunner/wptmanifest/tests/test_tokenizer.py361
-rw-r--r--tests/wpt/harness/wptrunner/wptrunner.py248
-rw-r--r--tests/wpt/harness/wptrunner/wpttest.py329
-rw-r--r--tests/wpt/run.py2
-rw-r--r--tests/wpt/update/__init__.py2
-rw-r--r--tests/wpt/update_css.py2
-rw-r--r--tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/executors/executorservo.py1
157 files changed, 4 insertions, 15095 deletions
diff --git a/python/mach_bootstrap.py b/python/mach_bootstrap.py
index f34689993a7..889a63f312c 100644
--- a/python/mach_bootstrap.py
+++ b/python/mach_bootstrap.py
@@ -115,7 +115,7 @@ def wpt_harness_path(is_firefox, topdir, *paths):
if is_firefox:
rel = os.path.join(wpt_root, "tests", "tools", "wptrunner")
else:
- rel = os.path.join(wpt_root, "harness")
+ rel = os.path.join(wpt_root, "web-platform-tests", "tools", "wptrunner")
return os.path.join(topdir, rel, *paths)
diff --git a/python/servo/devenv_commands.py b/python/servo/devenv_commands.py
index 804e7e1c425..49fe355c54b 100644
--- a/python/servo/devenv_commands.py
+++ b/python/servo/devenv_commands.py
@@ -285,29 +285,3 @@ class MachCommands(CommandBase):
# Fetch Cargo dependencies
with cd(self.context.topdir):
call(["cargo", "fetch"], env=self.build_env())
-
- @Command('wptrunner-upgrade',
- description='upgrade wptrunner.',
- category='devenv')
- def upgrade_wpt_runner(self):
- env = self.build_env()
- with cd(path.join(self.context.topdir, 'tests', 'wpt', 'harness')):
- code = call(["git", "init"], env=env)
- if code:
- return code
- # No need to report an error if this fails, as it will for the first use
- call(["git", "remote", "rm", "upstream"], env=env)
- code = call(
- ["git", "remote", "add", "upstream", "https://github.com/w3c/wptrunner.git"], env=env)
- if code:
- return code
- code = call(["git", "fetch", "upstream"], env=env)
- if code:
- return code
- code = call(["git", "reset", "--hard", "remotes/upstream/master"], env=env)
- if code:
- return code
- code = call(["rm", "-rf", ".git"], env=env)
- if code:
- return code
- return 0
diff --git a/tests/wpt/README.md b/tests/wpt/README.md
index 1c01473bd71..5dacaade2f8 100644
--- a/tests/wpt/README.md
+++ b/tests/wpt/README.md
@@ -186,20 +186,6 @@ This should create two commits in your servo repository with the
updated tests and updated metadata. The same process works for the
CSSWG tests, using the `update-css` and `test-css` mach commands.
-Updating the test harness
-=========================
-
-The easiest way to update the test harness is using git:
-
- cd tests/wpt/harness
- git init .
- git remote add origin https://github.com/w3c/wptrunner
- git fetch origin
- git checkout -f origin/master
- cd ../../..
-
-At this point you should commit the updated files in the *servo* git repository.
-
Servo-specific tests
====================
diff --git a/tests/wpt/harness/.gitignore b/tests/wpt/harness/.gitignore
deleted file mode 100644
index b48badadf8c..00000000000
--- a/tests/wpt/harness/.gitignore
+++ /dev/null
@@ -1,7 +0,0 @@
-*.py[co]
-*~
-*#
-\#*
-_virtualenv
-test/test.cfg
-test/metadata/MANIFEST.json
diff --git a/tests/wpt/harness/.travis.yml b/tests/wpt/harness/.travis.yml
deleted file mode 100644
index add6efd12ca..00000000000
--- a/tests/wpt/harness/.travis.yml
+++ /dev/null
@@ -1,20 +0,0 @@
-language: python
-python: 2.7
-
-sudo: false
-
-cache:
- directories:
- - $HOME/.cache/pip
-
-env:
- - TOXENV="{py27,pypy}-base"
- - TOXENV="{py27,pypy}-chrome"
- - TOXENV="{py27,pypy}-firefox"
- - TOXENV="{py27,pypy}-servo"
-
-install:
- - pip install -U tox
-
-script:
- - tox
diff --git a/tests/wpt/harness/MANIFEST.in b/tests/wpt/harness/MANIFEST.in
deleted file mode 100644
index ac7ad5cdc74..00000000000
--- a/tests/wpt/harness/MANIFEST.in
+++ /dev/null
@@ -1,13 +0,0 @@
-exclude MANIFEST.in
-include requirements.txt
-include wptrunner/browsers/b2g_setup/*
-include wptrunner.default.ini
-include wptrunner/testharness_runner.html
-include wptrunner/testharnessreport.js
-include wptrunner/testharnessreport-servo.js
-include wptrunner/executors/testharness_marionette.js
-include wptrunner/executors/testharness_webdriver.js
-include wptrunner/executors/reftest.js
-include wptrunner/executors/reftest-wait.js
-include wptrunner/config.json
-include wptrunner/browsers/server-locations.txt \ No newline at end of file
diff --git a/tests/wpt/harness/README.rst b/tests/wpt/harness/README.rst
deleted file mode 100644
index fc650eec45a..00000000000
--- a/tests/wpt/harness/README.rst
+++ /dev/null
@@ -1,242 +0,0 @@
-wptrunner: A web-platform-tests harness
-=======================================
-
-wptrunner is a harness for running the W3C `web-platform-tests testsuite`_.
-
-.. contents::
-
-Installation
-~~~~~~~~~~~~
-
-wptrunner is expected to be installed into a virtualenv using pip. For
-development, it can be installed using the `-e` option::
-
- pip install -e ./
-
-Running the Tests
-~~~~~~~~~~~~~~~~~
-
-After installation, the command ``wptrunner`` should be available to run
-the tests.
-
-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`.
-
-``--binary`` (required if product is `firefox` or `servo`)
- The path to a binary file for the product (browser) to test against.
-
-``--webdriver-binary`` (required if product is `chrome`)
- The path to a `driver` binary; e.g., a `chromedriver` binary.
-
-``--certutil-binary`` (required if product is `firefox` [#]_)
- The path to a `certutil` binary (for tests that must be run over https).
-
-``--metadata`` (required)
- The path to a directory containing test metadata. [#]_
-
-``--tests`` (required)
- The path to a directory containing a web-platform-tests checkout.
-
-``--prefs-root`` (required only when testing a Firefox binary)
- The path to a directory containing Firefox test-harness preferences. [#]_
-
-``--config`` (should default to `wptrunner.default.ini`)
- The path to the config (ini) file.
-
-.. [#] The ``--certutil-binary`` option is required when the product is
- ``firefox`` unless ``--ssl-type=none`` is specified.
-
-.. [#] The ``--metadata`` path is to a directory that contains:
-
- * a ``MANIFEST.json`` file (instructions on generating this file are
- available in the `detailed documentation
- <http://wptrunner.readthedocs.org/en/latest/usage.html#installing-wptrunner>`_);
- and
- * (optionally) any expectation files (see below)
-
-.. [#] Example ``--prefs-root`` value: ``~/mozilla-central/testing/profiles``.
-
-There are also a variety of other options available; use ``--help`` to
-list them.
-
--------------------------------
-Example: How to start wptrunner
--------------------------------
-
-To test a Firefox Nightly build in an OS X environment, you might start
-wptrunner using something similar to the following example::
-
- wptrunner --metadata=~/web-platform-tests/ --tests=~/web-platform-tests/ \
- --binary=~/mozilla-central/obj-x86_64-apple-darwin14.3.0/dist/Nightly.app/Contents/MacOS/firefox \
- --certutil-binary=~/mozilla-central/obj-x86_64-apple-darwin14.3.0/security/nss/cmd/certutil/certutil \
- --prefs-root=~/mozilla-central/testing/profiles
-
-And to test a Chromium build in an OS X environment, you might start
-wptrunner using something similar to the following example::
-
- wptrunner --metadata=~/web-platform-tests/ --tests=~/web-platform-tests/ \
- --binary=~/chromium/src/out/Release/Chromium.app/Contents/MacOS/Chromium \
- --webdriver-binary=/usr/local/bin/chromedriver --product=chrome
-
--------------------------------------
-Example: How to run a subset of tests
--------------------------------------
-
-To restrict a test run just to tests in a particular web-platform-tests
-subdirectory, specify the directory name in the positional arguments after
-the options; for example, run just the tests in the `dom` subdirectory::
-
- wptrunner --metadata=~/web-platform-tests/ --tests=~/web-platform-tests/ \
- --binary=/path/to/firefox --certutil-binary=/path/to/certutil \
- --prefs-root=/path/to/testing/profiles \
- dom
-
-Output
-~~~~~~
-
-By default wptrunner just dumps its entire output as raw JSON messages
-to stdout. This is convenient for piping into other tools, but not ideal
-for humans reading the output.
-
-As an alternative, you can use the ``--log-mach`` option, which provides
-output in a reasonable format for humans. The option requires a value:
-either the path for a file to write the `mach`-formatted output to, or
-"`-`" (a hyphen) to write the `mach`-formatted output to stdout.
-
-When using ``--log-mach``, output of the full raw JSON log is still
-available, from the ``--log-raw`` option. So to output the full raw JSON
-log to a file and a human-readable summary to stdout, you might start
-wptrunner using something similar to the following example::
-
- wptrunner --metadata=~/web-platform-tests/ --tests=~/web-platform-tests/ \
- --binary=/path/to/firefox --certutil-binary=/path/to/certutil \
- --prefs-root=/path/to/testing/profiles \
- --log-raw=output.log --log-mach=-
-
-Expectation Data
-~~~~~~~~~~~~~~~~
-
-wptrunner is designed to be used in an environment where it is not
-just necessary to know which tests passed, but to compare the results
-between runs. For this reason it is possible to store the results of a
-previous run in a set of ini-like "expectation files". This format is
-documented below. To generate the expectation files use `wptrunner` with
-the `--log-raw=/path/to/log/file` option. This can then be used as
-input to the `wptupdate` tool.
-
-Expectation File Format
-~~~~~~~~~~~~~~~~~~~~~~~
-
-Metadata about tests, notably including their expected results, is
-stored in a modified ini-like format that is designed to be human
-editable, but also to be machine updatable.
-
-Each test file that requires metadata to be specified (because it has
-a non-default expectation or because it is disabled, for example) has
-a corresponding expectation file in the `metadata` directory. For
-example a test file `html/test1.html` containing a failing test would
-have an expectation file called `html/test1.html.ini` in the
-`metadata` directory.
-
-An example of an expectation file is::
-
- example_default_key: example_value
-
- [filename.html]
- type: testharness
-
- [subtest1]
- expected: FAIL
-
- [subtest2]
- expected:
- if platform == 'win': TIMEOUT
- if platform == 'osx': ERROR
- FAIL
-
- [filename.html?query=something]
- type: testharness
- disabled: bug12345
-
-The file consists of two elements, key-value pairs and
-sections.
-
-Sections are delimited by headings enclosed in square brackets. Any
-closing square bracket in the heading itself my be escaped with a
-backslash. Each section may then contain any number of key-value pairs
-followed by any number of subsections. So that it is clear which data
-belongs to each section without the use of end-section markers, the
-data for each section (i.e. the key-value pairs and subsections) must
-be indented using spaces. Indentation need only be consistent, but
-using two spaces per level is recommended.
-
-In a test expectation file, each resource provided by the file has a
-single section, with the section heading being the part after the last
-`/` in the test url. Tests that have subsections may have subsections
-for those subtests in which the heading is the name of the subtest.
-
-Simple key-value pairs are of the form::
-
- key: value
-
-Note that unlike ini files, only `:` is a valid seperator; `=` will
-not work as expected. Key-value pairs may also have conditional
-values of the form::
-
- key:
- if condition1: value1
- if condition2: value2
- default
-
-In this case each conditional is evaluated in turn and the value is
-that on the right hand side of the first matching conditional. In the
-case that no condition matches, the unconditional default is used. If
-no condition matches and no default is provided it is equivalent to
-the key not being present. Conditionals use a simple python-like expression
-language e.g.::
-
- if debug and (platform == "linux" or platform == "osx"): FAIL
-
-For test expectations the avaliable variables are those in the
-`run_info` which for desktop are `version`, `os`, `bits`, `processor`,
-`debug` and `product`.
-
-Key-value pairs specified at the top level of the file before any
-sections are special as they provide defaults for the rest of the file
-e.g.::
-
- key1: value1
-
- [section 1]
- key2: value2
-
- [section 2]
- key1: value3
-
-In this case, inside section 1, `key1` would have the value `value1`
-and `key2` the value `value2` whereas in section 2 `key1` would have
-the value `value3` and `key2` would be undefined.
-
-The web-platform-test harness knows about several keys:
-
-`expected`
- Must evaluate to a possible test status indicating the expected
- result of the test. The implicit default is PASS or OK when the
- field isn't present.
-
-`disabled`
- Any value indicates that the test is disabled.
-
-`type`
- The test type e.g. `testharness`, `reftest`, or `wdspec`.
-
-`reftype`
- The type of comparison for reftests; either `==` or `!=`.
-
-`refurl`
- The reference url for reftests.
-
-.. _`web-platform-tests testsuite`: https://github.com/w3c/web-platform-tests
diff --git a/tests/wpt/harness/docs/Makefile b/tests/wpt/harness/docs/Makefile
deleted file mode 100644
index d02b6c5e7c4..00000000000
--- a/tests/wpt/harness/docs/Makefile
+++ /dev/null
@@ -1,177 +0,0 @@
-# Makefile for Sphinx documentation
-#
-
-# You can set these variables from the command line.
-SPHINXOPTS =
-SPHINXBUILD = sphinx-build
-PAPER =
-BUILDDIR = _build
-
-# User-friendly check for sphinx-build
-ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
-$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
-endif
-
-# Internal variables.
-PAPEROPT_a4 = -D latex_paper_size=a4
-PAPEROPT_letter = -D latex_paper_size=letter
-ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
-# the i18n builder cannot share the environment and doctrees with the others
-I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
-
-.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
-
-help:
- @echo "Please use \`make <target>' where <target> is one of"
- @echo " html to make standalone HTML files"
- @echo " dirhtml to make HTML files named index.html in directories"
- @echo " singlehtml to make a single large HTML file"
- @echo " pickle to make pickle files"
- @echo " json to make JSON files"
- @echo " htmlhelp to make HTML files and a HTML help project"
- @echo " qthelp to make HTML files and a qthelp project"
- @echo " devhelp to make HTML files and a Devhelp project"
- @echo " epub to make an epub"
- @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
- @echo " latexpdf to make LaTeX files and run them through pdflatex"
- @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
- @echo " text to make text files"
- @echo " man to make manual pages"
- @echo " texinfo to make Texinfo files"
- @echo " info to make Texinfo files and run them through makeinfo"
- @echo " gettext to make PO message catalogs"
- @echo " changes to make an overview of all changed/added/deprecated items"
- @echo " xml to make Docutils-native XML files"
- @echo " pseudoxml to make pseudoxml-XML files for display purposes"
- @echo " linkcheck to check all external links for integrity"
- @echo " doctest to run all doctests embedded in the documentation (if enabled)"
-
-clean:
- rm -rf $(BUILDDIR)/*
-
-html:
- $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
- @echo
- @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
-
-dirhtml:
- $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
- @echo
- @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
-
-singlehtml:
- $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
- @echo
- @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
-
-pickle:
- $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
- @echo
- @echo "Build finished; now you can process the pickle files."
-
-json:
- $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
- @echo
- @echo "Build finished; now you can process the JSON files."
-
-htmlhelp:
- $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
- @echo
- @echo "Build finished; now you can run HTML Help Workshop with the" \
- ".hhp project file in $(BUILDDIR)/htmlhelp."
-
-qthelp:
- $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
- @echo
- @echo "Build finished; now you can run "qcollectiongenerator" with the" \
- ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
- @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/wptrunner.qhcp"
- @echo "To view the help file:"
- @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/wptrunner.qhc"
-
-devhelp:
- $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
- @echo
- @echo "Build finished."
- @echo "To view the help file:"
- @echo "# mkdir -p $$HOME/.local/share/devhelp/wptrunner"
- @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/wptrunner"
- @echo "# devhelp"
-
-epub:
- $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
- @echo
- @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
-
-latex:
- $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
- @echo
- @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
- @echo "Run \`make' in that directory to run these through (pdf)latex" \
- "(use \`make latexpdf' here to do that automatically)."
-
-latexpdf:
- $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
- @echo "Running LaTeX files through pdflatex..."
- $(MAKE) -C $(BUILDDIR)/latex all-pdf
- @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
-
-latexpdfja:
- $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
- @echo "Running LaTeX files through platex and dvipdfmx..."
- $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
- @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
-
-text:
- $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
- @echo
- @echo "Build finished. The text files are in $(BUILDDIR)/text."
-
-man:
- $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
- @echo
- @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
-
-texinfo:
- $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
- @echo
- @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
- @echo "Run \`make' in that directory to run these through makeinfo" \
- "(use \`make info' here to do that automatically)."
-
-info:
- $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
- @echo "Running Texinfo files through makeinfo..."
- make -C $(BUILDDIR)/texinfo info
- @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
-
-gettext:
- $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
- @echo
- @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
-
-changes:
- $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
- @echo
- @echo "The overview file is in $(BUILDDIR)/changes."
-
-linkcheck:
- $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
- @echo
- @echo "Link check complete; look for any errors in the above output " \
- "or in $(BUILDDIR)/linkcheck/output.txt."
-
-doctest:
- $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
- @echo "Testing of doctests in the sources finished, look at the " \
- "results in $(BUILDDIR)/doctest/output.txt."
-
-xml:
- $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
- @echo
- @echo "Build finished. The XML files are in $(BUILDDIR)/xml."
-
-pseudoxml:
- $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
- @echo
- @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
diff --git a/tests/wpt/harness/docs/architecture.svg b/tests/wpt/harness/docs/architecture.svg
deleted file mode 100644
index b8d5aa21c19..00000000000
--- a/tests/wpt/harness/docs/architecture.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="780px" height="1087px" version="1.1"><defs><linearGradient x1="0%" y1="0%" x2="0%" y2="100%" id="mx-gradient-a9c4eb-1-a9c4eb-1-s-0"><stop offset="0%" style="stop-color:#A9C4EB"/><stop offset="100%" style="stop-color:#A9C4EB"/></linearGradient></defs><g transform="translate(0.5,0.5)"><rect x="498" y="498" width="120" height="60" fill="#e6d0de" stroke="#000000" pointer-events="none"/><g transform="translate(500,521)"><switch><foreignObject pointer-events="all" width="116" height="15" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.26; vertical-align: top; width: 116px; white-space: normal; text-align: center;">TestRunner</div></foreignObject><text x="58" y="14" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">[Not supported by viewer]</text></switch></g><rect x="338" y="778" width="120" height="60" fill="#f19c99" stroke="#000000" pointer-events="none"/><g transform="translate(340,801)"><switch><foreignObject pointer-events="all" width="116" height="15" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.26; vertical-align: top; width: 116px; white-space: normal; text-align: center;">Product under test</div></foreignObject><text x="58" y="14" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">[Not supported by viewer]</text></switch></g><rect x="338" y="388" width="120" height="60" fill="#e6d0de" stroke="#000000" pointer-events="none"/><g transform="translate(340,411)"><switch><foreignObject pointer-events="all" width="116" height="15" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.26; vertical-align: top; width: 116px; white-space: normal; text-align: center;">TestRunnerManager</div></foreignObject><text x="58" y="14" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">[Not supported by viewer]</text></switch></g><rect x="338" y="228" width="120" height="60" fill="#e6d0de" stroke="#000000" pointer-events="none"/><g transform="translate(340,251)"><switch><foreignObject pointer-events="all" width="116" height="15" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.26; vertical-align: top; width: 116px; white-space: normal; text-align: center;">ManagerGroup</div></foreignObject><text x="58" y="14" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">[Not supported by viewer]</text></switch></g><rect x="658" y="608" width="120" height="60" fill="#ffce9f" stroke="#000000" pointer-events="none"/><g transform="translate(660,631)"><switch><foreignObject pointer-events="all" width="116" height="15" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.26; vertical-align: top; width: 116px; white-space: normal; text-align: center;">Executor</div></foreignObject><text x="58" y="14" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">[Not supported by viewer]</text></switch></g><rect x="338" y="498" width="120" height="60" fill="url(#mx-gradient-a9c4eb-1-a9c4eb-1-s-0)" stroke="#000000" pointer-events="none"/><g transform="translate(340,521)"><switch><foreignObject pointer-events="all" width="116" height="15" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.26; vertical-align: top; width: 116px; white-space: normal; text-align: center;">Browser</div></foreignObject><text x="58" y="14" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">[Not supported by viewer]</text></switch></g><path d="M 398 288 L 398 382" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 398 387 L 395 380 L 398 382 L 402 380 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 398 448 L 398 492" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 398 497 L 395 490 L 398 492 L 402 490 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 618 528 L 684 603" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 687 607 L 680 604 L 684 603 L 685 600 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><rect x="498" y="608" width="120" height="60" fill="#a9c4eb" stroke="#000000" pointer-events="none"/><g transform="translate(500,631)"><switch><foreignObject pointer-events="all" width="116" height="15" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.26; vertical-align: top; width: 116px; white-space: normal; text-align: center;">ExecutorBrowser</div></foreignObject><text x="58" y="14" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">[Not supported by viewer]</text></switch></g><path d="M 624 638 L 658 638" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 619 638 L 626 635 L 624 638 L 626 642 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 428 448 L 552 496" fill="none" stroke="#000000" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="none"/><path d="M 557 498 L 549 498 L 552 496 L 552 492 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 398 558 L 398 772" fill="none" stroke="#000000" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="none"/><path d="M 398 777 L 395 770 L 398 772 L 402 770 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><rect x="338" y="48" width="120" height="60" fill="#e6d0de" stroke="#000000" pointer-events="none"/><g transform="translate(340,71)"><switch><foreignObject pointer-events="all" width="116" height="15" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.26; vertical-align: top; width: 116px; white-space: normal; text-align: center;">run_tests</div></foreignObject><text x="58" y="14" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">[Not supported by viewer]</text></switch></g><path d="M 458 78 L 652 78" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 657 78 L 650 82 L 652 78 L 650 75 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><rect x="658" y="48" width="120" height="60" fill="#e6d0de" stroke="#000000" pointer-events="none"/><g transform="translate(660,71)"><switch><foreignObject pointer-events="all" width="116" height="15" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.26; vertical-align: top; width: 116px; white-space: normal; text-align: center;">TestLoader</div></foreignObject><text x="58" y="14" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">[Not supported by viewer]</text></switch></g><rect x="71" y="48" width="120" height="60" fill="#e6d0de" stroke="#000000" pointer-events="none"/><g transform="translate(73,71)"><switch><foreignObject pointer-events="all" width="116" height="15" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.26; vertical-align: top; width: 116px; white-space: normal; text-align: center;">TestEnvironment</div></foreignObject><text x="58" y="14" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">[Not supported by viewer]</text></switch></g><rect x="151" y="618" width="120" height="60" fill="#b9e0a5" stroke="#000000" pointer-events="none"/><g transform="translate(153,641)"><switch><foreignObject pointer-events="all" width="116" height="15" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.26; vertical-align: top; width: 116px; white-space: normal; text-align: center;">wptserve</div></foreignObject><text x="58" y="14" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">[Not supported by viewer]</text></switch></g><rect x="1" y="618" width="120" height="60" fill="#b9e0a5" stroke="#000000" pointer-events="none"/><g transform="translate(3,641)"><switch><foreignObject pointer-events="all" width="116" height="15" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.26; vertical-align: top; width: 116px; white-space: normal; text-align: center;">pywebsocket</div></foreignObject><text x="58" y="14" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">[Not supported by viewer]</text></switch></g><path d="M 338 78 L 197 78" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 192 78 L 199 75 L 197 78 L 199 82 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 101 308 L 62 612" fill="none" stroke="#000000" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="none"/><path d="M 61 617 L 59 610 L 62 612 L 66 610 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 161 308 L 204 612" fill="none" stroke="#000000" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="none"/><path d="M 204 617 L 200 610 L 204 612 L 207 609 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 338 823 L 61 678" fill="none" stroke="#000000" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="none"/><path d="M 211 678 L 338 793" fill="none" stroke="#000000" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="none"/><path d="M 398 108 L 398 222" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 398 227 L 395 220 L 398 222 L 402 220 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 706 288 L 618 513" fill="none" stroke="#000000" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="none"/><rect x="658" y="388" width="70" height="40" fill="none" stroke="none" pointer-events="none"/><g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px"><text x="693" y="412">Queue.get</text></g><path d="M 458 808 L 718 668" fill="none" stroke="#000000" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="none"/><rect x="71" y="248" width="120" height="60" fill="#b9e0a5" stroke="#000000" pointer-events="none"/><g transform="translate(73,271)"><switch><foreignObject pointer-events="all" width="116" height="15" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.26; vertical-align: top; width: 116px; white-space: normal; text-align: center;">serve.py</div></foreignObject><text x="58" y="14" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">[Not supported by viewer]</text></switch></g><path d="M 131 108 L 131 242" fill="none" stroke="#000000" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="none"/><path d="M 131 247 L 128 240 L 131 242 L 135 240 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 88 973 L 132 973" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 137 973 L 130 977 L 132 973 L 130 970 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><rect x="138" y="1018" width="180" height="30" fill="none" stroke="none" pointer-events="none"/><g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px"><text x="228" y="1037">Communication (cross process)</text></g><path d="M 88 1002 L 132 1002" fill="none" stroke="#000000" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="none"/><path d="M 137 1002 L 130 1006 L 132 1002 L 130 999 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><rect x="138" y="958" width="180" height="30" fill="none" stroke="none" pointer-events="none"/><g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px"><text x="228" y="977">Ownership (same process)</text></g><path d="M 88 1033 L 138 1033" fill="none" stroke="#000000" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="none"/><rect x="143" y="988" width="180" height="30" fill="none" stroke="none" pointer-events="none"/><g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px"><text x="233" y="1007">Ownership (cross process)</text></g><rect x="428" y="966" width="50" height="15" fill="#e6d0de" stroke="#000000" pointer-events="none"/><rect x="428" y="990" width="50" height="15" fill="#a9c4eb" stroke="#000000" pointer-events="none"/><rect x="428" y="1015" width="50" height="15" fill="#ffce9f" stroke="#000000" pointer-events="none"/><rect x="428" y="1063" width="50" height="15" fill="#f19c99" stroke="#000000" pointer-events="none"/><rect x="428" y="1038" width="50" height="15" fill="#b9e0a5" stroke="#000000" pointer-events="none"/><rect x="485" y="958" width="90" height="30" fill="none" stroke="none" pointer-events="none"/><g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px"><text x="530" y="977">wptrunner class</text></g><rect x="486" y="983" width="150" height="30" fill="none" stroke="none" pointer-events="none"/><g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px"><text x="561" y="1002">Per-product wptrunner class</text></g><rect x="486" y="1008" width="150" height="30" fill="none" stroke="none" pointer-events="none"/><g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px"><text x="561" y="1027">Per-protocol wptrunner class</text></g><rect x="491" y="1031" width="150" height="30" fill="none" stroke="none" pointer-events="none"/><g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px"><text x="566" y="1050">Web-platform-tests component</text></g><rect x="486" y="1055" width="90" height="30" fill="none" stroke="none" pointer-events="none"/><g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px"><text x="531" y="1074">Browser process</text></g><path d="M 398 8 L 398 42" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 398 47 L 395 40 L 398 42 L 402 40 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><rect x="478" y="388" width="120" height="60" fill-opacity="0.5" fill="#e6d0de" stroke="#000000" stroke-opacity="0.5" pointer-events="none"/><g transform="translate(480,411)"><switch><foreignObject pointer-events="all" width="116" height="15" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.26; vertical-align: top; width: 116px; white-space: normal; text-align: center;">TestRunnerManager</div></foreignObject><text x="58" y="14" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">[Not supported by viewer]</text></switch></g><path d="M 398 288 L 533 384" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 537 387 L 529 386 L 533 384 L 533 380 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><rect x="198" y="388" width="120" height="60" fill-opacity="0.5" fill="#e6d0de" stroke="#000000" stroke-opacity="0.5" pointer-events="none"/><g transform="translate(200,411)"><switch><foreignObject pointer-events="all" width="116" height="15" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.26; vertical-align: top; width: 116px; white-space: normal; text-align: center;">TestRunnerManager</div></foreignObject><text x="58" y="14" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">[Not supported by viewer]</text></switch></g><path d="M 398 288 L 263 384" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 259 387 L 263 380 L 263 384 L 267 386 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><rect x="575" y="748" width="110" height="40" fill="none" stroke="none" pointer-events="none"/><g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px"><text x="630" y="758">Browser control</text><text x="630" y="772">protocol</text><text x="630" y="786">(e.g. WebDriver)</text></g><rect x="258" y="708" width="80" height="40" fill="none" stroke="none" pointer-events="none"/><g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px"><text x="298" y="732">HTTP</text></g><rect x="111" y="728" width="80" height="40" fill="none" stroke="none" pointer-events="none"/><g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px"><text x="151" y="752">websockets</text></g><rect x="658" y="228" width="120" height="60" fill="#e6d0de" stroke="#000000" pointer-events="none"/><g transform="translate(660,251)"><switch><foreignObject pointer-events="all" width="116" height="15" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.26; vertical-align: top; width: 116px; white-space: normal; text-align: center;">Tests Queue</div></foreignObject><text x="58" y="14" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">[Not supported by viewer]</text></switch></g><path d="M 718 108 L 718 222" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 718 227 L 715 220 L 718 222 L 722 220 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 428 970 L 428 970" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/></g></svg>
diff --git a/tests/wpt/harness/docs/conf.py b/tests/wpt/harness/docs/conf.py
deleted file mode 100644
index 39e5cc4f0d2..00000000000
--- a/tests/wpt/harness/docs/conf.py
+++ /dev/null
@@ -1,267 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# wptrunner documentation build configuration file, created by
-# sphinx-quickstart on Mon May 19 18:14:20 2014.
-#
-# This file is execfile()d with the current directory set to its
-# containing dir.
-#
-# Note that not all possible configuration values are present in this
-# autogenerated file.
-#
-# All configuration values have a default; values that are commented out
-# serve to show the default.
-
-import sys
-import os
-
-# If extensions (or modules to document with autodoc) are in another directory,
-# add these directories to sys.path here. If the directory is relative to the
-# documentation root, use os.path.abspath to make it absolute, like shown here.
-#sys.path.insert(0, os.path.abspath('.'))
-
-# -- General configuration ------------------------------------------------
-
-# If your documentation needs a minimal Sphinx version, state it here.
-#needs_sphinx = '1.0'
-
-# Add any Sphinx extension module names here, as strings. They can be
-# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
-# ones.
-extensions = [
- 'sphinx.ext.autodoc',
- 'sphinx.ext.intersphinx',
- 'sphinx.ext.viewcode',
-]
-
-# Add any paths that contain templates here, relative to this directory.
-templates_path = ['_templates']
-
-# The suffix of source filenames.
-source_suffix = '.rst'
-
-# The encoding of source files.
-#source_encoding = 'utf-8-sig'
-
-# The master toctree document.
-master_doc = 'index'
-
-# General information about the project.
-project = u'wptrunner'
-copyright = u''
-
-# The version info for the project you're documenting, acts as replacement for
-# |version| and |release|, also used in various other places throughout the
-# built documents.
-#
-# The short X.Y version.
-version = '0.3'
-# The full version, including alpha/beta/rc tags.
-release = '0.3'
-
-# The language for content autogenerated by Sphinx. Refer to documentation
-# for a list of supported languages.
-#language = None
-
-# There are two options for replacing |today|: either, you set today to some
-# non-false value, then it is used:
-#today = ''
-# Else, today_fmt is used as the format for a strftime call.
-#today_fmt = '%B %d, %Y'
-
-# List of patterns, relative to source directory, that match files and
-# directories to ignore when looking for source files.
-exclude_patterns = ['_build']
-
-# The reST default role (used for this markup: `text`) to use for all
-# documents.
-#default_role = None
-
-# If true, '()' will be appended to :func: etc. cross-reference text.
-#add_function_parentheses = True
-
-# If true, the current module name will be prepended to all description
-# unit titles (such as .. function::).
-#add_module_names = True
-
-# If true, sectionauthor and moduleauthor directives will be shown in the
-# output. They are ignored by default.
-#show_authors = False
-
-# The name of the Pygments (syntax highlighting) style to use.
-pygments_style = 'sphinx'
-
-# A list of ignored prefixes for module index sorting.
-#modindex_common_prefix = []
-
-# If true, keep warnings as "system message" paragraphs in the built documents.
-#keep_warnings = False
-
-
-# -- Options for HTML output ----------------------------------------------
-
-# The theme to use for HTML and HTML Help pages. See the documentation for
-# a list of builtin themes.
-html_theme = 'default'
-
-# Theme options are theme-specific and customize the look and feel of a theme
-# further. For a list of options available for each theme, see the
-# documentation.
-#html_theme_options = {}
-
-# Add any paths that contain custom themes here, relative to this directory.
-#html_theme_path = []
-
-# The name for this set of Sphinx documents. If None, it defaults to
-# "<project> v<release> documentation".
-#html_title = None
-
-# A shorter title for the navigation bar. Default is the same as html_title.
-#html_short_title = None
-
-# The name of an image file (relative to this directory) to place at the top
-# of the sidebar.
-#html_logo = None
-
-# The name of an image file (within the static path) to use as favicon of the
-# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
-# pixels large.
-#html_favicon = None
-
-# Add any paths that contain custom static files (such as style sheets) here,
-# relative to this directory. They are copied after the builtin static files,
-# so a file named "default.css" will overwrite the builtin "default.css".
-html_static_path = ['_static']
-
-# Add any extra paths that contain custom files (such as robots.txt or
-# .htaccess) here, relative to this directory. These files are copied
-# directly to the root of the documentation.
-#html_extra_path = []
-
-# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
-# using the given strftime format.
-#html_last_updated_fmt = '%b %d, %Y'
-
-# If true, SmartyPants will be used to convert quotes and dashes to
-# typographically correct entities.
-#html_use_smartypants = True
-
-# Custom sidebar templates, maps document names to template names.
-#html_sidebars = {}
-
-# Additional templates that should be rendered to pages, maps page names to
-# template names.
-#html_additional_pages = {}
-
-# If false, no module index is generated.
-#html_domain_indices = True
-
-# If false, no index is generated.
-#html_use_index = True
-
-# If true, the index is split into individual pages for each letter.
-#html_split_index = False
-
-# If true, links to the reST sources are added to the pages.
-#html_show_sourcelink = True
-
-# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
-#html_show_sphinx = True
-
-# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
-#html_show_copyright = True
-
-# If true, an OpenSearch description file will be output, and all pages will
-# contain a <link> tag referring to it. The value of this option must be the
-# base URL from which the finished HTML is served.
-#html_use_opensearch = ''
-
-# This is the file name suffix for HTML files (e.g. ".xhtml").
-#html_file_suffix = None
-
-# Output file base name for HTML help builder.
-htmlhelp_basename = 'wptrunnerdoc'
-
-
-# -- Options for LaTeX output ---------------------------------------------
-
-latex_elements = {
-# The paper size ('letterpaper' or 'a4paper').
-#'papersize': 'letterpaper',
-
-# The font size ('10pt', '11pt' or '12pt').
-#'pointsize': '10pt',
-
-# 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'),
-]
-
-# The name of an image file (relative to this directory) to place at the top of
-# the title page.
-#latex_logo = None
-
-# For "manual" documents, if this is true, then toplevel headings are parts,
-# not chapters.
-#latex_use_parts = False
-
-# If true, show page references after internal links.
-#latex_show_pagerefs = False
-
-# If true, show URL addresses after external links.
-#latex_show_urls = False
-
-# Documents to append as an appendix to all manuals.
-#latex_appendices = []
-
-# If false, no module index is generated.
-#latex_domain_indices = True
-
-
-# -- Options for manual page output ---------------------------------------
-
-# One entry per manual page. List of tuples
-# (source start file, name, description, authors, manual section).
-man_pages = [
- ('index', 'wptrunner', u'wptrunner Documentation',
- [u'James Graham'], 1)
-]
-
-# If true, show URL addresses after external links.
-#man_show_urls = False
-
-
-# -- Options for Texinfo output -------------------------------------------
-
-# Grouping the document tree into Texinfo files. List of tuples
-# (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'),
-]
-
-# Documents to append as an appendix to all manuals.
-#texinfo_appendices = []
-
-# If false, no module index is generated.
-#texinfo_domain_indices = True
-
-# How to display URL addresses: 'footnote', 'no', or 'inline'.
-#texinfo_show_urls = 'footnote'
-
-# If true, do not generate a @detailmenu in the "Top" node's menu.
-#texinfo_no_detailmenu = False
-
-
-# Example configuration for intersphinx: refer to the Python standard library.
-intersphinx_mapping = {'python': ('http://docs.python.org/', None),
- 'mozlog': ('http://mozbase.readthedocs.org/en/latest/', None)}
diff --git a/tests/wpt/harness/docs/design.rst b/tests/wpt/harness/docs/design.rst
deleted file mode 100644
index bf108a0087d..00000000000
--- a/tests/wpt/harness/docs/design.rst
+++ /dev/null
@@ -1,106 +0,0 @@
-wptrunner Design
-================
-
-The design of wptrunner is intended to meet the following
-requirements:
-
- * Possible to run tests from W3C web-platform-tests.
-
- * Tests should be run as fast as possible. In particular it should
- not be necessary to restart the browser between tests, or similar.
-
- * As far as possible, the tests should run in a "normal" browser and
- browsing context. In particular many tests assume that they are
- running in a top-level browsing context, so we must avoid the use
- of an ``iframe`` test container.
-
- * It must be possible to deal with all kinds of behaviour of the
- browser runder test, for example, crashing, hanging, etc.
-
- * It should be possible to add support for new platforms and browsers
- with minimal code changes.
-
- * It must be possible to run tests in parallel to further improve
- performance.
-
- * Test output must be in a machine readable form.
-
-Architecture
-------------
-
-In order to meet the above requirements, wptrunner is designed to
-push as much of the test scheduling as possible into the harness. This
-allows the harness to monitor the state of the browser and perform
-appropriate action if it gets into an unwanted state e.g. kill the
-browser if it appears to be hung.
-
-The harness will typically communicate with the browser via some remote
-control protocol such as WebDriver. However for browsers where no such
-protocol is supported, other implementation strategies are possible,
-typically at the expense of speed.
-
-The overall architecture of wptrunner is shown in the diagram below:
-
-.. image:: architecture.svg
-
-The main entry point to the code is :py:func:`run_tests` in
-``wptrunner.py``. This is responsible for setting up the test
-environment, loading the list of tests to be executed, and invoking
-the remainder of the code to actually execute some tests.
-
-The test environment is encapsulated in the
-:py:class:`TestEnvironment` class. This defers to code in
-``web-platform-tests`` which actually starts the required servers to
-run the tests.
-
-The set of tests to run is defined by the
-:py:class:`TestLoader`. This is constructed with a
-:py:class:`TestFilter` (not shown), which takes any filter arguments
-from the command line to restrict the set of tests that will be
-run. The :py:class:`TestLoader` reads both the ``web-platform-tests``
-JSON manifest and the expectation data stored in ini files and
-produces a :py:class:`multiprocessing.Queue` of tests to run, and
-their expected results.
-
-Actually running the tests happens through the
-:py:class:`ManagerGroup` object. This takes the :py:class:`Queue` of
-tests to be run and starts a :py:class:`testrunner.TestRunnerManager` for each
-instance of the browser under test that will be started. These
-:py:class:`TestRunnerManager` instances are each started in their own
-thread.
-
-A :py:class:`TestRunnerManager` coordinates starting the product under
-test, and outputting results from the test. In the case that the test
-has timed out or the browser has crashed, it has to restart the
-browser to ensure the test run can continue. The functionality for
-initialising the browser under test, and probing its state
-(e.g. whether the process is still alive) is implemented through a
-:py:class:`Browser` object. An implementation of this class must be
-provided for each product that is supported.
-
-The functionality for actually running the tests is provided by a
-:py:class:`TestRunner` object. :py:class:`TestRunner` instances are
-run in their own child process created with the
-:py:mod:`multiprocessing` module. This allows them to run concurrently
-and to be killed and restarted as required. Communication between the
-:py:class:`TestRunnerManager` and the :py:class:`TestRunner` is
-provided by a pair of queues, one for sending messages in each
-direction. In particular test results are sent from the
-:py:class:`TestRunner` to the :py:class:`TestRunnerManager` using one
-of these queues.
-
-The :py:class:`TestRunner` object is generic in that the same
-:py:class:`TestRunner` is used regardless of the product under
-test. However the details of how to run the test may vary greatly with
-the product since different products support different remote control
-protocols (or none at all). These protocol-specific parts are placed
-in the :py:class:`Executor` object. There is typically a different
-:py:class:`Executor` class for each combination of control protocol
-and test type. The :py:class:`TestRunner` is responsible for pulling
-each test off the :py:class:`Queue` of tests and passing it down to
-the :py:class:`Executor`.
-
-The executor often requires access to details of the particular
-browser instance that it is testing so that it knows e.g. which port
-to connect to to send commands to the browser. These details are
-encapsulated in the :py:class:`ExecutorBrowser` class.
diff --git a/tests/wpt/harness/docs/expectation.rst b/tests/wpt/harness/docs/expectation.rst
deleted file mode 100644
index 6a0c77684a3..00000000000
--- a/tests/wpt/harness/docs/expectation.rst
+++ /dev/null
@@ -1,248 +0,0 @@
-Expectation Data
-================
-
-Introduction
-------------
-
-For use in continuous integration systems, and other scenarios where
-regression tracking is required, wptrunner supports storing and
-loading the expected result of each test in a test run. Typically
-these expected results will initially be generated by running the
-testsuite in a baseline build. They may then be edited by humans as
-new features are added to the product that change the expected
-results. The expected results may also vary for a single product
-depending on the platform on which it is run. Therefore, the raw
-structured log data is not a suitable format for storing these
-files. Instead something is required that is:
-
- * Human readable
-
- * Human editable
-
- * Machine readable / writable
-
- * Capable of storing test id / result pairs
-
- * Suitable for storing in a version control system (i.e. text-based)
-
-The need for different results per platform means either having
-multiple expectation files for each platform, or having a way to
-express conditional values within a certain file. The former would be
-rather cumbersome for humans updating the expectation files, so the
-latter approach has been adopted, leading to the requirement:
-
- * Capable of storing result values that are conditional on the platform.
-
-There are few extant formats that meet these requirements, so
-wptrunner uses a bespoke ``expectation manifest`` format, which is
-closely based on the standard ``ini`` format.
-
-Directory Layout
-----------------
-
-Expectation manifest files must be stored under the ``metadata``
-directory passed to the test runner. The directory layout follows that
-of web-platform-tests with each test path having a corresponding
-manifest file. Tests that differ only by query string, or reftests
-with the same test path but different ref paths share the same
-reference file. The file name is taken from the last /-separated part
-of the path, suffixed with ``.ini``.
-
-As an optimisation, files which produce only default results
-(i.e. ``PASS`` or ``OK``) don't require a corresponding manifest file.
-
-For example a test with url::
-
- /spec/section/file.html?query=param
-
-would have an expectation file ::
-
- metadata/spec/section/file.html.ini
-
-
-.. _wptupdate-label:
-
-Generating Expectation Files
-----------------------------
-
-wptrunner provides the tool ``wptupdate`` to generate expectation
-files from the results of a set of baseline test runs. The basic
-syntax for this is::
-
- wptupdate [options] [logfile]...
-
-Each ``logfile`` is a structured log file from a previous run. These
-can be generated from wptrunner using the ``--log-raw`` option
-e.g. ``--log-raw=structured.log``. The default behaviour is to update
-all the test data for the particular combination of hardware and OS
-used in the run corresponding to the log data, whilst leaving any
-other expectations untouched.
-
-wptupdate takes several useful options:
-
-``--sync``
- Pull the latest version of web-platform-tests from the
- upstream specified in the config file. If this is specified in
- combination with logfiles, it is assumed that the results in the log
- files apply to the post-update tests.
-
-``--no-check-clean``
- Don't attempt to check if the working directory is clean before
- doing the update (assuming that the working directory is a git or
- mercurial tree).
-
-``--patch``
- Create a a git commit, or a mq patch, with the changes made by wptupdate.
-
-``--ignore-existing``
- Overwrite all the expectation data for any tests that have a result
- in the passed log files, not just data for the same platform.
-
-Examples
-~~~~~~~~
-
-Update the local copy of web-platform-tests without changing the
-expectation data and commit (or create a mq patch for) the result::
-
- wptupdate --patch --sync
-
-Update all the expectations from a set of cross-platform test runs::
-
- wptupdate --no-check-clean --patch osx.log linux.log windows.log
-
-Add expectation data for some new tests that are expected to be
-platform-independent::
-
- wptupdate --no-check-clean --patch --ignore-existing tests.log
-
-Manifest Format
----------------
-The format of the manifest files is based on the ini format. Files are
-divided into sections, each (apart from the root section) having a
-heading enclosed in square braces. Within each section are key-value
-pairs. There are several notable differences from standard .ini files,
-however:
-
- * Sections may be hierarchically nested, with significant whitespace
- indicating nesting depth.
-
- * Only ``:`` is valid as a key/value separator
-
-A simple example of a manifest file is::
-
- root_key: root_value
-
- [section]
- section_key: section_value
-
- [subsection]
- subsection_key: subsection_value
-
- [another_section]
- another_key: another_value
-
-Conditional Values
-~~~~~~~~~~~~~~~~~~
-
-In order to support values that depend on some external data, the
-right hand side of a key/value pair can take a set of conditionals
-rather than a plain value. These values are placed on a new line
-following the key, with significant indentation. Conditional values
-are prefixed with ``if`` and terminated with a colon, for example::
-
- key:
- if cond1: value1
- if cond2: value2
- value3
-
-In this example, the value associated with ``key`` is determined by
-first evaluating ``cond1`` against external data. If that is true,
-``key`` is assigned the value ``value1``, otherwise ``cond2`` is
-evaluated in the same way. If both ``cond1`` and ``cond2`` are false,
-the unconditional ``value3`` is used.
-
-Conditions themselves use a Python-like expression syntax. Operands
-can either be variables, corresponding to data passed in, numbers
-(integer or floating point; exponential notation is not supported) or
-quote-delimited strings. Equality is tested using ``==`` and
-inequality by ``!=``. The operators ``and``, ``or`` and ``not`` are
-used in the expected way. Parentheses can also be used for
-grouping. For example::
-
- key:
- if (a == 2 or a == 3) and b == "abc": value1
- if a == 1 or b != "abc": value2
- value3
-
-Here ``a`` and ``b`` are variables, the value of which will be
-supplied when the manifest is used.
-
-Expectation Manifests
----------------------
-
-When used for expectation data, manifests have the following format:
-
- * A section per test URL described by the manifest, with the section
- heading being the part of the test URL following the last ``/`` in
- the path (this allows multiple tests in a single manifest file with
- the same path part of the URL, but different query parts).
-
- * A subsection per subtest, with the heading being the title of the
- subtest.
-
- * A key ``type`` indicating the test type. This takes the values
- ``testharness`` and ``reftest``.
-
- * For reftests, keys ``reftype`` indicating the reference type
- (``==`` or ``!=``) and ``refurl`` indicating the URL of the
- reference.
-
- * A key ``expected`` giving the expectation value of each (sub)test.
-
- * A key ``disabled`` which can be set to any value to indicate that
- the (sub)test is disabled and should either not be run (for tests)
- or that its results should be ignored (subtests).
-
- * A key ``restart-after`` which can be set to any value to indicate that
- the runner should restart the browser after running this test (e.g. to
- clear out unwanted state).
-
- * Variables ``debug``, ``os``, ``version``, ``processor`` and
- ``bits`` that describe the configuration of the browser under
- test. ``debug`` is a boolean indicating whether a build is a debug
- build. ``os`` is a string indicating the operating system, and
- ``version`` a string indicating the particular version of that
- operating system. ``processor`` is a string indicating the
- processor architecture and ``bits`` an integer indicating the
- number of bits. This information is typically provided by
- :py:mod:`mozinfo`.
-
- * Top level keys are taken as defaults for the whole file. So, for
- example, a top level key with ``expected: FAIL`` would indicate
- that all tests and subtests in the file are expected to fail,
- unless they have an ``expected`` key of their own.
-
-An simple example manifest might look like::
-
- [test.html?variant=basic]
- type: testharness
-
- [Test something unsupported]
- expected: FAIL
-
- [test.html?variant=broken]
- expected: ERROR
-
- [test.html?variant=unstable]
- disabled: http://test.bugs.example.org/bugs/12345
-
-A more complex manifest with conditional properties might be::
-
- [canvas_test.html]
- expected:
- if os == "osx": FAIL
- if os == "windows" and version == "XP": FAIL
- PASS
-
-Note that ``PASS`` in the above works, but is unnecessary; ``PASS``
-(or ``OK``) is always the default expectation for (sub)tests.
diff --git a/tests/wpt/harness/docs/index.rst b/tests/wpt/harness/docs/index.rst
deleted file mode 100644
index 5147d3e31c3..00000000000
--- a/tests/wpt/harness/docs/index.rst
+++ /dev/null
@@ -1,24 +0,0 @@
-.. wptrunner documentation master file, created by
- sphinx-quickstart on Mon May 19 18:14:20 2014.
- You can adapt this file completely to your liking, but it should at least
- contain the root `toctree` directive.
-
-Welcome to wptrunner's documentation!
-=====================================
-
-Contents:
-
-.. toctree::
- :maxdepth: 2
-
- usage
- expectation
- design
-
-Indices and tables
-==================
-
-* :ref:`genindex`
-* :ref:`modindex`
-* :ref:`search`
-
diff --git a/tests/wpt/harness/docs/make.bat b/tests/wpt/harness/docs/make.bat
deleted file mode 100644
index 959c1615a28..00000000000
--- a/tests/wpt/harness/docs/make.bat
+++ /dev/null
@@ -1,242 +0,0 @@
-@ECHO OFF
-
-REM Command file for Sphinx documentation
-
-if "%SPHINXBUILD%" == "" (
- set SPHINXBUILD=sphinx-build
-)
-set BUILDDIR=_build
-set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
-set I18NSPHINXOPTS=%SPHINXOPTS% .
-if NOT "%PAPER%" == "" (
- set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
- set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
-)
-
-if "%1" == "" goto help
-
-if "%1" == "help" (
- :help
- echo.Please use `make ^<target^>` where ^<target^> is one of
- echo. html to make standalone HTML files
- echo. dirhtml to make HTML files named index.html in directories
- echo. singlehtml to make a single large HTML file
- echo. pickle to make pickle files
- echo. json to make JSON files
- echo. htmlhelp to make HTML files and a HTML help project
- echo. qthelp to make HTML files and a qthelp project
- echo. devhelp to make HTML files and a Devhelp project
- echo. epub to make an epub
- echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
- echo. text to make text files
- echo. man to make manual pages
- echo. texinfo to make Texinfo files
- echo. gettext to make PO message catalogs
- echo. changes to make an overview over all changed/added/deprecated items
- echo. xml to make Docutils-native XML files
- echo. pseudoxml to make pseudoxml-XML files for display purposes
- echo. linkcheck to check all external links for integrity
- echo. doctest to run all doctests embedded in the documentation if enabled
- goto end
-)
-
-if "%1" == "clean" (
- for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
- del /q /s %BUILDDIR%\*
- goto end
-)
-
-
-%SPHINXBUILD% 2> nul
-if errorlevel 9009 (
- echo.
- echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
- echo.installed, then set the SPHINXBUILD environment variable to point
- echo.to the full path of the 'sphinx-build' executable. Alternatively you
- echo.may add the Sphinx directory to PATH.
- echo.
- echo.If you don't have Sphinx installed, grab it from
- echo.http://sphinx-doc.org/
- exit /b 1
-)
-
-if "%1" == "html" (
- %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The HTML pages are in %BUILDDIR%/html.
- goto end
-)
-
-if "%1" == "dirhtml" (
- %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
- goto end
-)
-
-if "%1" == "singlehtml" (
- %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
- goto end
-)
-
-if "%1" == "pickle" (
- %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished; now you can process the pickle files.
- goto end
-)
-
-if "%1" == "json" (
- %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished; now you can process the JSON files.
- goto end
-)
-
-if "%1" == "htmlhelp" (
- %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished; now you can run HTML Help Workshop with the ^
-.hhp project file in %BUILDDIR%/htmlhelp.
- goto end
-)
-
-if "%1" == "qthelp" (
- %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished; now you can run "qcollectiongenerator" with the ^
-.qhcp project file in %BUILDDIR%/qthelp, like this:
- echo.^> qcollectiongenerator %BUILDDIR%\qthelp\wptrunner.qhcp
- echo.To view the help file:
- echo.^> assistant -collectionFile %BUILDDIR%\qthelp\wptrunner.ghc
- goto end
-)
-
-if "%1" == "devhelp" (
- %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished.
- goto end
-)
-
-if "%1" == "epub" (
- %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The epub file is in %BUILDDIR%/epub.
- goto end
-)
-
-if "%1" == "latex" (
- %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
- goto end
-)
-
-if "%1" == "latexpdf" (
- %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
- cd %BUILDDIR%/latex
- make all-pdf
- cd %BUILDDIR%/..
- echo.
- echo.Build finished; the PDF files are in %BUILDDIR%/latex.
- goto end
-)
-
-if "%1" == "latexpdfja" (
- %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
- cd %BUILDDIR%/latex
- make all-pdf-ja
- cd %BUILDDIR%/..
- echo.
- echo.Build finished; the PDF files are in %BUILDDIR%/latex.
- goto end
-)
-
-if "%1" == "text" (
- %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The text files are in %BUILDDIR%/text.
- goto end
-)
-
-if "%1" == "man" (
- %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The manual pages are in %BUILDDIR%/man.
- goto end
-)
-
-if "%1" == "texinfo" (
- %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
- goto end
-)
-
-if "%1" == "gettext" (
- %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
- goto end
-)
-
-if "%1" == "changes" (
- %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
- if errorlevel 1 exit /b 1
- echo.
- echo.The overview file is in %BUILDDIR%/changes.
- goto end
-)
-
-if "%1" == "linkcheck" (
- %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
- if errorlevel 1 exit /b 1
- echo.
- echo.Link check complete; look for any errors in the above output ^
-or in %BUILDDIR%/linkcheck/output.txt.
- goto end
-)
-
-if "%1" == "doctest" (
- %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
- if errorlevel 1 exit /b 1
- echo.
- echo.Testing of doctests in the sources finished, look at the ^
-results in %BUILDDIR%/doctest/output.txt.
- goto end
-)
-
-if "%1" == "xml" (
- %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The XML files are in %BUILDDIR%/xml.
- goto end
-)
-
-if "%1" == "pseudoxml" (
- %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml.
- goto end
-)
-
-:end
diff --git a/tests/wpt/harness/docs/usage.rst b/tests/wpt/harness/docs/usage.rst
deleted file mode 100644
index 8e74a4320c8..00000000000
--- a/tests/wpt/harness/docs/usage.rst
+++ /dev/null
@@ -1,238 +0,0 @@
-Getting Started
-===============
-
-Installing wptrunner
---------------------
-
-The easiest way to install wptrunner is into a virtualenv, using pip::
-
- virtualenv wptrunner
- cd wptrunner
- source bin/activate
- pip install wptrunner
-
-This will install the base dependencies for wptrunner, but not any
-extra dependencies required to test against specific browsers. In
-order to do this you must use use the extra requirements files in
-``$VIRTUAL_ENV/requirements/requirements_browser.txt``. For example,
-in order to test against Firefox you would have to run::
-
- pip install -r requirements/requirements_firefox.txt
-
-If you intend to work on the code, the ``-e`` option to pip should be
-used in combination with a source checkout i.e. inside a virtual
-environment created as above::
-
- git clone https://github.com/w3c/wptrunner.git
- cd wptrunner
- pip install -e ./
-
-In addition to the dependencies installed by pip, wptrunner requires
-a copy of the web-platform-tests repository. This can be located
-anywhere on the filesystem, but the easiest option is to put it
-under the same parent directory as the wptrunner checkout::
-
- git clone https://github.com/w3c/web-platform-tests.git
-
-It is also necessary to generate a web-platform-tests ``MANIFEST.json``
-file. It's recommended to also put that under the same parent directory as
-the wptrunner checkout, in a directory named ``meta``::
-
- mkdir meta
- cd web-platform-tests
- python manifest --path ../meta/MANIFEST.json
-
-The ``MANIFEST.json`` file needs to be regenerated each time the
-web-platform-tests checkout is updated. To aid with the update process
-there is a tool called ``wptupdate``, which is described in
-:ref:`wptupdate-label`.
-
-Running the Tests
------------------
-
-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`.
-
-``--binary`` (required if product is `firefox` or `servo`)
- The path to a binary file for the product (browser) to test against.
-
-``--webdriver-binary`` (required if product is `chrome`)
- The path to a `*driver` binary; e.g., a `chromedriver` binary.
-
-``--certutil-binary`` (required if product is `firefox` [#]_)
- The path to a `certutil` binary (for tests that must be run over https).
-
-``--metadata`` (required only when not `using default paths`_)
- The path to a directory containing test metadata. [#]_
-
-``--tests`` (required only when not `using default paths`_)
- The path to a directory containing a web-platform-tests checkout.
-
-``--prefs-root`` (required only when testing a Firefox binary)
- The path to a directory containing Firefox test-harness preferences. [#]_
-
-``--config`` (should default to `wptrunner.default.ini`)
- The path to the config (ini) file.
-
-.. [#] The ``--certutil-binary`` option is required when the product is
- ``firefox`` unless ``--ssl-type=none`` is specified.
-
-.. [#] The ``--metadata`` path is to a directory that contains:
-
- * a ``MANIFEST.json`` file (the web-platform-tests documentation has
- instructions on generating this file)
- * (optionally) any expectation files (see :ref:`wptupdate-label`)
-
-.. [#] Example ``--prefs-root`` value: ``~/mozilla-central/testing/profiles``.
-
-There are also a variety of other command-line options available; use
-``--help`` to list them.
-
-The following examples show how to start wptrunner with various options.
-
-------------------
-Starting wptrunner
-------------------
-
-The examples below assume the following directory layout,
-though no specific folder structure is required::
-
- ~/testtwf/wptrunner # wptrunner checkout
- ~/testtwf/web-platform-tests # web-platform-tests checkout
- ~/testtwf/meta # metadata
-
-To test a Firefox Nightly build in an OS X environment, you might start
-wptrunner using something similar to the following example::
-
- wptrunner --metadata=~/testtwf/meta/ --tests=~/testtwf/web-platform-tests/ \
- --binary=~/mozilla-central/obj-x86_64-apple-darwin14.3.0/dist/Nightly.app/Contents/MacOS/firefox \
- --certutil-binary=~/mozilla-central/obj-x86_64-apple-darwin14.3.0/security/nss/cmd/certutil/certutil \
- --prefs-root=~/mozilla-central/testing/profiles
-
-
-And to test a Chromium build in an OS X environment, you might start
-wptrunner using something similar to the following example::
-
- wptrunner --metadata=~/testtwf/meta/ --tests=~/testtwf/web-platform-tests/ \
- --binary=~/chromium/src/out/Release/Chromium.app/Contents/MacOS/Chromium \
- --webdriver-binary=/usr/local/bin/chromedriver --product=chrome
-
---------------------
-Running test subsets
---------------------
-
-To restrict a test run just to tests in a particular web-platform-tests
-subdirectory, specify the directory name in the positional arguments after
-the options; for example, run just the tests in the `dom` subdirectory::
-
- wptrunner --metadata=~/testtwf/meta --tests=~/testtwf/web-platform-tests/ \
- --binary=/path/to/firefox --certutil-binary=/path/to/certutil \
- --prefs-root=/path/to/testing/profiles \
- dom
-
--------------------
-Running in parallel
--------------------
-
-To speed up the testing process, use the ``--processes`` option to have
-wptrunner run multiple browser instances in parallel. For example, to
-have wptrunner attempt to run tests against with six browser instances
-in parallel, specify ``--processes=6``. But note that behaviour in this
-mode is necessarily less deterministic than with ``--processes=1`` (the
-default), so there may be more noise in the test results.
-
--------------------
-Using default paths
--------------------
-
-The (otherwise-required) ``--tests`` and ``--metadata`` command-line
-options/flags be omitted if any configuration file is found that
-contains a section specifying the ``tests`` and ``metadata`` keys.
-
-See the `Configuration File`_ section for more information about
-configuration files, including information about their expected
-locations.
-
-The content of the ``wptrunner.default.ini`` default configuration file
-makes wptrunner look for tests (that is, a web-platform-tests checkout)
-as a subdirectory of the current directory named ``tests``, and for
-metadata files in a subdirectory of the current directory named ``meta``.
-
-Output
-------
-
-wptrunner uses the :py:mod:`mozlog` package for output. This
-structures events such as test results or log messages as JSON objects
-that can then be fed to other tools for interpretation. More details
-about the message format are given in the
-:py:mod:`mozlog` documentation.
-
-By default the raw JSON messages are dumped to stdout. This is
-convenient for piping into other tools, but not ideal for humans
-reading the output. :py:mod:`mozlog` comes with several other
-formatters, which are accessible through command line options. The
-general format of these options is ``--log-name=dest``, where ``name``
-is the name of the format and ``dest`` is a path to a destination
-file, or ``-`` for stdout. The raw JSON data is written by the ``raw``
-formatter so, the default setup corresponds to ``--log-raw=-``.
-
-A reasonable output format for humans is provided as ``mach``. So in
-order to output the full raw log to a file and a human-readable
-summary to stdout, one might pass the options::
-
- --log-raw=output.log --log-mach=-
-
-Configuration File
-------------------
-
-wptrunner uses a ``.ini`` file to control some configuration
-sections. The file has three sections; ``[products]``,
-``[manifest:default]`` and ``[web-platform-tests]``.
-
-``[products]`` is used to
-define the set of available products. By default this section is empty
-which means that all the products distributed with wptrunner are
-enabled (although their dependencies may not be installed). The set
-of enabled products can be set by using the product name as the
-key. For built in products the value is empty. It is also possible to
-provide the path to a script implementing the browser functionality
-e.g.::
-
- [products]
- chrome =
- netscape4 = path/to/netscape.py
-
-``[manifest:default]`` specifies the default paths for the tests and metadata,
-relative to the config file. For example::
-
- [manifest:default]
- tests = ~/testtwf/web-platform-tests
- metadata = ~/testtwf/meta
-
-
-``[web-platform-tests]`` is used to set the properties of the upstream
-repository when updating the paths. ``remote_url`` specifies the git
-url to pull from; ``branch`` the branch to sync against and
-``sync_path`` the local path, relative to the configuration file, to
-use when checking out the tests e.g.::
-
- [web-platform-tests]
- remote_url = https://github.com/w3c/web-platform-tests.git
- branch = master
- sync_path = sync
-
-A configuration file must contain all the above fields; falling back
-to the default values for unspecified fields is not yet supported.
-
-The ``wptrunner`` and ``wptupdate`` commands will use configuration
-files in the following order:
-
- * Any path supplied with a ``--config`` flag to the command.
-
- * A file called ``wptrunner.ini`` in the current directory
-
- * The default configuration file (``wptrunner.default.ini`` in the
- source directory)
diff --git a/tests/wpt/harness/requirements.txt b/tests/wpt/harness/requirements.txt
deleted file mode 100644
index 319a2ff984a..00000000000
--- a/tests/wpt/harness/requirements.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-html5lib >= 0.99
-mozinfo >= 0.7
-mozlog >= 3.3
-mozdebug >= 0.1
diff --git a/tests/wpt/harness/requirements_b2g.txt b/tests/wpt/harness/requirements_b2g.txt
deleted file mode 100644
index 132e0a7ba66..00000000000
--- a/tests/wpt/harness/requirements_b2g.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-fxos_appgen >= 0.5
-mozdevice >= 0.41
-gaiatest >= 0.26
-marionette_client >= 0.7.10
-moznetwork >= 0.24
-mozprofile >= 0.21
-mozrunner >= 6.1
diff --git a/tests/wpt/harness/requirements_chrome.txt b/tests/wpt/harness/requirements_chrome.txt
deleted file mode 100644
index a2f54425f3e..00000000000
--- a/tests/wpt/harness/requirements_chrome.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-mozprocess >= 0.19
-selenium >= 2.41.0
diff --git a/tests/wpt/harness/requirements_firefox.txt b/tests/wpt/harness/requirements_firefox.txt
deleted file mode 100644
index 379e522acc4..00000000000
--- a/tests/wpt/harness/requirements_firefox.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-marionette_driver >= 0.4
-mozprofile >= 0.21
-mozprocess >= 0.19
-mozcrash >= 0.13
-mozrunner >= 6.7
diff --git a/tests/wpt/harness/requirements_servo.txt b/tests/wpt/harness/requirements_servo.txt
deleted file mode 100644
index 22bcfa123a5..00000000000
--- a/tests/wpt/harness/requirements_servo.txt
+++ /dev/null
@@ -1 +0,0 @@
-mozprocess >= 0.19
diff --git a/tests/wpt/harness/setup.py b/tests/wpt/harness/setup.py
deleted file mode 100644
index d4e425659c7..00000000000
--- a/tests/wpt/harness/setup.py
+++ /dev/null
@@ -1,73 +0,0 @@
-# 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 glob
-import os
-import sys
-import textwrap
-
-from setuptools import setup, find_packages
-
-here = os.path.split(__file__)[0]
-
-PACKAGE_NAME = 'wptrunner'
-PACKAGE_VERSION = '1.14'
-
-# Dependencies
-with open(os.path.join(here, "requirements.txt")) as f:
- deps = f.read().splitlines()
-
-# Browser-specific requirements
-requirements_files = glob.glob(os.path.join(here, "requirements_*.txt"))
-
-profile_dest = None
-dest_exists = False
-
-setup(name=PACKAGE_NAME,
- version=PACKAGE_VERSION,
- description="Harness for running the W3C web-platform-tests against various products",
- author='Mozilla Automation and Testing Team',
- author_email='tools@lists.mozilla.org',
- license='MPL 2.0',
- packages=find_packages(exclude=["tests", "metadata", "prefs"]),
- entry_points={
- 'console_scripts': [
- 'wptrunner = wptrunner.wptrunner:main',
- 'wptupdate = wptrunner.update:main',
- ]
- },
- zip_safe=False,
- platforms=['Any'],
- classifiers=['Development Status :: 4 - Beta',
- 'Environment :: Console',
- 'Intended Audience :: Developers',
- 'License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)',
- 'Operating System :: OS Independent'],
- package_data={"wptrunner": ["executors/testharness_marionette.js",
- "executors/testharness_webdriver.js",
- "executors/reftest.js",
- "executors/reftest-wait.js",
- "testharnessreport.js",
- "testharness_runner.html",
- "config.json",
- "wptrunner.default.ini",
- "browsers/server-locations.txt",
- "browsers/b2g_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)
- print textwrap.fill("""In order to use with one of the built-in browser
-products, you will need to install the extra dependencies. These are provided
-as requirements_[name].txt in the %s directory and can be installed using
-e.g.""" % path, 80)
-
- print """
-
-pip install -r %s/requirements_firefox.txt
-""" % path
diff --git a/tests/wpt/harness/test/metadata/reftest/reftest_and_fail.html.ini b/tests/wpt/harness/test/metadata/reftest/reftest_and_fail.html.ini
deleted file mode 100644
index 81aef049cd1..00000000000
--- a/tests/wpt/harness/test/metadata/reftest/reftest_and_fail.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[reftest_and_fail.html]
- type: reftest
- expected: FAIL
diff --git a/tests/wpt/harness/test/metadata/reftest/reftest_cycle_fail.html.ini b/tests/wpt/harness/test/metadata/reftest/reftest_cycle_fail.html.ini
deleted file mode 100644
index 472b33f7764..00000000000
--- a/tests/wpt/harness/test/metadata/reftest/reftest_cycle_fail.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[reftest_cycle_fail.html]
- type: reftest
- expected: FAIL
diff --git a/tests/wpt/harness/test/metadata/reftest/reftest_match_fail.html.ini b/tests/wpt/harness/test/metadata/reftest/reftest_match_fail.html.ini
deleted file mode 100644
index f3dc3362fac..00000000000
--- a/tests/wpt/harness/test/metadata/reftest/reftest_match_fail.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[reftest_match_fail.html]
- type: reftest
- expected: FAIL
diff --git a/tests/wpt/harness/test/metadata/reftest/reftest_mismatch_fail.html.ini b/tests/wpt/harness/test/metadata/reftest/reftest_mismatch_fail.html.ini
deleted file mode 100644
index 1055337e2d6..00000000000
--- a/tests/wpt/harness/test/metadata/reftest/reftest_mismatch_fail.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[reftest_mismatch_fail.html]
- type: reftest
- expected: FAIL
diff --git a/tests/wpt/harness/test/metadata/reftest/reftest_ref_timeout.html.ini b/tests/wpt/harness/test/metadata/reftest/reftest_ref_timeout.html.ini
deleted file mode 100644
index 8936241ad29..00000000000
--- a/tests/wpt/harness/test/metadata/reftest/reftest_ref_timeout.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[reftest_ref_timeout.html]
- type: reftest
- expected: TIMEOUT
diff --git a/tests/wpt/harness/test/metadata/reftest/reftest_timeout.html.ini b/tests/wpt/harness/test/metadata/reftest/reftest_timeout.html.ini
deleted file mode 100644
index 0d1b9bade95..00000000000
--- a/tests/wpt/harness/test/metadata/reftest/reftest_timeout.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[reftest_timeout.html]
- type: reftest
- expected: TIMEOUT
diff --git a/tests/wpt/harness/test/metadata/testharness/firefox/__dir__.ini b/tests/wpt/harness/test/metadata/testharness/firefox/__dir__.ini
deleted file mode 100644
index c9d164cd418..00000000000
--- a/tests/wpt/harness/test/metadata/testharness/firefox/__dir__.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-prefs: ["browser.display.foreground_color:#FF0000",
- "browser.display.background_color:#000000"] \ No newline at end of file
diff --git a/tests/wpt/harness/test/metadata/testharness/firefox/subdir/test_pref_reset.html.ini b/tests/wpt/harness/test/metadata/testharness/firefox/subdir/test_pref_reset.html.ini
deleted file mode 100644
index de0043c5149..00000000000
--- a/tests/wpt/harness/test/metadata/testharness/firefox/subdir/test_pref_reset.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[test_pref_reset.html]
- type: testharness
- prefs: [@Reset]
diff --git a/tests/wpt/harness/test/metadata/testharness/firefox/test_pref_set.html.ini b/tests/wpt/harness/test/metadata/testharness/firefox/test_pref_set.html.ini
deleted file mode 100644
index ca005cd7558..00000000000
--- a/tests/wpt/harness/test/metadata/testharness/firefox/test_pref_set.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[test_pref_set.html]
- type: testharness
- prefs: ["browser.display.foreground_color:#00FF00",
- "browser.display.background_color:#000000"]
diff --git a/tests/wpt/harness/test/metadata/testharness/subdir/__dir__.ini b/tests/wpt/harness/test/metadata/testharness/subdir/__dir__.ini
deleted file mode 100644
index a9157fbc6a9..00000000000
--- a/tests/wpt/harness/test/metadata/testharness/subdir/__dir__.ini
+++ /dev/null
@@ -1 +0,0 @@
-disabled: true \ No newline at end of file
diff --git a/tests/wpt/harness/test/metadata/testharness/subdir/testharness_1.html.ini b/tests/wpt/harness/test/metadata/testharness/subdir/testharness_1.html.ini
deleted file mode 100644
index 8be3d47e852..00000000000
--- a/tests/wpt/harness/test/metadata/testharness/subdir/testharness_1.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[testharness_1.html]
- type: testharness
- disabled: @False \ No newline at end of file
diff --git a/tests/wpt/harness/test/metadata/testharness/tags/__dir__.ini b/tests/wpt/harness/test/metadata/testharness/tags/__dir__.ini
deleted file mode 100644
index f599adda92b..00000000000
--- a/tests/wpt/harness/test/metadata/testharness/tags/__dir__.ini
+++ /dev/null
@@ -1 +0,0 @@
-tags: [dir-tag-1, dir-tag-2] \ No newline at end of file
diff --git a/tests/wpt/harness/test/metadata/testharness/tags/testharness_0.html.ini b/tests/wpt/harness/test/metadata/testharness/tags/testharness_0.html.ini
deleted file mode 100644
index 7fa297c7cea..00000000000
--- a/tests/wpt/harness/test/metadata/testharness/tags/testharness_0.html.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-tags: [file-tag]
-
-[testharness_0.html]
- type: testharness
- tags: [test-tag]
diff --git a/tests/wpt/harness/test/metadata/testharness/tags/testharness_1.html.ini b/tests/wpt/harness/test/metadata/testharness/tags/testharness_1.html.ini
deleted file mode 100644
index ecc07664f42..00000000000
--- a/tests/wpt/harness/test/metadata/testharness/tags/testharness_1.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[testharness_0.html]
- type: testharness
- tags: [test-1-tag]
diff --git a/tests/wpt/harness/test/metadata/testharness/tags/testharness_2.html.ini b/tests/wpt/harness/test/metadata/testharness/tags/testharness_2.html.ini
deleted file mode 100644
index d95e28832cc..00000000000
--- a/tests/wpt/harness/test/metadata/testharness/tags/testharness_2.html.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-tags: [file-tag]
-
-[testharness_2.html]
- type: testharness
- tags: [test-2-tag, @Reset]
diff --git a/tests/wpt/harness/test/metadata/testharness/testharness_0.html.ini b/tests/wpt/harness/test/metadata/testharness/testharness_0.html.ini
deleted file mode 100644
index 90b9a6e9f01..00000000000
--- a/tests/wpt/harness/test/metadata/testharness/testharness_0.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[testharness_0.html]
- type: testharness
- [Test that should fail]
- expected: FAIL
diff --git a/tests/wpt/harness/test/metadata/testharness/testharness_error.html.ini b/tests/wpt/harness/test/metadata/testharness/testharness_error.html.ini
deleted file mode 100644
index fa53e0733ab..00000000000
--- a/tests/wpt/harness/test/metadata/testharness/testharness_error.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[testharness_error.html]
- type: testharness
- expected: ERROR
diff --git a/tests/wpt/harness/test/metadata/testharness/testharness_timeout.html.ini b/tests/wpt/harness/test/metadata/testharness/testharness_timeout.html.ini
deleted file mode 100644
index 55eca5191ab..00000000000
--- a/tests/wpt/harness/test/metadata/testharness/testharness_timeout.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[testharness_timeout.html]
- type: testharness
- expected: TIMEOUT
diff --git a/tests/wpt/harness/test/test.cfg.example b/tests/wpt/harness/test/test.cfg.example
deleted file mode 100644
index db48226216c..00000000000
--- a/tests/wpt/harness/test/test.cfg.example
+++ /dev/null
@@ -1,20 +0,0 @@
-[general]
-tests=/path/to/web-platform-tests/
-metadata=/path/to/web-platform-tests/
-ssl-type=none
-
-# [firefox]
-# binary=/path/to/firefox
-# prefs-root=/path/to/gecko-src/testing/profiles/
-
-# [servo]
-# binary=/path/to/servo-src/target/release/servo
-# exclude=testharness # Because it needs a special testharness.js
-
-# [servodriver]
-# binary=/path/to/servo-src/target/release/servo
-# exclude=testharness # Because it needs a special testharness.js
-
-# [chrome]
-# binary=/path/to/chrome
-# webdriver-binary=/path/to/chromedriver
diff --git a/tests/wpt/harness/test/test.py b/tests/wpt/harness/test/test.py
deleted file mode 100644
index 034e317bd52..00000000000
--- a/tests/wpt/harness/test/test.py
+++ /dev/null
@@ -1,166 +0,0 @@
-import ConfigParser
-import argparse
-import json
-import os
-import sys
-import tempfile
-import threading
-import time
-from StringIO import StringIO
-
-from mozlog import structuredlog, reader
-from mozlog.handlers import BaseHandler, StreamHandler, StatusHandler
-from mozlog.formatters import MachFormatter
-from wptrunner import wptcommandline, wptrunner
-
-here = os.path.abspath(os.path.dirname(__file__))
-
-def setup_wptrunner_logging(logger):
- structuredlog.set_default_logger(logger)
- wptrunner.logger = logger
- wptrunner.wptlogging.setup_stdlib_logger()
-
-class ResultHandler(BaseHandler):
- def __init__(self, verbose=False, logger=None):
- self.inner = StreamHandler(sys.stdout, MachFormatter())
- BaseHandler.__init__(self, self.inner)
- self.product = None
- self.verbose = verbose
- self.logger = logger
-
- self.register_message_handlers("wptrunner-test", {"set-product": self.set_product})
-
- def set_product(self, product):
- self.product = product
-
- def __call__(self, data):
- if self.product is not None and data["action"] in ["suite_start", "suite_end"]:
- # Hack: mozlog sets some internal state to prevent multiple suite_start or
- # suite_end messages. We actually want that here (one from the metaharness
- # and one from the individual test type harness), so override that internal
- # state (a better solution might be to not share loggers, but this works well
- # enough)
- self.logger._state.suite_started = True
- return
-
- if (not self.verbose and
- (data["action"] == "process_output" or
- data["action"] == "log" and data["level"] not in ["error", "critical"])):
- return
-
- if "test" in data:
- data = data.copy()
- data["test"] = "%s: %s" % (self.product, data["test"])
-
- return self.inner(data)
-
-def test_settings():
- return {
- "include": "_test",
- "manifest-update": "",
- "no-capture-stdio": ""
- }
-
-def read_config():
- parser = ConfigParser.ConfigParser()
- parser.read("test.cfg")
-
- rv = {"general":{},
- "products":{}}
-
- rv["general"].update(dict(parser.items("general")))
-
- # This only allows one product per whatever for now
- for product in parser.sections():
- if product != "general":
- dest = rv["products"][product] = {}
- for key, value in parser.items(product):
- rv["products"][product][key] = value
-
- return rv
-
-def run_tests(product, kwargs):
- kwargs["test_paths"]["/_test/"] = {"tests_path": os.path.join(here, "testdata"),
- "metadata_path": os.path.join(here, "metadata")}
-
- wptrunner.run_tests(**kwargs)
-
-def settings_to_argv(settings):
- rv = []
- for name, value in settings.iteritems():
- key = "--%s" % name
- if not value:
- rv.append(key)
- elif isinstance(value, list):
- for item in value:
- rv.extend([key, item])
- else:
- rv.extend([key, value])
- return rv
-
-def set_from_args(settings, args):
- if args.test:
- settings["include"] = args.test
- if args.tags:
- settings["tags"] = args.tags
-
-def run(config, args):
- logger = structuredlog.StructuredLogger("web-platform-tests")
- logger.add_handler(ResultHandler(logger=logger, verbose=args.verbose))
- setup_wptrunner_logging(logger)
-
- parser = wptcommandline.create_parser()
-
- logger.suite_start(tests=[])
-
- for product, product_settings in config["products"].iteritems():
- if args.product and product not in args.product:
- continue
-
- settings = test_settings()
- settings.update(config["general"])
- settings.update(product_settings)
- settings["product"] = product
- set_from_args(settings, args)
-
- kwargs = vars(parser.parse_args(settings_to_argv(settings)))
- wptcommandline.check_args(kwargs)
-
- logger.send_message("wptrunner-test", "set-product", product)
-
- run_tests(product, kwargs)
-
- logger.send_message("wptrunner-test", "set-product", None)
- logger.suite_end()
-
-def get_parser():
- parser = argparse.ArgumentParser()
- parser.add_argument("-v", "--verbose", action="store_true", default=False,
- help="verbose log output")
- parser.add_argument("--product", action="append",
- help="Specific product to include in test run")
- parser.add_argument("--pdb", action="store_true",
- help="Invoke pdb on uncaught exception")
- parser.add_argument("--tag", action="append", dest="tags",
- help="tags to select tests")
- parser.add_argument("test", nargs="*",
- help="Specific tests to include in test run")
- return parser
-
-def main():
- config = read_config()
-
- args = get_parser().parse_args()
-
- try:
- run(config, args)
- except Exception:
- if args.pdb:
- import pdb, traceback
- print traceback.format_exc()
- pdb.post_mortem()
- else:
- raise
-
-if __name__ == "__main__":
- main()
diff --git a/tests/wpt/harness/test/testdata/reftest/green-ref.html b/tests/wpt/harness/test/testdata/reftest/green-ref.html
deleted file mode 100644
index 0e145d60b55..00000000000
--- a/tests/wpt/harness/test/testdata/reftest/green-ref.html
+++ /dev/null
@@ -1,4 +0,0 @@
-<link rel=match href=green.html>
-<style>
-:root {background-color:green}
-</style> \ No newline at end of file
diff --git a/tests/wpt/harness/test/testdata/reftest/green.html b/tests/wpt/harness/test/testdata/reftest/green.html
deleted file mode 100644
index 38167bb58d5..00000000000
--- a/tests/wpt/harness/test/testdata/reftest/green.html
+++ /dev/null
@@ -1,3 +0,0 @@
-<style>
-:root {background-color:green}
-</style> \ No newline at end of file
diff --git a/tests/wpt/harness/test/testdata/reftest/red.html b/tests/wpt/harness/test/testdata/reftest/red.html
deleted file mode 100644
index 2b677e00634..00000000000
--- a/tests/wpt/harness/test/testdata/reftest/red.html
+++ /dev/null
@@ -1,3 +0,0 @@
-<style>
-:root {background-color:red}
-</style> \ No newline at end of file
diff --git a/tests/wpt/harness/test/testdata/reftest/reftest.https.html b/tests/wpt/harness/test/testdata/reftest/reftest.https.html
deleted file mode 100644
index 5a45f10f35e..00000000000
--- a/tests/wpt/harness/test/testdata/reftest/reftest.https.html
+++ /dev/null
@@ -1,9 +0,0 @@
-<link rel=match href=green.html>
-<style>
-:root {background-color:red}
-</style>
-<script>
-if (window.location.protocol === "https:") {
- document.documentElement.style.backgroundColor = "green";
-}
-</script> \ No newline at end of file
diff --git a/tests/wpt/harness/test/testdata/reftest/reftest_and_fail.html b/tests/wpt/harness/test/testdata/reftest/reftest_and_fail.html
deleted file mode 100644
index 29601953562..00000000000
--- a/tests/wpt/harness/test/testdata/reftest/reftest_and_fail.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<title>Reftest chain that should fail</title>
-<link rel=match href=reftest_and_fail_0-ref.html>
-<style>
-:root {background-color:green}
-</style> \ No newline at end of file
diff --git a/tests/wpt/harness/test/testdata/reftest/reftest_and_fail_0-ref.html b/tests/wpt/harness/test/testdata/reftest/reftest_and_fail_0-ref.html
deleted file mode 100644
index 04fb9aa1517..00000000000
--- a/tests/wpt/harness/test/testdata/reftest/reftest_and_fail_0-ref.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<title>Reftest chain that should fail</title>
-<link rel=match href=red.html>
-<style>
-:root {background-color:green}
-</style> \ No newline at end of file
diff --git a/tests/wpt/harness/test/testdata/reftest/reftest_cycle.html b/tests/wpt/harness/test/testdata/reftest/reftest_cycle.html
deleted file mode 100644
index 4a84a3b6741..00000000000
--- a/tests/wpt/harness/test/testdata/reftest/reftest_cycle.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<title>Reftest with cycle, all match</title>
-<link rel=match href=reftest_cycle_0-ref.html>
-<style>
-:root {background-color:green}
-</style> \ No newline at end of file
diff --git a/tests/wpt/harness/test/testdata/reftest/reftest_cycle_0-ref.html b/tests/wpt/harness/test/testdata/reftest/reftest_cycle_0-ref.html
deleted file mode 100644
index 118bfd88447..00000000000
--- a/tests/wpt/harness/test/testdata/reftest/reftest_cycle_0-ref.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<title>OR match that should pass</title>
-<link rel=match href=reftest_cycle_1-ref.html>
-<style>
-:root {background-color:green}
-</style> \ No newline at end of file
diff --git a/tests/wpt/harness/test/testdata/reftest/reftest_cycle_1-ref.html b/tests/wpt/harness/test/testdata/reftest/reftest_cycle_1-ref.html
deleted file mode 100644
index 59be0b641de..00000000000
--- a/tests/wpt/harness/test/testdata/reftest/reftest_cycle_1-ref.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<title>Reftest with cycle, all match</title>
-<link rel=match href=reftest_cycle.html>
-<style>
-:root {background-color:green}
-</style> \ No newline at end of file
diff --git a/tests/wpt/harness/test/testdata/reftest/reftest_cycle_fail.html b/tests/wpt/harness/test/testdata/reftest/reftest_cycle_fail.html
deleted file mode 100644
index 175e76c4cc9..00000000000
--- a/tests/wpt/harness/test/testdata/reftest/reftest_cycle_fail.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<title>Reftest with cycle, fails</title>
-<link rel=match href=reftest_cycle_fail_0-ref.html>
-<style>
-:root {background-color:green}
-</style> \ No newline at end of file
diff --git a/tests/wpt/harness/test/testdata/reftest/reftest_cycle_fail_0-ref.html b/tests/wpt/harness/test/testdata/reftest/reftest_cycle_fail_0-ref.html
deleted file mode 100644
index c8e548c4622..00000000000
--- a/tests/wpt/harness/test/testdata/reftest/reftest_cycle_fail_0-ref.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<title>Reftest with cycle, fails</title>
-<link rel=mismatch href=reftest_cycle_fail.html>
-<style>
-:root {background-color:green}
-</style> \ No newline at end of file
diff --git a/tests/wpt/harness/test/testdata/reftest/reftest_match.html b/tests/wpt/harness/test/testdata/reftest/reftest_match.html
deleted file mode 100644
index 333cc6c1ecd..00000000000
--- a/tests/wpt/harness/test/testdata/reftest/reftest_match.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<title>rel=match that should pass</title>
-<link rel=match href=green.html>
-<style>
-:root {background-color:green}
-</style> \ No newline at end of file
diff --git a/tests/wpt/harness/test/testdata/reftest/reftest_match_fail.html b/tests/wpt/harness/test/testdata/reftest/reftest_match_fail.html
deleted file mode 100644
index a9272ef74da..00000000000
--- a/tests/wpt/harness/test/testdata/reftest/reftest_match_fail.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<title>rel=match that should fail</title>
-<link rel=match href=red.html>
-<style>
-:root {background-color:green}
-</style> \ No newline at end of file
diff --git a/tests/wpt/harness/test/testdata/reftest/reftest_mismatch.html b/tests/wpt/harness/test/testdata/reftest/reftest_mismatch.html
deleted file mode 100644
index af5fa0750d8..00000000000
--- a/tests/wpt/harness/test/testdata/reftest/reftest_mismatch.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<title>rel=mismatch that should pass</title>
-<link rel=mismatch href=red.html>
-<style>
-:root {background-color:green}
-</style> \ No newline at end of file
diff --git a/tests/wpt/harness/test/testdata/reftest/reftest_mismatch_fail.html b/tests/wpt/harness/test/testdata/reftest/reftest_mismatch_fail.html
deleted file mode 100644
index 8d160c4fc20..00000000000
--- a/tests/wpt/harness/test/testdata/reftest/reftest_mismatch_fail.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<title>rel=mismatch that should fail</title>
-<link rel=mismatch href=green.html>
-<style>
-:root {background-color:green}
-</style> \ No newline at end of file
diff --git a/tests/wpt/harness/test/testdata/reftest/reftest_or_0.html b/tests/wpt/harness/test/testdata/reftest/reftest_or_0.html
deleted file mode 100644
index 3a51de21644..00000000000
--- a/tests/wpt/harness/test/testdata/reftest/reftest_or_0.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<title>OR match that should pass</title>
-<link rel=match href=red.html>
-<link rel=match href=green.html>
-<style>
-:root {background-color:green}
-</style> \ No newline at end of file
diff --git a/tests/wpt/harness/test/testdata/reftest/reftest_ref_timeout-ref.html b/tests/wpt/harness/test/testdata/reftest/reftest_ref_timeout-ref.html
deleted file mode 100644
index 04cbb71e0c3..00000000000
--- a/tests/wpt/harness/test/testdata/reftest/reftest_ref_timeout-ref.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<html class="reftest-wait">
-<title>rel=match that should time out in the ref</title>
-<link rel=match href=reftest_ref_timeout-ref.html>
-<style>
-:root {background-color:green}
-</style>
diff --git a/tests/wpt/harness/test/testdata/reftest/reftest_ref_timeout.html b/tests/wpt/harness/test/testdata/reftest/reftest_ref_timeout.html
deleted file mode 100644
index aaf68f5cb5f..00000000000
--- a/tests/wpt/harness/test/testdata/reftest/reftest_ref_timeout.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<html>
-<title>rel=match that should time out in the ref</title>
-<link rel=match href=reftest_ref_timeout-ref.html>
-<style>
-:root {background-color:green}
-</style>
diff --git a/tests/wpt/harness/test/testdata/reftest/reftest_timeout.html b/tests/wpt/harness/test/testdata/reftest/reftest_timeout.html
deleted file mode 100644
index b10e676bf00..00000000000
--- a/tests/wpt/harness/test/testdata/reftest/reftest_timeout.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<html class="reftest-wait">
-<title>rel=match that should timeout</title>
-<link rel=match href=green.html>
-<style>
-:root {background-color:green}
-</style>
diff --git a/tests/wpt/harness/test/testdata/reftest/reftest_wait_0.html b/tests/wpt/harness/test/testdata/reftest/reftest_wait_0.html
deleted file mode 100644
index 0088c0cab88..00000000000
--- a/tests/wpt/harness/test/testdata/reftest/reftest_wait_0.html
+++ /dev/null
@@ -1,11 +0,0 @@
-<title>rel=match that should fail</title>
-<link rel=match href=red.html>
-<style>
-:root {background-color:red}
-</style>
-<body class="reftest-wait">
-<script>
-setTimeout(function() {
- document.documentElement.style.backgroundColor = "green";
- body.className = "";
-}, 2000); \ No newline at end of file
diff --git a/tests/wpt/harness/test/testdata/testharness/firefox/subdir/test_pref_inherit.html b/tests/wpt/harness/test/testdata/testharness/firefox/subdir/test_pref_inherit.html
deleted file mode 100644
index 10b285194b4..00000000000
--- a/tests/wpt/harness/test/testdata/testharness/firefox/subdir/test_pref_inherit.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<!doctype html>
-<title>Example pref test</title>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<p>Test requires the pref browser.display.foreground_color to be set to #00FF00</p>
-<script>
-test(function() {
- assert_equals(getComputedStyle(document.body).color, "rgb(255, 0, 0)");
-}, "Test that pref was set");
-</script>
diff --git a/tests/wpt/harness/test/testdata/testharness/firefox/subdir/test_pref_reset.html b/tests/wpt/harness/test/testdata/testharness/firefox/subdir/test_pref_reset.html
deleted file mode 100644
index 5c75c116052..00000000000
--- a/tests/wpt/harness/test/testdata/testharness/firefox/subdir/test_pref_reset.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<!doctype html>
-<title>Example pref test</title>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<p>Test requires the pref browser.display.foreground_color to be set to #00FF00</p>
-<script>
-test(function() {
- assert_equals(getComputedStyle(document.body).color, "rgb(0, 0, 0)");
-}, "Test that pref was reset");
-</script>
diff --git a/tests/wpt/harness/test/testdata/testharness/firefox/test_pref_dir.html b/tests/wpt/harness/test/testdata/testharness/firefox/test_pref_dir.html
deleted file mode 100644
index 105d9070c9d..00000000000
--- a/tests/wpt/harness/test/testdata/testharness/firefox/test_pref_dir.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<!doctype html>
-<title>Example pref test</title>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<p>Test requires the pref browser.display.foreground_color to be set to #FF0000</p>
-<script>
-test(function() {
- assert_equals(getComputedStyle(document.body).color, "rgb(255, 0, 0)");
-}, "Test that pref was set");
-</script>
diff --git a/tests/wpt/harness/test/testdata/testharness/firefox/test_pref_set.html b/tests/wpt/harness/test/testdata/testharness/firefox/test_pref_set.html
deleted file mode 100644
index 8e5e2989bf7..00000000000
--- a/tests/wpt/harness/test/testdata/testharness/firefox/test_pref_set.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<!doctype html>
-<title>Example pref test</title>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<p>Test requires the pref browser.display.foreground_color to be set to #00FF00</p>
-<script>
-test(function() {
- assert_equals(getComputedStyle(document.body).color, "rgb(0, 255, 0)");
-}, "Test that pref was set");
-</script>
diff --git a/tests/wpt/harness/test/testdata/testharness/subdir/testharness_1.html b/tests/wpt/harness/test/testdata/testharness/subdir/testharness_1.html
deleted file mode 100644
index fd2fc431d39..00000000000
--- a/tests/wpt/harness/test/testdata/testharness/subdir/testharness_1.html
+++ /dev/null
@@ -1,9 +0,0 @@
-<!doctype html>
-<title>Test should be enabled</title>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script>
-test(function() {
- assert_true(true);
-}, "Test that should pass");
-</script>
diff --git a/tests/wpt/harness/test/testdata/testharness/tags/testharness_0.html b/tests/wpt/harness/test/testdata/testharness/tags/testharness_0.html
deleted file mode 100644
index 5daf02a77d9..00000000000
--- a/tests/wpt/harness/test/testdata/testharness/tags/testharness_0.html
+++ /dev/null
@@ -1,9 +0,0 @@
-<!doctype html>
-<title>Test</title>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script>
-test(function() {
- assert_true(true);
-}, "Test that should pass");
-</script>
diff --git a/tests/wpt/harness/test/testdata/testharness/tags/testharness_1.html b/tests/wpt/harness/test/testdata/testharness/tags/testharness_1.html
deleted file mode 100644
index 5daf02a77d9..00000000000
--- a/tests/wpt/harness/test/testdata/testharness/tags/testharness_1.html
+++ /dev/null
@@ -1,9 +0,0 @@
-<!doctype html>
-<title>Test</title>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script>
-test(function() {
- assert_true(true);
-}, "Test that should pass");
-</script>
diff --git a/tests/wpt/harness/test/testdata/testharness/tags/testharness_2.html b/tests/wpt/harness/test/testdata/testharness/tags/testharness_2.html
deleted file mode 100644
index 5daf02a77d9..00000000000
--- a/tests/wpt/harness/test/testdata/testharness/tags/testharness_2.html
+++ /dev/null
@@ -1,9 +0,0 @@
-<!doctype html>
-<title>Test</title>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script>
-test(function() {
- assert_true(true);
-}, "Test that should pass");
-</script>
diff --git a/tests/wpt/harness/test/testdata/testharness/testharness.https.html b/tests/wpt/harness/test/testdata/testharness/testharness.https.html
deleted file mode 100644
index 5871eac0014..00000000000
--- a/tests/wpt/harness/test/testdata/testharness/testharness.https.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<!doctype html>
-<title>Example https test</title>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script>
-test(function() {
- assert_equals(window.location.protocol, "https:");
-}, "Test that file was loaded with the correct protocol");
-
-</script> \ No newline at end of file
diff --git a/tests/wpt/harness/test/testdata/testharness/testharness_0.html b/tests/wpt/harness/test/testdata/testharness/testharness_0.html
deleted file mode 100644
index ff0654cb9a0..00000000000
--- a/tests/wpt/harness/test/testdata/testharness/testharness_0.html
+++ /dev/null
@@ -1,9 +0,0 @@
-<!doctype html>
-<title>Test should be disabled</title>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script>
-test(function() {
- assert_true(false);
-}, "Test that should fail");
-</script>
diff --git a/tests/wpt/harness/test/testdata/testharness/testharness_error.html b/tests/wpt/harness/test/testdata/testharness/testharness_error.html
deleted file mode 100644
index 0ac5ba46a33..00000000000
--- a/tests/wpt/harness/test/testdata/testharness/testharness_error.html
+++ /dev/null
@@ -1,7 +0,0 @@
-<!doctype html>
-<title>testharness.js test that should error</title>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script>
-undefined_function()
-</script>
diff --git a/tests/wpt/harness/test/testdata/testharness/testharness_long_timeout.html b/tests/wpt/harness/test/testdata/testharness/testharness_long_timeout.html
deleted file mode 100644
index fc94e055be0..00000000000
--- a/tests/wpt/harness/test/testdata/testharness/testharness_long_timeout.html
+++ /dev/null
@@ -1,9 +0,0 @@
-<!doctype html>
-<title>testharness.js test with long timeout</title>
-<meta name=timeout content=long>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script>
-var t = async_test("Long timeout test");
-setTimeout(t.step_func_done(function() {assert_true(true)}), 15*1000);
-</script> \ No newline at end of file
diff --git a/tests/wpt/harness/test/testdata/testharness/testharness_timeout.html b/tests/wpt/harness/test/testdata/testharness/testharness_timeout.html
deleted file mode 100644
index b99915ac745..00000000000
--- a/tests/wpt/harness/test/testdata/testharness/testharness_timeout.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<!doctype html>
-<title>Simple testharness.js usage</title>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-
-// This file should time out, obviously \ No newline at end of file
diff --git a/tests/wpt/harness/tox.ini b/tests/wpt/harness/tox.ini
deleted file mode 100644
index 844a8d05b20..00000000000
--- a/tests/wpt/harness/tox.ini
+++ /dev/null
@@ -1,15 +0,0 @@
-[pytest]
-xfail_strict=true
-
-[tox]
-envlist = {py27,pypy}-{base,b2g,chrome,firefox,servo}
-
-[testenv]
-deps =
- pytest>=2.9
- -r{toxinidir}/requirements.txt
- chrome: -r{toxinidir}/requirements_chrome.txt
- firefox: -r{toxinidir}/requirements_firefox.txt
- servo: -r{toxinidir}/requirements_servo.txt
-
-commands = py.test []
diff --git a/tests/wpt/harness/wptrunner.default.ini b/tests/wpt/harness/wptrunner.default.ini
deleted file mode 100644
index 34d25f8056b..00000000000
--- a/tests/wpt/harness/wptrunner.default.ini
+++ /dev/null
@@ -1,11 +0,0 @@
-[products]
-
-[web-platform-tests]
-remote_url = https://github.com/w3c/web-platform-tests.git
-branch = master
-sync_path = %(pwd)s/sync
-
-[manifest:default]
-tests = %(pwd)s/tests
-metadata = %(pwd)s/meta
-url_base = / \ No newline at end of file
diff --git a/tests/wpt/harness/wptrunner/__init__.py b/tests/wpt/harness/wptrunner/__init__.py
deleted file mode 100644
index 6fbe8159b2d..00000000000
--- a/tests/wpt/harness/wptrunner/__init__.py
+++ /dev/null
@@ -1,3 +0,0 @@
-# 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/.
diff --git a/tests/wpt/harness/wptrunner/browsers/__init__.py b/tests/wpt/harness/wptrunner/browsers/__init__.py
deleted file mode 100644
index 8b34cc3963f..00000000000
--- a/tests/wpt/harness/wptrunner/browsers/__init__.py
+++ /dev/null
@@ -1,33 +0,0 @@
-# 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/.
-
-"""Subpackage where each product is defined. Each product is created by adding a
-a .py file containing a __wptrunner__ variable in the global scope. This must be
-a dictionary with the fields
-
-"product": Name of the product, assumed to be unique.
-"browser": String indicating the Browser implementation used to launch that
- product.
-"executor": Dictionary with keys as supported test types and values as the name
- of the Executor implemantation that will be used to run that test
- type.
-"browser_kwargs": String naming function that takes product, binary,
- prefs_root and the wptrunner.run_tests kwargs dict as arguments
- and returns a dictionary of kwargs to use when creating the
- Browser class.
-"executor_kwargs": String naming a function that takes http server url and
- timeout multiplier and returns kwargs to use when creating
- the executor class.
-"env_options": String naming a funtion of no arguments that returns the
- arguments passed to the TestEnvironment.
-
-All classes and functions named in the above dict must be imported into the
-module global scope.
-"""
-
-product_list = ["chrome",
- "edge",
- "firefox",
- "servo",
- "servodriver"]
diff --git a/tests/wpt/harness/wptrunner/browsers/b2g.py b/tests/wpt/harness/wptrunner/browsers/b2g.py
deleted file mode 100644
index bedb00a4943..00000000000
--- a/tests/wpt/harness/wptrunner/browsers/b2g.py
+++ /dev/null
@@ -1,243 +0,0 @@
-# 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 tempfile
-import shutil
-import subprocess
-
-import fxos_appgen
-import gaiatest
-import mozdevice
-import moznetwork
-import mozrunner
-from marionette import expected
-from marionette.by import By
-from marionette.wait import Wait
-from mozprofile import FirefoxProfile, Preferences
-
-from .base import get_free_port, BrowserError, Browser, ExecutorBrowser
-from ..executors.executormarionette import MarionetteTestharnessExecutor
-from ..hosts import HostsFile, HostsLine
-from ..environment import hostnames
-
-here = os.path.split(__file__)[0]
-
-__wptrunner__ = {"product": "b2g",
- "check_args": "check_args",
- "browser": "B2GBrowser",
- "executor": {"testharness": "B2GMarionetteTestharnessExecutor"},
- "browser_kwargs": "browser_kwargs",
- "executor_kwargs": "executor_kwargs",
- "env_options": "env_options"}
-
-
-def check_args(**kwargs):
- pass
-
-
-def browser_kwargs(test_environment, **kwargs):
- return {"prefs_root": kwargs["prefs_root"],
- "no_backup": kwargs.get("b2g_no_backup", False)}
-
-
-def executor_kwargs(test_type, server_config, cache_manager, run_info_data,
- **kwargs):
- timeout_multiplier = kwargs["timeout_multiplier"]
- if timeout_multiplier is None:
- timeout_multiplier = 2
-
- executor_kwargs = {"server_config": server_config,
- "timeout_multiplier": timeout_multiplier,
- "close_after_done": False}
-
- if test_type == "reftest":
- executor_kwargs["cache_manager"] = cache_manager
-
- return executor_kwargs
-
-
-def env_options():
- return {"host": "web-platform.test",
- "bind_hostname": "false",
- "test_server_port": False}
-
-
-class B2GBrowser(Browser):
- used_ports = set()
- init_timeout = 180
-
- def __init__(self, logger, prefs_root, no_backup=False):
- Browser.__init__(self, logger)
- logger.info("Waiting for device")
- subprocess.call(["adb", "wait-for-device"])
- self.device = mozdevice.DeviceManagerADB()
- self.marionette_port = get_free_port(2828, exclude=self.used_ports)
- self.used_ports.add(self.marionette_port)
- self.cert_test_app = None
- self.runner = None
- self.prefs_root = prefs_root
-
- self.no_backup = no_backup
- self.backup_path = None
- self.backup_paths = []
- self.backup_dirs = []
-
- def setup(self):
- self.logger.info("Running B2G setup")
- self.backup_path = tempfile.mkdtemp()
-
- self.logger.debug("Backing up device to %s" % (self.backup_path,))
-
- if not self.no_backup:
- self.backup_dirs = [("/data/local", os.path.join(self.backup_path, "local")),
- ("/data/b2g/mozilla", os.path.join(self.backup_path, "profile"))]
-
- self.backup_paths = [("/system/etc/hosts", os.path.join(self.backup_path, "hosts"))]
-
- for remote, local in self.backup_dirs:
- self.device.getDirectory(remote, local)
-
- for remote, local in self.backup_paths:
- self.device.getFile(remote, local)
-
- self.setup_hosts()
-
- def start(self):
- profile = FirefoxProfile()
-
- profile.set_preferences({"dom.disable_open_during_load": False,
- "marionette.defaultPrefs.enabled": True})
-
- self.logger.debug("Creating device runner")
- self.runner = mozrunner.B2GDeviceRunner(profile=profile)
- self.logger.debug("Starting device runner")
- self.runner.start()
- self.logger.debug("Device runner started")
-
- def setup_hosts(self):
- host_ip = moznetwork.get_ip()
-
- temp_dir = tempfile.mkdtemp()
- hosts_path = os.path.join(temp_dir, "hosts")
- remote_path = "/system/etc/hosts"
- try:
- self.device.getFile("/system/etc/hosts", hosts_path)
-
- with open(hosts_path) as f:
- hosts_file = HostsFile.from_file(f)
-
- for canonical_hostname in hostnames:
- hosts_file.set_host(HostsLine(host_ip, canonical_hostname))
-
- with open(hosts_path, "w") as f:
- hosts_file.to_file(f)
-
- self.logger.info("Installing hosts file")
-
- self.device.remount()
- self.device.removeFile(remote_path)
- self.device.pushFile(hosts_path, remote_path)
- finally:
- os.unlink(hosts_path)
- os.rmdir(temp_dir)
-
- def load_prefs(self):
- prefs_path = os.path.join(self.prefs_root, "prefs_general.js")
- if os.path.exists(prefs_path):
- preferences = Preferences.read_prefs(prefs_path)
- else:
- self.logger.warning("Failed to find base prefs file in %s" % prefs_path)
- preferences = []
-
- return preferences
-
- def stop(self):
- pass
-
- def on_output(self):
- raise NotImplementedError
-
- def cleanup(self):
- self.logger.debug("Running browser cleanup steps")
-
- self.device.remount()
-
- for remote, local in self.backup_dirs:
- self.device.removeDir(remote)
- self.device.pushDir(local, remote)
-
- for remote, local in self.backup_paths:
- self.device.removeFile(remote)
- self.device.pushFile(local, remote)
-
- shutil.rmtree(self.backup_path)
- self.device.reboot(wait=True)
-
- def pid(self):
- return None
-
- def is_alive(self):
- return True
-
- def executor_browser(self):
- return B2GExecutorBrowser, {"marionette_port": self.marionette_port}
-
-
-class B2GExecutorBrowser(ExecutorBrowser):
- # The following methods are called from a different process
- def __init__(self, *args, **kwargs):
- ExecutorBrowser.__init__(self, *args, **kwargs)
-
- import sys, subprocess
-
- self.device = mozdevice.ADBB2G()
- self.device.forward("tcp:%s" % self.marionette_port,
- "tcp:2828")
- self.executor = None
- self.marionette = None
- self.gaia_device = None
- self.gaia_apps = None
-
- def after_connect(self, executor):
- self.executor = executor
- self.marionette = executor.marionette
- self.executor.logger.debug("Running browser.after_connect steps")
-
- self.gaia_apps = gaiatest.GaiaApps(marionette=executor.marionette)
-
- self.executor.logger.debug("Waiting for homescreen to load")
-
- # Moved out of gaia_test temporarily
- self.executor.logger.info("Waiting for B2G to be ready")
- self.wait_for_homescreen(timeout=60)
-
- self.install_cert_app()
- self.use_cert_app()
-
- def install_cert_app(self):
- """Install the container app used to run the tests"""
- if fxos_appgen.is_installed("CertTest App"):
- self.executor.logger.info("CertTest App is already installed")
- return
- self.executor.logger.info("Installing CertTest App")
- app_path = os.path.join(here, "b2g_setup", "certtest_app.zip")
- fxos_appgen.install_app("CertTest App", app_path, marionette=self.marionette)
- self.executor.logger.debug("Install complete")
-
- def use_cert_app(self):
- """Start the app used to run the tests"""
- self.executor.logger.info("Homescreen loaded")
- self.gaia_apps.launch("CertTest App")
-
- def wait_for_homescreen(self, timeout):
- self.executor.logger.info("Waiting for home screen to load")
- Wait(self.marionette, timeout).until(expected.element_present(
- By.CSS_SELECTOR, '#homescreen[loading-state=false]'))
-
-
-class B2GMarionetteTestharnessExecutor(MarionetteTestharnessExecutor):
- def after_connect(self):
- self.browser.after_connect(self)
- MarionetteTestharnessExecutor.after_connect(self)
diff --git a/tests/wpt/harness/wptrunner/browsers/b2g_setup/certtest_app.zip b/tests/wpt/harness/wptrunner/browsers/b2g_setup/certtest_app.zip
deleted file mode 100644
index f9cbd5300ad..00000000000
--- a/tests/wpt/harness/wptrunner/browsers/b2g_setup/certtest_app.zip
+++ /dev/null
Binary files differ
diff --git a/tests/wpt/harness/wptrunner/browsers/base.py b/tests/wpt/harness/wptrunner/browsers/base.py
deleted file mode 100644
index 1d3b3d231c7..00000000000
--- a/tests/wpt/harness/wptrunner/browsers/base.py
+++ /dev/null
@@ -1,160 +0,0 @@
-# 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 platform
-import socket
-from abc import ABCMeta, abstractmethod
-
-from ..wptcommandline import require_arg
-
-here = os.path.split(__file__)[0]
-
-
-def cmd_arg(name, value=None):
- prefix = "-" if platform.system() == "Windows" else "--"
- rv = prefix + name
- if value is not None:
- rv += "=" + value
- return rv
-
-
-def get_free_port(start_port, exclude=None):
- """Get the first port number after start_port (inclusive) that is
- not currently bound.
-
- :param start_port: Integer port number at which to start testing.
- :param exclude: Set of port numbers to skip"""
- port = start_port
- while True:
- if exclude and port in exclude:
- port += 1
- continue
- s = socket.socket()
- try:
- s.bind(("127.0.0.1", port))
- except socket.error:
- port += 1
- else:
- return port
- finally:
- s.close()
-
-def browser_command(binary, args, debug_info):
- if debug_info:
- if debug_info.requiresEscapedArgs:
- args = [item.replace("&", "\\&") for item in args]
- debug_args = [debug_info.path] + debug_info.args
- else:
- debug_args = []
-
- command = [binary] + args
-
- return debug_args, command
-
-
-class BrowserError(Exception):
- pass
-
-
-class Browser(object):
- __metaclass__ = ABCMeta
-
- process_cls = None
- init_timeout = 30
-
- def __init__(self, logger):
- """Abstract class serving as the basis for Browser implementations.
-
- The Browser is used in the TestRunnerManager to start and stop the browser
- process, and to check the state of that process. This class also acts as a
- context manager, enabling it to do browser-specific setup at the start of
- the testrun and cleanup after the run is complete.
-
- :param logger: Structured logger to use for output.
- """
- self.logger = logger
-
- def __enter__(self):
- self.setup()
- return self
-
- def __exit__(self, *args, **kwargs):
- self.cleanup()
-
- def setup(self):
- """Used for browser-specific setup that happens at the start of a test run"""
- pass
-
- @abstractmethod
- def start(self):
- """Launch the browser object and get it into a state where is is ready to run tests"""
- pass
-
- @abstractmethod
- def stop(self):
- """Stop the running browser process."""
- pass
-
- @abstractmethod
- def pid(self):
- """pid of the browser process or None if there is no pid"""
- pass
-
- @abstractmethod
- def is_alive(self):
- """Boolean indicating whether the browser process is still running"""
- pass
-
- def setup_ssl(self, hosts):
- """Return a certificate to use for tests requiring ssl that will be trusted by the browser"""
- raise NotImplementedError("ssl testing not supported")
-
- def cleanup(self):
- """Browser-specific cleanup that is run after the testrun is finished"""
- pass
-
- def executor_browser(self):
- """Returns the ExecutorBrowser subclass for this Browser subclass and the keyword arguments
- with which it should be instantiated"""
- return ExecutorBrowser, {}
-
- def log_crash(self, process, test):
- """Return a list of dictionaries containing information about crashes that happend
- in the browser, or an empty list if no crashes occurred"""
- self.logger.crash(process, test)
-
-
-class NullBrowser(Browser):
- def start(self):
- """No-op browser to use in scenarios where the TestRunnerManager shouldn't
- actually own the browser process (e.g. Servo where we start one browser
- per test)"""
- pass
-
- def stop(self):
- pass
-
- def pid(self):
- return None
-
- def is_alive(self):
- return True
-
- def on_output(self, line):
- raise NotImplementedError
-
-
-class ExecutorBrowser(object):
- def __init__(self, **kwargs):
- """View of the Browser used by the Executor object.
- This is needed because the Executor runs in a child process and
- we can't ship Browser instances between processes on Windows.
-
- Typically this will have a few product-specific properties set,
- but in some cases it may have more elaborate methods for setting
- up the browser from the runner process.
- """
- for k, v in kwargs.iteritems():
- setattr(self, k, v)
diff --git a/tests/wpt/harness/wptrunner/browsers/chrome.py b/tests/wpt/harness/wptrunner/browsers/chrome.py
deleted file mode 100644
index 18491359456..00000000000
--- a/tests/wpt/harness/wptrunner/browsers/chrome.py
+++ /dev/null
@@ -1,81 +0,0 @@
-# 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/.
-
-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)
-
-
-__wptrunner__ = {"product": "chrome",
- "check_args": "check_args",
- "browser": "ChromeBrowser",
- "executor": {"testharness": "SeleniumTestharnessExecutor",
- "reftest": "SeleniumRefTestExecutor"},
- "browser_kwargs": "browser_kwargs",
- "executor_kwargs": "executor_kwargs",
- "env_options": "env_options"}
-
-
-def check_args(**kwargs):
- require_arg(kwargs, "webdriver_binary")
-
-
-def browser_kwargs(**kwargs):
- return {"binary": kwargs["binary"],
- "webdriver_binary": kwargs["webdriver_binary"]}
-
-
-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
- executor_kwargs["capabilities"] = dict(DesiredCapabilities.CHROME.items())
- if kwargs["binary"] is not None:
- executor_kwargs["capabilities"]["chromeOptions"] = {"binary": kwargs["binary"]}
-
- return executor_kwargs
-
-
-def env_options():
- return {"host": "web-platform.test",
- "bind_hostname": "true"}
-
-
-class ChromeBrowser(Browser):
- """Chrome is backed by chromedriver, which is supplied through
- ``wptrunner.webdriver.ChromeDriverServer``.
- """
-
- def __init__(self, logger, binary, webdriver_binary="chromedriver"):
- """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)
-
- def start(self):
- self.server.start(block=False)
-
- def stop(self):
- self.server.stop()
-
- 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}
diff --git a/tests/wpt/harness/wptrunner/browsers/edge.py b/tests/wpt/harness/wptrunner/browsers/edge.py
deleted file mode 100644
index 7c993fce1ac..00000000000
--- a/tests/wpt/harness/wptrunner/browsers/edge.py
+++ /dev/null
@@ -1,71 +0,0 @@
-# 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/.
-
-from .base import Browser, ExecutorBrowser, require_arg
-from ..webdriver_server import EdgeDriverServer
-from ..executors import executor_kwargs as base_executor_kwargs
-from ..executors.executorselenium import (SeleniumTestharnessExecutor,
- SeleniumRefTestExecutor)
-
-__wptrunner__ = {"product": "edge",
- "check_args": "check_args",
- "browser": "EdgeBrowser",
- "executor": {"testharness": "SeleniumTestharnessExecutor",
- "reftest": "SeleniumRefTestExecutor"},
- "browser_kwargs": "browser_kwargs",
- "executor_kwargs": "executor_kwargs",
- "env_options": "env_options"}
-
-
-def check_args(**kwargs):
- require_arg(kwargs, "webdriver_binary")
-
-def browser_kwargs(**kwargs):
- return {"webdriver_binary": kwargs["webdriver_binary"]}
-
-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
- executor_kwargs["capabilities"] = dict(DesiredCapabilities.EDGE.items())
- return executor_kwargs
-
-def env_options():
- return {"host": "web-platform.test",
- "bind_hostname": "true",
- "supports_debugger": False}
-
-class EdgeBrowser(Browser):
- used_ports = set()
-
- def __init__(self, logger, webdriver_binary):
- Browser.__init__(self, logger)
- self.server = EdgeDriverServer(self.logger, binary=webdriver_binary)
- self.webdriver_host = "localhost"
- self.webdriver_port = self.server.port
-
- def start(self):
- print self.server.url
- self.server.start()
-
- def stop(self):
- self.server.stop()
-
- def pid(self):
- return self.server.pid
-
- def is_alive(self):
- # TODO(ato): This only indicates the server 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}
diff --git a/tests/wpt/harness/wptrunner/browsers/firefox.py b/tests/wpt/harness/wptrunner/browsers/firefox.py
deleted file mode 100644
index ab75eb5ce50..00000000000
--- a/tests/wpt/harness/wptrunner/browsers/firefox.py
+++ /dev/null
@@ -1,264 +0,0 @@
-# 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 platform
-import subprocess
-import sys
-
-import mozinfo
-from mozprocess import ProcessHandler
-from mozprofile import FirefoxProfile, Preferences
-from mozprofile.permissions import ServerLocations
-from mozrunner import FirefoxRunner
-from mozcrash import mozcrash
-
-from .base import (get_free_port,
- Browser,
- ExecutorBrowser,
- require_arg,
- cmd_arg,
- browser_command)
-from ..executors import executor_kwargs as base_executor_kwargs
-from ..executors.executormarionette import (MarionetteTestharnessExecutor,
- MarionetteRefTestExecutor,
- MarionetteWdspecExecutor)
-from ..environment import hostnames
-
-
-here = os.path.join(os.path.split(__file__)[0])
-
-__wptrunner__ = {"product": "firefox",
- "check_args": "check_args",
- "browser": "FirefoxBrowser",
- "executor": {"testharness": "MarionetteTestharnessExecutor",
- "reftest": "MarionetteRefTestExecutor",
- "wdspec": "MarionetteWdspecExecutor"},
- "browser_kwargs": "browser_kwargs",
- "executor_kwargs": "executor_kwargs",
- "env_options": "env_options",
- "run_info_extras": "run_info_extras",
- "update_properties": "update_properties"}
-
-
-def check_args(**kwargs):
- require_arg(kwargs, "binary")
- if kwargs["ssl_type"] != "none":
- require_arg(kwargs, "certutil_binary")
-
-
-def browser_kwargs(**kwargs):
- return {"binary": kwargs["binary"],
- "prefs_root": kwargs["prefs_root"],
- "debug_info": kwargs["debug_info"],
- "symbols_path": kwargs["symbols_path"],
- "stackwalk_binary": kwargs["stackwalk_binary"],
- "certutil_binary": kwargs["certutil_binary"],
- "ca_certificate_path": kwargs["ssl_env"].ca_cert_path(),
- "e10s": kwargs["gecko_e10s"]}
-
-
-def executor_kwargs(test_type, server_config, cache_manager, run_info_data,
- **kwargs):
- executor_kwargs = base_executor_kwargs(test_type, server_config,
- cache_manager, **kwargs)
- executor_kwargs["close_after_done"] = True
- if kwargs["timeout_multiplier"] is None:
- if test_type == "reftest":
- if run_info_data["debug"] or run_info_data.get("asan"):
- executor_kwargs["timeout_multiplier"] = 4
- else:
- executor_kwargs["timeout_multiplier"] = 2
- elif run_info_data["debug"] or run_info_data.get("asan"):
- executor_kwargs["timeout_multiplier"] = 3
- if test_type == "wdspec":
- executor_kwargs["webdriver_binary"] = kwargs.get("webdriver_binary")
- return executor_kwargs
-
-
-def env_options():
- return {"host": "127.0.0.1",
- "external_host": "web-platform.test",
- "bind_hostname": "false",
- "certificate_domain": "web-platform.test",
- "supports_debugger": True}
-
-
-def run_info_extras(**kwargs):
- return {"e10s": kwargs["gecko_e10s"]}
-
-
-def update_properties():
- return ["debug", "e10s", "os", "version", "processor", "bits"], {"debug", "e10s"}
-
-
-class FirefoxBrowser(Browser):
- used_ports = set()
- init_timeout = 60
-
- def __init__(self, logger, binary, prefs_root, debug_info=None,
- symbols_path=None, stackwalk_binary=None, certutil_binary=None,
- ca_certificate_path=None, e10s=False):
- Browser.__init__(self, logger)
- self.binary = binary
- self.prefs_root = prefs_root
- self.marionette_port = None
- self.runner = None
- self.debug_info = debug_info
- self.profile = None
- self.symbols_path = symbols_path
- self.stackwalk_binary = stackwalk_binary
- self.ca_certificate_path = ca_certificate_path
- self.certutil_binary = certutil_binary
- self.e10s = e10s
-
- def start(self):
- self.marionette_port = get_free_port(2828, exclude=self.used_ports)
- self.used_ports.add(self.marionette_port)
-
- env = os.environ.copy()
- env["MOZ_DISABLE_NONLOCAL_CONNECTIONS"] = "1"
-
- locations = ServerLocations(filename=os.path.join(here, "server-locations.txt"))
-
- preferences = self.load_prefs()
-
- self.profile = FirefoxProfile(locations=locations,
- preferences=preferences)
- self.profile.set_preferences({"marionette.defaultPrefs.enabled": True,
- "marionette.defaultPrefs.port": self.marionette_port,
- "dom.disable_open_during_load": False,
- "network.dns.localDomains": ",".join(hostnames),
- "network.proxy.type": 0,
- "places.history.enabled": False})
- if self.e10s:
- self.profile.set_preferences({"browser.tabs.remote.autostart": True})
-
- # Bug 1262954: winxp + e10s, disable hwaccel
- if (self.e10s and platform.system() in ("Windows", "Microsoft") and
- '5.1' in platform.version()):
- self.profile.set_preferences({"layers.acceleration.disabled": True})
-
- if self.ca_certificate_path is not None:
- self.setup_ssl()
-
- debug_args, cmd = browser_command(self.binary, [cmd_arg("marionette"), "about:blank"],
- self.debug_info)
-
- self.runner = FirefoxRunner(profile=self.profile,
- binary=cmd[0],
- cmdargs=cmd[1:],
- env=env,
- process_class=ProcessHandler,
- process_args={"processOutputLine": [self.on_output]})
-
- self.logger.debug("Starting Firefox")
-
- self.runner.start(debug_args=debug_args, interactive=self.debug_info and self.debug_info.interactive)
- self.logger.debug("Firefox Started")
-
- def load_prefs(self):
- prefs_path = os.path.join(self.prefs_root, "prefs_general.js")
- if os.path.exists(prefs_path):
- preferences = Preferences.read_prefs(prefs_path)
- else:
- self.logger.warning("Failed to find base prefs file in %s" % prefs_path)
- preferences = []
-
- return preferences
-
- def stop(self):
- self.logger.debug("Stopping browser")
- if self.runner is not None:
- try:
- self.runner.stop()
- except OSError:
- # This can happen on Windows if the process is already dead
- pass
-
- def pid(self):
- if self.runner.process_handler is None:
- return None
-
- try:
- return self.runner.process_handler.pid
- except AttributeError:
- return None
-
- def on_output(self, line):
- """Write a line of output from the firefox process to the log"""
- self.logger.process_output(self.pid(),
- line.decode("utf8", "replace"),
- command=" ".join(self.runner.command))
-
- def is_alive(self):
- if self.runner:
- return self.runner.is_running()
- return False
-
- def cleanup(self):
- self.stop()
-
- def executor_browser(self):
- assert self.marionette_port is not None
- return ExecutorBrowser, {"marionette_port": self.marionette_port}
-
- def log_crash(self, process, test):
- dump_dir = os.path.join(self.profile.profile, "minidumps")
-
- mozcrash.log_crashes(self.logger,
- dump_dir,
- symbols_path=self.symbols_path,
- stackwalk_binary=self.stackwalk_binary,
- process=process,
- test=test)
-
- def setup_ssl(self):
- """Create a certificate database to use in the test profile. This is configured
- to trust the CA Certificate that has signed the web-platform.test server
- certificate."""
-
- self.logger.info("Setting up ssl")
-
- # Make sure the certutil libraries from the source tree are loaded when using a
- # local copy of certutil
- # TODO: Maybe only set this if certutil won't launch?
- env = os.environ.copy()
- certutil_dir = os.path.dirname(self.binary)
- if mozinfo.isMac:
- env_var = "DYLD_LIBRARY_PATH"
- elif mozinfo.isUnix:
- env_var = "LD_LIBRARY_PATH"
- else:
- env_var = "PATH"
-
-
- 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')
-
- def certutil(*args):
- cmd = [self.certutil_binary] + list(args)
- self.logger.process_output("certutil",
- subprocess.check_output(cmd,
- env=env,
- stderr=subprocess.STDOUT),
- " ".join(cmd))
-
- pw_path = os.path.join(self.profile.profile, ".crtdbpw")
- with open(pw_path, "w") as f:
- # Use empty password for certificate db
- f.write("\n")
-
- cert_db_path = self.profile.profile
-
- # Create a new certificate db
- certutil("-N", "-d", cert_db_path, "-f", pw_path)
-
- # Add the CA certificate to the database and mark as trusted to issue server certs
- certutil("-A", "-d", cert_db_path, "-f", pw_path, "-t", "CT,,",
- "-n", "web-platform-tests", "-i", self.ca_certificate_path)
-
- # List all certs in the database
- certutil("-L", "-d", cert_db_path)
diff --git a/tests/wpt/harness/wptrunner/browsers/server-locations.txt b/tests/wpt/harness/wptrunner/browsers/server-locations.txt
deleted file mode 100644
index 286f1259054..00000000000
--- a/tests/wpt/harness/wptrunner/browsers/server-locations.txt
+++ /dev/null
@@ -1,38 +0,0 @@
-#
-# 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/.
-
-# See /build/pgo/server-locations.txt for documentation on the format
-
-http://localhost:8000 primary
-
-http://web-platform.test:8000
-http://www.web-platform.test:8000
-http://www1.web-platform.test:8000
-http://www2.web-platform.test:8000
-http://xn--n8j6ds53lwwkrqhv28a.web-platform.test:8000
-http://xn--lve-6lad.web-platform.test:8000
-
-http://web-platform.test:8001
-http://www.web-platform.test:8001
-http://www1.web-platform.test:8001
-http://www2.web-platform.test:8001
-http://xn--n8j6ds53lwwkrqhv28a.web-platform.test:8001
-http://xn--lve-6lad.web-platform.test:8001
-
-https://web-platform.test:8443
-https://www.web-platform.test:8443
-https://www1.web-platform.test:8443
-https://www2.web-platform.test:8443
-https://xn--n8j6ds53lwwkrqhv28a.web-platform.test:8443
-https://xn--lve-6lad.web-platform.test:8443
-
-# These are actually ws servers, but until mozprofile is
-# fixed we have to pretend that they are http servers
-http://web-platform.test:8888
-http://www.web-platform.test:8888
-http://www1.web-platform.test:8888
-http://www2.web-platform.test:8888
-http://xn--n8j6ds53lwwkrqhv28a.web-platform.test:8888
-http://xn--lve-6lad.web-platform.test:8888
diff --git a/tests/wpt/harness/wptrunner/browsers/servo.py b/tests/wpt/harness/wptrunner/browsers/servo.py
deleted file mode 100644
index 639099a9dd7..00000000000
--- a/tests/wpt/harness/wptrunner/browsers/servo.py
+++ /dev/null
@@ -1,84 +0,0 @@
-# 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
-
-from .base import NullBrowser, ExecutorBrowser, require_arg
-from ..executors import executor_kwargs as base_executor_kwargs
-from ..executors.executorservo import ServoTestharnessExecutor, ServoRefTestExecutor, ServoWdspecExecutor
-
-here = os.path.join(os.path.split(__file__)[0])
-
-__wptrunner__ = {"product": "servo",
- "check_args": "check_args",
- "browser": "ServoBrowser",
- "executor": {"testharness": "ServoTestharnessExecutor",
- "reftest": "ServoRefTestExecutor",
- "wdspec": "ServoWdspecExecutor"},
- "browser_kwargs": "browser_kwargs",
- "executor_kwargs": "executor_kwargs",
- "env_options": "env_options",
- "run_info_extras": "run_info_extras",
- "update_properties": "update_properties"}
-
-
-def check_args(**kwargs):
- require_arg(kwargs, "binary")
-
-
-def browser_kwargs(**kwargs):
- return {"binary": kwargs["binary"],
- "debug_info": kwargs["debug_info"],
- "binary_args": kwargs["binary_args"],
- "user_stylesheets": kwargs.get("user_stylesheets"),
- "render_backend": kwargs.get("servo_backend"),
- "ca_certificate_path": kwargs["ssl_env"].ca_cert_path()}
-
-
-def executor_kwargs(test_type, server_config, cache_manager, run_info_data,
- **kwargs):
- rv = base_executor_kwargs(test_type, server_config,
- cache_manager, **kwargs)
- rv["pause_after_test"] = kwargs["pause_after_test"]
- return rv
-
-
-def env_options():
- return {"host": "127.0.0.1",
- "external_host": "web-platform.test",
- "bind_hostname": "true",
- "testharnessreport": "testharnessreport-servo.js",
- "supports_debugger": True}
-
-
-def run_info_extras(**kwargs):
- return {"backend": kwargs["servo_backend"]}
-
-
-def update_properties():
- return ["debug", "os", "version", "processor", "bits", "backend"], None
-
-
-def render_arg(render_backend):
- return {"cpu": "--cpu", "webrender": "-w"}[render_backend]
-
-
-class ServoBrowser(NullBrowser):
- def __init__(self, logger, binary, debug_info=None, binary_args=None,
- user_stylesheets=None, render_backend="webrender", ca_certificate_path=None):
- NullBrowser.__init__(self, logger)
- self.binary = binary
- self.debug_info = debug_info
- self.binary_args = binary_args or []
- self.user_stylesheets = user_stylesheets or []
- self.render_backend = render_backend
- self.ca_certificate_path = ca_certificate_path
-
- def executor_browser(self):
- return ExecutorBrowser, {"binary": self.binary,
- "debug_info": self.debug_info,
- "binary_args": self.binary_args,
- "user_stylesheets": self.user_stylesheets,
- "render_backend": self.render_backend,
- "ca_certificate_path": self.ca_certificate_path}
diff --git a/tests/wpt/harness/wptrunner/browsers/servodriver.py b/tests/wpt/harness/wptrunner/browsers/servodriver.py
deleted file mode 100644
index ab4dc7956b9..00000000000
--- a/tests/wpt/harness/wptrunner/browsers/servodriver.py
+++ /dev/null
@@ -1,162 +0,0 @@
-# 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 subprocess
-import tempfile
-
-from mozprocess import ProcessHandler
-
-from .base import Browser, require_arg, get_free_port, browser_command, ExecutorBrowser
-from .servo import render_arg
-from ..executors import executor_kwargs as base_executor_kwargs
-from ..executors.executorservodriver import (ServoWebDriverTestharnessExecutor,
- ServoWebDriverRefTestExecutor)
-
-here = os.path.join(os.path.split(__file__)[0])
-
-__wptrunner__ = {"product": "servodriver",
- "check_args": "check_args",
- "browser": "ServoWebDriverBrowser",
- "executor": {"testharness": "ServoWebDriverTestharnessExecutor",
- "reftest": "ServoWebDriverRefTestExecutor"},
- "browser_kwargs": "browser_kwargs",
- "executor_kwargs": "executor_kwargs",
- "env_options": "env_options",
- "run_info_extras": "run_info_extras",
- "update_properties": "update_properties"}
-
-hosts_text = """127.0.0.1 web-platform.test
-127.0.0.1 www.web-platform.test
-127.0.0.1 www1.web-platform.test
-127.0.0.1 www2.web-platform.test
-127.0.0.1 xn--n8j6ds53lwwkrqhv28a.web-platform.test
-127.0.0.1 xn--lve-6lad.web-platform.test
-"""
-
-
-def check_args(**kwargs):
- require_arg(kwargs, "binary")
-
-
-def browser_kwargs(**kwargs):
- return {"binary": kwargs["binary"],
- "debug_info": kwargs["debug_info"],
- "user_stylesheets": kwargs.get("user_stylesheets"),
- "render_backend": kwargs.get("servo_backend")}
-
-
-def executor_kwargs(test_type, server_config, cache_manager, run_info_data, **kwargs):
- rv = base_executor_kwargs(test_type, server_config,
- cache_manager, **kwargs)
- return rv
-
-
-def env_options():
- return {"host": "127.0.0.1",
- "external_host": "web-platform.test",
- "bind_hostname": "true",
- "testharnessreport": "testharnessreport-servodriver.js",
- "supports_debugger": True}
-
-
-def run_info_extras(**kwargs):
- return {"backend": kwargs["servo_backend"]}
-
-
-def update_properties():
- return ["debug", "os", "version", "processor", "bits", "backend"], None
-
-
-def make_hosts_file():
- hosts_fd, hosts_path = tempfile.mkstemp()
- with os.fdopen(hosts_fd, "w") as f:
- f.write(hosts_text)
- return hosts_path
-
-
-class ServoWebDriverBrowser(Browser):
- used_ports = set()
-
- def __init__(self, logger, binary, debug_info=None, webdriver_host="127.0.0.1",
- user_stylesheets=None, render_backend="webrender"):
- Browser.__init__(self, logger)
- self.binary = binary
- self.webdriver_host = webdriver_host
- self.webdriver_port = None
- self.proc = None
- self.debug_info = debug_info
- self.hosts_path = make_hosts_file()
- self.command = None
- self.user_stylesheets = user_stylesheets if user_stylesheets else []
- self.render_backend = render_backend
-
- def start(self):
- self.webdriver_port = get_free_port(4444, exclude=self.used_ports)
- self.used_ports.add(self.webdriver_port)
-
- env = os.environ.copy()
- env["HOST_FILE"] = self.hosts_path
- env["RUST_BACKTRACE"] = "1"
-
- debug_args, command = browser_command(self.binary,
- [render_arg(self.render_backend), "--hard-fail",
- "--webdriver", str(self.webdriver_port),
- "about:blank"],
- self.debug_info)
-
- for stylesheet in self.user_stylesheets:
- command += ["--user-stylesheet", stylesheet]
-
- self.command = command
-
- self.command = debug_args + self.command
-
- if not self.debug_info or not self.debug_info.interactive:
- self.proc = ProcessHandler(self.command,
- processOutputLine=[self.on_output],
- env=env,
- storeOutput=False)
- self.proc.run()
- else:
- self.proc = subprocess.Popen(self.command, env=env)
-
- self.logger.debug("Servo Started")
-
- def stop(self):
- self.logger.debug("Stopping browser")
- if self.proc is not None:
- try:
- self.proc.kill()
- except OSError:
- # This can happen on Windows if the process is already dead
- pass
-
- def pid(self):
- if self.proc is None:
- return None
-
- try:
- return self.proc.pid
- except AttributeError:
- return None
-
- def on_output(self, line):
- """Write a line of output from the process to the log"""
- self.logger.process_output(self.pid(),
- line.decode("utf8", "replace"),
- command=" ".join(self.command))
-
- def is_alive(self):
- if self.runner:
- return self.runner.is_running()
- return False
-
- def cleanup(self):
- self.stop()
-
- def executor_browser(self):
- assert self.webdriver_port is not None
- return ExecutorBrowser, {"webdriver_host": self.webdriver_host,
- "webdriver_port": self.webdriver_port}
diff --git a/tests/wpt/harness/wptrunner/browsers/webdriver.py b/tests/wpt/harness/wptrunner/browsers/webdriver.py
deleted file mode 100644
index 54b1c1b5ef9..00000000000
--- a/tests/wpt/harness/wptrunner/browsers/webdriver.py
+++ /dev/null
@@ -1,137 +0,0 @@
-# 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 errno
-import socket
-import time
-import traceback
-import urlparse
-
-import mozprocess
-
-from .base import get_free_port, cmd_arg
-
-
-__all__ = ["SeleniumLocalServer", "ChromedriverLocalServer"]
-
-
-class LocalServer(object):
- used_ports = set()
- default_endpoint = "/"
-
- def __init__(self, logger, binary, port=None, endpoint=None):
- self.logger = logger
- self.binary = binary
- self.port = port
- self.endpoint = endpoint or self.default_endpoint
-
- if self.port is None:
- self.port = get_free_port(4444, exclude=self.used_ports)
- self.used_ports.add(self.port)
- self.url = "http://127.0.0.1:%i%s" % (self.port, self.endpoint)
-
- self.proc, self.cmd = None, None
-
- def start(self):
- self.proc = mozprocess.ProcessHandler(
- self.cmd, processOutputLine=self.on_output)
- try:
- self.proc.run()
- except OSError as e:
- if e.errno == errno.ENOENT:
- raise IOError(
- "chromedriver executable not found: %s" % self.binary)
- raise
-
- self.logger.debug(
- "Waiting for server to become accessible: %s" % self.url)
- surl = urlparse.urlparse(self.url)
- addr = (surl.hostname, surl.port)
- try:
- wait_service(addr)
- except:
- self.logger.error(
- "Server was not accessible within the timeout:\n%s" % traceback.format_exc())
- raise
- else:
- self.logger.info("Server listening on port %i" % self.port)
-
- def stop(self):
- if hasattr(self.proc, "proc"):
- self.proc.kill()
-
- def is_alive(self):
- if hasattr(self.proc, "proc"):
- exitcode = self.proc.poll()
- return exitcode is None
- return False
-
- def on_output(self, line):
- self.logger.process_output(self.pid,
- line.decode("utf8", "replace"),
- command=" ".join(self.cmd))
-
- @property
- def pid(self):
- if hasattr(self.proc, "proc"):
- return self.proc.pid
-
-
-class SeleniumLocalServer(LocalServer):
- default_endpoint = "/wd/hub"
-
- def __init__(self, logger, binary, port=None):
- LocalServer.__init__(self, logger, binary, port=port)
- self.cmd = ["java",
- "-jar", self.binary,
- "-port", str(self.port)]
-
- def start(self):
- self.logger.debug("Starting local Selenium server")
- LocalServer.start(self)
-
- def stop(self):
- LocalServer.stop(self)
- self.logger.info("Selenium server stopped listening")
-
-
-class ChromedriverLocalServer(LocalServer):
- default_endpoint = "/wd/hub"
-
- def __init__(self, logger, binary="chromedriver", port=None, endpoint=None):
- LocalServer.__init__(self, logger, binary, port=port, endpoint=endpoint)
- # TODO: verbose logging
- self.cmd = [self.binary,
- cmd_arg("port", str(self.port)) if self.port else "",
- cmd_arg("url-base", self.endpoint) if self.endpoint else ""]
-
- def start(self):
- self.logger.debug("Starting local chromedriver server")
- LocalServer.start(self)
-
- def stop(self):
- LocalServer.stop(self)
- self.logger.info("chromedriver server stopped listening")
-
-
-def wait_service(addr, timeout=15):
- """Waits until network service given as a tuple of (host, port) becomes
- available or the `timeout` duration is reached, at which point
- ``socket.error`` is raised."""
- end = time.time() + timeout
- while end > time.time():
- so = socket.socket()
- try:
- so.connect(addr)
- except socket.timeout:
- pass
- except socket.error as e:
- if e[0] != errno.ECONNREFUSED:
- raise
- else:
- return True
- finally:
- so.close()
- time.sleep(0.5)
- raise socket.error("Service is unavailable: %s:%i" % addr)
diff --git a/tests/wpt/harness/wptrunner/config.json b/tests/wpt/harness/wptrunner/config.json
deleted file mode 100644
index d146424a0f0..00000000000
--- a/tests/wpt/harness/wptrunner/config.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{"host": "%(host)s",
- "ports":{"http":[8000, 8001],
- "https":[8443],
- "ws":[8888]},
- "check_subdomains":false,
- "bind_hostname":%(bind_hostname)s,
- "ssl":{}}
diff --git a/tests/wpt/harness/wptrunner/config.py b/tests/wpt/harness/wptrunner/config.py
deleted file mode 100644
index c0e44e1eb95..00000000000
--- a/tests/wpt/harness/wptrunner/config.py
+++ /dev/null
@@ -1,64 +0,0 @@
-# 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 ConfigParser
-import os
-import sys
-from collections import OrderedDict
-
-here = os.path.split(__file__)[0]
-
-class ConfigDict(dict):
- def __init__(self, base_path, *args, **kwargs):
- self.base_path = base_path
- dict.__init__(self, *args, **kwargs)
-
- def get_path(self, key, default=None):
- if key not in self:
- return default
- path = self[key]
- os.path.expanduser(path)
- return os.path.abspath(os.path.join(self.base_path, path))
-
-def read(config_path):
- config_path = os.path.abspath(config_path)
- config_root = os.path.split(config_path)[0]
- parser = ConfigParser.SafeConfigParser()
- success = parser.read(config_path)
- assert config_path in success, success
-
- subns = {"pwd": os.path.abspath(os.path.curdir)}
-
- rv = OrderedDict()
- for section in parser.sections():
- rv[section] = ConfigDict(config_root)
- for key in parser.options(section):
- rv[section][key] = parser.get(section, key, False, subns)
-
- return rv
-
-def path(argv=None):
- if argv is None:
- argv = []
- path = None
-
- for i, arg in enumerate(argv):
- if arg == "--config":
- if i + 1 < len(argv):
- path = argv[i + 1]
- elif arg.startswith("--config="):
- path = arg.split("=", 1)[1]
- if path is not None:
- break
-
- if path is None:
- if os.path.exists("wptrunner.ini"):
- path = os.path.abspath("wptrunner.ini")
- else:
- path = os.path.join(here, "..", "wptrunner.default.ini")
-
- return os.path.abspath(path)
-
-def load():
- return read(path(sys.argv))
diff --git a/tests/wpt/harness/wptrunner/environment.py b/tests/wpt/harness/wptrunner/environment.py
deleted file mode 100644
index 732b785589b..00000000000
--- a/tests/wpt/harness/wptrunner/environment.py
+++ /dev/null
@@ -1,212 +0,0 @@
-# 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 json
-import os
-import multiprocessing
-import signal
-import socket
-import sys
-import time
-
-from mozlog import get_default_logger, handlers
-
-from wptlogging import LogLevelRewriter
-
-here = os.path.split(__file__)[0]
-
-serve = None
-sslutils = None
-
-
-hostnames = ["web-platform.test",
- "www.web-platform.test",
- "www1.web-platform.test",
- "www2.web-platform.test",
- "xn--n8j6ds53lwwkrqhv28a.web-platform.test",
- "xn--lve-6lad.web-platform.test"]
-
-
-def do_delayed_imports(logger, test_paths):
- global serve, sslutils
-
- serve_root = serve_path(test_paths)
- sys.path.insert(0, serve_root)
-
- failed = []
-
- try:
- from tools.serve import serve
- except ImportError:
- failed.append("serve")
-
- try:
- import sslutils
- except ImportError:
- failed.append("sslutils")
-
- if failed:
- logger.critical(
- "Failed to import %s. Ensure that tests path %s contains web-platform-tests" %
- (", ".join(failed), serve_root))
- sys.exit(1)
-
-
-def serve_path(test_paths):
- return test_paths["/"]["tests_path"]
-
-
-def get_ssl_kwargs(**kwargs):
- if kwargs["ssl_type"] == "openssl":
- args = {"openssl_binary": kwargs["openssl_binary"]}
- 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"]}
- else:
- args = {}
- return args
-
-
-def ssl_env(logger, **kwargs):
- ssl_env_cls = sslutils.environments[kwargs["ssl_type"]]
- return ssl_env_cls(logger, **get_ssl_kwargs(**kwargs))
-
-
-class TestEnvironmentError(Exception):
- pass
-
-
-class TestEnvironment(object):
- def __init__(self, test_paths, ssl_env, pause_after_test, debug_info, options):
- """Context manager that owns the test environment i.e. the http and
- websockets servers"""
- self.test_paths = test_paths
- self.ssl_env = ssl_env
- self.server = None
- self.config = None
- self.external_config = None
- self.pause_after_test = pause_after_test
- self.test_server_port = options.pop("test_server_port", True)
- self.debug_info = debug_info
- self.options = options if options is not None else {}
-
- self.cache_manager = multiprocessing.Manager()
- self.stash = serve.stash.StashServer()
-
-
- def __enter__(self):
- self.stash.__enter__()
- self.ssl_env.__enter__()
- self.cache_manager.__enter__()
- self.setup_server_logging()
- self.config = self.load_config()
- serve.set_computed_defaults(self.config)
- self.external_config, self.servers = serve.start(self.config, self.ssl_env,
- self.get_routes())
- if self.options.get("supports_debugger") and self.debug_info and self.debug_info.interactive:
- self.ignore_interrupts()
- return self
-
- def __exit__(self, exc_type, exc_val, exc_tb):
- self.process_interrupts()
- for scheme, servers in self.servers.iteritems():
- for port, server in servers:
- server.kill()
- self.cache_manager.__exit__(exc_type, exc_val, exc_tb)
- self.ssl_env.__exit__(exc_type, exc_val, exc_tb)
- self.stash.__exit__()
-
- def ignore_interrupts(self):
- signal.signal(signal.SIGINT, signal.SIG_IGN)
-
- def process_interrupts(self):
- signal.signal(signal.SIGINT, signal.SIG_DFL)
-
- def load_config(self):
- default_config_path = os.path.join(serve_path(self.test_paths), "config.default.json")
- local_config_path = os.path.join(here, "config.json")
-
- with open(default_config_path) as f:
- default_config = json.load(f)
-
- with open(local_config_path) as f:
- data = f.read()
- local_config = json.loads(data % self.options)
-
- #TODO: allow non-default configuration for ssl
-
- local_config["external_host"] = self.options.get("external_host", None)
- local_config["ssl"]["encrypt_after_connect"] = self.options.get("encrypt_after_connect", False)
-
- config = serve.merge_json(default_config, local_config)
- config["doc_root"] = serve_path(self.test_paths)
-
- if not self.ssl_env.ssl_enabled:
- config["ports"]["https"] = [None]
-
- host = self.options.get("certificate_domain", config["host"])
- hosts = [host]
- hosts.extend("%s.%s" % (item[0], host) for item in serve.get_subdomains(host).values())
- key_file, certificate = self.ssl_env.host_cert_path(hosts)
-
- config["key_file"] = key_file
- config["certificate"] = certificate
-
- return config
-
- def setup_server_logging(self):
- server_logger = get_default_logger(component="wptserve")
- assert server_logger is not None
- log_filter = handlers.LogLevelFilter(lambda x:x, "info")
- # Downgrade errors to warnings for the server
- log_filter = LogLevelRewriter(log_filter, ["error"], "warning")
- server_logger.component_filter = log_filter
-
- try:
- #Set as the default logger for wptserve
- serve.set_logger(server_logger)
- serve.logger = server_logger
- except Exception:
- # This happens if logging has already been set up for wptserve
- pass
-
- def get_routes(self):
- route_builder = serve.RoutesBuilder()
-
- for path, format_args, content_type, route in [
- ("testharness_runner.html", {}, "text/html", "/testharness_runner.html"),
- (self.options.get("testharnessreport", "testharnessreport.js"),
- {"output": self.pause_after_test}, "text/javascript",
- "/resources/testharnessreport.js")]:
- path = os.path.normpath(os.path.join(here, path))
- route_builder.add_static(path, format_args, content_type, route)
-
- for url_base, paths in self.test_paths.iteritems():
- if url_base == "/":
- continue
- route_builder.add_mount_point(url_base, paths["tests_path"])
-
- if "/" not in self.test_paths:
- del route_builder.mountpoint_routes["/"]
-
- return route_builder.get_routes()
-
- def ensure_started(self):
- # Pause for a while to ensure that the server has a chance to start
- time.sleep(2)
- for scheme, servers in self.servers.iteritems():
- for port, server in servers:
- if self.test_server_port:
- s = socket.socket()
- try:
- s.connect((self.config["host"], port))
- except socket.error:
- raise EnvironmentError(
- "%s server on port %d failed to start" % (scheme, port))
- finally:
- s.close()
-
- if not server.is_alive():
- raise EnvironmentError("%s server on port %d failed to start" % (scheme, port))
diff --git a/tests/wpt/harness/wptrunner/executors/__init__.py b/tests/wpt/harness/wptrunner/executors/__init__.py
deleted file mode 100644
index 11e0c4cd70a..00000000000
--- a/tests/wpt/harness/wptrunner/executors/__init__.py
+++ /dev/null
@@ -1,8 +0,0 @@
-# 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/.
-
-from base import (executor_kwargs,
- testharness_result_converter,
- reftest_result_converter,
- TestExecutor)
diff --git a/tests/wpt/harness/wptrunner/executors/base.py b/tests/wpt/harness/wptrunner/executors/base.py
deleted file mode 100644
index f0ce1665888..00000000000
--- a/tests/wpt/harness/wptrunner/executors/base.py
+++ /dev/null
@@ -1,329 +0,0 @@
-# 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 hashlib
-import json
-import os
-import traceback
-import urlparse
-from abc import ABCMeta, abstractmethod
-
-from ..testrunner import Stop
-
-here = os.path.split(__file__)[0]
-
-
-def executor_kwargs(test_type, server_config, cache_manager, **kwargs):
- timeout_multiplier = kwargs["timeout_multiplier"]
- if timeout_multiplier is None:
- timeout_multiplier = 1
-
- executor_kwargs = {"server_config": server_config,
- "timeout_multiplier": timeout_multiplier,
- "debug_info": kwargs["debug_info"]}
-
- if test_type == "reftest":
- executor_kwargs["screenshot_cache"] = cache_manager.dict()
-
- return executor_kwargs
-
-
-def strip_server(url):
- """Remove the scheme and netloc from a url, leaving only the path and any query
- or fragment.
-
- url - the url to strip
-
- e.g. http://example.org:8000/tests?id=1#2 becomes /tests?id=1#2"""
-
- url_parts = list(urlparse.urlsplit(url))
- url_parts[0] = ""
- url_parts[1] = ""
- return urlparse.urlunsplit(url_parts)
-
-
-class TestharnessResultConverter(object):
- harness_codes = {0: "OK",
- 1: "ERROR",
- 2: "TIMEOUT"}
-
- test_codes = {0: "PASS",
- 1: "FAIL",
- 2: "TIMEOUT",
- 3: "NOTRUN"}
-
- def __call__(self, test, result):
- """Convert a JSON result into a (TestResult, [SubtestResult]) tuple"""
- result_url, status, message, stack, subtest_results = result
- assert result_url == test.url, ("Got results from %s, expected %s" %
- (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])
-
-
-testharness_result_converter = TestharnessResultConverter()
-
-
-def reftest_result_converter(self, test, result):
- return (test.result_cls(result["status"], result["message"],
- extra=result.get("extra")), [])
-
-
-def pytest_result_converter(self, test, data):
- harness_data, subtest_data = data
-
- if subtest_data is None:
- subtest_data = []
-
- harness_result = test.result_cls(*harness_data)
- subtest_results = [test.subtest_result_cls(*item) for item in subtest_data]
-
- return (harness_result, subtest_results)
-
-
-class ExecutorException(Exception):
- def __init__(self, status, message):
- self.status = status
- self.message = message
-
-
-class TestExecutor(object):
- __metaclass__ = ABCMeta
-
- test_type = None
- convert_result = None
-
- def __init__(self, browser, server_config, timeout_multiplier=1,
- debug_info=None):
- """Abstract Base class for object that actually executes the tests in a
- specific browser. Typically there will be a different TestExecutor
- subclass for each test type and method of executing tests.
-
- :param browser: ExecutorBrowser instance providing properties of the
- browser that will be tested.
- :param server_config: Dictionary of wptserve server configuration of the
- form stored in TestEnvironment.external_config
- :param timeout_multiplier: Multiplier relative to base timeout to use
- when setting test timeout.
- """
- self.runner = None
- self.browser = browser
- self.server_config = server_config
- self.timeout_multiplier = timeout_multiplier
- self.debug_info = debug_info
- self.last_environment = {"protocol": "http",
- "prefs": {}}
- self.protocol = None # This must be set in subclasses
-
- @property
- def logger(self):
- """StructuredLogger for this executor"""
- if self.runner is not None:
- return self.runner.logger
-
- def setup(self, runner):
- """Run steps needed before tests can be started e.g. connecting to
- browser instance
-
- :param runner: TestRunner instance that is going to run the tests"""
- self.runner = runner
- if self.protocol is not None:
- self.protocol.setup(runner)
-
- def teardown(self):
- """Run cleanup steps after tests have finished"""
- if self.protocol is not None:
- self.protocol.teardown()
-
- def run_test(self, test):
- """Run a particular test.
-
- :param test: The test to run"""
- if test.environment != self.last_environment:
- self.on_environment_change(test.environment)
-
- try:
- result = self.do_test(test)
- except Exception as e:
- result = self.result_from_exception(test, e)
-
- if result is Stop:
- return result
-
- # log result of parent test
- if result[0].status == "ERROR":
- self.logger.debug(result[0].message)
-
- self.last_environment = test.environment
-
- self.runner.send_message("test_ended", test, result)
-
- def server_url(self, protocol):
- return "%s://%s:%s" % (protocol,
- self.server_config["host"],
- self.server_config["ports"][protocol][0])
-
- def test_url(self, test):
- return urlparse.urljoin(self.server_url(test.environment["protocol"]), test.url)
-
- @abstractmethod
- def do_test(self, test):
- """Test-type and protocol specific implementation of running a
- specific test.
-
- :param test: The test to run."""
- pass
-
- def on_environment_change(self, new_environment):
- pass
-
- def result_from_exception(self, test, e):
- if hasattr(e, "status") and e.status in test.result_cls.statuses:
- status = e.status
- else:
- status = "ERROR"
- message = unicode(getattr(e, "message", ""))
- if message:
- message += "\n"
- message += traceback.format_exc(e)
- return test.result_cls(status, message), []
-
-
-class TestharnessExecutor(TestExecutor):
- convert_result = testharness_result_converter
-
-
-class RefTestExecutor(TestExecutor):
- convert_result = reftest_result_converter
-
- def __init__(self, browser, server_config, timeout_multiplier=1, screenshot_cache=None,
- debug_info=None):
- TestExecutor.__init__(self, browser, server_config,
- timeout_multiplier=timeout_multiplier,
- debug_info=debug_info)
-
- self.screenshot_cache = screenshot_cache
-
-
-class RefTestImplementation(object):
- def __init__(self, executor):
- self.timeout_multiplier = executor.timeout_multiplier
- self.executor = executor
- # Cache of url:(screenshot hash, screenshot). Typically the
- # screenshot is None, but we set this value if a test fails
- # and the screenshot was taken from the cache so that we may
- # retrieve the screenshot from the cache directly in the future
- self.screenshot_cache = self.executor.screenshot_cache
- self.message = None
-
- @property
- def logger(self):
- return self.executor.logger
-
- def get_hash(self, test, viewport_size, dpi):
- timeout = test.timeout * self.timeout_multiplier
- key = (test.url, viewport_size, dpi)
-
- if key not in self.screenshot_cache:
- success, data = self.executor.screenshot(test, viewport_size, dpi)
-
- if not success:
- return False, data
-
- screenshot = data
- hash_value = hashlib.sha1(screenshot).hexdigest()
-
- self.screenshot_cache[key] = (hash_value, None)
-
- rv = (hash_value, screenshot)
- else:
- rv = self.screenshot_cache[key]
-
- self.message.append("%s %s" % (test.url, rv[0]))
- return True, rv
-
- def is_pass(self, lhs_hash, rhs_hash, relation):
- assert relation in ("==", "!=")
- self.message.append("Testing %s %s %s" % (lhs_hash, relation, rhs_hash))
- return ((relation == "==" and lhs_hash == rhs_hash) or
- (relation == "!=" and lhs_hash != rhs_hash))
-
- def run_test(self, test):
- viewport_size = test.viewport_size
- dpi = test.dpi
- self.message = []
-
- # Depth-first search of reference tree, with the goal
- # of reachings a leaf node with only pass results
-
- stack = list(((test, item[0]), item[1]) for item in reversed(test.references))
- while stack:
- hashes = [None, None]
- screenshots = [None, None]
-
- nodes, relation = stack.pop()
-
- for i, node in enumerate(nodes):
- success, data = self.get_hash(node, viewport_size, dpi)
- if success is False:
- return {"status": data[0], "message": data[1]}
-
- hashes[i], screenshots[i] = data
-
- if self.is_pass(hashes[0], hashes[1], relation):
- if nodes[1].references:
- stack.extend(list(((nodes[1], item[0]), item[1]) for item in reversed(nodes[1].references)))
- else:
- # We passed
- return {"status":"PASS", "message": None}
-
- # We failed, so construct a failure message
-
- for i, (node, screenshot) in enumerate(zip(nodes, screenshots)):
- if screenshot is None:
- success, screenshot = self.retake_screenshot(node, viewport_size, dpi)
- if success:
- screenshots[i] = screenshot
-
- log_data = [{"url": nodes[0].url, "screenshot": screenshots[0]}, relation,
- {"url": nodes[1].url, "screenshot": screenshots[1]}]
-
- return {"status": "FAIL",
- "message": "\n".join(self.message),
- "extra": {"reftest_screenshots": log_data}}
-
- def retake_screenshot(self, node, viewport_size, dpi):
- success, data = self.executor.screenshot(node, viewport_size, dpi)
- if not success:
- return False, data
-
- key = (node.url, viewport_size, dpi)
- hash_val, _ = self.screenshot_cache[key]
- self.screenshot_cache[key] = hash_val, data
- return True, data
-
-
-class WdspecExecutor(TestExecutor):
- convert_result = pytest_result_converter
-
-
-class Protocol(object):
- def __init__(self, executor, browser):
- self.executor = executor
- self.browser = browser
-
- @property
- def logger(self):
- return self.executor.logger
-
- def setup(self, runner):
- pass
-
- def teardown(self):
- pass
-
- def wait(self):
- pass
diff --git a/tests/wpt/harness/wptrunner/executors/executormarionette.py b/tests/wpt/harness/wptrunner/executors/executormarionette.py
deleted file mode 100644
index 8495d3b45ee..00000000000
--- a/tests/wpt/harness/wptrunner/executors/executormarionette.py
+++ /dev/null
@@ -1,561 +0,0 @@
-# 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 hashlib
-import httplib
-import os
-import socket
-import threading
-import time
-import traceback
-import urlparse
-import uuid
-from collections import defaultdict
-
-from ..wpttest import WdspecResult, WdspecSubtestResult
-
-errors = None
-marionette = None
-pytestrunner = None
-webdriver = None
-
-here = os.path.join(os.path.split(__file__)[0])
-
-from .base import (ExecutorException,
- Protocol,
- RefTestExecutor,
- RefTestImplementation,
- TestExecutor,
- TestharnessExecutor,
- testharness_result_converter,
- reftest_result_converter,
- strip_server,
- WdspecExecutor)
-from ..testrunner import Stop
-from ..webdriver_server import GeckoDriverServer
-
-# Extra timeout to use after internal test timeout at which the harness
-# should force a timeout
-extra_timeout = 5 # seconds
-
-
-def do_delayed_imports():
- global errors, marionette
-
- # Marionette client used to be called marionette, recently it changed
- # to marionette_driver for unfathomable reasons
- try:
- import marionette
- from marionette import errors
- except ImportError:
- from marionette_driver import marionette, errors
-
-
-class MarionetteProtocol(Protocol):
- def __init__(self, executor, browser):
- do_delayed_imports()
-
- Protocol.__init__(self, executor, browser)
- self.marionette = None
- self.marionette_port = browser.marionette_port
-
- def setup(self, runner):
- """Connect to browser via Marionette."""
- Protocol.setup(self, runner)
-
- self.logger.debug("Connecting to Marionette on port %i" % self.marionette_port)
- self.marionette = marionette.Marionette(host='localhost',
- port=self.marionette_port,
- socket_timeout=None)
-
- # XXX Move this timeout somewhere
- self.logger.debug("Waiting for Marionette connection")
- while True:
- success = self.marionette.wait_for_port(60)
- #When running in a debugger wait indefinitely for firefox to start
- if success or self.executor.debug_info is None:
- break
-
- session_started = False
- if success:
- try:
- self.logger.debug("Starting Marionette session")
- self.marionette.start_session()
- except Exception as e:
- self.logger.warning("Starting marionette session failed: %s" % e)
- else:
- self.logger.debug("Marionette session started")
- session_started = True
-
- if not success or not session_started:
- self.logger.warning("Failed to connect to Marionette")
- self.executor.runner.send_message("init_failed")
- else:
- try:
- self.after_connect()
- except Exception:
- self.logger.warning("Post-connection steps failed")
- self.logger.error(traceback.format_exc())
- self.executor.runner.send_message("init_failed")
- else:
- self.executor.runner.send_message("init_succeeded")
-
- def teardown(self):
- try:
- self.marionette.delete_session()
- except Exception:
- # This is typically because the session never started
- pass
- del self.marionette
-
- @property
- def is_alive(self):
- """Check if the Marionette connection is still active."""
- try:
- self.marionette.current_window_handle
- except Exception:
- return False
- return True
-
- def after_connect(self):
- self.load_runner("http")
-
- def load_runner(self, protocol):
- # Check if we previously had a test window open, and if we did make sure it's closed
- self.marionette.execute_script("if (window.wrappedJSObject.win) {window.wrappedJSObject.win.close()}")
- url = urlparse.urljoin(self.executor.server_url(protocol), "/testharness_runner.html")
- self.logger.debug("Loading %s" % url)
- try:
- self.marionette.navigate(url)
- except Exception as e:
- self.logger.critical(
- "Loading initial page %s failed. Ensure that the "
- "there are no other programs bound to this port and "
- "that your firewall rules or network setup does not "
- "prevent access.\e%s" % (url, traceback.format_exc(e)))
- self.marionette.execute_script(
- "document.title = '%s'" % threading.current_thread().name.replace("'", '"'))
-
- def wait(self):
- socket_timeout = self.marionette.client.sock.gettimeout()
- if socket_timeout:
- self.marionette.set_script_timeout((socket_timeout / 2) * 1000)
-
- while True:
- try:
- self.marionette.execute_async_script("")
- except errors.ScriptTimeoutException:
- self.logger.debug("Script timed out")
- pass
- except (socket.timeout, IOError):
- self.logger.debug("Socket closed")
- break
- except Exception as e:
- self.logger.error(traceback.format_exc(e))
- break
-
- def on_environment_change(self, old_environment, new_environment):
- #Unset all the old prefs
- for name in old_environment.get("prefs", {}).iterkeys():
- value = self.executor.original_pref_values[name]
- if value is None:
- self.clear_user_pref(name)
- else:
- self.set_pref(name, value)
-
- for name, value in new_environment.get("prefs", {}).iteritems():
- self.executor.original_pref_values[name] = self.get_pref(name)
- self.set_pref(name, value)
-
- def set_pref(self, name, value):
- if value.lower() not in ("true", "false"):
- try:
- int(value)
- except ValueError:
- value = "'%s'" % value
- else:
- value = value.lower()
-
- self.logger.info("Setting pref %s (%s)" % (name, value))
-
- script = """
- let prefInterface = Components.classes["@mozilla.org/preferences-service;1"]
- .getService(Components.interfaces.nsIPrefBranch);
- let pref = '%s';
- let type = prefInterface.getPrefType(pref);
- let value = %s;
- switch(type) {
- case prefInterface.PREF_STRING:
- prefInterface.setCharPref(pref, value);
- break;
- case prefInterface.PREF_BOOL:
- prefInterface.setBoolPref(pref, value);
- break;
- case prefInterface.PREF_INT:
- prefInterface.setIntPref(pref, value);
- break;
- }
- """ % (name, value)
- with self.marionette.using_context(self.marionette.CONTEXT_CHROME):
- self.marionette.execute_script(script)
-
- def clear_user_pref(self, name):
- self.logger.info("Clearing pref %s" % (name))
- script = """
- let prefInterface = Components.classes["@mozilla.org/preferences-service;1"]
- .getService(Components.interfaces.nsIPrefBranch);
- let pref = '%s';
- prefInterface.clearUserPref(pref);
- """ % name
- with self.marionette.using_context(self.marionette.CONTEXT_CHROME):
- self.marionette.execute_script(script)
-
- def get_pref(self, name):
- script = """
- let prefInterface = Components.classes["@mozilla.org/preferences-service;1"]
- .getService(Components.interfaces.nsIPrefBranch);
- let pref = '%s';
- let type = prefInterface.getPrefType(pref);
- switch(type) {
- case prefInterface.PREF_STRING:
- return prefInterface.getCharPref(pref);
- case prefInterface.PREF_BOOL:
- return prefInterface.getBoolPref(pref);
- case prefInterface.PREF_INT:
- return prefInterface.getIntPref(pref);
- case prefInterface.PREF_INVALID:
- return null;
- }
- """ % name
- with self.marionette.using_context(self.marionette.CONTEXT_CHROME):
- self.marionette.execute_script(script)
-
-
-class RemoteMarionetteProtocol(Protocol):
- def __init__(self, executor, browser):
- do_delayed_imports()
- Protocol.__init__(self, executor, browser)
- self.session = None
- self.webdriver_binary = executor.webdriver_binary
- self.marionette_port = browser.marionette_port
- self.server = None
-
- def setup(self, runner):
- """Connect to browser via the Marionette HTTP server."""
- try:
- self.server = GeckoDriverServer(
- self.logger, self.marionette_port, binary=self.webdriver_binary)
- self.server.start(block=False)
- self.logger.info(
- "WebDriver HTTP server listening at %s" % self.server.url)
-
- self.logger.info(
- "Establishing new WebDriver session with %s" % self.server.url)
- self.session = webdriver.Session(
- self.server.host, self.server.port, self.server.base_path)
- except Exception:
- self.logger.error(traceback.format_exc())
- self.executor.runner.send_message("init_failed")
- else:
- self.executor.runner.send_message("init_succeeded")
-
- def teardown(self):
- try:
- if self.session.session_id is not None:
- self.session.end()
- except Exception:
- pass
- if self.server is not None and self.server.is_alive:
- self.server.stop()
-
- @property
- def is_alive(self):
- """Test that the Marionette connection is still alive.
-
- Because the remote communication happens over HTTP we need to
- make an explicit request to the remote. It is allowed for
- WebDriver spec tests to not have a WebDriver session, since this
- may be what is tested.
-
- An HTTP request to an invalid path that results in a 404 is
- proof enough to us that the server is alive and kicking.
- """
- conn = httplib.HTTPConnection(self.server.host, self.server.port)
- conn.request("HEAD", self.server.base_path + "invalid")
- res = conn.getresponse()
- return res.status == 404
-
-
-class ExecuteAsyncScriptRun(object):
- def __init__(self, logger, func, marionette, url, timeout):
- self.logger = logger
- self.result = (None, None)
- self.marionette = marionette
- self.func = func
- self.url = url
- self.timeout = timeout
- self.result_flag = threading.Event()
-
- def run(self):
- timeout = self.timeout
-
- try:
- if timeout is not None:
- self.marionette.set_script_timeout((timeout + extra_timeout) * 1000)
- else:
- # We just want it to never time out, really, but marionette doesn't
- # make that possible. It also seems to time out immediately if the
- # timeout is set too high. This works at least.
- self.marionette.set_script_timeout(2**31 - 1)
- except IOError:
- self.logger.error("Lost marionette connection before starting test")
- return Stop
-
- executor = threading.Thread(target = self._run)
- executor.start()
-
- if timeout is not None:
- wait_timeout = timeout + 2 * extra_timeout
- else:
- wait_timeout = None
-
- flag = self.result_flag.wait(wait_timeout)
- if self.result[1] is None:
- self.logger.debug("Timed out waiting for a result")
- self.result = False, ("EXTERNAL-TIMEOUT", None)
- return self.result
-
- def _run(self):
- try:
- self.result = True, self.func(self.marionette, self.url, self.timeout)
- except errors.ScriptTimeoutException:
- self.logger.debug("Got a marionette timeout")
- self.result = False, ("EXTERNAL-TIMEOUT", None)
- except (socket.timeout, IOError):
- # This can happen on a crash
- # Also, should check after the test if the firefox process is still running
- # and otherwise ignore any other result and set it to crash
- self.result = False, ("CRASH", None)
- except Exception as e:
- message = getattr(e, "message", "")
- if message:
- message += "\n"
- message += traceback.format_exc(e)
- self.result = False, ("ERROR", e)
-
- finally:
- self.result_flag.set()
-
-
-class MarionetteTestharnessExecutor(TestharnessExecutor):
- def __init__(self, browser, server_config, timeout_multiplier=1,
- close_after_done=True, debug_info=None, **kwargs):
- """Marionette-based executor for testharness.js tests"""
- TestharnessExecutor.__init__(self, browser, server_config,
- timeout_multiplier=timeout_multiplier,
- debug_info=debug_info)
-
- self.protocol = MarionetteProtocol(self, browser)
- self.script = open(os.path.join(here, "testharness_marionette.js")).read()
- self.close_after_done = close_after_done
- self.window_id = str(uuid.uuid4())
-
- self.original_pref_values = {}
-
- if marionette is None:
- do_delayed_imports()
-
- def is_alive(self):
- return self.protocol.is_alive
-
- def on_environment_change(self, new_environment):
- self.protocol.on_environment_change(self.last_environment, new_environment)
-
- if new_environment["protocol"] != self.last_environment["protocol"]:
- self.protocol.load_runner(new_environment["protocol"])
-
- def do_test(self, test):
- timeout = (test.timeout * self.timeout_multiplier if self.debug_info is None
- else None)
-
- success, data = ExecuteAsyncScriptRun(self.logger,
- self.do_testharness,
- self.protocol.marionette,
- self.test_url(test),
- timeout).run()
- if success:
- return self.convert_result(test, data)
-
- return (test.result_cls(*data), [])
-
- def do_testharness(self, marionette, url, timeout):
- if self.close_after_done:
- marionette.execute_script("if (window.wrappedJSObject.win) {window.wrappedJSObject.win.close()}")
-
- if timeout is not None:
- timeout_ms = str(timeout * 1000)
- else:
- timeout_ms = "null"
-
- script = self.script % {"abs_url": url,
- "url": strip_server(url),
- "window_id": self.window_id,
- "timeout_multiplier": self.timeout_multiplier,
- "timeout": timeout_ms,
- "explicit_timeout": timeout is None}
-
- rv = marionette.execute_async_script(script, new_sandbox=False)
- return rv
-
-
-class MarionetteRefTestExecutor(RefTestExecutor):
- def __init__(self, browser, server_config, timeout_multiplier=1,
- screenshot_cache=None, close_after_done=True,
- debug_info=None, **kwargs):
-
- """Marionette-based executor for reftests"""
- RefTestExecutor.__init__(self,
- browser,
- server_config,
- screenshot_cache=screenshot_cache,
- timeout_multiplier=timeout_multiplier,
- debug_info=debug_info)
- self.protocol = MarionetteProtocol(self, browser)
- self.implementation = RefTestImplementation(self)
- self.close_after_done = close_after_done
- self.has_window = False
- self.original_pref_values = {}
-
- with open(os.path.join(here, "reftest.js")) as f:
- self.script = f.read()
- with open(os.path.join(here, "reftest-wait.js")) as f:
- self.wait_script = f.read()
-
- def is_alive(self):
- return self.protocol.is_alive
-
- def on_environment_change(self, new_environment):
- self.protocol.on_environment_change(self.last_environment, new_environment)
-
- def do_test(self, test):
- if self.close_after_done and self.has_window:
- self.protocol.marionette.close()
- self.protocol.marionette.switch_to_window(
- self.protocol.marionette.window_handles[-1])
- self.has_window = False
-
- if not self.has_window:
- self.protocol.marionette.execute_script(self.script)
- self.protocol.marionette.switch_to_window(self.protocol.marionette.window_handles[-1])
- self.has_window = True
-
- result = self.implementation.run_test(test)
- return self.convert_result(test, result)
-
- def screenshot(self, test, viewport_size, dpi):
- # https://github.com/w3c/wptrunner/issues/166
- assert viewport_size is None
- assert dpi is None
-
- timeout = self.timeout_multiplier * test.timeout if self.debug_info is None else None
-
- test_url = self.test_url(test)
-
- return ExecuteAsyncScriptRun(self.logger,
- self._screenshot,
- self.protocol.marionette,
- test_url,
- timeout).run()
-
- def _screenshot(self, marionette, url, timeout):
- marionette.navigate(url)
-
- marionette.execute_async_script(self.wait_script)
-
- screenshot = marionette.screenshot()
- # strip off the data:img/png, part of the url
- if screenshot.startswith("data:image/png;base64,"):
- screenshot = screenshot.split(",", 1)[1]
-
- return screenshot
-
-
-class WdspecRun(object):
- def __init__(self, func, session, path, timeout):
- self.func = func
- self.result = (None, None)
- self.session = session
- self.path = path
- self.timeout = timeout
- self.result_flag = threading.Event()
-
- def run(self):
- """Runs function in a thread and interrupts it if it exceeds the
- given timeout. Returns (True, (Result, [SubtestResult ...])) in
- case of success, or (False, (status, extra information)) in the
- event of failure.
- """
-
- executor = threading.Thread(target=self._run)
- executor.start()
-
- flag = self.result_flag.wait(self.timeout)
- if self.result[1] is None:
- self.result = False, ("EXTERNAL-TIMEOUT", None)
-
- return self.result
-
- def _run(self):
- try:
- self.result = True, self.func(self.session, self.path, self.timeout)
- except (socket.timeout, IOError):
- self.result = False, ("CRASH", None)
- except Exception as e:
- message = getattr(e, "message")
- if message:
- message += "\n"
- message += traceback.format_exc(e)
- self.result = False, ("ERROR", message)
- finally:
- self.result_flag.set()
-
-
-class MarionetteWdspecExecutor(WdspecExecutor):
- def __init__(self, browser, server_config, webdriver_binary,
- timeout_multiplier=1, close_after_done=True, debug_info=None):
- self.do_delayed_imports()
- WdspecExecutor.__init__(self, browser, server_config,
- timeout_multiplier=timeout_multiplier,
- debug_info=debug_info)
- self.webdriver_binary = webdriver_binary
- self.protocol = RemoteMarionetteProtocol(self, browser)
-
- def is_alive(self):
- return self.protocol.is_alive
-
- def on_environment_change(self, new_environment):
- pass
-
- def do_test(self, test):
- timeout = test.timeout * self.timeout_multiplier + extra_timeout
-
- success, data = WdspecRun(self.do_wdspec,
- self.protocol.session,
- test.path,
- timeout).run()
-
- if success:
- return self.convert_result(test, data)
-
- return (test.result_cls(*data), [])
-
- def do_wdspec(self, session, path, timeout):
- harness_result = ("OK", None)
- subtest_results = pytestrunner.run(path, session, timeout=timeout)
- return (harness_result, subtest_results)
-
- def do_delayed_imports(self):
- global pytestrunner, webdriver
- from . import pytestrunner
- import webdriver
diff --git a/tests/wpt/harness/wptrunner/executors/executorselenium.py b/tests/wpt/harness/wptrunner/executors/executorselenium.py
deleted file mode 100644
index f5d65f499b0..00000000000
--- a/tests/wpt/harness/wptrunner/executors/executorselenium.py
+++ /dev/null
@@ -1,263 +0,0 @@
-# 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 socket
-import sys
-import threading
-import time
-import traceback
-import urlparse
-import uuid
-
-from .base import (ExecutorException,
- Protocol,
- RefTestExecutor,
- RefTestImplementation,
- TestExecutor,
- TestharnessExecutor,
- testharness_result_converter,
- reftest_result_converter,
- strip_server)
-from ..testrunner import Stop
-
-here = os.path.join(os.path.split(__file__)[0])
-
-webdriver = None
-exceptions = None
-RemoteConnection = None
-
-extra_timeout = 5
-
-def do_delayed_imports():
- global webdriver
- global exceptions
- global RemoteConnection
- from selenium import webdriver
- from selenium.common import exceptions
- from selenium.webdriver.remote.remote_connection import RemoteConnection
-
-class SeleniumProtocol(Protocol):
- def __init__(self, executor, browser, capabilities, **kwargs):
- do_delayed_imports()
-
- Protocol.__init__(self, executor, browser)
- self.capabilities = capabilities
- self.url = browser.webdriver_url
- self.webdriver = None
-
- def setup(self, runner):
- """Connect to browser via Selenium's WebDriver implementation."""
- self.runner = runner
- self.logger.debug("Connecting to Selenium on URL: %s" % self.url)
-
- session_started = False
- try:
- self.webdriver = webdriver.Remote(command_executor=RemoteConnection(self.url.strip("/"),
- resolve_ip=False),
- desired_capabilities=self.capabilities)
- except:
- self.logger.warning(
- "Connecting to Selenium failed:\n%s" % traceback.format_exc())
- else:
- self.logger.debug("Selenium session started")
- session_started = True
-
- if not session_started:
- self.logger.warning("Failed to connect to Selenium")
- self.executor.runner.send_message("init_failed")
- else:
- try:
- self.after_connect()
- except:
- print >> sys.stderr, traceback.format_exc()
- self.logger.warning(
- "Failed to connect to navigate initial page")
- self.executor.runner.send_message("init_failed")
- else:
- self.executor.runner.send_message("init_succeeded")
-
- def teardown(self):
- self.logger.debug("Hanging up on Selenium session")
- try:
- self.webdriver.quit()
- except:
- pass
- del self.webdriver
-
- def is_alive(self):
- try:
- # Get a simple property over the connection
- self.webdriver.current_window_handle
- # TODO what exception?
- except (socket.timeout, exceptions.ErrorInResponseException):
- return False
- return True
-
- def after_connect(self):
- self.load_runner("http")
-
- def load_runner(self, protocol):
- url = urlparse.urljoin(self.executor.server_url(protocol),
- "/testharness_runner.html")
- self.logger.debug("Loading %s" % url)
- self.webdriver.get(url)
- self.webdriver.execute_script("document.title = '%s'" %
- threading.current_thread().name.replace("'", '"'))
-
- def wait(self):
- while True:
- try:
- self.webdriver.execute_async_script("");
- except exceptions.TimeoutException:
- pass
- except (socket.timeout, exceptions.NoSuchWindowException,
- exceptions.ErrorInResponseException, IOError):
- break
- except Exception as e:
- self.logger.error(traceback.format_exc(e))
- break
-
-
-class SeleniumRun(object):
- def __init__(self, func, webdriver, url, timeout):
- self.func = func
- self.result = None
- self.webdriver = webdriver
- self.url = url
- self.timeout = timeout
- self.result_flag = threading.Event()
-
- def run(self):
- timeout = self.timeout
-
- try:
- self.webdriver.set_script_timeout((timeout + extra_timeout) * 1000)
- except exceptions.ErrorInResponseException:
- self.logger.error("Lost webdriver connection")
- return Stop
-
- executor = threading.Thread(target=self._run)
- executor.start()
-
- flag = self.result_flag.wait(timeout + 2 * extra_timeout)
- if self.result is None:
- assert not flag
- self.result = False, ("EXTERNAL-TIMEOUT", None)
-
- return self.result
-
- def _run(self):
- try:
- self.result = True, self.func(self.webdriver, self.url, self.timeout)
- except exceptions.TimeoutException:
- self.result = False, ("EXTERNAL-TIMEOUT", None)
- except (socket.timeout, exceptions.ErrorInResponseException):
- self.result = False, ("CRASH", None)
- except Exception as e:
- message = getattr(e, "message", "")
- if message:
- message += "\n"
- message += traceback.format_exc(e)
- self.result = False, ("ERROR", e)
- finally:
- self.result_flag.set()
-
-
-class SeleniumTestharnessExecutor(TestharnessExecutor):
- def __init__(self, browser, server_config, timeout_multiplier=1,
- close_after_done=True, capabilities=None, debug_info=None):
- """Selenium-based executor for testharness.js tests"""
- TestharnessExecutor.__init__(self, browser, server_config,
- timeout_multiplier=timeout_multiplier,
- debug_info=debug_info)
- self.protocol = SeleniumProtocol(self, browser, capabilities)
- with open(os.path.join(here, "testharness_webdriver.js")) as f:
- self.script = f.read()
- self.close_after_done = close_after_done
- self.window_id = str(uuid.uuid4())
-
- def is_alive(self):
- return self.protocol.is_alive()
-
- def on_protocol_change(self, new_protocol):
- self.protocol.load_runner(new_protocol)
-
- def do_test(self, test):
- url = self.test_url(test)
-
- success, data = SeleniumRun(self.do_testharness,
- self.protocol.webdriver,
- url,
- test.timeout * self.timeout_multiplier).run()
-
- if success:
- return self.convert_result(test, data)
-
- return (test.result_cls(*data), [])
-
- def do_testharness(self, webdriver, url, timeout):
- return webdriver.execute_async_script(
- self.script % {"abs_url": url,
- "url": strip_server(url),
- "window_id": self.window_id,
- "timeout_multiplier": self.timeout_multiplier,
- "timeout": timeout * 1000})
-
-class SeleniumRefTestExecutor(RefTestExecutor):
- def __init__(self, browser, server_config, timeout_multiplier=1,
- screenshot_cache=None, close_after_done=True,
- debug_info=None, capabilities=None):
- """Selenium WebDriver-based executor for reftests"""
- RefTestExecutor.__init__(self,
- browser,
- server_config,
- screenshot_cache=screenshot_cache,
- timeout_multiplier=timeout_multiplier,
- debug_info=debug_info)
- self.protocol = SeleniumProtocol(self, browser,
- capabilities=capabilities)
- self.implementation = RefTestImplementation(self)
- self.close_after_done = close_after_done
- self.has_window = False
-
- with open(os.path.join(here, "reftest.js")) as f:
- self.script = f.read()
- with open(os.path.join(here, "reftest-wait_webdriver.js")) as f:
- self.wait_script = f.read()
-
- def is_alive(self):
- return self.protocol.is_alive()
-
- def do_test(self, test):
- self.logger.info("Test requires OS-level window focus")
-
- self.protocol.webdriver.set_window_size(600, 600)
-
- result = self.implementation.run_test(test)
-
- return self.convert_result(test, result)
-
- def screenshot(self, test, viewport_size, dpi):
- # https://github.com/w3c/wptrunner/issues/166
- assert viewport_size is None
- assert dpi is None
-
- return SeleniumRun(self._screenshot,
- self.protocol.webdriver,
- self.test_url(test),
- test.timeout).run()
-
- def _screenshot(self, webdriver, url, timeout):
- webdriver.get(url)
-
- webdriver.execute_async_script(self.wait_script)
-
- screenshot = webdriver.get_screenshot_as_base64()
-
- # strip off the data:img/png, part of the url
- if screenshot.startswith("data:image/png;base64,"):
- screenshot = screenshot.split(",", 1)[1]
-
- return screenshot
diff --git a/tests/wpt/harness/wptrunner/executors/executorservo.py b/tests/wpt/harness/wptrunner/executors/executorservo.py
deleted file mode 100644
index e4a10f55bfe..00000000000
--- a/tests/wpt/harness/wptrunner/executors/executorservo.py
+++ /dev/null
@@ -1,372 +0,0 @@
-# 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 base64
-import hashlib
-import httplib
-import json
-import os
-import subprocess
-import tempfile
-import threading
-import traceback
-import urlparse
-import uuid
-from collections import defaultdict
-
-from mozprocess import ProcessHandler
-
-from .base import (ExecutorException,
- Protocol,
- RefTestImplementation,
- testharness_result_converter,
- reftest_result_converter,
- WdspecExecutor)
-from .process import ProcessTestExecutor
-from ..browsers.base import browser_command
-from ..wpttest import WdspecResult, WdspecSubtestResult
-from ..webdriver_server import ServoDriverServer
-from .executormarionette import WdspecRun
-
-pytestrunner = None
-render_arg = None
-webdriver = None
-
-extra_timeout = 5 # seconds
-
-def do_delayed_imports():
- global render_arg
- from ..browsers.servo import render_arg
-
-hosts_text = """127.0.0.1 web-platform.test
-127.0.0.1 www.web-platform.test
-127.0.0.1 www1.web-platform.test
-127.0.0.1 www2.web-platform.test
-127.0.0.1 xn--n8j6ds53lwwkrqhv28a.web-platform.test
-127.0.0.1 xn--lve-6lad.web-platform.test
-"""
-
-def make_hosts_file():
- hosts_fd, hosts_path = tempfile.mkstemp()
- with os.fdopen(hosts_fd, "w") as f:
- f.write(hosts_text)
- return hosts_path
-
-
-class ServoTestharnessExecutor(ProcessTestExecutor):
- convert_result = testharness_result_converter
-
- def __init__(self, browser, server_config, timeout_multiplier=1, debug_info=None,
- pause_after_test=False):
- do_delayed_imports()
- ProcessTestExecutor.__init__(self, browser, server_config,
- timeout_multiplier=timeout_multiplier,
- debug_info=debug_info)
- self.pause_after_test = pause_after_test
- self.result_data = None
- self.result_flag = None
- self.protocol = Protocol(self, browser)
- self.hosts_path = make_hosts_file()
-
- def teardown(self):
- try:
- os.unlink(self.hosts_path)
- except OSError:
- pass
- ProcessTestExecutor.teardown(self)
-
- def do_test(self, test):
- self.result_data = None
- self.result_flag = threading.Event()
-
- args = [render_arg(self.browser.render_backend), "--hard-fail", "-u", "Servo/wptrunner",
- "-Z", "replace-surrogates", "-z", self.test_url(test)]
- for stylesheet in self.browser.user_stylesheets:
- args += ["--user-stylesheet", stylesheet]
- for pref, value in test.environment.get('prefs', {}).iteritems():
- args += ["--pref", "%s=%s" % (pref, value)]
- if self.browser.ca_certificate_path:
- args += ["--certificate-path", self.browser.ca_certificate_path]
- args += self.browser.binary_args
- debug_args, command = browser_command(self.binary, args, self.debug_info)
-
- self.command = command
-
- if self.pause_after_test:
- self.command.remove("-z")
-
- self.command = debug_args + self.command
-
- env = os.environ.copy()
- env["HOST_FILE"] = self.hosts_path
- env["RUST_BACKTRACE"] = "1"
-
-
- if not self.interactive:
- self.proc = ProcessHandler(self.command,
- processOutputLine=[self.on_output],
- onFinish=self.on_finish,
- env=env,
- storeOutput=False)
- self.proc.run()
- else:
- self.proc = subprocess.Popen(self.command, env=env)
-
- try:
- timeout = test.timeout * self.timeout_multiplier
-
- # Now wait to get the output we expect, or until we reach the timeout
- if not self.interactive and not self.pause_after_test:
- wait_timeout = timeout + 5
- self.result_flag.wait(wait_timeout)
- else:
- wait_timeout = None
- self.proc.wait()
-
- proc_is_running = True
-
- if self.result_flag.is_set():
- if self.result_data is not None:
- result = self.convert_result(test, self.result_data)
- else:
- self.proc.wait()
- result = (test.result_cls("CRASH", None), [])
- proc_is_running = False
- else:
- result = (test.result_cls("TIMEOUT", None), [])
-
-
- if proc_is_running:
- if self.pause_after_test:
- self.logger.info("Pausing until the browser exits")
- self.proc.wait()
- else:
- self.proc.kill()
- except KeyboardInterrupt:
- self.proc.kill()
- raise
-
- return result
-
- def on_output(self, line):
- prefix = "ALERT: RESULT: "
- line = line.decode("utf8", "replace")
- if line.startswith(prefix):
- self.result_data = json.loads(line[len(prefix):])
- self.result_flag.set()
- else:
- if self.interactive:
- print line
- else:
- self.logger.process_output(self.proc.pid,
- line,
- " ".join(self.command))
-
- def on_finish(self):
- self.result_flag.set()
-
-
-class TempFilename(object):
- def __init__(self, directory):
- self.directory = directory
- self.path = None
-
- def __enter__(self):
- self.path = os.path.join(self.directory, str(uuid.uuid4()))
- return self.path
-
- def __exit__(self, *args, **kwargs):
- try:
- os.unlink(self.path)
- except OSError:
- pass
-
-
-class ServoRefTestExecutor(ProcessTestExecutor):
- convert_result = reftest_result_converter
-
- def __init__(self, browser, server_config, binary=None, timeout_multiplier=1,
- screenshot_cache=None, debug_info=None, pause_after_test=False):
- do_delayed_imports()
- ProcessTestExecutor.__init__(self,
- browser,
- server_config,
- timeout_multiplier=timeout_multiplier,
- debug_info=debug_info)
-
- self.protocol = Protocol(self, browser)
- self.screenshot_cache = screenshot_cache
- self.implementation = RefTestImplementation(self)
- self.tempdir = tempfile.mkdtemp()
- self.hosts_path = make_hosts_file()
-
- def teardown(self):
- try:
- os.unlink(self.hosts_path)
- except OSError:
- pass
- os.rmdir(self.tempdir)
- ProcessTestExecutor.teardown(self)
-
- def screenshot(self, test, viewport_size, dpi):
- full_url = self.test_url(test)
-
- with TempFilename(self.tempdir) as output_path:
- debug_args, command = browser_command(
- self.binary,
- [render_arg(self.browser.render_backend), "--hard-fail", "--exit",
- "-u", "Servo/wptrunner", "-Z", "disable-text-aa,load-webfonts-synchronously,replace-surrogates",
- "--output=%s" % output_path, full_url] + self.browser.binary_args,
- self.debug_info)
-
- for stylesheet in self.browser.user_stylesheets:
- command += ["--user-stylesheet", stylesheet]
-
- for pref, value in test.environment.get('prefs', {}).iteritems():
- command += ["--pref", "%s=%s" % (pref, value)]
-
- command += ["--resolution", viewport_size or "800x600"]
-
- if self.browser.ca_certificate_path:
- command += ["--certificate-path", self.browser.ca_certificate_path]
-
- if dpi:
- command += ["--device-pixel-ratio", dpi]
-
- # Run ref tests in headless mode
- command += ["-z"]
-
- self.command = debug_args + command
-
- env = os.environ.copy()
- env["HOST_FILE"] = self.hosts_path
- env["RUST_BACKTRACE"] = "1"
-
- if not self.interactive:
- self.proc = ProcessHandler(self.command,
- processOutputLine=[self.on_output],
- env=env)
-
-
- try:
- self.proc.run()
- timeout = test.timeout * self.timeout_multiplier + 5
- rv = self.proc.wait(timeout=timeout)
- except KeyboardInterrupt:
- self.proc.kill()
- raise
- else:
- self.proc = subprocess.Popen(self.command,
- env=env)
- try:
- rv = self.proc.wait()
- except KeyboardInterrupt:
- self.proc.kill()
- raise
-
- if rv is None:
- self.proc.kill()
- return False, ("EXTERNAL-TIMEOUT", None)
-
- if rv != 0 or not os.path.exists(output_path):
- return False, ("CRASH", None)
-
- with open(output_path) as f:
- # Might need to strip variable headers or something here
- data = f.read()
- return True, base64.b64encode(data)
-
- def do_test(self, test):
- result = self.implementation.run_test(test)
-
- return self.convert_result(test, result)
-
- def on_output(self, line):
- line = line.decode("utf8", "replace")
- if self.interactive:
- print line
- else:
- self.logger.process_output(self.proc.pid,
- line,
- " ".join(self.command))
-
-class ServoWdspecProtocol(Protocol):
- def __init__(self, executor, browser):
- self.do_delayed_imports()
- Protocol.__init__(self, executor, browser)
- self.session = None
- self.server = None
-
- def setup(self, runner):
- try:
- self.server = ServoDriverServer(self.logger, binary=self.browser.binary, binary_args=self.browser.binary_args, render_backend=self.browser.render_backend)
- self.server.start(block=False)
- self.logger.info(
- "WebDriver HTTP server listening at %s" % self.server.url)
-
- self.logger.info(
- "Establishing new WebDriver session with %s" % self.server.url)
- self.session = webdriver.Session(
- self.server.host, self.server.port, self.server.base_path)
- except Exception:
- self.logger.error(traceback.format_exc())
- self.executor.runner.send_message("init_failed")
- else:
- self.executor.runner.send_message("init_succeeded")
-
- def teardown(self):
- if self.server is not None:
- try:
- if self.session.session_id is not None:
- self.session.end()
- except Exception:
- pass
- if self.server.is_alive:
- self.server.stop()
-
- @property
- def is_alive(self):
- conn = httplib.HTTPConnection(self.server.host, self.server.port)
- conn.request("HEAD", self.server.base_path + "invalid")
- res = conn.getresponse()
- return res.status == 404
-
- def do_delayed_imports(self):
- global pytestrunner, webdriver
- from . import pytestrunner
- import webdriver
-
-
-class ServoWdspecExecutor(WdspecExecutor):
- def __init__(self, browser, server_config,
- timeout_multiplier=1, close_after_done=True, debug_info=None,
- **kwargs):
- WdspecExecutor.__init__(self, browser, server_config,
- timeout_multiplier=timeout_multiplier,
- debug_info=debug_info)
- self.protocol = ServoWdspecProtocol(self, browser)
-
- def is_alive(self):
- return self.protocol.is_alive
-
- def on_environment_change(self, new_environment):
- pass
-
- def do_test(self, test):
- timeout = test.timeout * self.timeout_multiplier + extra_timeout
-
- success, data = WdspecRun(self.do_wdspec,
- self.protocol.session,
- test.path,
- timeout).run()
-
- if success:
- return self.convert_result(test, data)
-
- return (test.result_cls(*data), [])
-
- def do_wdspec(self, session, path, timeout):
- harness_result = ("OK", None)
- subtest_results = pytestrunner.run(path, session, timeout=timeout)
- return (harness_result, subtest_results)
diff --git a/tests/wpt/harness/wptrunner/executors/executorservodriver.py b/tests/wpt/harness/wptrunner/executors/executorservodriver.py
deleted file mode 100644
index 279658d0cd1..00000000000
--- a/tests/wpt/harness/wptrunner/executors/executorservodriver.py
+++ /dev/null
@@ -1,261 +0,0 @@
-# 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 json
-import os
-import socket
-import threading
-import time
-import traceback
-
-from .base import (Protocol,
- RefTestExecutor,
- RefTestImplementation,
- TestharnessExecutor,
- strip_server)
-from ..testrunner import Stop
-
-webdriver = None
-
-here = os.path.join(os.path.split(__file__)[0])
-
-extra_timeout = 5
-
-
-def do_delayed_imports():
- global webdriver
- from tools import webdriver
-
-
-class ServoWebDriverProtocol(Protocol):
- def __init__(self, executor, browser, capabilities, **kwargs):
- do_delayed_imports()
- Protocol.__init__(self, executor, browser)
- self.capabilities = capabilities
- self.host = browser.webdriver_host
- self.port = browser.webdriver_port
- self.session = None
-
- def setup(self, runner):
- """Connect to browser via WebDriver."""
- self.runner = runner
-
- url = "http://%s:%d" % (self.host, self.port)
- session_started = False
- try:
- self.session = webdriver.Session(self.host, self.port,
- extension=webdriver.servo.ServoCommandExtensions)
- self.session.start()
- except:
- self.logger.warning(
- "Connecting with WebDriver failed:\n%s" % traceback.format_exc())
- else:
- self.logger.debug("session started")
- session_started = True
-
- if not session_started:
- self.logger.warning("Failed to connect via WebDriver")
- self.executor.runner.send_message("init_failed")
- else:
- self.executor.runner.send_message("init_succeeded")
-
- def teardown(self):
- self.logger.debug("Hanging up on WebDriver session")
- try:
- self.session.end()
- except:
- pass
-
- def is_alive(self):
- try:
- # Get a simple property over the connection
- self.session.window_handle
- # TODO what exception?
- except Exception:
- return False
- return True
-
- def after_connect(self):
- pass
-
- def wait(self):
- while True:
- try:
- self.session.execute_async_script("")
- except webdriver.TimeoutException:
- pass
- except (socket.timeout, IOError):
- break
- except Exception as e:
- self.logger.error(traceback.format_exc(e))
- break
-
- def on_environment_change(self, old_environment, new_environment):
- #Unset all the old prefs
- self.session.extension.reset_prefs(*old_environment.get("prefs", {}).keys())
- self.session.extension.set_prefs(new_environment.get("prefs", {}))
-
-
-class ServoWebDriverRun(object):
- def __init__(self, func, session, url, timeout, current_timeout=None):
- self.func = func
- self.result = None
- self.session = session
- self.url = url
- self.timeout = timeout
- self.result_flag = threading.Event()
-
- def run(self):
- executor = threading.Thread(target=self._run)
- executor.start()
-
- flag = self.result_flag.wait(self.timeout + extra_timeout)
- if self.result is None:
- assert not flag
- self.result = False, ("EXTERNAL-TIMEOUT", None)
-
- return self.result
-
- def _run(self):
- try:
- self.result = True, self.func(self.session, self.url, self.timeout)
- except webdriver.TimeoutException:
- self.result = False, ("EXTERNAL-TIMEOUT", None)
- except (socket.timeout, IOError):
- self.result = False, ("CRASH", None)
- except Exception as e:
- message = getattr(e, "message", "")
- if message:
- message += "\n"
- message += traceback.format_exc(e)
- self.result = False, ("ERROR", e)
- finally:
- self.result_flag.set()
-
-
-def timeout_func(timeout):
- if timeout:
- t0 = time.time()
- return lambda: time.time() - t0 > timeout + extra_timeout
- else:
- return lambda: False
-
-
-class ServoWebDriverTestharnessExecutor(TestharnessExecutor):
- def __init__(self, browser, server_config, timeout_multiplier=1,
- close_after_done=True, capabilities=None, debug_info=None):
- TestharnessExecutor.__init__(self, browser, server_config, timeout_multiplier=1,
- debug_info=None)
- self.protocol = ServoWebDriverProtocol(self, browser, capabilities=capabilities)
- with open(os.path.join(here, "testharness_servodriver.js")) as f:
- self.script = f.read()
- self.timeout = None
-
- def on_protocol_change(self, new_protocol):
- pass
-
- def is_alive(self):
- return self.protocol.is_alive()
-
- def do_test(self, test):
- url = self.test_url(test)
-
- timeout = test.timeout * self.timeout_multiplier + extra_timeout
-
- if timeout != self.timeout:
- try:
- self.protocol.session.timeouts.script = timeout
- self.timeout = timeout
- except IOError:
- self.logger.error("Lost webdriver connection")
- return Stop
-
- success, data = ServoWebDriverRun(self.do_testharness,
- self.protocol.session,
- url,
- timeout).run()
-
- if success:
- return self.convert_result(test, data)
-
- return (test.result_cls(*data), [])
-
- def do_testharness(self, session, url, timeout):
- session.url = url
- result = json.loads(
- session.execute_async_script(
- self.script % {"abs_url": url,
- "url": strip_server(url),
- "timeout_multiplier": self.timeout_multiplier,
- "timeout": timeout * 1000}))
- # Prevent leaking every page in history until Servo develops a more sane
- # page cache
- session.back()
- return result
-
-
-class TimeoutError(Exception):
- pass
-
-
-class ServoWebDriverRefTestExecutor(RefTestExecutor):
- def __init__(self, browser, server_config, timeout_multiplier=1,
- screenshot_cache=None, capabilities=None, debug_info=None):
- """Selenium WebDriver-based executor for reftests"""
- RefTestExecutor.__init__(self,
- browser,
- server_config,
- screenshot_cache=screenshot_cache,
- timeout_multiplier=timeout_multiplier,
- debug_info=debug_info)
- self.protocol = ServoWebDriverProtocol(self, browser,
- capabilities=capabilities)
- self.implementation = RefTestImplementation(self)
- self.timeout = None
- with open(os.path.join(here, "reftest-wait_servodriver.js")) as f:
- self.wait_script = f.read()
-
- def is_alive(self):
- return self.protocol.is_alive()
-
- def do_test(self, test):
- try:
- result = self.implementation.run_test(test)
- return self.convert_result(test, result)
- except IOError:
- return test.result_cls("CRASH", None), []
- except TimeoutError:
- return test.result_cls("TIMEOUT", None), []
- except Exception as e:
- message = getattr(e, "message", "")
- if message:
- message += "\n"
- message += traceback.format_exc(e)
- return test.result_cls("ERROR", message), []
-
- def screenshot(self, test, viewport_size, dpi):
- # https://github.com/w3c/wptrunner/issues/166
- assert viewport_size is None
- assert dpi is None
-
- timeout = (test.timeout * self.timeout_multiplier + extra_timeout
- if self.debug_info is None else None)
-
- if self.timeout != timeout:
- try:
- self.protocol.session.timeouts.script = timeout
- self.timeout = timeout
- except IOError:
- self.logger.error("Lost webdriver connection")
- return Stop
-
- return ServoWebDriverRun(self._screenshot,
- self.protocol.session,
- self.test_url(test),
- timeout).run()
-
- def _screenshot(self, session, url, timeout):
- session.url = url
- session.execute_async_script(self.wait_script)
- return session.screenshot()
diff --git a/tests/wpt/harness/wptrunner/executors/process.py b/tests/wpt/harness/wptrunner/executors/process.py
deleted file mode 100644
index 45f33ab2c75..00000000000
--- a/tests/wpt/harness/wptrunner/executors/process.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# 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/.
-
-from .base import TestExecutor
-
-
-class ProcessTestExecutor(TestExecutor):
- def __init__(self, *args, **kwargs):
- TestExecutor.__init__(self, *args, **kwargs)
- self.binary = self.browser.binary
- self.interactive = (False if self.debug_info is None
- else self.debug_info.interactive)
-
- def setup(self, runner):
- self.runner = runner
- self.runner.send_message("init_succeeded")
- return True
-
- def is_alive(self):
- return True
-
- def do_test(self, test):
- raise NotImplementedError
diff --git a/tests/wpt/harness/wptrunner/executors/pytestrunner/__init__.py b/tests/wpt/harness/wptrunner/executors/pytestrunner/__init__.py
deleted file mode 100644
index de3a34a794b..00000000000
--- a/tests/wpt/harness/wptrunner/executors/pytestrunner/__init__.py
+++ /dev/null
@@ -1,6 +0,0 @@
-# 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/.
-
-from . import fixtures
-from .runner import run
diff --git a/tests/wpt/harness/wptrunner/executors/pytestrunner/fixtures.py b/tests/wpt/harness/wptrunner/executors/pytestrunner/fixtures.py
deleted file mode 100644
index 81796d69883..00000000000
--- a/tests/wpt/harness/wptrunner/executors/pytestrunner/fixtures.py
+++ /dev/null
@@ -1,136 +0,0 @@
-# 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 pytest
-import webdriver
-
-import contextlib
-import httplib
-
-
-"""pytest fixtures for use in Python-based WPT tests.
-
-The purpose of test fixtures is to provide a fixed baseline upon which
-tests can reliably and repeatedly execute.
-"""
-
-
-class Session(object):
- """Fixture to allow access to wptrunner's existing WebDriver session
- in tests.
-
- The session is not created by default to enable testing of session
- creation. However, a function-scoped session will be implicitly created
- at the first call to a WebDriver command. This means methods such as
- `session.send_command` and `session.session_id` are possible to use
- without having a session.
-
- To illustrate implicit session creation::
-
- def test_session_scope(session):
- # at this point there is no session
- assert session.session_id is None
-
- # window_id is a WebDriver command,
- # and implicitly creates the session for us
- assert session.window_id is not None
-
- # we now have a session
- assert session.session_id is not None
-
- You can also access the session in custom fixtures defined in the
- tests, such as a setup function::
-
- @pytest.fixture(scope="function")
- def setup(request, session):
- session.url = "https://example.org"
-
- def test_something(setup, session):
- assert session.url == "https://example.org"
-
- When the test function goes out of scope, any remaining user prompts
- and opened windows are closed, and the current browsing context is
- switched back to the top-level browsing context.
- """
-
- def __init__(self, client):
- self.client = client
-
- @pytest.fixture(scope="function")
- def session(self, request):
- # finalisers are popped off a stack,
- # making their ordering reverse
- request.addfinalizer(self.switch_to_top_level_browsing_context)
- request.addfinalizer(self.restore_windows)
- request.addfinalizer(self.dismiss_user_prompts)
-
- return self.client
-
- def dismiss_user_prompts(self):
- """Dismisses any open user prompts in windows."""
- current_window = self.client.window_handle
-
- for window in self.windows():
- self.client.window_handle = window
- try:
- self.client.alert.dismiss()
- except webdriver.NoSuchAlertException:
- pass
-
- self.client.window_handle = current_window
-
- def restore_windows(self):
- """Closes superfluous windows opened by the test without ending
- the session implicitly by closing the last window.
- """
- current_window = self.client.window_handle
-
- for window in self.windows(exclude=[current_window]):
- self.client.window_handle = window
- if len(self.client.window_handles) > 1:
- self.client.close()
-
- self.client.window_handle = current_window
-
- def switch_to_top_level_browsing_context(self):
- """If the current browsing context selected by WebDriver is a
- `<frame>` or an `<iframe>`, switch it back to the top-level
- browsing context.
- """
- self.client.switch_frame(None)
-
- def windows(self, exclude=None):
- """Set of window handles, filtered by an `exclude` list if
- provided.
- """
- if exclude is None:
- exclude = []
- wins = [w for w in self.client.handles if w not in exclude]
- return set(wins)
-
-
-class HTTPRequest(object):
- def __init__(self, host, port):
- self.host = host
- self.port = port
-
- def head(self, path):
- return self._request("HEAD", path)
-
- def get(self, path):
- return self._request("GET", path)
-
- @contextlib.contextmanager
- def _request(self, method, path):
- conn = httplib.HTTPConnection(self.host, self.port)
- try:
- conn.request(method, path)
- yield conn.getresponse()
- finally:
- conn.close()
-
-
-@pytest.fixture(scope="module")
-def http(session):
- return HTTPRequest(session.transport.host, session.transport.port)
diff --git a/tests/wpt/harness/wptrunner/executors/pytestrunner/runner.py b/tests/wpt/harness/wptrunner/executors/pytestrunner/runner.py
deleted file mode 100644
index 4f2ead1b6d9..00000000000
--- a/tests/wpt/harness/wptrunner/executors/pytestrunner/runner.py
+++ /dev/null
@@ -1,114 +0,0 @@
-# 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/.
-
-"""Provides interface to deal with pytest.
-
-Usage::
-
- session = webdriver.client.Session("127.0.0.1", "4444", "/")
- harness_result = ("OK", None)
- subtest_results = pytestrunner.run("/path/to/test", session.url)
- return (harness_result, subtest_results)
-"""
-
-import errno
-import shutil
-import tempfile
-
-from . import fixtures
-
-
-pytest = None
-
-
-def do_delayed_imports():
- global pytest
- import pytest
-
-
-def run(path, session, timeout=0):
- """Run Python test at ``path`` in pytest. The provided ``session``
- is exposed as a fixture available in the scope of the test functions.
-
- :param path: Path to the test file.
- :param session: WebDriver session to expose.
- :param timeout: Duration before interrupting potentially hanging
- tests. If 0, there is no timeout.
-
- :returns: List of subtest results, which are tuples of (test id,
- status, message, stacktrace).
- """
-
- if pytest is None:
- do_delayed_imports()
-
- recorder = SubtestResultRecorder()
- plugins = [recorder,
- fixtures,
- fixtures.Session(session)]
-
- # TODO(ato): Deal with timeouts
-
- with TemporaryDirectory() as cache:
- pytest.main(["--strict", # turn warnings into errors
- "--verbose", # show each individual subtest
- "--capture", "no", # enable stdout/stderr from tests
- "--basetemp", cache, # temporary directory
- path],
- plugins=plugins)
-
- return recorder.results
-
-
-class SubtestResultRecorder(object):
- def __init__(self):
- self.results = []
-
- def pytest_runtest_logreport(self, report):
- if report.passed and report.when == "call":
- self.record_pass(report)
- elif report.failed:
- if report.when != "call":
- self.record_error(report)
- else:
- self.record_fail(report)
- elif report.skipped:
- self.record_skip(report)
-
- def record_pass(self, report):
- self.record(report.nodeid, "PASS")
-
- def record_fail(self, report):
- self.record(report.nodeid, "FAIL", stack=report.longrepr)
-
- def record_error(self, report):
- # error in setup/teardown
- if report.when != "call":
- message = "%s error" % report.when
- self.record(report.nodeid, "ERROR", message, report.longrepr)
-
- def record_skip(self, report):
- self.record(report.nodeid, "ERROR",
- "In-test skip decorators are disallowed, "
- "please use WPT metadata to ignore tests.")
-
- def record(self, test, status, message=None, stack=None):
- if stack is not None:
- stack = str(stack)
- new_result = (test, status, message, stack)
- self.results.append(new_result)
-
-
-class TemporaryDirectory(object):
- def __enter__(self):
- self.path = tempfile.mkdtemp(prefix="pytest-")
- return self.path
-
- def __exit__(self, *args):
- try:
- shutil.rmtree(self.path)
- except OSError as e:
- # no such file or directory
- if e.errno != errno.ENOENT:
- raise
diff --git a/tests/wpt/harness/wptrunner/executors/reftest-wait.js b/tests/wpt/harness/wptrunner/executors/reftest-wait.js
deleted file mode 100644
index a2bc6656533..00000000000
--- a/tests/wpt/harness/wptrunner/executors/reftest-wait.js
+++ /dev/null
@@ -1,22 +0,0 @@
-/* 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/. */
-
-function test(x) {
- log("classList: " + root.classList);
- if (!root.classList.contains("reftest-wait")) {
- observer.disconnect();
- marionetteScriptFinished();
- }
-}
-
-var root = document.documentElement;
-var observer = new MutationObserver(test);
-
-observer.observe(root, {attributes: true});
-
-if (document.readyState != "complete") {
- onload = test
-} else {
- test();
-}
diff --git a/tests/wpt/harness/wptrunner/executors/reftest-wait_servodriver.js b/tests/wpt/harness/wptrunner/executors/reftest-wait_servodriver.js
deleted file mode 100644
index 6040b4336cd..00000000000
--- a/tests/wpt/harness/wptrunner/executors/reftest-wait_servodriver.js
+++ /dev/null
@@ -1,20 +0,0 @@
-/* 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/.
- */
-
-callback = arguments[arguments.length - 1];
-
-function check_done() {
- if (!document.body.classList.contains('reftest-wait')) {
- callback();
- } else {
- setTimeout(check_done, 50);
- }
-}
-
-if (document.readyState === 'complete') {
- check_done();
-} else {
- addEventListener("load", check_done);
-}
diff --git a/tests/wpt/harness/wptrunner/executors/reftest-wait_webdriver.js b/tests/wpt/harness/wptrunner/executors/reftest-wait_webdriver.js
deleted file mode 100644
index 187f5daac83..00000000000
--- a/tests/wpt/harness/wptrunner/executors/reftest-wait_webdriver.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* 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/. */
-
-var callback = arguments[arguments.length - 1];
-
-function test(x) {
- if (!root.classList.contains("reftest-wait")) {
- observer.disconnect();
- callback()
- }
-}
-
-var root = document.documentElement;
-var observer = new MutationObserver(test);
-
-observer.observe(root, {attributes: true});
-
-if (document.readyState != "complete") {
- onload = test;
-} else {
- test();
-}
diff --git a/tests/wpt/harness/wptrunner/executors/reftest.js b/tests/wpt/harness/wptrunner/executors/reftest.js
deleted file mode 100644
index 3d7a9b6d223..00000000000
--- a/tests/wpt/harness/wptrunner/executors/reftest.js
+++ /dev/null
@@ -1,5 +0,0 @@
-/* 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/. */
-
-var win = window.open("about:blank", "test", "width=600,height=600");
diff --git a/tests/wpt/harness/wptrunner/executors/testharness_marionette.js b/tests/wpt/harness/wptrunner/executors/testharness_marionette.js
deleted file mode 100644
index 1a1b685fefa..00000000000
--- a/tests/wpt/harness/wptrunner/executors/testharness_marionette.js
+++ /dev/null
@@ -1,36 +0,0 @@
-/* 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/. */
-
-window.wrappedJSObject.timeout_multiplier = %(timeout_multiplier)d;
-window.wrappedJSObject.explicit_timeout = %(explicit_timeout)d;
-
-window.wrappedJSObject.addEventListener("message", function listener(event) {
- if (event.data.type != "complete") {
- return;
- }
- window.wrappedJSObject.removeEventListener("message", listener);
- clearTimeout(timer);
- var tests = event.data.tests;
- var status = event.data.status;
-
- var subtest_results = tests.map(function(x) {
- return [x.name, x.status, x.message, x.stack]
- });
-
- marionetteScriptFinished(["%(url)s",
- status.status,
- status.message,
- status.stack,
- subtest_results]);
-}, false);
-
-window.wrappedJSObject.win = window.open("%(abs_url)s", "%(window_id)s");
-
-var timer = null;
-if (%(timeout)s) {
- timer = setTimeout(function() {
- log("Timeout fired");
- window.wrappedJSObject.win.timeout();
- }, %(timeout)s);
-}
diff --git a/tests/wpt/harness/wptrunner/executors/testharness_servodriver.js b/tests/wpt/harness/wptrunner/executors/testharness_servodriver.js
deleted file mode 100644
index 20aeb34b9ee..00000000000
--- a/tests/wpt/harness/wptrunner/executors/testharness_servodriver.js
+++ /dev/null
@@ -1,6 +0,0 @@
-/* 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/. */
-
-window.__wd_results_callback__ = arguments[arguments.length - 1];
-window.__wd_results_timer__ = setTimeout(timeout, %(timeout)s);
diff --git a/tests/wpt/harness/wptrunner/executors/testharness_webdriver.js b/tests/wpt/harness/wptrunner/executors/testharness_webdriver.js
deleted file mode 100644
index f78f9aef05b..00000000000
--- a/tests/wpt/harness/wptrunner/executors/testharness_webdriver.js
+++ /dev/null
@@ -1,33 +0,0 @@
-/* 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/. */
-
-var callback = arguments[arguments.length - 1];
-window.timeout_multiplier = %(timeout_multiplier)d;
-
-window.addEventListener("message", function f(event) {
- if (event.data.type != "complete") {
- return;
- }
- window.removeEventListener("message", f);
-
- var tests = event.data.tests;
- var status = event.data.status;
-
- var subtest_results = tests.map(function(x) {
- return [x.name, x.status, x.message, x.stack]
- });
- clearTimeout(timer);
- callback(["%(url)s",
- status.status,
- status.message,
- status.stack,
- subtest_results]);
-}, false);
-
-window.win = window.open("%(abs_url)s", "%(window_id)s");
-
-var timer = setTimeout(function() {
- window.win.timeout();
- window.win.close();
-}, %(timeout)s);
diff --git a/tests/wpt/harness/wptrunner/executors/webdriver.py b/tests/wpt/harness/wptrunner/executors/webdriver.py
deleted file mode 100644
index dee2a1c2337..00000000000
--- a/tests/wpt/harness/wptrunner/executors/webdriver.py
+++ /dev/null
@@ -1,642 +0,0 @@
-import errno
-import httplib
-import json
-import socket
-import time
-import urlparse
-from collections import defaultdict
-
-element_key = "element-6066-11e4-a52e-4f735466cecf"
-
-
-class WebDriverException(Exception):
- http_status = None
- status_code = None
-
- def __init__(self, message):
- self.message = message
-
-
-class ElementNotSelectableException(WebDriverException):
- http_status = 400
- status_code = "element not selectable"
-
-
-class ElementNotVisibleException(WebDriverException):
- http_status = 400
- status_code = "element not visible"
-
-
-class InvalidArgumentException(WebDriverException):
- http_status = 400
- status_code = "invalid argument"
-
-
-class InvalidCookieDomainException(WebDriverException):
- http_status = 400
- status_code = "invalid cookie domain"
-
-
-class InvalidElementCoordinatesException(WebDriverException):
- http_status = 400
- status_code = "invalid element coordinates"
-
-
-class InvalidElementStateException(WebDriverException):
- http_status = 400
- status_code = "invalid cookie domain"
-
-
-class InvalidSelectorException(WebDriverException):
- http_status = 400
- status_code = "invalid selector"
-
-
-class InvalidSessionIdException(WebDriverException):
- http_status = 404
- status_code = "invalid session id"
-
-
-class JavascriptErrorException(WebDriverException):
- http_status = 500
- status_code = "javascript error"
-
-
-class MoveTargetOutOfBoundsException(WebDriverException):
- http_status = 500
- status_code = "move target out of bounds"
-
-
-class NoSuchAlertException(WebDriverException):
- http_status = 400
- status_code = "no such alert"
-
-
-class NoSuchElementException(WebDriverException):
- http_status = 404
- status_code = "no such element"
-
-
-class NoSuchFrameException(WebDriverException):
- http_status = 400
- status_code = "no such frame"
-
-
-class NoSuchWindowException(WebDriverException):
- http_status = 400
- status_code = "no such window"
-
-
-class ScriptTimeoutException(WebDriverException):
- http_status = 408
- status_code = "script timeout"
-
-
-class SessionNotCreatedException(WebDriverException):
- http_status = 500
- status_code = "session not created"
-
-
-class StaleElementReferenceException(WebDriverException):
- http_status = 400
- status_code = "stale element reference"
-
-
-class TimeoutException(WebDriverException):
- http_status = 408
- status_code = "timeout"
-
-
-class UnableToSetCookieException(WebDriverException):
- http_status = 500
- status_code = "unable to set cookie"
-
-
-class UnexpectedAlertOpenException(WebDriverException):
- http_status = 500
- status_code = "unexpected alert open"
-
-
-class UnknownErrorException(WebDriverException):
- http_status = 500
- status_code = "unknown error"
-
-
-class UnknownCommandException(WebDriverException):
- http_status = (404, 405)
- status_code = "unknown command"
-
-
-class UnsupportedOperationException(WebDriverException):
- http_status = 500
- status_code = "unsupported operation"
-
-
-def group_exceptions():
- exceptions = defaultdict(dict)
- for item in _objs:
- if type(item) == type and issubclass(item, WebDriverException):
- if not isinstance(item.http_status, tuple):
- statuses = (item.http_status,)
- else:
- statuses = item.http_status
-
- for status in statuses:
- exceptions[status][item.status_code] = item
- return exceptions
-
-
-_objs = locals().values()
-_exceptions = group_exceptions()
-del _objs
-del group_exceptions
-
-
-def wait_for_port(host, port, timeout=60):
- """ Wait for the specified Marionette host/port to be available."""
- starttime = time.time()
- poll_interval = 0.1
- while time.time() - starttime < timeout:
- sock = None
- try:
- sock = socket.socket()
- sock.connect((host, port))
- return True
- except socket.error as e:
- if e[0] != errno.ECONNREFUSED:
- raise
- finally:
- if sock:
- sock.close()
- time.sleep(poll_interval)
- return False
-
-
-class Transport(object):
- def __init__(self, host, port, url_prefix="", port_timeout=60):
- self.host = host
- self.port = port
- self.port_timeout = port_timeout
- if url_prefix == "":
- self.path_prefix = "/"
- else:
- self.path_prefix = "/%s/" % url_prefix.strip("/")
- self._connection = None
-
- def connect(self):
- wait_for_port(self.host, self.port, self.port_timeout)
- self._connection = httplib.HTTPConnection(self.host, self.port)
-
- def close_connection(self):
- if self._connection:
- self._connection.close()
- self._connection = None
-
- def url(self, suffix):
- return urlparse.urljoin(self.url_prefix, suffix)
-
- def send(self, method, url, body=None, headers=None, key=None):
- if not self._connection:
- self.connect()
-
- if body is None and method == "POST":
- body = {}
-
- if isinstance(body, dict):
- body = json.dumps(body)
-
- if isinstance(body, unicode):
- body = body.encode("utf-8")
-
- if headers is None:
- headers = {}
-
- url = self.path_prefix + url
-
- self._connection.request(method, url, body, headers)
-
- try:
- resp = self._connection.getresponse()
- except Exception:
- # This should probably be more specific
- raise IOError
- resp_body = resp.read()
-
- try:
- data = json.loads(resp_body)
- except:
- raise WebDriverException("Could not parse response body as JSON: %s" % body)
-
- if resp.status != 200:
- cls = _exceptions.get(resp.status, {}).get(data.get("status", None), WebDriverException)
- raise cls(data.get("message", ""))
-
- if key is not None:
- data = data[key]
-
- if not data:
- data = None
-
- return data
-
-
-def command(func):
- def inner(self, *args, **kwargs):
- if hasattr(self, "session"):
- session_id = self.session.session_id
- else:
- session_id = self.session_id
-
- if session_id is None:
- raise SessionNotCreatedException("Session not created")
- return func(self, *args, **kwargs)
-
- inner.__name__ = func.__name__
- inner.__doc__ = func.__doc__
-
- return inner
-
-
-class Timeouts(object):
- def __init__(self, session):
- self.session = session
- self._script = 30
- self._load = 0
- self._implicit_wait = 0
-
- def _set_timeouts(self, name, value):
- body = {"type": name,
- "ms": value * 1000}
- return self.session.send_command("POST", "timeouts", body)
-
- @property
- def script(self):
- return self._script
-
- @script.setter
- def script(self, value):
- self._set_timeouts("script", value)
- self._script = value
-
- @property
- def load(self):
- return self._load
-
- @load.setter
- def set_load(self, value):
- self._set_timeouts("page load", value)
- self._script = value
-
- @property
- def implicit_wait(self):
- return self._implicit_wait
-
- @implicit_wait.setter
- def implicit_wait(self, value):
- self._set_timeouts("implicit wait", value)
- self._implicit_wait = value
-
-
-class Window(object):
- def __init__(self, session):
- self.session = session
-
- @property
- @command
- def size(self):
- return self.session.send_command("GET", "window/size")
-
- @size.setter
- @command
- def size(self, (height, width)):
- body = {"width": width,
- "height": height}
-
- return self.session.send_command("POST", "window/size", body)
-
- @property
- @command
- def maximize(self):
- return self.session.send_command("POST", "window/maximize")
-
-
-class Find(object):
- def __init__(self, session):
- self.session = session
-
- @command
- def css(self, selector, all=True):
- return self._find_element("css selector", selector, all)
-
- def _find_element(self, strategy, selector, all):
- route = "elements" if all else "element"
-
- body = {"using": strategy,
- "value": selector}
-
- data = self.session.send_command("POST", route, body, key="value")
-
- if all:
- rv = [self.session._element(item) for item in data]
- else:
- rv = self.session._element(data)
-
- return rv
-
-
-class Cookies(object):
- def __init__(self, session):
- self.session = session
-
- def __getitem__(self, name):
- self.session.send_command("GET", "cookie/%s" % name, {}, key="value")
-
- def __setitem__(self, name, value):
- cookie = {"name": name,
- "value": None}
-
- if isinstance(name, (str, unicode)):
- cookie["value"] = value
- elif hasattr(value, "value"):
- cookie["value"] = value.value
- self.session.send_command("POST", "cookie/%s" % name, {}, key="value")
-
-
-class Session(object):
- def __init__(self, host, port, url_prefix="", desired_capabilities=None, port_timeout=60,
- extension=None):
- self.transport = Transport(host, port, url_prefix, port_timeout)
- self.desired_capabilities = desired_capabilities
- self.session_id = None
- self.timeouts = None
- self.window = None
- self.find = None
- self._element_cache = {}
- self.extension = None
- self.extension_cls = extension
-
- def start(self):
- desired_capabilities = self.desired_capabilities if self.desired_capabilities else {}
- body = {"capabilities": {"desiredCapabilites": desired_capabilities}}
-
- rv = self.transport.send("POST", "session", body=body)
- self.session_id = rv["sessionId"]
-
- self.timeouts = Timeouts(self)
- self.window = Window(self)
- self.find = Find(self)
- if self.extension_cls:
- self.extension = self.extension_cls(self)
-
- return rv["value"]
-
- @command
- def end(self):
- url = "session/%s" % self.session_id
- self.transport.send("DELETE", url)
- self.session_id = None
- self.timeouts = None
- self.window = None
- self.find = None
- self.extension = None
- self.transport.close_connection()
-
- def __enter__(self):
- resp = self.start()
- if resp.error:
- raise Exception(resp)
- return self
-
- def __exit__(self, *args, **kwargs):
- resp = self.end()
- if resp.error:
- raise Exception(resp)
-
- def send_command(self, method, url, body=None, key=None):
- url = urlparse.urljoin("session/%s/" % self.session_id, url)
- return self.transport.send(method, url, body, key=key)
-
- @property
- @command
- def url(self):
- return self.send_command("GET", "url", key="value")
-
- @url.setter
- @command
- def url(self, url):
- if urlparse.urlsplit(url).netloc is None:
- return self.url(url)
- body = {"url": url}
- return self.send_command("POST", "url", body)
-
- @command
- def back(self):
- return self.send_command("POST", "back")
-
- @command
- def forward(self):
- return self.send_command("POST", "forward")
-
- @command
- def refresh(self):
- return self.send_command("POST", "refresh")
-
- @property
- @command
- def title(self):
- return self.send_command("GET", "title", key="value")
-
- @property
- @command
- def handle(self):
- return self.send_command("GET", "window_handle", key="value")
-
- @handle.setter
- @command
- def handle(self, handle):
- body = {"handle": handle}
- return self.send_command("POST", "window", body=body)
-
- def switch_frame(self, frame):
- if frame == "parent":
- url = "frame/parent"
- body = None
- else:
- url = "frame"
- if isinstance(frame, Element):
- body = {"id": frame.json()}
- else:
- body = {"id": frame}
-
- return self.send_command("POST", url, body)
-
- @command
- def close(self):
- return self.send_command("DELETE", "window_handle")
-
- @property
- @command
- def handles(self):
- return self.send_command("GET", "window_handles", key="value")
-
- @property
- @command
- def active_element(self):
- data = self.send_command("GET", "element/active", key="value")
- if data is not None:
- return self._element(data)
-
- def _element(self, data):
- elem_id = data[element_key]
- assert elem_id
- if elem_id in self._element_cache:
- return self._element_cache[elem_id]
- return Element(self, elem_id)
-
- @command
- def cookies(self, name=None):
- if name is None:
- url = "cookie"
- else:
- url = "cookie/%s" % name
- return self.send_command("GET", url, {}, key="value")
-
- @command
- def set_cookie(self, name, value, path=None, domain=None, secure=None, expiry=None):
- body = {"name": name,
- "value": value}
- if path is not None:
- body["path"] = path
- if domain is not None:
- body["domain"] = domain
- if secure is not None:
- body["secure"] = secure
- if expiry is not None:
- body["expiry"] = expiry
- self.send_command("POST", "cookie", {"cookie": body})
-
- def delete_cookie(self, name=None):
- if name is None:
- url = "cookie"
- else:
- url = "cookie/%s" % name
- self.send_command("DELETE", url, {}, key="value")
-
- #[...]
-
- @command
- def execute_script(self, script, args=None):
- if args is None:
- args = []
-
- body = {
- "script": script,
- "args": args
- }
- return self.send_command("POST", "execute", body, key="value")
-
- @command
- def execute_async_script(self, script, args=None):
- if args is None:
- args = []
-
- body = {
- "script": script,
- "args": args
- }
- return self.send_command("POST", "execute_async", body, key="value")
-
- #[...]
-
- @command
- def screenshot(self):
- return self.send_command("GET", "screenshot", key="value")
-
-
-class Element(object):
- def __init__(self, session, id):
- self.session = session
- self.id = id
- assert id not in self.session._element_cache
- self.session._element_cache[self.id] = self
-
- def json(self):
- return {element_key: self.id}
-
- @property
- def session_id(self):
- return self.session.session_id
-
- def url(self, suffix):
- return "element/%s/%s" % (self.id, suffix)
-
- @command
- def find_element(self, strategy, selector):
- body = {"using": strategy,
- "value": selector}
-
- elem = self.session.send_command("POST", self.url("element"), body, key="value")
- return self.session.element(elem)
-
- @command
- def click(self):
- self.session.send_command("POST", self.url("click"), {})
-
- @command
- def tap(self):
- self.session.send_command("POST", self.url("tap"), {})
-
- @command
- def clear(self):
- self.session.send_command("POST", self.url("clear"), {})
-
- @command
- def send_keys(self, keys):
- if isinstance(keys, (str, unicode)):
- keys = [char for char in keys]
-
- body = {"value": keys}
-
- return self.session.send_command("POST", self.url("value"), body)
-
- @property
- @command
- def text(self):
- return self.session.send_command("GET", self.url("text"))
-
- @property
- @command
- def name(self):
- return self.session.send_command("GET", self.url("name"))
-
- @command
- def style(self, property_name):
- return self.session.send_command("GET", self.url("css/%s" % property_name))
-
- @property
- @command
- def rect(self):
- return self.session.send_command("GET", self.url("rect"))
-
- @command
- def attribute(self, name):
- return self.session.send_command("GET", self.url("attribute/%s" % name))
-
-class ServoExtensions(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)
diff --git a/tests/wpt/harness/wptrunner/expected.py b/tests/wpt/harness/wptrunner/expected.py
deleted file mode 100644
index 2ebc8101365..00000000000
--- a/tests/wpt/harness/wptrunner/expected.py
+++ /dev/null
@@ -1,18 +0,0 @@
-# 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
-
-
-def expected_path(metadata_path, test_path):
- """Path to the expectation data file for a given test path.
-
- This is defined as metadata_path + relative_test_path + .ini
-
- :param metadata_path: Path to the root of the metadata directory
- :param test_path: Relative path to the test file from the test root
- """
- args = list(test_path.split("/"))
- args[-1] += ".ini"
- return os.path.join(metadata_path, *args)
diff --git a/tests/wpt/harness/wptrunner/hosts.py b/tests/wpt/harness/wptrunner/hosts.py
deleted file mode 100644
index 99daada6f08..00000000000
--- a/tests/wpt/harness/wptrunner/hosts.py
+++ /dev/null
@@ -1,104 +0,0 @@
-# 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/.
-
-from __future__ import unicode_literals
-
-
-class HostsLine(object):
- def __init__(self, ip_address, canonical_hostname, aliases=None, comment=None):
- self.ip_address = ip_address
- self.canonical_hostname = canonical_hostname
- self.aliases = aliases if aliases is not None else []
- self.comment = comment
- if self.ip_address is None:
- assert self.canonical_hostname is None
- assert not self.aliases
- assert self.comment is not None
-
- @classmethod
- def from_string(cls, line):
- if not line.strip():
- return
-
- line = line.strip()
-
- ip_address = None
- canonical_hostname = None
- aliases = []
- comment = None
-
- comment_parts = line.split("#", 1)
- if len(comment_parts) > 1:
- comment = comment_parts[1]
-
- data = comment_parts[0].strip()
-
- if data:
- fields = data.split()
- if len(fields) < 2:
- raise ValueError("Invalid hosts line")
-
- ip_address = fields[0]
- canonical_hostname = fields[1]
- aliases = fields[2:]
-
- return cls(ip_address, canonical_hostname, aliases, comment)
-
-
-class HostsFile(object):
- def __init__(self):
- self.data = []
- self.by_hostname = {}
-
- def set_host(self, host):
- if host.canonical_hostname is None:
- self.data.append(host)
- elif host.canonical_hostname in self.by_hostname:
- old_host = self.by_hostname[host.canonical_hostname]
- old_host.ip_address = host.ip_address
- old_host.aliases = host.aliases
- old_host.comment = host.comment
- else:
- self.data.append(host)
- self.by_hostname[host.canonical_hostname] = host
-
- @classmethod
- def from_file(cls, f):
- rv = cls()
- for line in f:
- host = HostsLine.from_string(line)
- if host is not None:
- rv.set_host(host)
- return rv
-
- def to_string(self):
- field_widths = [0, 0]
- for line in self.data:
- if line.ip_address is not None:
- field_widths[0] = max(field_widths[0], len(line.ip_address))
- field_widths[1] = max(field_widths[1], len(line.canonical_hostname))
-
- lines = []
-
- for host in self.data:
- line = ""
- if host.ip_address is not None:
- ip_string = host.ip_address.ljust(field_widths[0])
- hostname_str = host.canonical_hostname
- if host.aliases:
- hostname_str = "%s %s" % (hostname_str.ljust(field_widths[1]),
- " ".join(host.aliases))
- line = "%s %s" % (ip_string, hostname_str)
- if host.comment:
- if line:
- line += " "
- line += "#%s" % host.comment
- lines.append(line)
-
- lines.append("")
-
- return "\n".join(lines)
-
- def to_file(self, f):
- f.write(self.to_string().encode("utf8"))
diff --git a/tests/wpt/harness/wptrunner/manifestexpected.py b/tests/wpt/harness/wptrunner/manifestexpected.py
deleted file mode 100644
index c0e22a843fd..00000000000
--- a/tests/wpt/harness/wptrunner/manifestexpected.py
+++ /dev/null
@@ -1,256 +0,0 @@
-# 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 urlparse
-
-from wptmanifest.backends import static
-from wptmanifest.backends.static import ManifestItem
-
-import expected
-
-"""Manifest structure used to store expected results of a test.
-
-Each manifest file is represented by an ExpectedManifest that
-has one or more TestNode children, one per test in the manifest.
-Each TestNode has zero or more SubtestNode children, one for each
-known subtest of the test.
-"""
-
-def data_cls_getter(output_node, visited_node):
- # visited_node is intentionally unused
- if output_node is None:
- return ExpectedManifest
- if isinstance(output_node, ExpectedManifest):
- return TestNode
- if isinstance(output_node, TestNode):
- return SubtestNode
- raise ValueError
-
-
-def bool_prop(name, node):
- """Boolean property"""
- try:
- return node.get(name)
- except KeyError:
- return None
-
-
-def tags(node):
- """Set of tags that have been applied to the test"""
- try:
- value = node.get("tags")
- if isinstance(value, (str, unicode)):
- return {value}
- return set(value)
- except KeyError:
- return set()
-
-
-def prefs(node):
- def value(ini_value):
- if isinstance(ini_value, (str, unicode)):
- return tuple(ini_value.split(":", 1))
- else:
- return (ini_value, None)
-
- try:
- node_prefs = node.get("prefs")
- if type(node_prefs) in (str, unicode):
- prefs = {value(node_prefs)}
- rv = dict(value(item) for item in node_prefs)
- except KeyError:
- rv = {}
- return rv
-
-
-class ExpectedManifest(ManifestItem):
- def __init__(self, name, test_path, url_base):
- """Object representing all the tests in a particular manifest
-
- :param name: Name of the AST Node associated with this object.
- Should always be None since this should always be associated with
- the root node of the AST.
- :param test_path: Path of the test file associated with this manifest.
- :param url_base: Base url for serving the tests in this manifest
- """
- if name is not None:
- raise ValueError("ExpectedManifest should represent the root node")
- if test_path is None:
- raise ValueError("ExpectedManifest requires a test path")
- if url_base is None:
- raise ValueError("ExpectedManifest requires a base url")
- ManifestItem.__init__(self, name)
- self.child_map = {}
- self.test_path = test_path
- self.url_base = url_base
-
- def append(self, child):
- """Add a test to the manifest"""
- ManifestItem.append(self, child)
- self.child_map[child.id] = child
-
- def _remove_child(self, child):
- del self.child_map[child.id]
- ManifestItem.remove_child(self, child)
- assert len(self.child_map) == len(self.children)
-
- def get_test(self, test_id):
- """Get a test from the manifest by ID
-
- :param test_id: ID of the test to return."""
- return self.child_map.get(test_id)
-
- @property
- def url(self):
- return urlparse.urljoin(self.url_base,
- "/".join(self.test_path.split(os.path.sep)))
-
- @property
- def disabled(self):
- return bool_prop("disabled", self)
-
- @property
- def restart_after(self):
- return bool_prop("restart-after", self)
-
- @property
- def tags(self):
- return tags(self)
-
- @property
- def prefs(self):
- return prefs(self)
-
-
-class DirectoryManifest(ManifestItem):
- @property
- def disabled(self):
- return bool_prop("disabled", self)
-
- @property
- def restart_after(self):
- return bool_prop("restart-after", self)
-
- @property
- def tags(self):
- return tags(self)
-
- @property
- def prefs(self):
- return prefs(self)
-
-
-class TestNode(ManifestItem):
- def __init__(self, name):
- """Tree node associated with a particular test in a manifest
-
- :param name: name of the test"""
- assert name is not None
- ManifestItem.__init__(self, name)
- self.updated_expected = []
- self.new_expected = []
- self.subtests = {}
- self.default_status = None
- self._from_file = True
-
- @property
- def is_empty(self):
- required_keys = set(["type"])
- if set(self._data.keys()) != required_keys:
- return False
- return all(child.is_empty for child in self.children)
-
- @property
- def test_type(self):
- return self.get("type")
-
- @property
- def id(self):
- return urlparse.urljoin(self.parent.url, self.name)
-
- @property
- def disabled(self):
- return bool_prop("disabled", self)
-
- @property
- def restart_after(self):
- return bool_prop("restart-after", self)
-
- @property
- def tags(self):
- return tags(self)
-
- @property
- def prefs(self):
- return prefs(self)
-
- def append(self, node):
- """Add a subtest to the current test
-
- :param node: AST Node associated with the subtest"""
- child = ManifestItem.append(self, node)
- self.subtests[child.name] = child
-
- def get_subtest(self, name):
- """Get the SubtestNode corresponding to a particular subtest, by name
-
- :param name: Name of the node to return"""
- if name in self.subtests:
- return self.subtests[name]
- return None
-
-
-class SubtestNode(TestNode):
- def __init__(self, name):
- """Tree node associated with a particular subtest in a manifest
-
- :param name: name of the subtest"""
- TestNode.__init__(self, name)
-
- @property
- def is_empty(self):
- if self._data:
- return False
- return True
-
-
-def get_manifest(metadata_root, test_path, url_base, run_info):
- """Get the ExpectedManifest for a particular test path, or None if there is no
- metadata stored for that test path.
-
- :param metadata_root: Absolute path to the root of the metadata directory
- :param test_path: Path to the test(s) relative to the test root
- :param url_base: Base url for serving the tests in this manifest
- :param run_info: Dictionary of properties of the test run for which the expectation
- values should be computed.
- """
- manifest_path = expected.expected_path(metadata_root, test_path)
- try:
- with open(manifest_path) as f:
- return static.compile(f,
- run_info,
- data_cls_getter=data_cls_getter,
- test_path=test_path,
- url_base=url_base)
- except IOError:
- return None
-
-def get_dir_manifest(metadata_root, path, run_info):
- """Get the ExpectedManifest for a particular test path, or None if there is no
- metadata stored for that test path.
-
- :param metadata_root: Absolute path to the root of the metadata directory
- :param path: Path to the ini file relative to the metadata root
- :param run_info: Dictionary of properties of the test run for which the expectation
- values should be computed.
- """
- full_path = os.path.join(metadata_root, path)
- try:
- with open(full_path) as f:
- return static.compile(f,
- run_info,
- data_cls_getter=lambda x,y: DirectoryManifest)
- except IOError:
- return None
diff --git a/tests/wpt/harness/wptrunner/manifestinclude.py b/tests/wpt/harness/wptrunner/manifestinclude.py
deleted file mode 100644
index d9b4ee455a6..00000000000
--- a/tests/wpt/harness/wptrunner/manifestinclude.py
+++ /dev/null
@@ -1,144 +0,0 @@
-# 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/.
-
-"""Manifest structure used to store paths that should be included in a test run.
-
-The manifest is represented by a tree of IncludeManifest objects, the root
-representing the file and each subnode representing a subdirectory that should
-be included or excluded.
-"""
-import glob
-import os
-import urlparse
-
-from wptmanifest.node import DataNode
-from wptmanifest.backends import conditional
-from wptmanifest.backends.conditional import ManifestItem
-
-
-class IncludeManifest(ManifestItem):
- def __init__(self, node):
- """Node in a tree structure representing the paths
- that should be included or excluded from the test run.
-
- :param node: AST Node corresponding to this Node.
- """
- ManifestItem.__init__(self, node)
- self.child_map = {}
-
- @classmethod
- def create(cls):
- """Create an empty IncludeManifest tree"""
- node = DataNode(None)
- return cls(node)
-
- def append(self, child):
- ManifestItem.append(self, child)
- self.child_map[child.name] = child
- assert len(self.child_map) == len(self.children)
-
- def include(self, test):
- """Return a boolean indicating whether a particular test should be
- included in a test run, based on the IncludeManifest tree rooted on
- this object.
-
- :param test: The test object"""
- path_components = self._get_components(test.url)
- return self._include(test, path_components)
-
- def _include(self, test, path_components):
- if path_components:
- next_path_part = path_components.pop()
- if next_path_part in self.child_map:
- return self.child_map[next_path_part]._include(test, path_components)
-
- node = self
- while node:
- try:
- skip_value = self.get("skip", {"test_type": test.item_type}).lower()
- assert skip_value in ("true", "false")
- return skip_value != "true"
- except KeyError:
- if node.parent is not None:
- node = node.parent
- else:
- # Include by default
- return True
-
- def _get_components(self, url):
- rv = []
- url_parts = urlparse.urlsplit(url)
- variant = ""
- if url_parts.query:
- variant += "?" + url_parts.query
- if url_parts.fragment:
- variant += "#" + url_parts.fragment
- if variant:
- rv.append(variant)
- rv.extend([item for item in reversed(url_parts.path.split("/")) if item])
- return rv
-
- def _add_rule(self, test_manifests, url, direction):
- maybe_path = os.path.join(os.path.abspath(os.curdir), url)
- rest, last = os.path.split(maybe_path)
- variant = ""
- if "#" in last:
- last, fragment = last.rsplit("#", 1)
- variant += "#" + fragment
- if "?" in last:
- last, query = last.rsplit("?", 1)
- variant += "?" + query
-
- maybe_path = os.path.join(rest, last)
- paths = glob.glob(maybe_path)
-
- if paths:
- urls = []
- for path in paths:
- for manifest, data in test_manifests.iteritems():
- rel_path = os.path.relpath(path, data["tests_path"])
- if ".." not in rel_path.split(os.sep):
- urls.append(data["url_base"] + rel_path.replace(os.path.sep, "/") + variant)
- break
- else:
- urls = [url]
-
- assert direction in ("include", "exclude")
-
- for url in urls:
- components = self._get_components(url)
-
- node = self
- while components:
- component = components.pop()
- if component not in node.child_map:
- new_node = IncludeManifest(DataNode(component))
- node.append(new_node)
- new_node.set("skip", node.get("skip", {}))
-
- node = node.child_map[component]
-
- skip = False if direction == "include" else True
- node.set("skip", str(skip))
-
- def add_include(self, test_manifests, url_prefix):
- """Add a rule indicating that tests under a url path
- should be included in test runs
-
- :param url_prefix: The url prefix to include
- """
- return self._add_rule(test_manifests, url_prefix, "include")
-
- def add_exclude(self, test_manifests, url_prefix):
- """Add a rule indicating that tests under a url path
- should be excluded from test runs
-
- :param url_prefix: The url prefix to exclude
- """
- return self._add_rule(test_manifests, url_prefix, "exclude")
-
-
-def get_manifest(manifest_path):
- with open(manifest_path) as f:
- return conditional.compile(f, data_cls_getter=lambda x, y: IncludeManifest)
diff --git a/tests/wpt/harness/wptrunner/manifestupdate.py b/tests/wpt/harness/wptrunner/manifestupdate.py
deleted file mode 100644
index 6affbdbb59f..00000000000
--- a/tests/wpt/harness/wptrunner/manifestupdate.py
+++ /dev/null
@@ -1,453 +0,0 @@
-# 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 urlparse
-from collections import namedtuple, defaultdict
-
-from wptmanifest.node import (DataNode, ConditionalNode, BinaryExpressionNode,
- BinaryOperatorNode, VariableNode, StringNode, NumberNode,
- UnaryExpressionNode, UnaryOperatorNode, KeyValueNode)
-from wptmanifest.backends import conditional
-from wptmanifest.backends.conditional import ManifestItem
-
-import expected
-
-"""Manifest structure used to update the expected results of a test
-
-Each manifest file is represented by an ExpectedManifest that has one
-or more TestNode children, one per test in the manifest. Each
-TestNode has zero or more SubtestNode children, one for each known
-subtest of the test.
-
-In these representations, conditionals expressions in the manifest are
-not evaluated upfront but stored as python functions to be evaluated
-at runtime.
-
-When a result for a test is to be updated set_result on the
-[Sub]TestNode is called to store the new result, alongside the
-existing conditional that result's run info matched, if any. Once all
-new results are known, coalesce_expected is called to compute the new
-set of results and conditionals. The AST of the underlying parsed manifest
-is updated with the changes, and the result is serialised to a file.
-"""
-
-Result = namedtuple("Result", ["run_info", "status"])
-
-
-def data_cls_getter(output_node, visited_node):
- # visited_node is intentionally unused
- if output_node is None:
- return ExpectedManifest
- elif isinstance(output_node, ExpectedManifest):
- return TestNode
- elif isinstance(output_node, TestNode):
- return SubtestNode
- else:
- raise ValueError
-
-
-class ExpectedManifest(ManifestItem):
- def __init__(self, node, test_path=None, url_base=None, property_order=None,
- boolean_properties=None):
- """Object representing all the tests in a particular manifest
-
- :param node: AST Node associated with this object. If this is None,
- a new AST is created to associate with this manifest.
- :param test_path: Path of the test file associated with this manifest.
- :param url_base: Base url for serving the tests in this manifest.
- :param property_order: List of properties to use in expectation metadata
- from most to least significant.
- :param boolean_properties: Set of properties in property_order that should
- be treated as boolean.
- """
- if node is None:
- node = DataNode(None)
- ManifestItem.__init__(self, node)
- self.child_map = {}
- self.test_path = test_path
- self.url_base = url_base
- assert self.url_base is not None
- self.modified = False
- self.boolean_properties = boolean_properties
- self.property_order = property_order
-
- def append(self, child):
- ManifestItem.append(self, child)
- if child.id in self.child_map:
- print "Warning: Duplicate heading %s" % child.id
- self.child_map[child.id] = child
-
- def _remove_child(self, child):
- del self.child_map[child.id]
- ManifestItem._remove_child(self, child)
-
- def get_test(self, test_id):
- """Return a TestNode by test id, or None if no test matches
-
- :param test_id: The id of the test to look up"""
-
- return self.child_map[test_id]
-
- def has_test(self, test_id):
- """Boolean indicating whether the current test has a known child test
- with id test id
-
- :param test_id: The id of the test to look up"""
-
- return test_id in self.child_map
-
- @property
- def url(self):
- return urlparse.urljoin(self.url_base,
- "/".join(self.test_path.split(os.path.sep)))
-
-class TestNode(ManifestItem):
- def __init__(self, node):
- """Tree node associated with a particular test in a manifest
-
- :param node: AST node associated with the test"""
-
- ManifestItem.__init__(self, node)
- self.updated_expected = []
- self.new_expected = []
- self.subtests = {}
- self.default_status = None
- self._from_file = True
-
- @classmethod
- def create(cls, test_type, test_id):
- """Create a TestNode corresponding to a given test
-
- :param test_type: The type of the test
- :param test_id: The id of the test"""
-
- url = test_id
- name = url.split("/")[-1]
- node = DataNode(name)
- self = cls(node)
-
- self.set("type", test_type)
- self._from_file = False
- return self
-
- @property
- def is_empty(self):
- required_keys = set(["type"])
- if set(self._data.keys()) != required_keys:
- return False
- return all(child.is_empty for child in self.children)
-
- @property
- def test_type(self):
- """The type of the test represented by this TestNode"""
-
- return self.get("type", None)
-
- @property
- def id(self):
- """The id of the test represented by this TestNode"""
- return urlparse.urljoin(self.parent.url, self.name)
-
- def disabled(self, run_info):
- """Boolean indicating whether this test is disabled when run in an
- environment with the given run_info
-
- :param run_info: Dictionary of run_info parameters"""
-
- return self.get("disabled", run_info) is not None
-
- def set_result(self, run_info, result):
- """Set the result of the test in a particular run
-
- :param run_info: Dictionary of run_info parameters corresponding
- to this run
- :param result: Status of the test in this run"""
-
- if self.default_status is not None:
- assert self.default_status == result.default_expected
- else:
- self.default_status = result.default_expected
-
- # Add this result to the list of results satisfying
- # any condition in the list of updated results it matches
- for (cond, values) in self.updated_expected:
- if cond(run_info):
- values.append(Result(run_info, result.status))
- if result.status != cond.value:
- self.root.modified = True
- break
- else:
- # We didn't find a previous value for this
- self.new_expected.append(Result(run_info, result.status))
- self.root.modified = True
-
- def coalesce_expected(self):
- """Update the underlying manifest AST for this test based on all the
- added results.
-
- This will update existing conditionals if they got the same result in
- all matching runs in the updated results, will delete existing conditionals
- that get more than one different result in the updated run, and add new
- conditionals for anything that doesn't match an existing conditional.
-
- Conditionals not matched by any added result are not changed."""
-
- final_conditionals = []
-
- try:
- unconditional_status = self.get("expected")
- except KeyError:
- unconditional_status = self.default_status
-
- for conditional_value, results in self.updated_expected:
- if not results:
- # The conditional didn't match anything in these runs so leave it alone
- final_conditionals.append(conditional_value)
- elif all(results[0].status == result.status for result in results):
- # All the new values for this conditional matched, so update the node
- result = results[0]
- if (result.status == unconditional_status and
- conditional_value.condition_node is not None):
- self.remove_value("expected", conditional_value)
- else:
- conditional_value.value = result.status
- final_conditionals.append(conditional_value)
- elif conditional_value.condition_node is not None:
- # Blow away the existing condition and rebuild from scratch
- # This isn't sure to work if we have a conditional later that matches
- # these values too, but we can hope, verify that we get the results
- # we expect, and if not let a human sort it out
- self.remove_value("expected", conditional_value)
- self.new_expected.extend(results)
- elif conditional_value.condition_node is None:
- self.new_expected.extend(result for result in results
- if result.status != unconditional_status)
-
- # It is an invariant that nothing in new_expected matches an existing
- # condition except for the default condition
-
- if self.new_expected:
- if all(self.new_expected[0].status == result.status
- for result in self.new_expected) and not self.updated_expected:
- status = self.new_expected[0].status
- if status != self.default_status:
- self.set("expected", status, condition=None)
- final_conditionals.append(self._data["expected"][-1])
- else:
- for conditional_node, status in group_conditionals(
- self.new_expected,
- property_order=self.root.property_order,
- boolean_properties=self.root.boolean_properties):
- if status != unconditional_status:
- self.set("expected", status, condition=conditional_node.children[0])
- final_conditionals.append(self._data["expected"][-1])
-
- if ("expected" in self._data and
- len(self._data["expected"]) > 0 and
- self._data["expected"][-1].condition_node is None and
- self._data["expected"][-1].value == self.default_status):
-
- self.remove_value("expected", self._data["expected"][-1])
-
- if ("expected" in self._data and
- len(self._data["expected"]) == 0):
- for child in self.node.children:
- if (isinstance(child, KeyValueNode) and
- child.data == "expected"):
- child.remove()
- break
-
- def _add_key_value(self, node, values):
- ManifestItem._add_key_value(self, node, values)
- if node.data == "expected":
- self.updated_expected = []
- for value in values:
- self.updated_expected.append((value, []))
-
- def clear_expected(self):
- """Clear all the expected data for this test and all of its subtests"""
-
- self.updated_expected = []
- if "expected" in self._data:
- for child in self.node.children:
- if (isinstance(child, KeyValueNode) and
- child.data == "expected"):
- child.remove()
- del self._data["expected"]
- break
-
- for subtest in self.subtests.itervalues():
- subtest.clear_expected()
-
- def append(self, node):
- child = ManifestItem.append(self, node)
- self.subtests[child.name] = child
-
- def get_subtest(self, name):
- """Return a SubtestNode corresponding to a particular subtest of
- the current test, creating a new one if no subtest with that name
- already exists.
-
- :param name: Name of the subtest"""
-
- if name in self.subtests:
- return self.subtests[name]
- else:
- subtest = SubtestNode.create(name)
- self.append(subtest)
- return subtest
-
-
-class SubtestNode(TestNode):
- def __init__(self, node):
- assert isinstance(node, DataNode)
- TestNode.__init__(self, node)
-
- @classmethod
- def create(cls, name):
- node = DataNode(name)
- self = cls(node)
- return self
-
- @property
- def is_empty(self):
- if self._data:
- return False
- return True
-
-
-def group_conditionals(values, property_order=None, boolean_properties=None):
- """Given a list of Result objects, return a list of
- (conditional_node, status) pairs representing the conditional
- expressions that are required to match each status
-
- :param values: List of Results
- :param property_order: List of properties to use in expectation metadata
- from most to least significant.
- :param boolean_properties: Set of properties in property_order that should
- be treated as boolean."""
-
- by_property = defaultdict(set)
- for run_info, status in values:
- for prop_name, prop_value in run_info.iteritems():
- by_property[(prop_name, prop_value)].add(status)
-
- if property_order is None:
- property_order = ["debug", "os", "version", "processor", "bits"]
-
- if boolean_properties is None:
- boolean_properties = set(["debug"])
- else:
- boolean_properties = set(boolean_properties)
-
- # If we have more than one value, remove any properties that are common
- # for all the values
- if len(values) > 1:
- for key, statuses in by_property.copy().iteritems():
- if len(statuses) == len(values):
- del by_property[key]
-
- properties = set(item[0] for item in by_property.iterkeys())
- include_props = []
-
- for prop in property_order:
- if prop in properties:
- include_props.append(prop)
-
- conditions = {}
-
- for run_info, status in values:
- prop_set = tuple((prop, run_info[prop]) for prop in include_props)
- if prop_set in conditions:
- continue
-
- expr = make_expr(prop_set, status, boolean_properties=boolean_properties)
- conditions[prop_set] = (expr, status)
-
- return conditions.values()
-
-
-def make_expr(prop_set, status, boolean_properties=None):
- """Create an AST that returns the value ``status`` given all the
- properties in prop_set match.
-
- :param prop_set: tuple of (property name, value) pairs for each
- property in this expression and the value it must match
- :param status: Status on RHS when all the given properties match
- :param boolean_properties: Set of properties in property_order that should
- be treated as boolean.
- """
- root = ConditionalNode()
-
- assert len(prop_set) > 0
-
- expressions = []
- for prop, value in prop_set:
- number_types = (int, float, long)
- value_cls = (NumberNode
- if type(value) in number_types
- else StringNode)
- if prop not in boolean_properties:
- expressions.append(
- BinaryExpressionNode(
- BinaryOperatorNode("=="),
- VariableNode(prop),
- value_cls(unicode(value))
- ))
- else:
- if value:
- expressions.append(VariableNode(prop))
- else:
- expressions.append(
- UnaryExpressionNode(
- UnaryOperatorNode("not"),
- VariableNode(prop)
- ))
- if len(expressions) > 1:
- prev = expressions[-1]
- for curr in reversed(expressions[:-1]):
- node = BinaryExpressionNode(
- BinaryOperatorNode("and"),
- curr,
- prev)
- prev = node
- else:
- node = expressions[0]
-
- root.append(node)
- root.append(StringNode(status))
-
- return root
-
-
-def get_manifest(metadata_root, test_path, url_base, property_order=None,
- boolean_properties=None):
- """Get the ExpectedManifest for a particular test path, or None if there is no
- metadata stored for that test path.
-
- :param metadata_root: Absolute path to the root of the metadata directory
- :param test_path: Path to the test(s) relative to the test root
- :param url_base: Base url for serving the tests in this manifest
- :param property_order: List of properties to use in expectation metadata
- from most to least significant.
- :param boolean_properties: Set of properties in property_order that should
- be treated as boolean."""
- manifest_path = expected.expected_path(metadata_root, test_path)
- try:
- with open(manifest_path) as f:
- return compile(f, test_path, url_base, property_order=property_order,
- boolean_properties=boolean_properties)
- except IOError:
- return None
-
-
-def compile(manifest_file, test_path, url_base, property_order=None,
- boolean_properties=None):
- return conditional.compile(manifest_file,
- data_cls_getter=data_cls_getter,
- test_path=test_path,
- url_base=url_base,
- property_order=property_order,
- boolean_properties=boolean_properties)
diff --git a/tests/wpt/harness/wptrunner/metadata.py b/tests/wpt/harness/wptrunner/metadata.py
deleted file mode 100644
index e59419192c6..00000000000
--- a/tests/wpt/harness/wptrunner/metadata.py
+++ /dev/null
@@ -1,353 +0,0 @@
-# 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 shutil
-import sys
-import tempfile
-import types
-import uuid
-from collections import defaultdict
-
-from mozlog import reader
-from mozlog import structuredlog
-
-import expected
-import manifestupdate
-import testloader
-import wptmanifest
-import wpttest
-from vcs import git
-manifest = None # Module that will be imported relative to test_root
-manifestitem = None
-
-logger = structuredlog.StructuredLogger("web-platform-tests")
-
-
-def load_test_manifests(serve_root, test_paths):
- do_delayed_imports(serve_root)
- manifest_loader = testloader.ManifestLoader(test_paths, False)
- return manifest_loader.load()
-
-
-def update_expected(test_paths, serve_root, log_file_names,
- rev_old=None, rev_new="HEAD", ignore_existing=False,
- sync_root=None, property_order=None, boolean_properties=None):
- """Update the metadata files for web-platform-tests based on
- the results obtained in a previous run"""
-
- manifests = load_test_manifests(serve_root, test_paths)
-
- change_data = {}
-
- if sync_root is not None:
- if rev_old is not None:
- rev_old = git("rev-parse", rev_old, repo=sync_root).strip()
- rev_new = git("rev-parse", rev_new, repo=sync_root).strip()
-
- if rev_old is not None:
- change_data = load_change_data(rev_old, rev_new, repo=sync_root)
-
-
- expected_map_by_manifest = update_from_logs(manifests,
- *log_file_names,
- ignore_existing=ignore_existing,
- property_order=property_order,
- boolean_properties=boolean_properties)
-
- for test_manifest, expected_map in expected_map_by_manifest.iteritems():
- url_base = manifests[test_manifest]["url_base"]
- metadata_path = test_paths[url_base]["metadata_path"]
- write_changes(metadata_path, expected_map)
-
- results_changed = [item.test_path for item in expected_map.itervalues() if item.modified]
-
- return unexpected_changes(manifests, change_data, results_changed)
-
-
-def do_delayed_imports(serve_root):
- global manifest, manifestitem
- from manifest import manifest, item as manifestitem
-
-
-def files_in_repo(repo_root):
- return git("ls-tree", "-r", "--name-only", "HEAD").split("\n")
-
-
-def rev_range(rev_old, rev_new, symmetric=False):
- joiner = ".." if not symmetric else "..."
- return "".join([rev_old, joiner, rev_new])
-
-
-def paths_changed(rev_old, rev_new, repo):
- data = git("diff", "--name-status", rev_range(rev_old, rev_new), repo=repo)
- lines = [tuple(item.strip() for item in line.strip().split("\t", 1))
- for line in data.split("\n") if line.strip()]
- output = set(lines)
- return output
-
-
-def load_change_data(rev_old, rev_new, repo):
- changes = paths_changed(rev_old, rev_new, repo)
- rv = {}
- status_keys = {"M": "modified",
- "A": "new",
- "D": "deleted"}
- # TODO: deal with renames
- for item in changes:
- rv[item[1]] = status_keys[item[0]]
- return rv
-
-
-def unexpected_changes(manifests, change_data, files_changed):
- files_changed = set(files_changed)
-
- root_manifest = None
- for manifest, paths in manifests.iteritems():
- if paths["url_base"] == "/":
- root_manifest = manifest
- break
- else:
- return []
-
- return [fn for _, fn, _ in root_manifest if fn in files_changed and change_data.get(fn) != "M"]
-
-# For each testrun
-# Load all files and scan for the suite_start entry
-# Build a hash of filename: properties
-# For each different set of properties, gather all chunks
-# For each chunk in the set of chunks, go through all tests
-# for each test, make a map of {conditionals: [(platform, new_value)]}
-# Repeat for each platform
-# For each test in the list of tests:
-# for each conditional:
-# If all the new values match (or there aren't any) retain that conditional
-# If any new values mismatch mark the test as needing human attention
-# Check if all the RHS values are the same; if so collapse the conditionals
-
-
-def update_from_logs(manifests, *log_filenames, **kwargs):
- ignore_existing = kwargs.get("ignore_existing", False)
- property_order = kwargs.get("property_order")
- boolean_properties = kwargs.get("boolean_properties")
-
- expected_map = {}
- id_test_map = {}
-
- for test_manifest, paths in manifests.iteritems():
- expected_map_manifest, id_path_map_manifest = create_test_tree(
- paths["metadata_path"],
- test_manifest,
- property_order=property_order,
- boolean_properties=boolean_properties)
- expected_map[test_manifest] = expected_map_manifest
- id_test_map.update(id_path_map_manifest)
-
- updater = ExpectedUpdater(manifests, expected_map, id_test_map,
- ignore_existing=ignore_existing)
- for log_filename in log_filenames:
- with open(log_filename) as f:
- updater.update_from_log(f)
-
- for manifest_expected in expected_map.itervalues():
- for tree in manifest_expected.itervalues():
- for test in tree.iterchildren():
- for subtest in test.iterchildren():
- subtest.coalesce_expected()
- test.coalesce_expected()
-
- return expected_map
-
-def directory_manifests(metadata_path):
- rv = []
- for dirpath, dirname, filenames in os.walk(metadata_path):
- if "__dir__.ini" in filenames:
- rel_path = os.path.relpath(dirpath, metadata_path)
- rv.append(os.path.join(rel_path, "__dir__.ini"))
- return rv
-
-def write_changes(metadata_path, expected_map):
- # First write the new manifest files to a temporary directory
- temp_path = tempfile.mkdtemp(dir=os.path.split(metadata_path)[0])
- write_new_expected(temp_path, expected_map)
-
- # Keep all __dir__.ini files (these are not in expected_map because they
- # aren't associated with a specific test)
- keep_files = directory_manifests(metadata_path)
-
- # Copy all files in the root to the temporary location since
- # these cannot be ini files
- keep_files.extend(item for item in os.listdir(metadata_path) if
- not os.path.isdir(os.path.join(metadata_path, item)))
-
- for item in keep_files:
- dest_dir = os.path.dirname(os.path.join(temp_path, item))
- if not os.path.exists(dest_dir):
- os.makedirs(dest_dir)
- shutil.copyfile(os.path.join(metadata_path, item),
- os.path.join(temp_path, item))
-
- # Then move the old manifest files to a new location
- temp_path_2 = metadata_path + str(uuid.uuid4())
- os.rename(metadata_path, temp_path_2)
- # Move the new files to the destination location and remove the old files
- os.rename(temp_path, metadata_path)
- shutil.rmtree(temp_path_2)
-
-
-def write_new_expected(metadata_path, expected_map):
- # Serialize the data back to a file
- for tree in expected_map.itervalues():
- if not tree.is_empty:
- manifest_str = wptmanifest.serialize(tree.node, skip_empty_data=True)
- assert manifest_str != ""
- path = expected.expected_path(metadata_path, tree.test_path)
- dir = os.path.split(path)[0]
- if not os.path.exists(dir):
- os.makedirs(dir)
- with open(path, "w") as f:
- f.write(manifest_str)
-
-
-class ExpectedUpdater(object):
- def __init__(self, test_manifests, expected_tree, id_path_map, ignore_existing=False):
- self.test_manifests = test_manifests
- self.expected_tree = expected_tree
- self.id_path_map = id_path_map
- self.ignore_existing = ignore_existing
- self.run_info = None
- self.action_map = {"suite_start": self.suite_start,
- "test_start": self.test_start,
- "test_status": self.test_status,
- "test_end": self.test_end}
- self.tests_visited = {}
-
- self.test_cache = {}
-
- def update_from_log(self, log_file):
- self.run_info = None
- log_reader = reader.read(log_file)
- reader.each_log(log_reader, self.action_map)
-
- def suite_start(self, data):
- self.run_info = data["run_info"]
-
- def test_id(self, id):
- if type(id) in types.StringTypes:
- return id
- else:
- return tuple(id)
-
- def test_start(self, data):
- test_id = self.test_id(data["test"])
- try:
- test_manifest, test = self.id_path_map[test_id]
- expected_node = self.expected_tree[test_manifest][test].get_test(test_id)
- except KeyError:
- print "Test not found %s, skipping" % test_id
- return
- self.test_cache[test_id] = expected_node
-
- if test_id not in self.tests_visited:
- if self.ignore_existing:
- expected_node.clear_expected()
- self.tests_visited[test_id] = set()
-
- def test_status(self, data):
- test_id = self.test_id(data["test"])
- test = self.test_cache.get(test_id)
- if test is None:
- return
- test_cls = wpttest.manifest_test_cls[test.test_type]
-
- subtest = test.get_subtest(data["subtest"])
-
- self.tests_visited[test.id].add(data["subtest"])
-
- result = test_cls.subtest_result_cls(
- data["subtest"],
- data["status"],
- data.get("message"))
-
- subtest.set_result(self.run_info, result)
-
- def test_end(self, data):
- test_id = self.test_id(data["test"])
- test = self.test_cache.get(test_id)
- if test is None:
- return
- test_cls = wpttest.manifest_test_cls[test.test_type]
-
- if data["status"] == "SKIP":
- return
-
- result = test_cls.result_cls(
- data["status"],
- data.get("message"))
-
- test.set_result(self.run_info, result)
- del self.test_cache[test_id]
-
-
-def create_test_tree(metadata_path, test_manifest, property_order=None,
- boolean_properties=None):
- expected_map = {}
- id_test_map = {}
- exclude_types = frozenset(["stub", "helper", "manual", "support", "conformancechecker"])
- all_types = [item.item_type for item in manifestitem.__dict__.itervalues()
- if type(item) == type and
- issubclass(item, manifestitem.ManifestItem) and
- item.item_type is not None]
- include_types = set(all_types) - exclude_types
- for _, test_path, tests in test_manifest.itertypes(*include_types):
- expected_data = load_expected(test_manifest, metadata_path, test_path, tests,
- property_order=property_order,
- boolean_properties=boolean_properties)
- if expected_data is None:
- expected_data = create_expected(test_manifest,
- test_path,
- tests,
- property_order=property_order,
- boolean_properties=boolean_properties)
-
- for test in tests:
- id_test_map[test.id] = (test_manifest, test)
- expected_map[test] = expected_data
-
- return expected_map, id_test_map
-
-
-def create_expected(test_manifest, test_path, tests, property_order=None,
- boolean_properties=None):
- expected = manifestupdate.ExpectedManifest(None, test_path, test_manifest.url_base,
- property_order=property_order,
- boolean_properties=boolean_properties)
- for test in tests:
- expected.append(manifestupdate.TestNode.create(test.item_type, test.id))
- return expected
-
-
-def load_expected(test_manifest, metadata_path, test_path, tests, property_order=None,
- boolean_properties=None):
- expected_manifest = manifestupdate.get_manifest(metadata_path,
- test_path,
- test_manifest.url_base,
- property_order=property_order,
- boolean_properties=boolean_properties)
- if expected_manifest is None:
- return
-
- tests_by_id = {item.id: item for item in tests}
-
- # Remove expected data for tests that no longer exist
- for test in expected_manifest.iterchildren():
- if not test.id in tests_by_id:
- test.remove()
-
- # Add tests that don't have expected data
- for test in tests:
- if not expected_manifest.has_test(test.id):
- expected_manifest.append(manifestupdate.TestNode.create(test.item_type, test.id))
-
- return expected_manifest
diff --git a/tests/wpt/harness/wptrunner/products.py b/tests/wpt/harness/wptrunner/products.py
deleted file mode 100644
index 25fc7a49d6a..00000000000
--- a/tests/wpt/harness/wptrunner/products.py
+++ /dev/null
@@ -1,72 +0,0 @@
-# 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 importlib
-import imp
-
-from .browsers import product_list
-
-def products_enabled(config):
- names = config.get("products", {}).keys()
- if not names:
- return product_list
- else:
- return names
-
-def product_module(config, product):
- here = os.path.join(os.path.split(__file__)[0])
- product_dir = os.path.join(here, "browsers")
-
- if product not in products_enabled(config):
- raise ValueError("Unknown product %s" % product)
-
- path = config.get("products", {}).get(product, None)
- if path:
- module = imp.load_source('wptrunner.browsers.' + product, path)
- else:
- module = importlib.import_module("wptrunner.browsers." + product)
-
- if not hasattr(module, "__wptrunner__"):
- raise ValueError("Product module does not define __wptrunner__ variable")
-
- return module
-
-
-def load_product(config, product):
- module = product_module(config, product)
- data = module.__wptrunner__
-
- check_args = getattr(module, data["check_args"])
- browser_cls = getattr(module, data["browser"])
- browser_kwargs = getattr(module, data["browser_kwargs"])
- executor_kwargs = getattr(module, data["executor_kwargs"])
- env_options = getattr(module, data["env_options"])()
- run_info_extras = (getattr(module, data["run_info_extras"])
- if "run_info_extras" in data else lambda **kwargs:{})
-
- executor_classes = {}
- for test_type, cls_name in data["executor"].iteritems():
- cls = getattr(module, cls_name)
- executor_classes[test_type] = cls
-
- return (check_args,
- browser_cls, browser_kwargs,
- executor_classes, executor_kwargs,
- env_options, run_info_extras)
-
-
-def load_product_update(config, product):
- """Return tuple of (property_order, boolean_properties) indicating the
- run_info properties to use when constructing the expectation data for
- this product. None for either key indicates that the default keys
- appropriate for distinguishing based on platform will be used."""
-
- module = product_module(config, product)
- data = module.__wptrunner__
-
- update_properties = (getattr(module, data["update_properties"])()
- if "update_properties" in data else (None, None))
-
- return update_properties
diff --git a/tests/wpt/harness/wptrunner/reduce.py b/tests/wpt/harness/wptrunner/reduce.py
deleted file mode 100644
index c4487b9d356..00000000000
--- a/tests/wpt/harness/wptrunner/reduce.py
+++ /dev/null
@@ -1,197 +0,0 @@
-# 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 sys
-import tempfile
-from cStringIO import StringIO
-from collections import defaultdict
-
-import wptrunner
-import wpttest
-
-from mozlog import commandline, reader
-
-logger = None
-
-
-def setup_logging(args, defaults):
- global logger
- logger = commandline.setup_logging("web-platform-tests-unstable", args, defaults)
- wptrunner.setup_stdlib_logger()
-
- for name in args.keys():
- if name.startswith("log_"):
- args.pop(name)
-
- return logger
-
-
-def group(items, size):
- rv = []
- i = 0
- while i < len(items):
- rv.append(items[i:i + size])
- i += size
-
- return rv
-
-
-def next_power_of_two(num):
- rv = 1
- while rv < num:
- rv = rv << 1
- return rv
-
-
-class Reducer(object):
- def __init__(self, target, **kwargs):
- self.target = target
-
- self.test_type = kwargs["test_types"][0]
- run_info = wpttest.get_run_info(kwargs["metadata_root"],
- kwargs["product"],
- debug=False)
- test_filter = wptrunner.TestFilter(include=kwargs["include"])
- self.test_loader = wptrunner.TestLoader(kwargs["tests_root"],
- kwargs["metadata_root"],
- [self.test_type],
- run_info,
- manifest_filer=test_filter)
- if kwargs["repeat"] == 1:
- logger.critical("Need to specify --repeat with more than one repetition")
- sys.exit(1)
- self.kwargs = kwargs
-
- def run(self):
- all_tests = self.get_initial_tests()
-
- tests = all_tests[:-1]
- target_test = [all_tests[-1]]
-
- if self.unstable(target_test):
- return target_test
-
- if not self.unstable(all_tests):
- return []
-
- chunk_size = next_power_of_two(int(len(tests) / 2))
- logger.debug("Using chunk size %i" % chunk_size)
-
- while chunk_size >= 1:
- logger.debug("%i tests remain" % len(tests))
- chunks = group(tests, chunk_size)
- chunk_results = [None] * len(chunks)
-
- for i, chunk in enumerate(chunks):
- logger.debug("Running chunk %i/%i of size %i" % (i + 1, len(chunks), chunk_size))
- trial_tests = []
- chunk_str = ""
- for j, inc_chunk in enumerate(chunks):
- if i != j and chunk_results[j] in (None, False):
- chunk_str += "+"
- trial_tests.extend(inc_chunk)
- else:
- chunk_str += "-"
- logger.debug("Using chunks %s" % chunk_str)
- trial_tests.extend(target_test)
-
- chunk_results[i] = self.unstable(trial_tests)
-
- # if i == len(chunks) - 2 and all(item is False for item in chunk_results[:-1]):
- # Dangerous? optimisation that if you got stability for 0..N-1 chunks
- # it must be unstable with the Nth chunk
- # chunk_results[i+1] = True
- # continue
-
- new_tests = []
- keep_str = ""
- for result, chunk in zip(chunk_results, chunks):
- if not result:
- keep_str += "+"
- new_tests.extend(chunk)
- else:
- keep_str += "-"
-
- logger.debug("Keeping chunks %s" % keep_str)
-
- tests = new_tests
-
- chunk_size = int(chunk_size / 2)
-
- return tests + target_test
-
- def unstable(self, tests):
- logger.debug("Running with %i tests" % len(tests))
-
- self.test_loader.tests = {self.test_type: tests}
-
- stdout, stderr = sys.stdout, sys.stderr
- sys.stdout = StringIO()
- sys.stderr = StringIO()
-
- with tempfile.NamedTemporaryFile() as f:
- args = self.kwargs.copy()
- args["log_raw"] = [f]
- args["capture_stdio"] = False
- wptrunner.setup_logging(args, {})
- wptrunner.run_tests(test_loader=self.test_loader, **args)
- wptrunner.logger.remove_handler(wptrunner.logger.handlers[0])
- is_unstable = self.log_is_unstable(f)
-
- sys.stdout, sys.stderr = stdout, stderr
-
- logger.debug("Result was unstable with chunk removed"
- if is_unstable else "stable")
-
- return is_unstable
-
- def log_is_unstable(self, log_f):
- log_f.seek(0)
-
- statuses = defaultdict(set)
-
- def handle_status(item):
- if item["test"] == self.target:
- statuses[item["subtest"]].add(item["status"])
-
- def handle_end(item):
- if item["test"] == self.target:
- statuses[None].add(item["status"])
-
- reader.each_log(reader.read(log_f),
- {"test_status": handle_status,
- "test_end": handle_end})
-
- logger.debug(str(statuses))
-
- if not statuses:
- logger.error("Didn't get any useful output from wptrunner")
- log_f.seek(0)
- for item in reader.read(log_f):
- logger.debug(item)
- return None
-
- return any(len(item) > 1 for item in statuses.itervalues())
-
- def get_initial_tests(self):
- # Need to pass in arguments
-
- all_tests = self.test_loader.tests[self.test_type]
- tests = []
- for item in all_tests:
- tests.append(item)
- if item.url == self.target:
- break
-
- logger.debug("Starting with tests: %s" % ("\n".join(item.id for item in tests)))
-
- return tests
-
-
-def do_reduce(**kwargs):
- target = kwargs.pop("target")
- reducer = Reducer(target, **kwargs)
-
- unstable_set = reducer.run()
- return unstable_set
diff --git a/tests/wpt/harness/wptrunner/testharness_runner.html b/tests/wpt/harness/wptrunner/testharness_runner.html
deleted file mode 100644
index 1cc80a270e2..00000000000
--- a/tests/wpt/harness/wptrunner/testharness_runner.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<!doctype html>
-<title></title>
-<script>
-var timeout_multiplier = 1;
-var win = null;
-</script>
diff --git a/tests/wpt/harness/wptrunner/testharnessreport-servo.js b/tests/wpt/harness/wptrunner/testharnessreport-servo.js
deleted file mode 100644
index f5fda2c6614..00000000000
--- a/tests/wpt/harness/wptrunner/testharnessreport-servo.js
+++ /dev/null
@@ -1,21 +0,0 @@
-/* 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/. */
-
-var props = {output:%(output)d};
-var start_loc = document.createElement('a');
-start_loc.href = location.href;
-setup(props);
-
-add_completion_callback(function (tests, harness_status) {
- var id = start_loc.pathname + start_loc.search + start_loc.hash;
- console.log("ALERT: RESULT: " + JSON.stringify([
- id,
- harness_status.status,
- harness_status.message,
- harness_status.stack,
- tests.map(function(t) {
- return [t.name, t.status, t.message, t.stack]
- }),
- ]));
-});
diff --git a/tests/wpt/harness/wptrunner/testharnessreport-servodriver.js b/tests/wpt/harness/wptrunner/testharnessreport-servodriver.js
deleted file mode 100644
index 9008944ef5a..00000000000
--- a/tests/wpt/harness/wptrunner/testharnessreport-servodriver.js
+++ /dev/null
@@ -1,27 +0,0 @@
-/* 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/. */
-
-setup({output:%(output)d});
-
-add_completion_callback(function() {
- add_completion_callback(function (tests, status) {
- var subtest_results = tests.map(function(x) {
- return [x.name, x.status, x.message, x.stack]
- });
- var id = location.pathname + location.search + location.hash;
- var results = JSON.stringify([id,
- status.status,
- status.message,
- status.stack,
- subtest_results]);
- (function done() {
- if (window.__wd_results_callback__) {
- clearTimeout(__wd_results_timer__);
- __wd_results_callback__(results)
- } else {
- setTimeout(done, 20);
- }
- })()
- })
-});
diff --git a/tests/wpt/harness/wptrunner/testharnessreport.js b/tests/wpt/harness/wptrunner/testharnessreport.js
deleted file mode 100644
index 79559773f72..00000000000
--- a/tests/wpt/harness/wptrunner/testharnessreport.js
+++ /dev/null
@@ -1,17 +0,0 @@
-/* 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/. */
-
-var props = {output:%(output)d,
- explicit_timeout: true,
- message_events: ["completion"]};
-
-if (window.opener && "timeout_multiplier" in window.opener) {
- props["timeout_multiplier"] = window.opener.timeout_multiplier;
-}
-
-if (window.opener && window.opener.explicit_timeout) {
- props["explicit_timeout"] = window.opener.explicit_timeout;
-}
-
-setup(props);
diff --git a/tests/wpt/harness/wptrunner/testloader.py b/tests/wpt/harness/wptrunner/testloader.py
deleted file mode 100644
index 73cf2cabaca..00000000000
--- a/tests/wpt/harness/wptrunner/testloader.py
+++ /dev/null
@@ -1,621 +0,0 @@
-import json
-import os
-import sys
-import urlparse
-from abc import ABCMeta, abstractmethod
-from Queue import Empty
-from collections import defaultdict, OrderedDict, deque
-from multiprocessing import Queue
-
-import manifestinclude
-import manifestexpected
-import wpttest
-from mozlog import structured
-
-manifest = None
-manifest_update = None
-
-def do_delayed_imports():
- # This relies on an already loaded module having set the sys.path correctly :(
- global manifest, manifest_update
- from manifest import manifest
- from manifest import update as manifest_update
-
-class TestChunker(object):
- def __init__(self, total_chunks, chunk_number):
- self.total_chunks = total_chunks
- self.chunk_number = chunk_number
- assert self.chunk_number <= self.total_chunks
- self.logger = structured.get_default_logger()
- assert self.logger
-
- def __call__(self, manifest):
- raise NotImplementedError
-
-
-class Unchunked(TestChunker):
- def __init__(self, *args, **kwargs):
- TestChunker.__init__(self, *args, **kwargs)
- assert self.total_chunks == 1
-
- def __call__(self, manifest):
- for item in manifest:
- yield item
-
-
-class HashChunker(TestChunker):
- def __call__(self):
- chunk_index = self.chunk_number - 1
- for test_type, test_path, tests in manifest:
- if hash(test_path) % self.total_chunks == chunk_index:
- yield test_type, test_path, tests
-
-class EqualTimeChunker(TestChunker):
- def _group_by_directory(self, manifest_items):
- """Split the list of manifest items into a ordered dict that groups tests in
- so that anything in the same subdirectory beyond a depth of 3 is in the same
- group. So all tests in a/b/c, a/b/c/d and a/b/c/e will be grouped together
- and separate to tests in a/b/f
-
- Returns: tuple (ordered dict of {test_dir: PathData}, total estimated runtime)
- """
-
- class PathData(object):
- def __init__(self, path):
- self.path = path
- self.time = 0
- self.tests = []
-
- by_dir = OrderedDict()
- total_time = 0
-
- 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:
- by_dir[test_dir] = PathData(test_dir)
-
- data = by_dir[test_dir]
- time = sum(wpttest.DEFAULT_TIMEOUT if test.timeout !=
- "long" else wpttest.LONG_TIMEOUT for test in tests)
- data.time += time
- total_time += time
- data.tests.append((test_type, test_path, tests))
-
- return by_dir, total_time
-
- def _maybe_remove(self, chunks, i, direction):
- """Trial removing a chunk from one chunk to an adjacent one.
-
- :param chunks: - the list of all chunks
- :param i: - the chunk index in the list of chunks to try removing from
- :param direction: either "next" if we are going to move from the end to
- the subsequent chunk, or "prev" if we are going to move
- from the start into the previous chunk.
-
- :returns bool: Did a chunk get moved?"""
- source_chunk = chunks[i]
- if direction == "next":
- target_chunk = chunks[i+1]
- path_index = -1
- move_func = lambda: target_chunk.appendleft(source_chunk.pop())
- elif direction == "prev":
- target_chunk = chunks[i-1]
- path_index = 0
- move_func = lambda: target_chunk.append(source_chunk.popleft())
- else:
- raise ValueError("Unexpected move direction %s" % direction)
-
- return self._maybe_move(source_chunk, target_chunk, path_index, move_func)
-
- def _maybe_add(self, chunks, i, direction):
- """Trial adding a chunk from one chunk to an adjacent one.
-
- :param chunks: - the list of all chunks
- :param i: - the chunk index in the list of chunks to try adding to
- :param direction: either "next" if we are going to remove from the
- the subsequent chunk, or "prev" if we are going to remove
- from the the previous chunk.
-
- :returns bool: Did a chunk get moved?"""
- target_chunk = chunks[i]
- if direction == "next":
- source_chunk = chunks[i+1]
- path_index = 0
- move_func = lambda: target_chunk.append(source_chunk.popleft())
- elif direction == "prev":
- source_chunk = chunks[i-1]
- path_index = -1
- move_func = lambda: target_chunk.appendleft(source_chunk.pop())
- else:
- raise ValueError("Unexpected move direction %s" % direction)
-
- return self._maybe_move(source_chunk, target_chunk, path_index, move_func)
-
- def _maybe_move(self, source_chunk, target_chunk, path_index, move_func):
- """Move from one chunk to another, assess the change in badness,
- and keep the move iff it decreases the badness score.
-
- :param source_chunk: chunk to move from
- :param target_chunk: chunk to move to
- :param path_index: 0 if we are moving from the start or -1 if we are moving from the
- end
- :param move_func: Function that actually moves between chunks"""
- if len(source_chunk.paths) <= 1:
- return False
-
- move_time = source_chunk.paths[path_index].time
-
- new_source_badness = self._badness(source_chunk.time - move_time)
- new_target_badness = self._badness(target_chunk.time + move_time)
-
- delta_badness = ((new_source_badness + new_target_badness) -
- (source_chunk.badness + target_chunk.badness))
- if delta_badness < 0:
- move_func()
- return True
-
- return False
-
- def _badness(self, time):
- """Metric of badness for a specific chunk
-
- :param time: the time for a specific chunk"""
- return (time - self.expected_time)**2
-
- def _get_chunk(self, manifest_items):
- by_dir, total_time = self._group_by_directory(manifest_items)
-
- if len(by_dir) < self.total_chunks:
- raise ValueError("Tried to split into %i chunks, but only %i subdirectories included" % (
- self.total_chunks, len(by_dir)))
-
- self.expected_time = float(total_time) / self.total_chunks
-
- chunks = self._create_initial_chunks(by_dir)
-
- while True:
- # Move a test from one chunk to the next until doing so no longer
- # reduces the badness
- got_improvement = self._update_chunks(chunks)
- if not got_improvement:
- break
-
- self.logger.debug(self.expected_time)
- for i, chunk in chunks.iteritems():
- self.logger.debug("%i: %i, %i" % (i + 1, chunk.time, chunk.badness))
-
- assert self._all_tests(by_dir) == self._chunked_tests(chunks)
-
- return self._get_tests(chunks)
-
- @staticmethod
- def _all_tests(by_dir):
- """Return a set of all tests in the manifest from a grouping by directory"""
- return set(x[0] for item in by_dir.itervalues()
- for x in item.tests)
-
- @staticmethod
- def _chunked_tests(chunks):
- """Return a set of all tests in the manifest from the chunk list"""
- return set(x[0] for chunk in chunks.itervalues()
- for path in chunk.paths
- for x in path.tests)
-
-
- def _create_initial_chunks(self, by_dir):
- """Create an initial unbalanced list of chunks.
-
- :param by_dir: All tests in the manifest grouped by subdirectory
- :returns list: A list of Chunk objects"""
-
- class Chunk(object):
- def __init__(self, paths, index):
- """List of PathData objects that together form a single chunk of
- tests"""
- self.paths = deque(paths)
- self.time = sum(item.time for item in paths)
- self.index = index
-
- def appendleft(self, path):
- """Add a PathData object to the start of the chunk"""
- self.paths.appendleft(path)
- self.time += path.time
-
- def append(self, path):
- """Add a PathData object to the end of the chunk"""
- self.paths.append(path)
- self.time += path.time
-
- def pop(self):
- """Remove PathData object from the end of the chunk"""
- assert len(self.paths) > 1
- self.time -= self.paths[-1].time
- return self.paths.pop()
-
- def popleft(self):
- """Remove PathData object from the start of the chunk"""
- assert len(self.paths) > 1
- self.time -= self.paths[0].time
- return self.paths.popleft()
-
- @property
- def badness(self_):
- """Badness metric for this chunk"""
- return self._badness(self_.time)
-
- initial_size = len(by_dir) / self.total_chunks
- chunk_boundaries = [initial_size * i
- for i in xrange(self.total_chunks)] + [len(by_dir)]
-
- chunks = OrderedDict()
- for i, lower in enumerate(chunk_boundaries[:-1]):
- upper = chunk_boundaries[i + 1]
- paths = by_dir.values()[lower:upper]
- chunks[i] = Chunk(paths, i)
-
- assert self._all_tests(by_dir) == self._chunked_tests(chunks)
-
- return chunks
-
- def _update_chunks(self, chunks):
- """Run a single iteration of the chunk update algorithm.
-
- :param chunks: - List of chunks
- """
- #TODO: consider replacing this with a heap
- sorted_chunks = sorted(chunks.values(), key=lambda x:-x.badness)
- got_improvement = False
- for chunk in sorted_chunks:
- if chunk.time < self.expected_time:
- f = self._maybe_add
- else:
- f = self._maybe_remove
-
- if chunk.index == 0:
- order = ["next"]
- elif chunk.index == self.total_chunks - 1:
- order = ["prev"]
- else:
- if chunk.time < self.expected_time:
- # First try to add a test from the neighboring chunk with the
- # greatest total time
- if chunks[chunk.index + 1].time > chunks[chunk.index - 1].time:
- order = ["next", "prev"]
- else:
- order = ["prev", "next"]
- else:
- # First try to remove a test and add to the neighboring chunk with the
- # lowest total time
- if chunks[chunk.index + 1].time > chunks[chunk.index - 1].time:
- order = ["prev", "next"]
- else:
- order = ["next", "prev"]
-
- for direction in order:
- if f(chunks, chunk.index, direction):
- got_improvement = True
- break
-
- if got_improvement:
- break
-
- return got_improvement
-
- def _get_tests(self, chunks):
- """Return the list of tests corresponding to the chunk number we are running.
-
- :param chunks: List of chunks"""
- tests = []
- for path in chunks[self.chunk_number - 1].paths:
- tests.extend(path.tests)
-
- return tests
-
- def __call__(self, manifest_iter):
- manifest = list(manifest_iter)
- tests = self._get_chunk(manifest)
- for item in tests:
- yield item
-
-
-class TestFilter(object):
- def __init__(self, test_manifests, include=None, exclude=None, manifest_path=None):
- if manifest_path is not None and include is None:
- self.manifest = manifestinclude.get_manifest(manifest_path)
- else:
- self.manifest = manifestinclude.IncludeManifest.create()
-
- if include:
- self.manifest.set("skip", "true")
- for item in include:
- self.manifest.add_include(test_manifests, item)
-
- if exclude:
- for item in exclude:
- self.manifest.add_exclude(test_manifests, item)
-
- def __call__(self, manifest_iter):
- for test_type, test_path, tests in manifest_iter:
- include_tests = set()
- for test in tests:
- if self.manifest.include(test):
- include_tests.add(test)
-
- if include_tests:
- yield test_type, test_path, include_tests
-
-class TagFilter(object):
- def __init__(self, tags):
- self.tags = set(tags)
-
- def __call__(self, test_iter):
- for test in test_iter:
- if test.tags & self.tags:
- yield test
-
-class ManifestLoader(object):
- def __init__(self, test_paths, force_manifest_update=False):
- do_delayed_imports()
- self.test_paths = test_paths
- self.force_manifest_update = force_manifest_update
- self.logger = structured.get_default_logger()
- if self.logger is None:
- self.logger = structured.structuredlog.StructuredLogger("ManifestLoader")
-
- def load(self):
- rv = {}
- for url_base, paths in self.test_paths.iteritems():
- manifest_file = self.load_manifest(url_base=url_base,
- **paths)
- path_data = {"url_base": url_base}
- path_data.update(paths)
- rv[manifest_file] = path_data
- return rv
-
- def create_manifest(self, manifest_path, tests_path, url_base="/"):
- self.update_manifest(manifest_path, tests_path, url_base, recreate=True)
-
- def update_manifest(self, manifest_path, tests_path, url_base="/",
- recreate=False):
- self.logger.info("Updating test manifest %s" % manifest_path)
-
- json_data = None
- if not recreate:
- try:
- with open(manifest_path) as f:
- json_data = json.load(f)
- except IOError:
- #If the existing file doesn't exist just create one from scratch
- pass
-
- if not json_data:
- manifest_file = manifest.Manifest(url_base)
- else:
- try:
- manifest_file = manifest.Manifest.from_json(tests_path, json_data)
- except manifest.ManifestVersionMismatch:
- manifest_file = manifest.Manifest(url_base)
-
- manifest_update.update(tests_path, manifest_file, True)
-
- manifest.write(manifest_file, manifest_path)
-
- def load_manifest(self, tests_path, metadata_path, url_base="/"):
- manifest_path = os.path.join(metadata_path, "MANIFEST.json")
- if (not os.path.exists(manifest_path) or
- self.force_manifest_update):
- self.update_manifest(manifest_path, tests_path, url_base)
- manifest_file = manifest.load(tests_path, manifest_path)
- if manifest_file.url_base != url_base:
- self.logger.info("Updating url_base in manifest from %s to %s" % (manifest_file.url_base,
- url_base))
- manifest_file.url_base = url_base
- manifest.write(manifest_file, manifest_path)
-
- return manifest_file
-
-def iterfilter(filters, iter):
- for f in filters:
- iter = f(iter)
- for item in iter:
- yield item
-
-class TestLoader(object):
- def __init__(self,
- test_manifests,
- test_types,
- run_info,
- manifest_filters=None,
- meta_filters=None,
- chunk_type="none",
- total_chunks=1,
- chunk_number=1,
- include_https=True):
-
- self.test_types = test_types
- self.run_info = run_info
-
- self.manifest_filters = manifest_filters if manifest_filters is not None else []
- self.meta_filters = meta_filters if meta_filters is not None else []
-
- self.manifests = test_manifests
- self.tests = None
- self.disabled_tests = None
- self.include_https = include_https
-
- self.chunk_type = chunk_type
- self.total_chunks = total_chunks
- self.chunk_number = chunk_number
-
- self.chunker = {"none": Unchunked,
- "hash": HashChunker,
- "equal_time": EqualTimeChunker}[chunk_type](total_chunks,
- chunk_number)
-
- self._test_ids = None
-
- self.directory_manifests = {}
-
- self._load_tests()
-
- @property
- def test_ids(self):
- if self._test_ids is None:
- self._test_ids = []
- for test_dict in [self.disabled_tests, self.tests]:
- for test_type in self.test_types:
- self._test_ids += [item.id for item in test_dict[test_type]]
- return self._test_ids
-
- def get_test(self, manifest_test, inherit_metadata, test_metadata):
- if test_metadata is not None:
- inherit_metadata.append(test_metadata)
- test_metadata = test_metadata.get_test(manifest_test.id)
-
- return wpttest.from_manifest(manifest_test, inherit_metadata, test_metadata)
-
- def load_dir_metadata(self, test_manifest, metadata_path, test_path):
- rv = []
- path_parts = os.path.dirname(test_path).split(os.path.sep)
- for i in xrange(1,len(path_parts) + 1):
- path = os.path.join(os.path.sep.join(path_parts[:i]), "__dir__.ini")
- if path not in self.directory_manifests:
- self.directory_manifests[path] = manifestexpected.get_dir_manifest(
- metadata_path, path, self.run_info)
- manifest = self.directory_manifests[path]
- if manifest is not None:
- rv.append(manifest)
- return rv
-
- def load_metadata(self, test_manifest, metadata_path, test_path):
- inherit_metadata = self.load_dir_metadata(test_manifest, metadata_path, test_path)
- test_metadata = manifestexpected.get_manifest(
- metadata_path, test_path, test_manifest.url_base, self.run_info)
- return inherit_metadata, test_metadata
-
- def iter_tests(self):
- manifest_items = []
-
- for manifest in sorted(self.manifests.keys(), key=lambda x:x.url_base):
- manifest_iter = iterfilter(self.manifest_filters,
- manifest.itertypes(*self.test_types))
- manifest_items.extend(manifest_iter)
-
- if self.chunker is not None:
- manifest_items = self.chunker(manifest_items)
-
- for test_type, test_path, tests in manifest_items:
- manifest_file = iter(tests).next().manifest
- metadata_path = self.manifests[manifest_file]["metadata_path"]
- inherit_metadata, test_metadata = self.load_metadata(manifest_file, metadata_path, test_path)
-
- for test in iterfilter(self.meta_filters,
- self.iter_wpttest(inherit_metadata, test_metadata, tests)):
- yield test_path, test_type, test
-
- def iter_wpttest(self, inherit_metadata, test_metadata, tests):
- for manifest_test in tests:
- yield self.get_test(manifest_test, inherit_metadata, test_metadata)
-
- def _load_tests(self):
- """Read in the tests from the manifest file and add them to a queue"""
- tests = {"enabled":defaultdict(list),
- "disabled":defaultdict(list)}
-
- for test_path, test_type, test in self.iter_tests():
- enabled = not test.disabled()
- if not self.include_https and test.environment["protocol"] == "https":
- enabled = False
- key = "enabled" if enabled else "disabled"
- tests[key][test_type].append(test)
-
- self.tests = tests["enabled"]
- self.disabled_tests = tests["disabled"]
-
- def groups(self, test_types, chunk_type="none", total_chunks=1, chunk_number=1):
- groups = set()
-
- for test_type in test_types:
- for test in self.tests[test_type]:
- group = test.url.split("/")[1]
- groups.add(group)
-
- return groups
-
-
-class TestSource(object):
- __metaclass__ = ABCMeta
-
- @abstractmethod
- def queue_tests(self, test_queue):
- pass
-
- @abstractmethod
- def requeue_test(self, test):
- pass
-
- def __enter__(self):
- return self
-
- def __exit__(self, *args, **kwargs):
- pass
-
-
-class SingleTestSource(TestSource):
- def __init__(self, test_queue):
- self.test_queue = test_queue
-
- @classmethod
- def queue_tests(cls, test_queue, test_type, tests):
- for test in tests[test_type]:
- test_queue.put(test)
-
- def get_queue(self):
- if self.test_queue.empty():
- return None
- return self.test_queue
-
- def requeue_test(self, test):
- self.test_queue.put(test)
-
-class PathGroupedSource(TestSource):
- def __init__(self, test_queue):
- self.test_queue = test_queue
- self.current_queue = None
-
- @classmethod
- def queue_tests(cls, test_queue, test_type, tests, depth=None):
- if depth is True:
- depth = None
-
- prev_path = None
- group = None
-
- for test in tests[test_type]:
- path = urlparse.urlsplit(test.url).path.split("/")[1:-1][:depth]
- if path != prev_path:
- group = []
- test_queue.put(group)
- prev_path = path
-
- group.append(test)
-
- def get_queue(self):
- if not self.current_queue or self.current_queue.empty():
- try:
- data = self.test_queue.get(block=True, timeout=1)
- self.current_queue = Queue()
- for item in data:
- self.current_queue.put(item)
- except Empty:
- return None
-
- return self.current_queue
-
- def requeue_test(self, test):
- self.current_queue.put(test)
-
- def __exit__(self, *args, **kwargs):
- if self.current_queue:
- self.current_queue.close()
diff --git a/tests/wpt/harness/wptrunner/testrunner.py b/tests/wpt/harness/wptrunner/testrunner.py
deleted file mode 100644
index 38cc4220310..00000000000
--- a/tests/wpt/harness/wptrunner/testrunner.py
+++ /dev/null
@@ -1,672 +0,0 @@
-# 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/.
-
-from __future__ import unicode_literals
-
-import multiprocessing
-import sys
-import threading
-import traceback
-from Queue import Empty
-from multiprocessing import Process, current_process, Queue
-
-from mozlog import structuredlog
-
-# Special value used as a sentinal in various commands
-Stop = object()
-
-
-class MessageLogger(object):
- def __init__(self, message_func):
- self.send_message = message_func
-
- def _log_data(self, action, **kwargs):
- self.send_message("log", action, kwargs)
-
- def process_output(self, process, data, command):
- self._log_data("process_output", process=process, data=data, command=command)
-
-
-def _log_func(level_name):
- def log(self, message):
- self._log_data(level_name.lower(), message=message)
- log.__doc__ = """Log a message with level %s
-
-:param message: The string message to log
-""" % level_name
- log.__name__ = str(level_name).lower()
- return log
-
-# Create all the methods on StructuredLog for debug levels
-for level_name in structuredlog.log_levels:
- setattr(MessageLogger, level_name.lower(), _log_func(level_name))
-
-
-class TestRunner(object):
- def __init__(self, test_queue, command_queue, result_queue, executor):
- """Class implementing the main loop for running tests.
-
- This class delegates the job of actually running a test to the executor
- that is passed in.
-
- :param test_queue: subprocess.Queue containing the tests to run
- :param command_queue: subprocess.Queue used to send commands to the
- process
- :param result_queue: subprocess.Queue used to send results to the
- parent TestManager process
- :param executor: TestExecutor object that will actually run a test.
- """
- self.test_queue = test_queue
- self.command_queue = command_queue
- self.result_queue = result_queue
-
- self.executor = executor
- self.name = current_process().name
- self.logger = MessageLogger(self.send_message)
-
- def __enter__(self):
- return self
-
- def __exit__(self, exc_type, exc_value, traceback):
- self.teardown()
-
- def setup(self):
- self.executor.setup(self)
-
- def teardown(self):
- self.executor.teardown()
- self.send_message("runner_teardown")
- self.result_queue = None
- self.command_queue = None
- self.browser = None
-
- def run(self):
- """Main loop accepting commands over the pipe and triggering
- the associated methods"""
- self.setup()
- commands = {"run_test": self.run_test,
- "stop": self.stop,
- "wait": self.wait}
- while True:
- command, args = self.command_queue.get()
- try:
- rv = commands[command](*args)
- except Exception:
- self.send_message("error",
- "Error running command %s with arguments %r:\n%s" %
- (command, args, traceback.format_exc()))
- else:
- if rv is Stop:
- break
-
- def stop(self):
- return Stop
-
- def run_test(self):
- if not self.executor.is_alive():
- self.send_message("restart_runner")
- return
- try:
- # Need to block here just to allow for contention with other processes
- test = self.test_queue.get(block=True, timeout=1)
- except Empty:
- # If we are running tests in groups (e.g. by-dir) then this queue might be
- # empty but there could be other test queues. restart_runner won't actually
- # start the runner if there aren't any more tests to run
- self.send_message("restart_runner")
- return
- else:
- self.send_message("test_start", test)
- try:
- return self.executor.run_test(test)
- except Exception:
- self.logger.critical(traceback.format_exc())
- raise
-
- def wait(self):
- self.executor.protocol.wait()
- self.send_message("after_test_ended", True)
-
- def send_message(self, command, *args):
- self.result_queue.put((command, args))
-
-
-def start_runner(test_queue, runner_command_queue, runner_result_queue,
- executor_cls, executor_kwargs,
- executor_browser_cls, executor_browser_kwargs,
- stop_flag):
- """Launch a TestRunner in a new process"""
- try:
- browser = executor_browser_cls(**executor_browser_kwargs)
- executor = executor_cls(browser, **executor_kwargs)
- with TestRunner(test_queue, runner_command_queue, runner_result_queue, executor) as runner:
- try:
- runner.run()
- except KeyboardInterrupt:
- stop_flag.set()
- except Exception:
- runner_result_queue.put(("log", ("critical", {"message": traceback.format_exc()})))
- print >> sys.stderr, traceback.format_exc()
- stop_flag.set()
- finally:
- runner_command_queue = None
- runner_result_queue = None
-
-
-manager_count = 0
-
-
-def next_manager_number():
- global manager_count
- local = manager_count = manager_count + 1
- return local
-
-
-class TestRunnerManager(threading.Thread):
- init_lock = threading.Lock()
-
- def __init__(self, suite_name, test_queue, test_source_cls, browser_cls, browser_kwargs,
- executor_cls, executor_kwargs, stop_flag, pause_after_test=False,
- pause_on_unexpected=False, restart_on_unexpected=True, debug_info=None):
- """Thread that owns a single TestRunner process and any processes required
- by the TestRunner (e.g. the Firefox binary).
-
- TestRunnerManagers are responsible for launching the browser process and the
- runner process, and for logging the test progress. The actual test running
- is done by the TestRunner. In particular they:
-
- * Start the binary of the program under test
- * Start the TestRunner
- * Tell the TestRunner to start a test, if any
- * Log that the test started
- * Log the test results
- * Take any remedial action required e.g. restart crashed or hung
- processes
- """
- self.suite_name = suite_name
-
- self.test_queue = test_queue
- self.test_source_cls = test_source_cls
-
- self.browser_cls = browser_cls
- self.browser_kwargs = browser_kwargs
-
- self.executor_cls = executor_cls
- self.executor_kwargs = executor_kwargs
-
- self.test_source = None
-
- self.browser = None
- self.browser_pid = None
- self.browser_started = False
-
- # Flags used to shut down this thread if we get a sigint
- self.parent_stop_flag = stop_flag
- self.child_stop_flag = multiprocessing.Event()
-
- self.pause_after_test = pause_after_test
- self.pause_on_unexpected = pause_on_unexpected
- self.restart_on_unexpected = restart_on_unexpected
- self.debug_info = debug_info
-
- self.manager_number = next_manager_number()
-
- self.command_queue = Queue()
- self.remote_queue = Queue()
-
- self.test_runner_proc = None
-
- threading.Thread.__init__(self, name="Thread-TestrunnerManager-%i" % self.manager_number)
- # This is started in the actual new thread
- self.logger = None
-
- # The test that is currently running
- self.test = None
-
- self.unexpected_count = 0
-
- # This may not really be what we want
- self.daemon = True
-
- self.init_fail_count = 0
- self.max_init_fails = 5
- self.init_timer = None
-
- self.restart_count = 0
- self.max_restarts = 5
-
- def run(self):
- """Main loop for the TestManager.
-
- TestManagers generally receive commands from their
- TestRunner updating them on the status of a test. They
- may also have a stop flag set by the main thread indicating
- that the manager should shut down the next time the event loop
- spins."""
- self.logger = structuredlog.StructuredLogger(self.suite_name)
- with self.browser_cls(self.logger, **self.browser_kwargs) as browser, self.test_source_cls(self.test_queue) as test_source:
- self.browser = browser
- self.test_source = test_source
- try:
- if self.init() is Stop:
- return
- while True:
- commands = {"init_succeeded": self.init_succeeded,
- "init_failed": self.init_failed,
- "test_start": self.test_start,
- "test_ended": self.test_ended,
- "after_test_ended": self.after_test_ended,
- "restart_runner": self.restart_runner,
- "runner_teardown": self.runner_teardown,
- "log": self.log,
- "error": self.error}
- try:
- command, data = self.command_queue.get(True, 1)
- except IOError:
- if not self.should_stop():
- self.logger.error("Got IOError from poll")
- self.restart_count += 1
- if self.restart_runner() is Stop:
- break
- except Empty:
- command = None
-
- if self.should_stop():
- self.logger.debug("A flag was set; stopping")
- break
-
- if command is not None:
- self.restart_count = 0
- if commands[command](*data) is Stop:
- break
- else:
- if (self.debug_info and self.debug_info.interactive and
- self.browser_started and not browser.is_alive()):
- self.logger.debug("Debugger exited")
- break
- if not self.test_runner_proc.is_alive():
- if not self.command_queue.empty():
- # We got a new message so process that
- continue
-
- # If we got to here the runner presumably shut down
- # unexpectedly
- self.logger.info("Test runner process shut down")
-
- if self.test is not None:
- # This could happen if the test runner crashed for some other
- # reason
- # Need to consider the unlikely case where one test causes the
- # runner process to repeatedly die
- self.logger.critical("Last test did not complete")
- break
- self.logger.warning(
- "More tests found, but runner process died, restarting")
- self.restart_count += 1
- if self.restart_runner() is Stop:
- break
- finally:
- self.logger.debug("TestRunnerManager main loop terminating, starting cleanup")
- self.stop_runner()
- self.teardown()
- self.logger.debug("TestRunnerManager main loop terminated")
-
- def should_stop(self):
- return self.child_stop_flag.is_set() or self.parent_stop_flag.is_set()
-
- def init(self):
- """Launch the browser that is being tested,
- and the TestRunner process that will run the tests."""
- # It seems that this lock is helpful to prevent some race that otherwise
- # sometimes stops the spawned processes initalising correctly, and
- # leaves this thread hung
- if self.init_timer is not None:
- self.init_timer.cancel()
-
- self.logger.debug("Init called, starting browser and runner")
-
- def init_failed():
- # This is called from a seperate thread, so we send a message to the
- # main loop so we get back onto the manager thread
- self.logger.debug("init_failed called from timer")
- if self.command_queue:
- self.command_queue.put(("init_failed", ()))
- else:
- self.logger.debug("Setting child stop flag in init_failed")
- self.child_stop_flag.set()
-
- with self.init_lock:
- # Guard against problems initialising the browser or the browser
- # remote control method
- if self.debug_info is None:
- self.init_timer = threading.Timer(self.browser.init_timeout, init_failed)
-
- test_queue = self.test_source.get_queue()
- if test_queue is None:
- self.logger.info("No more tests")
- return Stop
-
- try:
- if self.init_timer is not None:
- self.init_timer.start()
- self.browser.start()
- self.browser_pid = self.browser.pid()
- self.start_test_runner(test_queue)
- except:
- self.logger.warning("Failure during init %s" % traceback.format_exc())
- if self.init_timer is not None:
- self.init_timer.cancel()
- self.logger.error(traceback.format_exc())
- succeeded = False
- else:
- succeeded = True
- self.browser_started = True
-
- # This has to happen after the lock is released
- if not succeeded:
- self.init_failed()
-
- def init_succeeded(self):
- """Callback when we have started the browser, started the remote
- control connection, and we are ready to start testing."""
- self.logger.debug("Init succeeded")
- if self.init_timer is not None:
- self.init_timer.cancel()
- self.init_fail_count = 0
- self.start_next_test()
-
- def init_failed(self):
- """Callback when starting the browser or the remote control connect
- fails."""
- self.init_fail_count += 1
- self.logger.warning("Init failed %i" % self.init_fail_count)
- if self.init_timer is not None:
- self.init_timer.cancel()
- if self.init_fail_count < self.max_init_fails:
- self.restart_runner()
- else:
- self.logger.critical("Test runner failed to initialise correctly; shutting down")
- return Stop
-
- def start_test_runner(self, test_queue):
- # Note that we need to be careful to start the browser before the
- # test runner to ensure that any state set when the browser is started
- # can be passed in to the test runner.
- assert self.command_queue is not None
- assert self.remote_queue is not None
- self.logger.info("Starting runner")
- executor_browser_cls, executor_browser_kwargs = self.browser.executor_browser()
-
- args = (test_queue,
- self.remote_queue,
- self.command_queue,
- self.executor_cls,
- self.executor_kwargs,
- executor_browser_cls,
- executor_browser_kwargs,
- self.child_stop_flag)
- self.test_runner_proc = Process(target=start_runner,
- args=args,
- name="Thread-TestRunner-%i" % self.manager_number)
- self.test_runner_proc.start()
- self.logger.debug("Test runner started")
-
- def send_message(self, command, *args):
- self.remote_queue.put((command, args))
-
- def cleanup(self):
- if self.init_timer is not None:
- self.init_timer.cancel()
- self.logger.debug("TestManager cleanup")
-
- while True:
- try:
- self.logger.warning(" ".join(map(repr, self.command_queue.get_nowait())))
- except Empty:
- break
-
- while True:
- try:
- self.logger.warning(" ".join(map(repr, self.remote_queue.get_nowait())))
- except Empty:
- break
-
- def teardown(self):
- self.logger.debug("teardown in testrunnermanager")
- self.test_runner_proc = None
- self.command_queue.close()
- self.remote_queue.close()
- self.command_queue = None
- self.remote_queue = None
-
- def ensure_runner_stopped(self):
- if self.test_runner_proc is None:
- return
-
- self.test_runner_proc.join(10)
- if self.test_runner_proc.is_alive():
- # This might leak a file handle from the queue
- self.logger.warning("Forcibly terminating runner process")
- self.test_runner_proc.terminate()
- self.test_runner_proc.join(10)
- else:
- self.logger.debug("Testrunner exited with code %i" % self.test_runner_proc.exitcode)
-
- def runner_teardown(self):
- self.ensure_runner_stopped()
- return Stop
-
- def stop_runner(self):
- """Stop the TestRunner and the Firefox binary."""
- self.logger.debug("Stopping runner")
- if self.test_runner_proc is None:
- return
- try:
- self.browser.stop()
- self.browser_started = False
- if self.test_runner_proc.is_alive():
- self.send_message("stop")
- self.ensure_runner_stopped()
- finally:
- self.cleanup()
-
- def start_next_test(self):
- self.send_message("run_test")
-
- def test_start(self, test):
- self.test = test
- self.logger.test_start(test.id)
-
- def test_ended(self, test, results):
- """Handle the end of a test.
-
- Output the result of each subtest, and the result of the overall
- harness to the logs.
- """
- assert test == self.test
- # Write the result of each subtest
- file_result, test_results = results
- subtest_unexpected = False
- for result in test_results:
- if test.disabled(result.name):
- continue
- expected = test.expected(result.name)
- is_unexpected = expected != result.status
-
- if is_unexpected:
- self.unexpected_count += 1
- self.logger.debug("Unexpected count in this thread %i" % self.unexpected_count)
- subtest_unexpected = True
- self.logger.test_status(test.id,
- result.name,
- result.status,
- message=result.message,
- expected=expected,
- stack=result.stack)
-
- # TODO: consider changing result if there is a crash dump file
-
- # Write the result of the test harness
- expected = test.expected()
- status = file_result.status if file_result.status != "EXTERNAL-TIMEOUT" else "TIMEOUT"
- is_unexpected = expected != status
- if is_unexpected:
- self.unexpected_count += 1
- self.logger.debug("Unexpected count in this thread %i" % self.unexpected_count)
- if status == "CRASH":
- self.browser.log_crash(process=self.browser_pid, test=test.id)
-
- self.logger.test_end(test.id,
- status,
- message=file_result.message,
- expected=expected,
- extra=file_result.extra)
-
- self.test = None
-
- 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))
-
- if (self.pause_after_test or
- (self.pause_on_unexpected and (subtest_unexpected or is_unexpected))):
- self.logger.info("Pausing until the browser exits")
- self.send_message("wait")
- else:
- self.after_test_ended(restart_before_next)
-
- def after_test_ended(self, restart_before_next):
- # Handle starting the next test, with a runner restart if required
- if restart_before_next:
- return self.restart_runner()
- else:
- return self.start_next_test()
-
- def restart_runner(self):
- """Stop and restart the TestRunner"""
- if self.restart_count >= self.max_restarts:
- return Stop
- self.stop_runner()
- return self.init()
-
- def log(self, action, kwargs):
- getattr(self.logger, action)(**kwargs)
-
- def error(self, message):
- self.logger.error(message)
- self.restart_runner()
-
-
-class TestQueue(object):
- def __init__(self, test_source_cls, test_type, tests, **kwargs):
- self.queue = None
- self.test_source_cls = test_source_cls
- self.test_type = test_type
- self.tests = tests
- self.kwargs = kwargs
-
- def __enter__(self):
- if not self.tests[self.test_type]:
- return None
-
- self.queue = Queue()
- has_tests = self.test_source_cls.queue_tests(self.queue,
- self.test_type,
- self.tests,
- **self.kwargs)
- # There is a race condition that means sometimes we continue
- # before the tests have been written to the underlying pipe.
- # Polling the pipe for data here avoids that
- self.queue._reader.poll(10)
- assert not self.queue.empty()
- return self.queue
-
- def __exit__(self, *args, **kwargs):
- if self.queue is not None:
- self.queue.close()
- self.queue = None
-
-
-class ManagerGroup(object):
- def __init__(self, suite_name, size, test_source_cls, test_source_kwargs,
- browser_cls, browser_kwargs,
- executor_cls, executor_kwargs,
- pause_after_test=False,
- pause_on_unexpected=False,
- restart_on_unexpected=True,
- debug_info=None):
- """Main thread object that owns all the TestManager threads."""
- self.suite_name = suite_name
- self.size = size
- self.test_source_cls = test_source_cls
- self.test_source_kwargs = test_source_kwargs
- self.browser_cls = browser_cls
- self.browser_kwargs = browser_kwargs
- self.executor_cls = executor_cls
- self.executor_kwargs = executor_kwargs
- self.pause_after_test = pause_after_test
- self.pause_on_unexpected = pause_on_unexpected
- self.restart_on_unexpected = restart_on_unexpected
- self.debug_info = debug_info
-
- self.pool = set()
- # Event that is polled by threads so that they can gracefully exit in the face
- # of sigint
- self.stop_flag = threading.Event()
- self.logger = structuredlog.StructuredLogger(suite_name)
- self.test_queue = None
-
- def __enter__(self):
- return self
-
- def __exit__(self, exc_type, exc_val, exc_tb):
- self.stop()
-
- def run(self, test_type, tests):
- """Start all managers in the group"""
- self.logger.debug("Using %i processes" % self.size)
-
- self.test_queue = TestQueue(self.test_source_cls,
- test_type,
- tests,
- **self.test_source_kwargs)
- with self.test_queue as test_queue:
- if test_queue is None:
- self.logger.info("No %s tests to run" % test_type)
- return
- for _ in range(self.size):
- manager = TestRunnerManager(self.suite_name,
- test_queue,
- self.test_source_cls,
- self.browser_cls,
- self.browser_kwargs,
- self.executor_cls,
- self.executor_kwargs,
- self.stop_flag,
- self.pause_after_test,
- self.pause_on_unexpected,
- self.restart_on_unexpected,
- self.debug_info)
- manager.start()
- self.pool.add(manager)
- self.wait()
-
- def is_alive(self):
- """Boolean indicating whether any manager in the group is still alive"""
- return any(manager.is_alive() for manager in self.pool)
-
- def wait(self):
- """Wait for all the managers in the group to finish"""
- for item in self.pool:
- item.join()
-
- def stop(self):
- """Set the stop flag so that all managers in the group stop as soon
- as possible"""
- self.stop_flag.set()
- self.logger.debug("Stop flag set in ManagerGroup")
-
- def unexpected_count(self):
- return sum(item.unexpected_count for item in self.pool)
diff --git a/tests/wpt/harness/wptrunner/tests/__init__.py b/tests/wpt/harness/wptrunner/tests/__init__.py
deleted file mode 100644
index c580d191c1b..00000000000
--- a/tests/wpt/harness/wptrunner/tests/__init__.py
+++ /dev/null
@@ -1,3 +0,0 @@
-# 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/.
diff --git a/tests/wpt/harness/wptrunner/tests/test_chunker.py b/tests/wpt/harness/wptrunner/tests/test_chunker.py
deleted file mode 100644
index 60b34b804a2..00000000000
--- a/tests/wpt/harness/wptrunner/tests/test_chunker.py
+++ /dev/null
@@ -1,86 +0,0 @@
-# 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 unittest
-import sys
-from os.path import join, dirname
-from mozlog import structured
-
-import pytest
-
-sys.path.insert(0, join(dirname(__file__), "..", ".."))
-
-from wptrunner.testloader import EqualTimeChunker
-
-structured.set_default_logger(structured.structuredlog.StructuredLogger("TestChunker"))
-
-class MockTest(object):
- def __init__(self, id, timeout=10):
- self.id = id
- self.item_type = "testharness"
- self.timeout = timeout
-
-
-def make_mock_manifest(*items):
- rv = []
- for dir_path, num_tests in items:
- for i in range(num_tests):
- rv.append((dir_path + "/%i.test" % i, set([MockTest(i)])))
- return rv
-
-
-class TestEqualTimeChunker(unittest.TestCase):
-
- def test_include_all(self):
- tests = make_mock_manifest(("a", 10), ("a/b", 10), ("c", 10))
-
- chunk_1 = list(EqualTimeChunker(3, 1)(tests))
- chunk_2 = list(EqualTimeChunker(3, 2)(tests))
- chunk_3 = list(EqualTimeChunker(3, 3)(tests))
-
- self.assertEquals(tests[:10], chunk_1)
- self.assertEquals(tests[10:20], chunk_2)
- self.assertEquals(tests[20:], chunk_3)
-
- def test_include_all_1(self):
- tests = make_mock_manifest(("a", 5), ("a/b", 5), ("c", 10), ("d", 10))
-
- chunk_1 = list(EqualTimeChunker(3, 1)(tests))
- chunk_2 = list(EqualTimeChunker(3, 2)(tests))
- chunk_3 = list(EqualTimeChunker(3, 3)(tests))
-
- self.assertEquals(tests[:10], chunk_1)
- self.assertEquals(tests[10:20], chunk_2)
- self.assertEquals(tests[20:], chunk_3)
-
- def test_long(self):
- tests = make_mock_manifest(("a", 100), ("a/b", 1), ("c", 1))
-
- chunk_1 = list(EqualTimeChunker(3, 1)(tests))
- chunk_2 = list(EqualTimeChunker(3, 2)(tests))
- chunk_3 = list(EqualTimeChunker(3, 3)(tests))
-
- self.assertEquals(tests[:100], chunk_1)
- self.assertEquals(tests[100:101], chunk_2)
- self.assertEquals(tests[101:102], chunk_3)
-
- def test_long_1(self):
- tests = make_mock_manifest(("a", 1), ("a/b", 100), ("c", 1))
-
- chunk_1 = list(EqualTimeChunker(3, 1)(tests))
- chunk_2 = list(EqualTimeChunker(3, 2)(tests))
- chunk_3 = list(EqualTimeChunker(3, 3)(tests))
-
- self.assertEquals(tests[:1], chunk_1)
- self.assertEquals(tests[1:101], chunk_2)
- self.assertEquals(tests[101:102], chunk_3)
-
- def test_too_few_dirs(self):
- with self.assertRaises(ValueError):
- tests = make_mock_manifest(("a", 1), ("a/b", 100), ("c", 1))
- list(EqualTimeChunker(4, 1)(tests))
-
-
-if __name__ == "__main__":
- unittest.main()
diff --git a/tests/wpt/harness/wptrunner/tests/test_hosts.py b/tests/wpt/harness/wptrunner/tests/test_hosts.py
deleted file mode 100644
index 3f9006273df..00000000000
--- a/tests/wpt/harness/wptrunner/tests/test_hosts.py
+++ /dev/null
@@ -1,60 +0,0 @@
-# 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 unittest
-import sys
-from os.path import join, dirname
-from cStringIO import StringIO
-
-sys.path.insert(0, join(dirname(__file__), "..", ".."))
-
-from wptrunner import hosts
-
-
-class HostsTest(unittest.TestCase):
- def do_test(self, input, expected):
- host_file = hosts.HostsFile.from_file(StringIO(input))
- self.assertEquals(host_file.to_string(), expected)
-
- def test_simple(self):
- self.do_test("""127.0.0.1 \tlocalhost alias # comment
-# Another comment""",
- """127.0.0.1 localhost alias # comment
-# Another comment
-""")
-
- def test_blank_lines(self):
- self.do_test("""127.0.0.1 \tlocalhost alias # comment
-
-\r
- \t
-# Another comment""",
- """127.0.0.1 localhost alias # comment
-# Another comment
-""")
-
- def test_whitespace(self):
- self.do_test(""" \t127.0.0.1 \tlocalhost alias # comment \r
- \t# Another comment""",
- """127.0.0.1 localhost alias # comment
-# Another comment
-""")
-
- def test_alignment(self):
- self.do_test("""127.0.0.1 \tlocalhost alias
-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()
diff --git a/tests/wpt/harness/wptrunner/tests/test_update.py b/tests/wpt/harness/wptrunner/tests/test_update.py
deleted file mode 100644
index 50878ac56dc..00000000000
--- a/tests/wpt/harness/wptrunner/tests/test_update.py
+++ /dev/null
@@ -1,332 +0,0 @@
-# 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 unittest
-import StringIO
-
-import pytest
-
-from .. import metadata, manifestupdate
-from mozlog import structuredlog, handlers, formatters
-
-
-class TestExpectedUpdater(unittest.TestCase):
- def create_manifest(self, data, test_path="path/to/test.ini"):
- f = StringIO.StringIO(data)
- return manifestupdate.compile(f, test_path)
-
- def create_updater(self, data, **kwargs):
- expected_tree = {}
- id_path_map = {}
- for test_path, test_ids, manifest_str in data:
- if isinstance(test_ids, (str, unicode)):
- test_ids = [test_ids]
- expected_tree[test_path] = self.create_manifest(manifest_str, test_path)
- for test_id in test_ids:
- id_path_map[test_id] = test_path
-
- return metadata.ExpectedUpdater(expected_tree, id_path_map, **kwargs)
-
- def create_log(self, *args, **kwargs):
- logger = structuredlog.StructuredLogger("expected_test")
- data = StringIO.StringIO()
- handler = handlers.StreamHandler(data, formatters.JSONFormatter())
- logger.add_handler(handler)
-
- log_entries = ([("suite_start", {"tests": [], "run_info": kwargs.get("run_info", {})})] +
- list(args) +
- [("suite_end", {})])
-
- for item in log_entries:
- action, kwargs = item
- getattr(logger, action)(**kwargs)
- logger.remove_handler(handler)
- data.seek(0)
- return data
-
-
- def coalesce_results(self, trees):
- for tree in trees:
- for test in tree.iterchildren():
- for subtest in test.iterchildren():
- subtest.coalesce_expected()
- test.coalesce_expected()
-
- @pytest.mark.xfail
- def test_update_0(self):
- prev_data = [("path/to/test.htm.ini", ["/path/to/test.htm"], """[test.htm]
- type: testharness
- [test1]
- expected: FAIL""")]
-
- new_data = self.create_log(("test_start", {"test": "/path/to/test.htm"}),
- ("test_status", {"test": "/path/to/test.htm",
- "subtest": "test1",
- "status": "PASS",
- "expected": "FAIL"}),
- ("test_end", {"test": "/path/to/test.htm",
- "status": "OK"}))
- updater = self.create_updater(prev_data)
- updater.update_from_log(new_data)
-
- new_manifest = updater.expected_tree["path/to/test.htm.ini"]
- self.coalesce_results([new_manifest])
- self.assertTrue(new_manifest.is_empty)
-
- @pytest.mark.xfail
- def test_update_1(self):
- test_id = "/path/to/test.htm"
- prev_data = [("path/to/test.htm.ini", [test_id], """[test.htm]
- type: testharness
- [test1]
- expected: ERROR""")]
-
- new_data = self.create_log(("test_start", {"test": test_id}),
- ("test_status", {"test": test_id,
- "subtest": "test1",
- "status": "FAIL",
- "expected": "ERROR"}),
- ("test_end", {"test": test_id,
- "status": "OK"}))
- updater = self.create_updater(prev_data)
- updater.update_from_log(new_data)
-
- new_manifest = updater.expected_tree["path/to/test.htm.ini"]
- self.coalesce_results([new_manifest])
- self.assertFalse(new_manifest.is_empty)
- self.assertEquals(new_manifest.get_test(test_id).children[0].get("expected"), "FAIL")
-
- @pytest.mark.xfail
- def test_new_subtest(self):
- test_id = "/path/to/test.htm"
- prev_data = [("path/to/test.htm.ini", [test_id], """[test.htm]
- type: testharness
- [test1]
- expected: FAIL""")]
-
- new_data = self.create_log(("test_start", {"test": test_id}),
- ("test_status", {"test": test_id,
- "subtest": "test1",
- "status": "FAIL",
- "expected": "FAIL"}),
- ("test_status", {"test": test_id,
- "subtest": "test2",
- "status": "FAIL",
- "expected": "PASS"}),
- ("test_end", {"test": test_id,
- "status": "OK"}))
- updater = self.create_updater(prev_data)
- updater.update_from_log(new_data)
-
- new_manifest = updater.expected_tree["path/to/test.htm.ini"]
- self.coalesce_results([new_manifest])
- self.assertFalse(new_manifest.is_empty)
- self.assertEquals(new_manifest.get_test(test_id).children[0].get("expected"), "FAIL")
- self.assertEquals(new_manifest.get_test(test_id).children[1].get("expected"), "FAIL")
-
- @pytest.mark.xfail
- def test_update_multiple_0(self):
- test_id = "/path/to/test.htm"
- prev_data = [("path/to/test.htm.ini", [test_id], """[test.htm]
- type: testharness
- [test1]
- expected: FAIL""")]
-
- new_data_0 = self.create_log(("test_start", {"test": test_id}),
- ("test_status", {"test": test_id,
- "subtest": "test1",
- "status": "FAIL",
- "expected": "FAIL"}),
- ("test_end", {"test": test_id,
- "status": "OK"}),
- run_info={"debug": False, "os": "osx"})
-
- new_data_1 = self.create_log(("test_start", {"test": test_id}),
- ("test_status", {"test": test_id,
- "subtest": "test1",
- "status": "TIMEOUT",
- "expected": "FAIL"}),
- ("test_end", {"test": test_id,
- "status": "OK"}),
- run_info={"debug": False, "os": "linux"})
- updater = self.create_updater(prev_data)
-
- updater.update_from_log(new_data_0)
- updater.update_from_log(new_data_1)
-
- new_manifest = updater.expected_tree["path/to/test.htm.ini"]
-
- self.coalesce_results([new_manifest])
-
- self.assertFalse(new_manifest.is_empty)
- self.assertEquals(new_manifest.get_test(test_id).children[0].get(
- "expected", {"debug": False, "os": "osx"}), "FAIL")
- self.assertEquals(new_manifest.get_test(test_id).children[0].get(
- "expected", {"debug": False, "os": "linux"}), "TIMEOUT")
-
- @pytest.mark.xfail
- def test_update_multiple_1(self):
- test_id = "/path/to/test.htm"
- prev_data = [("path/to/test.htm.ini", [test_id], """[test.htm]
- type: testharness
- [test1]
- expected: FAIL""")]
-
- new_data_0 = self.create_log(("test_start", {"test": test_id}),
- ("test_status", {"test": test_id,
- "subtest": "test1",
- "status": "FAIL",
- "expected": "FAIL"}),
- ("test_end", {"test": test_id,
- "status": "OK"}),
- run_info={"debug": False, "os": "osx"})
-
- new_data_1 = self.create_log(("test_start", {"test": test_id}),
- ("test_status", {"test": test_id,
- "subtest": "test1",
- "status": "TIMEOUT",
- "expected": "FAIL"}),
- ("test_end", {"test": test_id,
- "status": "OK"}),
- run_info={"debug": False, "os": "linux"})
- updater = self.create_updater(prev_data)
-
- updater.update_from_log(new_data_0)
- updater.update_from_log(new_data_1)
-
- new_manifest = updater.expected_tree["path/to/test.htm.ini"]
-
- self.coalesce_results([new_manifest])
-
- self.assertFalse(new_manifest.is_empty)
- self.assertEquals(new_manifest.get_test(test_id).children[0].get(
- "expected", {"debug": False, "os": "osx"}), "FAIL")
- self.assertEquals(new_manifest.get_test(test_id).children[0].get(
- "expected", {"debug": False, "os": "linux"}), "TIMEOUT")
- self.assertEquals(new_manifest.get_test(test_id).children[0].get(
- "expected", {"debug": False, "os": "windows"}), "FAIL")
-
- @pytest.mark.xfail
- def test_update_multiple_2(self):
- test_id = "/path/to/test.htm"
- prev_data = [("path/to/test.htm.ini", [test_id], """[test.htm]
- type: testharness
- [test1]
- expected: FAIL""")]
-
- new_data_0 = self.create_log(("test_start", {"test": test_id}),
- ("test_status", {"test": test_id,
- "subtest": "test1",
- "status": "FAIL",
- "expected": "FAIL"}),
- ("test_end", {"test": test_id,
- "status": "OK"}),
- run_info={"debug": False, "os": "osx"})
-
- new_data_1 = self.create_log(("test_start", {"test": test_id}),
- ("test_status", {"test": test_id,
- "subtest": "test1",
- "status": "TIMEOUT",
- "expected": "FAIL"}),
- ("test_end", {"test": test_id,
- "status": "OK"}),
- run_info={"debug": True, "os": "osx"})
- updater = self.create_updater(prev_data)
-
- updater.update_from_log(new_data_0)
- updater.update_from_log(new_data_1)
-
- new_manifest = updater.expected_tree["path/to/test.htm.ini"]
-
- self.coalesce_results([new_manifest])
-
- self.assertFalse(new_manifest.is_empty)
- self.assertEquals(new_manifest.get_test(test_id).children[0].get(
- "expected", {"debug": False, "os": "osx"}), "FAIL")
- self.assertEquals(new_manifest.get_test(test_id).children[0].get(
- "expected", {"debug": True, "os": "osx"}), "TIMEOUT")
-
- @pytest.mark.xfail
- def test_update_multiple_3(self):
- test_id = "/path/to/test.htm"
- prev_data = [("path/to/test.htm.ini", [test_id], """[test.htm]
- type: testharness
- [test1]
- expected:
- if debug: FAIL
- if not debug and os == "osx": TIMEOUT""")]
-
- new_data_0 = self.create_log(("test_start", {"test": test_id}),
- ("test_status", {"test": test_id,
- "subtest": "test1",
- "status": "FAIL",
- "expected": "FAIL"}),
- ("test_end", {"test": test_id,
- "status": "OK"}),
- run_info={"debug": False, "os": "osx"})
-
- new_data_1 = self.create_log(("test_start", {"test": test_id}),
- ("test_status", {"test": test_id,
- "subtest": "test1",
- "status": "TIMEOUT",
- "expected": "FAIL"}),
- ("test_end", {"test": test_id,
- "status": "OK"}),
- run_info={"debug": True, "os": "osx"})
- updater = self.create_updater(prev_data)
-
- updater.update_from_log(new_data_0)
- updater.update_from_log(new_data_1)
-
- new_manifest = updater.expected_tree["path/to/test.htm.ini"]
-
- self.coalesce_results([new_manifest])
-
- self.assertFalse(new_manifest.is_empty)
- self.assertEquals(new_manifest.get_test(test_id).children[0].get(
- "expected", {"debug": False, "os": "osx"}), "FAIL")
- self.assertEquals(new_manifest.get_test(test_id).children[0].get(
- "expected", {"debug": True, "os": "osx"}), "TIMEOUT")
-
- @pytest.mark.xfail
- def test_update_ignore_existing(self):
- test_id = "/path/to/test.htm"
- prev_data = [("path/to/test.htm.ini", [test_id], """[test.htm]
- type: testharness
- [test1]
- expected:
- if debug: TIMEOUT
- if not debug and os == "osx": NOTRUN""")]
-
- new_data_0 = self.create_log(("test_start", {"test": test_id}),
- ("test_status", {"test": test_id,
- "subtest": "test1",
- "status": "FAIL",
- "expected": "PASS"}),
- ("test_end", {"test": test_id,
- "status": "OK"}),
- run_info={"debug": False, "os": "linux"})
-
- new_data_1 = self.create_log(("test_start", {"test": test_id}),
- ("test_status", {"test": test_id,
- "subtest": "test1",
- "status": "FAIL",
- "expected": "PASS"}),
- ("test_end", {"test": test_id,
- "status": "OK"}),
- run_info={"debug": True, "os": "windows"})
- updater = self.create_updater(prev_data, ignore_existing=True)
-
- updater.update_from_log(new_data_0)
- updater.update_from_log(new_data_1)
-
- new_manifest = updater.expected_tree["path/to/test.htm.ini"]
-
- self.coalesce_results([new_manifest])
-
- self.assertFalse(new_manifest.is_empty)
- self.assertEquals(new_manifest.get_test(test_id).children[0].get(
- "expected", {"debug": True, "os": "osx"}), "FAIL")
- self.assertEquals(new_manifest.get_test(test_id).children[0].get(
- "expected", {"debug": False, "os": "osx"}), "FAIL")
diff --git a/tests/wpt/harness/wptrunner/update/__init__.py b/tests/wpt/harness/wptrunner/update/__init__.py
deleted file mode 100644
index 84c19fd949c..00000000000
--- a/tests/wpt/harness/wptrunner/update/__init__.py
+++ /dev/null
@@ -1,51 +0,0 @@
-# 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.structured import structuredlog, commandline
-
-from .. import wptcommandline
-
-from update import WPTUpdate
-
-def remove_logging_args(args):
- """Take logging args out of the dictionary of command line arguments so
- they are not passed in as kwargs to the update code. This is particularly
- necessary here because the arguments are often of type file, which cannot
- be serialized.
-
- :param args: Dictionary of command line arguments.
- """
- for name in args.keys():
- if name.startswith("log_"):
- args.pop(name)
-
-
-def setup_logging(args, defaults):
- """Use the command line arguments to set up the logger.
-
- :param args: Dictionary of command line arguments.
- :param defaults: Dictionary of {formatter_name: stream} to use if
- no command line logging is specified"""
- logger = commandline.setup_logging("web-platform-tests-update", args, defaults)
-
- remove_logging_args(args)
-
- return logger
-
-
-def run_update(logger, **kwargs):
- updater = WPTUpdate(logger, **kwargs)
- return updater.run()
-
-
-def main():
- args = wptcommandline.parse_args_update()
- logger = setup_logging(args, {"mach": sys.stdout})
- assert structuredlog.get_default_logger() is not None
- success = run_update(logger, **args)
- sys.exit(0 if success else 1)
-
diff --git a/tests/wpt/harness/wptrunner/update/base.py b/tests/wpt/harness/wptrunner/update/base.py
deleted file mode 100644
index 981ae2b7087..00000000000
--- a/tests/wpt/harness/wptrunner/update/base.py
+++ /dev/null
@@ -1,69 +0,0 @@
-# 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/.
-
-exit_unclean = object()
-exit_clean = object()
-
-
-class Step(object):
- provides = []
-
- def __init__(self, logger):
- self.logger = logger
-
- def run(self, step_index, state):
- """Base class for state-creating steps.
-
- When a Step is run() the current state is checked to see
- if the state from this step has already been created. If it
- has the restore() method is invoked. Otherwise the create()
- method is invoked with the state object. This is expected to
- add items with all the keys in __class__.provides to the state
- object.
- """
-
- name = self.__class__.__name__
-
- try:
- stored_step = state.steps[step_index]
- except IndexError:
- stored_step = None
-
- if stored_step == name:
- self.restore(state)
- elif stored_step is None:
- self.create(state)
- assert set(self.provides).issubset(set(state.keys()))
- state.steps = state.steps + [name]
- else:
- raise ValueError("Expected a %s step, got a %s step" % (name, stored_step))
-
- def create(self, data):
- raise NotImplementedError
-
- def restore(self, state):
- self.logger.debug("Step %s using stored state" % (self.__class__.__name__,))
- for key in self.provides:
- assert key in state
-
-
-class StepRunner(object):
- steps = []
-
- def __init__(self, logger, state):
- """Class that runs a specified series of Steps with a common State"""
- self.state = state
- self.logger = logger
- if "steps" not in state:
- state.steps = []
-
- def run(self):
- rv = None
- for step_index, step in enumerate(self.steps):
- self.logger.debug("Starting step %s" % step.__name__)
- rv = step(self.logger).run(step_index, self.state)
- if rv in (exit_clean, exit_unclean):
- break
-
- return rv
diff --git a/tests/wpt/harness/wptrunner/update/metadata.py b/tests/wpt/harness/wptrunner/update/metadata.py
deleted file mode 100644
index c62dfec465e..00000000000
--- a/tests/wpt/harness/wptrunner/update/metadata.py
+++ /dev/null
@@ -1,75 +0,0 @@
-# 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
-
-from .. import metadata, products
-
-from base import Step, StepRunner
-
-class GetUpdatePropertyList(Step):
- provides = ["property_order", "boolean_properties"]
-
-
- def create(self, state):
- property_order, boolean_properties = products.load_product_update(
- state.config, state.product)
- state.property_order = property_order
- state.boolean_properties = boolean_properties
-
-
-class UpdateExpected(Step):
- """Do the metadata update on the local checkout"""
-
- provides = ["needs_human"]
-
- def create(self, state):
- if state.sync_tree is not None:
- sync_root = state.sync_tree.root
- else:
- sync_root = None
-
- state.needs_human = metadata.update_expected(state.paths,
- state.serve_root,
- state.run_log,
- rev_old=None,
- ignore_existing=state.ignore_existing,
- sync_root=sync_root,
- property_order=state.property_order,
- boolean_properties=state.boolean_properties)
-
-
-class CreateMetadataPatch(Step):
- """Create a patch/commit for the metadata checkout"""
-
- def create(self, state):
- if state.no_patch:
- return
-
- local_tree = state.local_tree
- sync_tree = state.sync_tree
-
- if sync_tree is not None:
- name = "web-platform-tests_update_%s_metadata" % sync_tree.rev
- message = "Update %s expected data to revision %s" % (state.suite_name, sync_tree.rev)
- else:
- name = "web-platform-tests_update_metadata"
- message = "Update %s expected data" % state.suite_name
-
- local_tree.create_patch(name, message)
-
- if not local_tree.is_clean:
- metadata_paths = [manifest_path["metadata_path"]
- for manifest_path in state.paths.itervalues()]
- for path in metadata_paths:
- local_tree.add_new(os.path.relpath(path, local_tree.root))
- local_tree.update_patch(include=metadata_paths)
- local_tree.commit_patch()
-
-
-class MetadataUpdateRunner(StepRunner):
- """(Sub)Runner for updating metadata"""
- steps = [GetUpdatePropertyList,
- UpdateExpected,
- CreateMetadataPatch]
diff --git a/tests/wpt/harness/wptrunner/update/state.py b/tests/wpt/harness/wptrunner/update/state.py
deleted file mode 100644
index 1d95cac5a1b..00000000000
--- a/tests/wpt/harness/wptrunner/update/state.py
+++ /dev/null
@@ -1,137 +0,0 @@
-# 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 cPickle as pickle
-
-here = os.path.abspath(os.path.split(__file__)[0])
-
-class State(object):
- filename = os.path.join(here, ".wpt-update.lock")
-
- def __new__(cls, logger):
- rv = cls.load(logger)
- if rv is not None:
- logger.debug("Existing state found")
- return rv
-
- logger.debug("No existing state found")
- return object.__new__(cls, logger)
-
- def __init__(self, logger):
- """Object containing state variables created when running Steps.
-
- On write the state is serialized to disk, such that it can be restored in
- the event that the program is interrupted before all steps are complete.
- Note that this only works well if the values are immutable; mutating an
- existing value will not cause the data to be serialized.
-
- Variables are set and get as attributes e.g. state_obj.spam = "eggs".
-
- :param parent: Parent State object or None if this is the root object.
- """
-
- if hasattr(self, "_data"):
- return
-
- self._data = [{}]
- self._logger = logger
- self._index = 0
-
- def __getstate__(self):
- rv = self.__dict__.copy()
- del rv["_logger"]
- return rv
-
- @classmethod
- def load(cls, logger):
- """Load saved state from a file"""
- try:
- with open(cls.filename) as f:
- try:
- rv = pickle.load(f)
- logger.debug("Loading data %r" % (rv._data,))
- rv._logger = logger
- rv._index = 0
- return rv
- except EOFError:
- logger.warning("Found empty state file")
- except IOError:
- logger.debug("IOError loading stored state")
-
- def push(self, init_values):
- """Push a new clean state dictionary
-
- :param init_values: List of variable names in the current state dict to copy
- into the new state dict."""
-
- return StateContext(self, init_values)
-
- def save(self):
- """Write the state to disk"""
- with open(self.filename, "w") as f:
- pickle.dump(self, f)
-
- def is_empty(self):
- return len(self._data) == 1 and self._data[0] == {}
-
- def clear(self):
- """Remove all state and delete the stored copy."""
- try:
- os.unlink(self.filename)
- except OSError:
- pass
- self._data = [{}]
-
-
- def __setattr__(self, key, value):
- if key.startswith("_"):
- object.__setattr__(self, key, value)
- else:
- self._data[self._index][key] = value
- self.save()
-
- def __getattr__(self, key):
- if key.startswith("_"):
- raise AttributeError
- try:
- return self._data[self._index][key]
- except KeyError:
- raise AttributeError
-
- def __contains__(self, key):
- return key in self._data[self._index]
-
- def update(self, items):
- """Add a dictionary of {name: value} pairs to the state"""
- self._data[self._index].update(items)
- self.save()
-
- def keys(self):
- return self._data[self._index].keys()
-
-class StateContext(object):
- def __init__(self, state, init_values):
- self.state = state
- self.init_values = init_values
-
- def __enter__(self):
- if len(self.state._data) == self.state._index + 1:
- # This is the case where there is no stored state
- new_state = {}
- for key in self.init_values:
- new_state[key] = self.state._data[self.state._index][key]
- self.state._data.append(new_state)
- self.state._index += 1
- self.state._logger.debug("Incremented index to %s" % self.state._index)
-
- def __exit__(self, *args, **kwargs):
- if len(self.state._data) > 1:
- assert self.state._index == len(self.state._data) - 1
- self.state._data.pop()
- self.state._index -= 1
- self.state._logger.debug("Decremented index to %s" % self.state._index)
- assert self.state._index >= 0
- else:
- raise ValueError("Tried to pop the top state")
diff --git a/tests/wpt/harness/wptrunner/update/sync.py b/tests/wpt/harness/wptrunner/update/sync.py
deleted file mode 100644
index 8fa4544ac1d..00000000000
--- a/tests/wpt/harness/wptrunner/update/sync.py
+++ /dev/null
@@ -1,181 +0,0 @@
-# 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 shutil
-import sys
-import uuid
-
-from .. import testloader
-
-from base import Step, StepRunner
-from tree import Commit
-
-here = os.path.abspath(os.path.split(__file__)[0])
-
-bsd_license = """W3C 3-clause BSD License
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
-* Redistributions of works must retain the original copyright notice, this
- list of conditions and the following disclaimer.
-
-* Redistributions in binary form must reproduce the original copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
-* Neither the name of the W3C nor the names of its contributors may be
- used to endorse or promote products derived from this work without
- specific prior written permission.
-
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
-"""
-
-
-def copy_wpt_tree(tree, dest):
- """Copy the working copy of a Tree to a destination directory.
-
- :param tree: The Tree to copy.
- :param dest: The destination directory"""
- if os.path.exists(dest):
- assert os.path.isdir(dest)
-
- shutil.rmtree(dest)
- os.mkdir(dest)
-
- for tree_path in tree.paths():
- source_path = os.path.join(tree.root, tree_path)
- dest_path = os.path.join(dest, tree_path)
-
- dest_dir = os.path.split(dest_path)[0]
- if not os.path.isdir(source_path):
- if not os.path.exists(dest_dir):
- os.makedirs(dest_dir)
- shutil.copy2(source_path, dest_path)
-
- for source, destination in [("testharness_runner.html", ""),
- ("testharnessreport.js", "resources/")]:
- source_path = os.path.join(here, os.pardir, source)
- dest_path = os.path.join(dest, destination, os.path.split(source)[1])
- shutil.copy2(source_path, dest_path)
-
- add_license(dest)
-
-
-def add_license(dest):
- """Write the bsd license string to a LICENSE file.
-
- :param dest: Directory in which to place the LICENSE file."""
- with open(os.path.join(dest, "LICENSE"), "w") as f:
- f.write(bsd_license)
-
-class UpdateCheckout(Step):
- """Pull changes from upstream into the local sync tree."""
-
- provides = ["local_branch"]
-
- def create(self, state):
- sync_tree = state.sync_tree
- state.local_branch = uuid.uuid4().hex
- sync_tree.update(state.sync["remote_url"],
- state.sync["branch"],
- state.local_branch)
- sync_path = os.path.abspath(sync_tree.root)
- if not sync_path in sys.path:
- from update import setup_paths
- setup_paths(sync_path)
-
- def restore(self, state):
- assert os.path.abspath(state.sync_tree.root) in sys.path
- Step.restore(self, state)
-
-
-class GetSyncTargetCommit(Step):
- """Find the commit that we will sync to."""
-
- provides = ["sync_commit"]
-
- def create(self, state):
- if state.target_rev is None:
- #Use upstream branch HEAD as the base commit
- state.sync_commit = state.sync_tree.get_remote_sha1(state.sync["remote_url"],
- state.sync["branch"])
- else:
- state.sync_commit = Commit(state.sync_tree, state.rev)
-
- state.sync_tree.checkout(state.sync_commit.sha1, state.local_branch, force=True)
- self.logger.debug("New base commit is %s" % state.sync_commit.sha1)
-
-
-class LoadManifest(Step):
- """Load the test manifest"""
-
- provides = ["manifest_path", "test_manifest"]
-
- def create(self, state):
- from manifest import manifest
- state.manifest_path = os.path.join(state.metadata_path, "MANIFEST.json")
- state.test_manifest = manifest.Manifest("/")
-
-
-class UpdateManifest(Step):
- """Update the manifest to match the tests in the sync tree checkout"""
-
- def create(self, state):
- from manifest import manifest, update
- update.update(state.sync["path"], state.test_manifest)
- manifest.write(state.test_manifest, state.manifest_path)
-
-
-class CopyWorkTree(Step):
- """Copy the sync tree over to the destination in the local tree"""
-
- def create(self, state):
- copy_wpt_tree(state.sync_tree,
- state.tests_path)
-
-
-class CreateSyncPatch(Step):
- """Add the updated test files to a commit/patch in the local tree."""
-
- def create(self, state):
- if state.no_patch:
- return
-
- local_tree = state.local_tree
- sync_tree = state.sync_tree
-
- local_tree.create_patch("web-platform-tests_update_%s" % sync_tree.rev,
- "Update %s to revision %s" % (state.suite_name, sync_tree.rev))
- local_tree.add_new(os.path.relpath(state.tests_path,
- local_tree.root))
- updated = local_tree.update_patch(include=[state.tests_path,
- state.metadata_path])
- local_tree.commit_patch()
-
- if not updated:
- self.logger.info("Nothing to sync")
-
-
-class SyncFromUpstreamRunner(StepRunner):
- """(Sub)Runner for doing an upstream sync"""
- steps = [UpdateCheckout,
- GetSyncTargetCommit,
- LoadManifest,
- UpdateManifest,
- CopyWorkTree,
- CreateSyncPatch]
diff --git a/tests/wpt/harness/wptrunner/update/tree.py b/tests/wpt/harness/wptrunner/update/tree.py
deleted file mode 100644
index 05b35c24674..00000000000
--- a/tests/wpt/harness/wptrunner/update/tree.py
+++ /dev/null
@@ -1,387 +0,0 @@
-# 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 re
-import subprocess
-
-from .. import vcs
-from ..vcs import bind_to_repo, git, hg
-
-
-def get_unique_name(existing, initial):
- """Get a name either equal to initial or of the form initial_N, for some
- integer N, that is not in the set existing.
-
-
- :param existing: Set of names that must not be chosen.
- :param initial: Name, or name prefix, to use"""
- if initial not in existing:
- return initial
- for i in xrange(len(existing) + 1):
- test = "%s_%s" % (initial, i + 1)
- if test not in existing:
- return test
- assert False
-
-class NoVCSTree(object):
- name = "non-vcs"
-
- def __init__(self, root=None):
- if root is None:
- root = os.path.abspath(os.curdir)
- self.root = root
-
- @classmethod
- def is_type(cls, path=None):
- return True
-
- @property
- def is_clean(self):
- return True
-
- def add_new(self, prefix=None):
- pass
-
- def create_patch(self, patch_name, message):
- pass
-
- def update_patch(self, include=None):
- pass
-
- def commit_patch(self):
- pass
-
-
-class HgTree(object):
- name = "mercurial"
-
- def __init__(self, root=None):
- if root is None:
- root = hg("root").strip()
- self.root = root
- self.hg = vcs.bind_to_repo(hg, self.root)
-
- def __getstate__(self):
- rv = self.__dict__.copy()
- del rv['hg']
- return rv
-
- def __setstate__(self, dict):
- self.__dict__.update(dict)
- self.hg = vcs.bind_to_repo(vcs.hg, self.root)
-
- @classmethod
- def is_type(cls, path=None):
- kwargs = {"log_error": False}
- if path is not None:
- kwargs["repo"] = path
- try:
- hg("root", **kwargs)
- except:
- return False
- return True
-
- @property
- def is_clean(self):
- return self.hg("status").strip() == ""
-
- def add_new(self, prefix=None):
- if prefix is not None:
- args = ("-I", prefix)
- else:
- args = ()
- self.hg("add", *args)
-
- def create_patch(self, patch_name, message):
- try:
- self.hg("qinit", log_error=False)
- except subprocess.CalledProcessError:
- pass
-
- patch_names = [item.strip() for item in self.hg("qseries").split("\n") if item.strip()]
-
- suffix = 0
- test_name = patch_name
- while test_name in patch_names:
- suffix += 1
- test_name = "%s-%i" % (patch_name, suffix)
-
- self.hg("qnew", test_name, "-X", self.root, "-m", message)
-
- def update_patch(self, include=None):
- if include is not None:
- args = []
- for item in include:
- args.extend(["-I", item])
- else:
- args = ()
-
- self.hg("qrefresh", *args)
- return True
-
- def commit_patch(self):
- self.hg("qfinish")
-
- def contains_commit(self, commit):
- try:
- self.hg("identify", "-r", commit.sha1)
- return True
- except subprocess.CalledProcessError:
- return False
-
-
-class GitTree(object):
- name = "git"
-
- def __init__(self, root=None):
- if root is None:
- root = git("rev-parse", "--show-toplevel").strip()
- self.root = root
- self.git = vcs.bind_to_repo(git, self.root)
- self.message = None
- self.commit_cls = Commit
-
- def __getstate__(self):
- rv = self.__dict__.copy()
- del rv['git']
- return rv
-
- def __setstate__(self, dict):
- self.__dict__.update(dict)
- self.git = vcs.bind_to_repo(vcs.git, self.root)
-
- @classmethod
- def is_type(cls, path=None):
- kwargs = {"log_error": False}
- if path is not None:
- kwargs["repo"] = path
- try:
- git("rev-parse", "--show-toplevel", **kwargs)
- except:
- return False
- return True
-
- @property
- def rev(self):
- """Current HEAD revision"""
- if vcs.is_git_root(self.root):
- return self.git("rev-parse", "HEAD").strip()
- else:
- return None
-
- @property
- def is_clean(self):
- return self.git("status").strip() == ""
-
- def add_new(self, prefix=None):
- """Add files to the staging area.
-
- :param prefix: None to include all files or a path prefix to
- add all files under that path.
- """
- if prefix is None:
- args = ("-a",)
- else:
- args = ("--no-ignore-removal", prefix)
- self.git("add", *args)
-
- def list_refs(self, ref_filter=None):
- """Get a list of sha1, name tuples for references in a repository.
-
- :param ref_filter: Pattern that reference name must match (from the end,
- matching whole /-delimited segments only
- """
- args = []
- if ref_filter is not None:
- args.append(ref_filter)
- data = self.git("show-ref", *args)
- rv = []
- for line in data.split("\n"):
- if not line.strip():
- continue
- sha1, ref = line.split()
- rv.append((sha1, ref))
- return rv
-
- def list_remote(self, remote, ref_filter=None):
- """Return a list of (sha1, name) tupes for references in a remote.
-
- :param remote: URL of the remote to list.
- :param ref_filter: Pattern that the reference name must match.
- """
- args = []
- if ref_filter is not None:
- args.append(ref_filter)
- data = self.git("ls-remote", remote, *args)
- rv = []
- for line in data.split("\n"):
- if not line.strip():
- continue
- sha1, ref = line.split()
- rv.append((sha1, ref))
- return rv
-
- def get_remote_sha1(self, remote, branch):
- """Return the SHA1 of a particular branch in a remote.
-
- :param remote: the remote URL
- :param branch: the branch name"""
- for sha1, ref in self.list_remote(remote, branch):
- if ref == "refs/heads/%s" % branch:
- return self.commit_cls(self, sha1)
- assert False
-
- def create_patch(self, patch_name, message):
- # In git a patch is actually a commit
- self.message = message
-
- def update_patch(self, include=None):
- """Commit the staged changes, or changes to listed files.
-
- :param include: Either None, to commit staged changes, or a list
- of filenames (which must already be in the repo)
- to commit
- """
- if include is not None:
- args = tuple(include)
- else:
- args = ()
-
- if self.git("status", "-uno", "-z", *args).strip():
- self.git("add", *args)
- return True
- return False
-
- def commit_patch(self):
- assert self.message is not None
-
- if self.git("diff", "--name-only", "--staged", "-z").strip():
- self.git("commit", "-m", self.message)
- return True
-
- return False
-
- def init(self):
- self.git("init")
- assert vcs.is_git_root(self.root)
-
- def checkout(self, rev, branch=None, force=False):
- """Checkout a particular revision, optionally into a named branch.
-
- :param rev: Revision identifier (e.g. SHA1) to checkout
- :param branch: Branch name to use
- :param force: Force-checkout
- """
- assert rev is not None
-
- args = []
- if branch:
- branches = [ref[len("refs/heads/"):] for sha1, ref in self.list_refs()
- if ref.startswith("refs/heads/")]
- branch = get_unique_name(branches, branch)
-
- args += ["-b", branch]
-
- if force:
- args.append("-f")
- args.append(rev)
- self.git("checkout", *args)
-
- def update(self, remote, remote_branch, local_branch):
- """Fetch from the remote and checkout into a local branch.
-
- :param remote: URL to the remote repository
- :param remote_branch: Branch on the remote repository to check out
- :param local_branch: Local branch name to check out into
- """
- if not vcs.is_git_root(self.root):
- self.init()
- self.git("clean", "-xdf")
- self.git("fetch", remote, "%s:%s" % (remote_branch, local_branch))
- self.checkout(local_branch)
- self.git("submodule", "update", "--init", "--recursive")
-
- def clean(self):
- self.git("checkout", self.rev)
- self.git("branch", "-D", self.local_branch)
-
- def paths(self):
- """List paths in the tree"""
- repo_paths = [self.root] + [os.path.join(self.root, path)
- for path in self.submodules()]
-
- rv = []
-
- for repo_path in repo_paths:
- paths = vcs.git("ls-tree", "-r", "--name-only", "HEAD", repo=repo_path).split("\n")
- rel_path = os.path.relpath(repo_path, self.root)
- rv.extend(os.path.join(rel_path, item.strip()) for item in paths if item.strip())
-
- return rv
-
- def submodules(self):
- """List submodule directories"""
- output = self.git("submodule", "status", "--recursive")
- rv = []
- for line in output.split("\n"):
- line = line.strip()
- if not line:
- continue
- parts = line.split(" ")
- rv.append(parts[1])
- return rv
-
- def contains_commit(self, commit):
- try:
- self.git("rev-parse", "--verify", commit.sha1)
- return True
- except subprocess.CalledProcessError:
- return False
-
-
-class CommitMessage(object):
- def __init__(self, text):
- self.text = text
- self._parse_message()
-
- def __str__(self):
- return self.text
-
- def _parse_message(self):
- lines = self.text.splitlines()
- self.full_summary = lines[0]
- self.body = "\n".join(lines[1:])
-
-
-class Commit(object):
- msg_cls = CommitMessage
-
- _sha1_re = re.compile("^[0-9a-f]{40}$")
-
- def __init__(self, tree, sha1):
- """Object representing a commit in a specific GitTree.
-
- :param tree: GitTree to which this commit belongs.
- :param sha1: Full sha1 string for the commit
- """
- assert self._sha1_re.match(sha1)
-
- self.tree = tree
- self.git = tree.git
- self.sha1 = sha1
- self.author, self.email, self.message = self._get_meta()
-
- def __getstate__(self):
- rv = self.__dict__.copy()
- del rv['git']
- return rv
-
- def __setstate__(self, dict):
- self.__dict__.update(dict)
- self.git = self.tree.git
-
- def _get_meta(self):
- author, email, message = self.git("show", "-s", "--format=format:%an\n%ae\n%B", self.sha1).split("\n", 2)
- return author, email, self.msg_cls(message)
diff --git a/tests/wpt/harness/wptrunner/update/update.py b/tests/wpt/harness/wptrunner/update/update.py
deleted file mode 100644
index 213622c2a1a..00000000000
--- a/tests/wpt/harness/wptrunner/update/update.py
+++ /dev/null
@@ -1,158 +0,0 @@
-# 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 metadata import MetadataUpdateRunner
-from sync import SyncFromUpstreamRunner
-from tree import GitTree, HgTree, NoVCSTree
-
-from .. import environment as env
-from base import Step, StepRunner, exit_clean, exit_unclean
-from state import State
-
-def setup_paths(sync_path):
- sys.path.insert(0, os.path.abspath(sync_path))
- from tools import localpaths
-
-class LoadConfig(Step):
- """Step for loading configuration from the ini file and kwargs."""
-
- provides = ["sync", "paths", "metadata_path", "tests_path"]
-
- def create(self, state):
- state.sync = {"remote_url": state.kwargs["remote_url"],
- "branch": state.kwargs["branch"],
- "path": state.kwargs["sync_path"]}
-
- state.paths = state.kwargs["test_paths"]
- state.tests_path = state.paths["/"]["tests_path"]
- state.metadata_path = state.paths["/"]["metadata_path"]
-
- assert state.tests_path.startswith("/")
-
-
-class LoadTrees(Step):
- """Step for creating a Tree for the local copy and a GitTree for the
- upstream sync."""
-
- provides = ["local_tree", "sync_tree"]
-
- def create(self, state):
- if os.path.exists(state.sync["path"]):
- sync_tree = GitTree(root=state.sync["path"])
- else:
- sync_tree = None
-
- if GitTree.is_type():
- local_tree = GitTree()
- elif HgTree.is_type():
- local_tree = HgTree()
- else:
- local_tree = NoVCSTree()
-
- state.update({"local_tree": local_tree,
- "sync_tree": sync_tree})
-
-
-class SyncFromUpstream(Step):
- """Step that synchronises a local copy of the code with upstream."""
-
- def create(self, state):
- if not state.kwargs["sync"]:
- return
-
- if not state.sync_tree:
- os.mkdir(state.sync["path"])
- state.sync_tree = GitTree(root=state.sync["path"])
-
- kwargs = state.kwargs
- with state.push(["sync", "paths", "metadata_path", "tests_path", "local_tree",
- "sync_tree"]):
- state.target_rev = kwargs["rev"]
- state.no_patch = kwargs["no_patch"]
- state.suite_name = kwargs["suite_name"]
- runner = SyncFromUpstreamRunner(self.logger, state)
- runner.run()
-
-
-class UpdateMetadata(Step):
- """Update the expectation metadata from a set of run logs"""
-
- def create(self, state):
- if not state.kwargs["run_log"]:
- return
-
- kwargs = state.kwargs
- with state.push(["local_tree", "sync_tree", "paths", "serve_root"]):
- state.run_log = kwargs["run_log"]
- state.ignore_existing = kwargs["ignore_existing"]
- state.no_patch = kwargs["no_patch"]
- state.suite_name = kwargs["suite_name"]
- state.product = kwargs["product"]
- state.config = kwargs["config"]
- runner = MetadataUpdateRunner(self.logger, state)
- runner.run()
-
-
-class UpdateRunner(StepRunner):
- """Runner for doing an overall update."""
- steps = [LoadConfig,
- LoadTrees,
- SyncFromUpstream,
- UpdateMetadata]
-
-
-class WPTUpdate(object):
- def __init__(self, logger, runner_cls=UpdateRunner, **kwargs):
- """Object that controls the running of a whole wptupdate.
-
- :param runner_cls: Runner subclass holding the overall list of
- steps to run.
- :param kwargs: Command line arguments
- """
- self.runner_cls = runner_cls
- self.serve_root = kwargs["test_paths"]["/"]["tests_path"]
-
- if not kwargs["sync"]:
- setup_paths(self.serve_root)
- else:
- if os.path.exists(kwargs["sync_path"]):
- # If the sync path doesn't exist we defer this until it does
- setup_paths(kwargs["sync_path"])
-
- self.state = State(logger)
- self.kwargs = kwargs
- self.logger = logger
-
- def run(self, **kwargs):
- if self.kwargs["abort"]:
- self.abort()
- return exit_clean
-
- if not self.kwargs["continue"] and not self.state.is_empty():
- self.logger.error("Found existing state. Run with --continue to resume or --abort to clear state")
- return exit_unclean
-
- if self.kwargs["continue"]:
- if self.state.is_empty():
- self.logger.error("No sync in progress?")
- return exit_clean
-
- self.kwargs = self.state.kwargs
- else:
- self.state.kwargs = self.kwargs
-
- self.state.serve_root = self.serve_root
-
- update_runner = self.runner_cls(self.logger, self.state)
- rv = update_runner.run()
- if rv in (exit_clean, None):
- self.state.clear()
-
- return rv
-
- def abort(self):
- self.state.clear()
diff --git a/tests/wpt/harness/wptrunner/vcs.py b/tests/wpt/harness/wptrunner/vcs.py
deleted file mode 100644
index 6dfb9d59277..00000000000
--- a/tests/wpt/harness/wptrunner/vcs.py
+++ /dev/null
@@ -1,53 +0,0 @@
-# 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 subprocess
-from functools import partial
-
-from mozlog import get_default_logger
-
-logger = None
-
-def vcs(bin_name):
- def inner(command, *args, **kwargs):
- global logger
-
- if logger is None:
- logger = get_default_logger("vcs")
-
- repo = kwargs.pop("repo", None)
- log_error = kwargs.pop("log_error", True)
- if kwargs:
- raise TypeError, kwargs
-
- args = list(args)
-
- proc_kwargs = {}
- if repo is not None:
- proc_kwargs["cwd"] = repo
-
- command_line = [bin_name, command] + args
- logger.debug(" ".join(command_line))
- try:
- return subprocess.check_output(command_line, stderr=subprocess.STDOUT, **proc_kwargs)
- except subprocess.CalledProcessError as e:
- if log_error:
- logger.error(e.output)
- raise
- return inner
-
-git = vcs("git")
-hg = vcs("hg")
-
-
-def bind_to_repo(vcs_func, repo):
- return partial(vcs_func, repo=repo)
-
-
-def is_git_root(path):
- try:
- rv = git("rev-parse", "--show-cdup", repo=path)
- except subprocess.CalledProcessError:
- return False
- return rv == "\n"
diff --git a/tests/wpt/harness/wptrunner/webdriver_server.py b/tests/wpt/harness/wptrunner/webdriver_server.py
deleted file mode 100644
index 3b2b095a4a5..00000000000
--- a/tests/wpt/harness/wptrunner/webdriver_server.py
+++ /dev/null
@@ -1,238 +0,0 @@
-# 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 abc
-import errno
-import os
-import platform
-import socket
-import threading
-import time
-import traceback
-import urlparse
-
-import mozprocess
-
-
-__all__ = ["SeleniumServer", "ChromeDriverServer",
- "GeckoDriverServer", "ServoDriverServer",
- "WebDriverServer"]
-
-
-class WebDriverServer(object):
- __metaclass__ = abc.ABCMeta
-
- default_base_path = "/"
- _used_ports = set()
-
- def __init__(self, logger, binary, host="127.0.0.1", port=None,
- base_path="", env=None):
- self.logger = logger
- self.binary = binary
- self.host = host
- if base_path == "":
- self.base_path = self.default_base_path
- else:
- self.base_path = base_path
- self.env = os.environ.copy() if env is None else env
-
- self._port = port
- self._cmd = None
- self._proc = None
-
- @abc.abstractmethod
- def make_command(self):
- """Returns the full command for starting the server process as a list."""
-
- def start(self, block=False):
- try:
- self._run(block)
- except KeyboardInterrupt:
- self.stop()
-
- def _run(self, block):
- self._cmd = self.make_command()
- self._proc = mozprocess.ProcessHandler(
- self._cmd,
- processOutputLine=self.on_output,
- env=self.env,
- storeOutput=False)
-
- try:
- self._proc.run()
- except OSError as e:
- if e.errno == errno.ENOENT:
- raise IOError(
- "WebDriver HTTP server executable not found: %s" % self.binary)
- raise
-
- self.logger.debug(
- "Waiting for server to become accessible: %s" % self.url)
- try:
- wait_for_service((self.host, self.port))
- except:
- self.logger.error(
- "WebDriver HTTP server was not accessible "
- "within the timeout:\n%s" % traceback.format_exc())
- raise
-
- if block:
- self._proc.wait()
-
- def stop(self):
- if self.is_alive:
- return self._proc.kill()
- return not self.is_alive
-
- @property
- def is_alive(self):
- return hasattr(self._proc, "proc") and self._proc.poll() is None
-
- def on_output(self, line):
- self.logger.process_output(self.pid,
- line.decode("utf8", "replace"),
- command=" ".join(self._cmd))
-
- @property
- def pid(self):
- if self._proc is not None:
- return self._proc.pid
-
- @property
- def url(self):
- return "http://%s:%i%s" % (self.host, self.port, self.base_path)
-
- @property
- def port(self):
- if self._port is None:
- self._port = self._find_next_free_port()
- return self._port
-
- @staticmethod
- def _find_next_free_port():
- port = get_free_port(4444, exclude=WebDriverServer._used_ports)
- WebDriverServer._used_ports.add(port)
- return port
-
-
-class SeleniumServer(WebDriverServer):
- default_base_path = "/wd/hub"
-
- def make_command(self):
- return ["java", "-jar", self.binary, "-port", str(self.port)]
-
-
-class ChromeDriverServer(WebDriverServer):
- default_base_path = "/wd/hub"
-
- def __init__(self, logger, binary="chromedriver", port=None,
- base_path=""):
- WebDriverServer.__init__(
- self, logger, binary, port=port, base_path=base_path)
-
- 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 ""]
-
-
-class EdgeDriverServer(WebDriverServer):
- def __init__(self, logger, binary="MicrosoftWebDriver.exe", port=None,
- base_path="", host="localhost"):
- WebDriverServer.__init__(
- self, logger, binary, host=host, port=port)
-
- def make_command(self):
- return [self.binary,
- "--port=%s" % str(self.port)]
-
-
-class GeckoDriverServer(WebDriverServer):
- def __init__(self, logger, marionette_port=2828, binary="wires",
- host="127.0.0.1", port=None):
- env = os.environ.copy()
- env["RUST_BACKTRACE"] = "1"
- WebDriverServer.__init__(self, logger, binary, host=host, port=port, env=env)
- self.marionette_port = marionette_port
-
- def make_command(self):
- return [self.binary,
- "--connect-existing",
- "--marionette-port", str(self.marionette_port),
- "--host", self.host,
- "--port", str(self.port)]
-
-
-class ServoDriverServer(WebDriverServer):
- def __init__(self, logger, binary="servo", binary_args=None, host="127.0.0.1", port=None, render_backend=None):
- env = os.environ.copy()
- env["RUST_BACKTRACE"] = "1"
- WebDriverServer.__init__(self, logger, binary, host=host, port=port, env=env)
- self.binary_args = binary_args
- self.render_backend = render_backend
-
- def make_command(self):
- command = [self.binary,
- "--webdriver", str(self.port),
- "--hard-fail",
- "--headless"]
- if self.binary_args:
- command += self.binary_args
- if self.render_backend == "cpu":
- command += ["--cpu"]
- elif self.render_backend == "webrender":
- command += ["--webrender"]
- return command
-
-
-def cmd_arg(name, value=None):
- prefix = "-" if platform.system() == "Windows" else "--"
- rv = prefix + name
- if value is not None:
- rv += "=" + value
- return rv
-
-
-def get_free_port(start_port, exclude=None):
- """Get the first port number after start_port (inclusive) that is
- not currently bound.
-
- :param start_port: Integer port number at which to start testing.
- :param exclude: Set of port numbers to skip"""
- port = start_port
- while True:
- if exclude and port in exclude:
- port += 1
- continue
- s = socket.socket()
- try:
- s.bind(("127.0.0.1", port))
- except socket.error:
- port += 1
- else:
- return port
- finally:
- s.close()
-
-
-def wait_for_service(addr, timeout=15):
- """Waits until network service given as a tuple of (host, port) becomes
- available or the `timeout` duration is reached, at which point
- ``socket.error`` is raised."""
- end = time.time() + timeout
- while end > time.time():
- so = socket.socket()
- try:
- so.connect(addr)
- except socket.timeout:
- pass
- except socket.error as e:
- if e[0] != errno.ECONNREFUSED:
- raise
- else:
- return True
- finally:
- so.close()
- time.sleep(0.5)
- raise socket.error("Service is unavailable: %s:%i" % addr)
diff --git a/tests/wpt/harness/wptrunner/wptcommandline.py b/tests/wpt/harness/wptrunner/wptcommandline.py
deleted file mode 100644
index d7dd0534729..00000000000
--- a/tests/wpt/harness/wptrunner/wptcommandline.py
+++ /dev/null
@@ -1,427 +0,0 @@
-# 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 ast
-import os
-import sys
-from collections import OrderedDict
-from distutils.spawn import find_executable
-
-import config
-import wpttest
-
-
-def abs_path(path):
- return os.path.abspath(os.path.expanduser(path))
-
-
-def url_or_path(path):
- import urlparse
-
- parsed = urlparse.urlparse(path)
- if len(parsed.scheme) > 2:
- return path
- else:
- return abs_path(path)
-
-
-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]):
- print >> sys.stderr, "Missing required argument %s" % name
- sys.exit(1)
-
-
-def create_parser(product_choices=None):
- from mozlog import commandline
-
- import products
-
- if product_choices is None:
- config_data = config.load()
- product_choices = products.products_enabled(config_data)
-
- parser = argparse.ArgumentParser(description="""Runner for web-platform-tests tests.""",
- usage="""%(prog)s [OPTION]... [TEST]...
-
-TEST is either the full path to a test file to run, or the URL of a test excluding
-scheme host and port.""")
- parser.add_argument("--manifest-update", action="store_true", default=False,
- help="Regenerate the test manifest.")
-
- parser.add_argument("--timeout-multiplier", action="store", type=float, default=None,
- help="Multiplier relative to standard test timeout to use")
- parser.add_argument("--run-by-dir", type=int, nargs="?", default=False,
- help="Split run into groups by directories. With a parameter,"
- "limit the depth of splits e.g. --run-by-dir=1 to split by top-level"
- "directory")
- parser.add_argument("--processes", action="store", type=int, default=None,
- help="Number of simultaneous processes to use")
-
- parser.add_argument("--no-capture-stdio", action="store_true", default=False,
- help="Don't capture stdio and write to logging")
-
- mode_group = parser.add_argument_group("Mode")
- mode_group.add_argument("--list-test-groups", action="store_true",
- default=False,
- help="List the top level directories containing tests that will run.")
- mode_group.add_argument("--list-disabled", action="store_true",
- default=False,
- help="List the tests that are disabled on the current platform")
-
- test_selection_group = parser.add_argument_group("Test Selection")
- test_selection_group.add_argument("--test-types", action="store",
- nargs="*", default=wpttest.enabled_tests,
- choices=wpttest.enabled_tests,
- help="Test types to run")
- test_selection_group.add_argument("--include", action="append",
- help="URL prefix to include")
- test_selection_group.add_argument("--exclude", action="append",
- help="URL prefix to exclude")
- test_selection_group.add_argument("--include-manifest", type=abs_path,
- help="Path to manifest listing tests to include")
- 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.")
-
- debugging_group = parser.add_argument_group("Debugging")
- debugging_group.add_argument('--debugger', const="__default__", nargs="?",
- help="run under a debugger, e.g. gdb or valgrind")
- debugging_group.add_argument('--debugger-args', help="arguments to the debugger")
- debugging_group.add_argument("--repeat", action="store", type=int, default=1,
- help="Number of times to run the tests")
- debugging_group.add_argument("--repeat-until-unexpected", action="store_true", default=None,
- help="Run tests in a loop until one returns an unexpected result")
- debugging_group.add_argument('--pause-after-test', action="store_true", default=None,
- help="Halt the test runner after each test (this happens by default if only a single test is run)")
- debugging_group.add_argument('--no-pause-after-test', dest="pause_after_test", action="store_false",
- help="Don't halt the test runner irrespective of the number of tests run")
-
- debugging_group.add_argument('--pause-on-unexpected', action="store_true",
- help="Halt the test runner when an unexpected result is encountered")
- debugging_group.add_argument('--no-restart-on-unexpected', dest="restart_on_unexpected",
- default=True, action="store_false",
- help="Don't restart on an unexpected result")
-
- debugging_group.add_argument("--symbols-path", action="store", type=url_or_path,
- help="Path or url to symbols file used to analyse crash minidumps.")
- debugging_group.add_argument("--stackwalk-binary", action="store", type=abs_path,
- help="Path to stackwalker program used to analyse minidumps.")
-
- debugging_group.add_argument("--pdb", action="store_true",
- help="Drop into pdb on python exception")
-
- config_group = parser.add_argument_group("Configuration")
- config_group.add_argument("--binary", action="store",
- type=abs_path, help="Binary to run tests against")
- config_group.add_argument('--binary-arg',
- default=[], action="append", dest="binary_args",
- help="Extra argument for the binary (servo)")
- config_group.add_argument("--webdriver-binary", action="store", metavar="BINARY",
- type=abs_path, help="WebDriver server binary to use")
-
- config_group.add_argument("--metadata", action="store", type=abs_path, dest="metadata_root",
- help="Path to root directory containing test metadata"),
- config_group.add_argument("--tests", action="store", type=abs_path, dest="tests_root",
- help="Path to root directory containing test files"),
- config_group.add_argument("--run-info", action="store", type=abs_path,
- help="Path to directory containing extra json files to add to run info")
- config_group.add_argument("--product", action="store", choices=product_choices,
- default=None, help="Browser against which to run tests")
- config_group.add_argument("--config", action="store", type=abs_path, dest="config",
- help="Path to config file")
-
- build_type = parser.add_mutually_exclusive_group()
- build_type.add_argument("--debug-build", dest="debug", action="store_true",
- default=None,
- help="Build is a debug build (overrides any mozinfo file)")
- build_type.add_argument("--release-build", dest="debug", action="store_false",
- default=None,
- help="Build is a release (overrides any mozinfo file)")
-
-
- chunking_group = parser.add_argument_group("Test Chunking")
- chunking_group.add_argument("--total-chunks", action="store", type=int, default=1,
- help="Total number of chunks to use")
- chunking_group.add_argument("--this-chunk", action="store", type=int, default=1,
- help="Chunk number to run")
- chunking_group.add_argument("--chunk-type", action="store", choices=["none", "equal_time", "hash"],
- default=None, help="Chunking type to use")
-
- ssl_group = parser.add_argument_group("SSL/TLS")
- ssl_group.add_argument("--ssl-type", action="store", default=None,
- choices=["openssl", "pregenerated", "none"],
- help="Type of ssl support to enable (running without ssl may lead to spurious errors)")
-
- ssl_group.add_argument("--openssl-binary", action="store",
- help="Path to openssl binary", default="openssl")
- ssl_group.add_argument("--certutil-binary", action="store",
- help="Path to certutil binary for use with Firefox + ssl")
-
- ssl_group.add_argument("--ca-cert-path", action="store", type=abs_path,
- help="Path to ca certificate when using pregenerated ssl certificates")
- ssl_group.add_argument("--host-key-path", action="store", type=abs_path,
- help="Path to host private key when using pregenerated ssl certificates")
- ssl_group.add_argument("--host-cert-path", action="store", type=abs_path,
- help="Path to host certificate when using pregenerated ssl certificates")
-
- gecko_group = parser.add_argument_group("Gecko-specific")
- gecko_group.add_argument("--prefs-root", dest="prefs_root", action="store", type=abs_path,
- help="Path to the folder containing browser prefs")
- gecko_group.add_argument("--disable-e10s", dest="gecko_e10s", action="store_false", default=True,
- help="Run tests without electrolysis preferences")
-
- servo_group = parser.add_argument_group("Servo-specific")
- servo_group.add_argument("--user-stylesheet",
- default=[], action="append", dest="user_stylesheets",
- help="Inject a user CSS stylesheet into every test.")
- servo_group.add_argument("--servo-backend",
- default="webrender", choices=["cpu", "webrender"],
- help="Rendering backend to use with Servo.")
-
-
- parser.add_argument("test_list", nargs="*",
- help="List of URLs for tests to run, or paths including tests to run. "
- "(equivalent to --include)")
-
- commandline.add_logging_group(parser)
- return parser
-
-
-def set_from_config(kwargs):
- if kwargs["config"] is None:
- config_path = config.path()
- else:
- config_path = kwargs["config"]
-
- kwargs["config_path"] = config_path
-
- kwargs["config"] = config.read(kwargs["config_path"])
-
- keys = {"paths": [("prefs", "prefs_root", True),
- ("run_info", "run_info", True)],
- "web-platform-tests": [("remote_url", "remote_url", False),
- ("branch", "branch", False),
- ("sync_path", "sync_path", True)],
- "SSL": [("openssl_binary", "openssl_binary", True),
- ("certutil_binary", "certutil_binary", True),
- ("ca_cert_path", "ca_cert_path", True),
- ("host_cert_path", "host_cert_path", True),
- ("host_key_path", "host_key_path", True)]}
-
- for section, values in keys.iteritems():
- for config_value, kw_value, is_path in values:
- if kw_value in kwargs and kwargs[kw_value] is None:
- if not is_path:
- new_value = kwargs["config"].get(section, config.ConfigDict({})).get(config_value)
- else:
- new_value = kwargs["config"].get(section, config.ConfigDict({})).get_path(config_value)
- kwargs[kw_value] = new_value
-
- kwargs["test_paths"] = get_test_paths(kwargs["config"])
-
- if kwargs["tests_root"]:
- if "/" not in kwargs["test_paths"]:
- kwargs["test_paths"]["/"] = {}
- kwargs["test_paths"]["/"]["tests_path"] = kwargs["tests_root"]
-
- if kwargs["metadata_root"]:
- if "/" not in kwargs["test_paths"]:
- kwargs["test_paths"]["/"] = {}
- kwargs["test_paths"]["/"]["metadata_path"] = kwargs["metadata_root"]
-
- kwargs["suite_name"] = kwargs["config"].get("web-platform-tests", {}).get("name", "web-platform-tests")
-
-
-def get_test_paths(config):
- # Set up test_paths
- test_paths = OrderedDict()
-
- for section in config.iterkeys():
- if section.startswith("manifest:"):
- manifest_opts = config.get(section)
- url_base = manifest_opts.get("url_base", "/")
- test_paths[url_base] = {
- "tests_path": manifest_opts.get_path("tests"),
- "metadata_path": manifest_opts.get_path("metadata")}
-
- return test_paths
-
-
-def exe_path(name):
- if name is None:
- return
-
- path = find_executable(name)
- if path and os.access(path, os.X_OK):
- return path
- else:
- return None
-
-
-def check_args(kwargs):
- set_from_config(kwargs)
-
- for test_paths in kwargs["test_paths"].itervalues():
- if not ("tests_path" in test_paths and
- "metadata_path" in test_paths):
- print "Fatal: must specify both a test path and metadata path"
- sys.exit(1)
- for key, path in test_paths.iteritems():
- name = key.split("_", 1)[0]
-
- if not os.path.exists(path):
- print "Fatal: %s path %s does not exist" % (name, path)
- sys.exit(1)
-
- if not os.path.isdir(path):
- print "Fatal: %s path %s is not a directory" % (name, path)
- sys.exit(1)
-
- if kwargs["product"] is None:
- kwargs["product"] = "firefox"
-
- if kwargs["test_list"]:
- if kwargs["include"] is not None:
- kwargs["include"].extend(kwargs["test_list"])
- else:
- kwargs["include"] = kwargs["test_list"]
-
- if kwargs["run_info"] is None:
- kwargs["run_info"] = kwargs["config_path"]
-
- if kwargs["this_chunk"] > 1:
- require_arg(kwargs, "total_chunks", lambda x: x >= kwargs["this_chunk"])
-
- if kwargs["chunk_type"] is None:
- if kwargs["total_chunks"] > 1:
- kwargs["chunk_type"] = "equal_time"
- else:
- kwargs["chunk_type"] = "none"
-
- if kwargs["processes"] is None:
- kwargs["processes"] = 1
-
- if kwargs["debugger"] is not None:
- import mozdebug
- if kwargs["debugger"] == "__default__":
- kwargs["debugger"] = mozdebug.get_default_debugger_name()
- debug_info = mozdebug.get_debugger_info(kwargs["debugger"],
- kwargs["debugger_args"])
- if debug_info and debug_info.interactive:
- if kwargs["processes"] != 1:
- kwargs["processes"] = 1
- kwargs["no_capture_stdio"] = True
- kwargs["debug_info"] = debug_info
- else:
- kwargs["debug_info"] = None
-
- if kwargs["binary"] is not None:
- if not os.path.exists(kwargs["binary"]):
- print >> sys.stderr, "Binary path %s does not exist" % kwargs["binary"]
- sys.exit(1)
-
- if kwargs["ssl_type"] is None:
- if None not in (kwargs["ca_cert_path"], kwargs["host_cert_path"], kwargs["host_key_path"]):
- kwargs["ssl_type"] = "pregenerated"
- elif exe_path(kwargs["openssl_binary"]) is not None:
- kwargs["ssl_type"] = "openssl"
- else:
- kwargs["ssl_type"] = "none"
-
- if kwargs["ssl_type"] == "pregenerated":
- require_arg(kwargs, "ca_cert_path", lambda x:os.path.exists(x))
- require_arg(kwargs, "host_cert_path", lambda x:os.path.exists(x))
- require_arg(kwargs, "host_key_path", lambda x:os.path.exists(x))
-
- elif kwargs["ssl_type"] == "openssl":
- path = exe_path(kwargs["openssl_binary"])
- if path is None:
- print >> sys.stderr, "openssl-binary argument missing or not a valid executable"
- sys.exit(1)
- kwargs["openssl_binary"] = path
-
- if kwargs["ssl_type"] != "none" and kwargs["product"] == "firefox":
- path = exe_path(kwargs["certutil_binary"])
- if path is None:
- print >> sys.stderr, "certutil-binary argument missing or not a valid executable"
- sys.exit(1)
- kwargs["certutil_binary"] = path
-
- return kwargs
-
-
-def check_args_update(kwargs):
- set_from_config(kwargs)
-
- if kwargs["product"] is None:
- kwargs["product"] = "firefox"
-
-
-def create_parser_update(product_choices=None):
- from mozlog.structured import commandline
-
- import products
-
- if product_choices is None:
- config_data = config.load()
- product_choices = products.products_enabled(config_data)
-
- parser = argparse.ArgumentParser("web-platform-tests-update",
- description="Update script for web-platform-tests tests.")
- parser.add_argument("--product", action="store", choices=product_choices,
- default=None, help="Browser for which metadata is being updated")
- parser.add_argument("--config", action="store", type=abs_path, help="Path to config file")
- parser.add_argument("--metadata", action="store", type=abs_path, dest="metadata_root",
- help="Path to the folder containing test metadata"),
- parser.add_argument("--tests", action="store", type=abs_path, dest="tests_root",
- help="Path to web-platform-tests"),
- parser.add_argument("--sync-path", action="store", type=abs_path,
- help="Path to store git checkout of web-platform-tests during update"),
- parser.add_argument("--remote_url", action="store",
- help="URL of web-platfrom-tests repository to sync against"),
- parser.add_argument("--branch", action="store", type=abs_path,
- help="Remote branch to sync against")
- parser.add_argument("--rev", action="store", help="Revision to sync to")
- parser.add_argument("--no-patch", action="store_true",
- help="Don't create an mq patch or git commit containing the changes.")
- parser.add_argument("--sync", dest="sync", action="store_true", default=False,
- help="Sync the tests with the latest from upstream")
- 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("--continue", action="store_true", help="Continue a previously started run of the update script")
- parser.add_argument("--abort", action="store_true", help="Clear state from a previous incomplete run of the update script")
- # Should make this required iff run=logfile
- parser.add_argument("run_log", nargs="*", type=abs_path,
- help="Log file from run of tests")
- commandline.add_logging_group(parser)
- return parser
-
-
-def create_parser_reduce(product_choices=None):
- parser = create_parser(product_choices)
- parser.add_argument("target", action="store", help="Test id that is unstable")
- return parser
-
-
-def parse_args():
- parser = create_parser()
- rv = vars(parser.parse_args())
- check_args(rv)
- return rv
-
-
-def parse_args_update():
- parser = create_parser_update()
- rv = vars(parser.parse_args())
- check_args_update(rv)
- return rv
-
-
-def parse_args_reduce():
- parser = create_parser_reduce()
- rv = vars(parser.parse_args())
- check_args(rv)
- return rv
diff --git a/tests/wpt/harness/wptrunner/wptlogging.py b/tests/wpt/harness/wptrunner/wptlogging.py
deleted file mode 100644
index 047e025fad1..00000000000
--- a/tests/wpt/harness/wptrunner/wptlogging.py
+++ /dev/null
@@ -1,125 +0,0 @@
-# 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 logging
-import sys
-import threading
-from StringIO import StringIO
-from multiprocessing import Queue
-
-from mozlog import commandline, stdadapter
-
-def setup(args, defaults):
- logger = commandline.setup_logging("web-platform-tests", args, defaults)
- setup_stdlib_logger()
-
- for name in args.keys():
- if name.startswith("log_"):
- args.pop(name)
-
- return logger
-
-
-def setup_stdlib_logger():
- logging.root.handlers = []
- logging.root = stdadapter.std_logging_adapter(logging.root)
-
-
-class LogLevelRewriter(object):
- """Filter that replaces log messages at specified levels with messages
- at a different level.
-
- This can be used to e.g. downgrade log messages from ERROR to WARNING
- in some component where ERRORs are not critical.
-
- :param inner: Handler to use for messages that pass this filter
- :param from_levels: List of levels which should be affected
- :param to_level: Log level to set for the affected messages
- """
- def __init__(self, inner, from_levels, to_level):
- self.inner = inner
- self.from_levels = [item.upper() for item in from_levels]
- self.to_level = to_level.upper()
-
- def __call__(self, data):
- if data["action"] == "log" and data["level"].upper() in self.from_levels:
- data = data.copy()
- data["level"] = self.to_level
- return self.inner(data)
-
-
-
-class LogThread(threading.Thread):
- def __init__(self, queue, logger, level):
- self.queue = queue
- self.log_func = getattr(logger, level)
- threading.Thread.__init__(self, name="Thread-Log")
- self.daemon = True
-
- def run(self):
- while True:
- try:
- msg = self.queue.get()
- except (EOFError, IOError):
- break
- if msg is None:
- break
- else:
- self.log_func(msg)
-
-
-class LoggingWrapper(StringIO):
- """Wrapper for file like objects to redirect output to logger
- instead"""
-
- def __init__(self, queue, prefix=None):
- StringIO.__init__(self)
- self.queue = queue
- self.prefix = prefix
-
- def write(self, data):
- if isinstance(data, str):
- data = data.decode("utf8")
-
- if data.endswith("\n"):
- data = data[:-1]
- if data.endswith("\r"):
- data = data[:-1]
- if not data:
- return
- if self.prefix is not None:
- data = "%s: %s" % (self.prefix, data)
- self.queue.put(data)
-
- def flush(self):
- pass
-
-
-class CaptureIO(object):
- def __init__(self, logger, do_capture):
- self.logger = logger
- self.do_capture = do_capture
- self.logging_queue = None
- self.logging_thread = None
- self.original_stdio = None
-
- def __enter__(self):
- if self.do_capture:
- self.original_stdio = (sys.stdout, sys.stderr)
- self.logging_queue = Queue()
- self.logging_thread = LogThread(self.logging_queue, self.logger, "info")
- sys.stdout = LoggingWrapper(self.logging_queue, prefix="STDOUT")
- sys.stderr = LoggingWrapper(self.logging_queue, prefix="STDERR")
- self.logging_thread.start()
-
- def __exit__(self, *args, **kwargs):
- if self.do_capture:
- sys.stdout, sys.stderr = self.original_stdio
- if self.logging_queue is not None:
- self.logger.info("Closing logging queue")
- self.logging_queue.put(None)
- if self.logging_thread is not None:
- self.logging_thread.join(10)
- self.logging_queue.close()
- self.logger.info("queue closed")
diff --git a/tests/wpt/harness/wptrunner/wptmanifest/__init__.py b/tests/wpt/harness/wptrunner/wptmanifest/__init__.py
deleted file mode 100644
index 36544846779..00000000000
--- a/tests/wpt/harness/wptrunner/wptmanifest/__init__.py
+++ /dev/null
@@ -1,8 +0,0 @@
-# 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/.
-
-from serializer import serialize
-from parser import parse
-from backends.static import compile as compile_static
-from backends.conditional import compile as compile_condition
diff --git a/tests/wpt/harness/wptrunner/wptmanifest/backends/__init__.py b/tests/wpt/harness/wptrunner/wptmanifest/backends/__init__.py
deleted file mode 100644
index c580d191c1b..00000000000
--- a/tests/wpt/harness/wptrunner/wptmanifest/backends/__init__.py
+++ /dev/null
@@ -1,3 +0,0 @@
-# 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/.
diff --git a/tests/wpt/harness/wptrunner/wptmanifest/backends/conditional.py b/tests/wpt/harness/wptrunner/wptmanifest/backends/conditional.py
deleted file mode 100644
index f7921c67ad2..00000000000
--- a/tests/wpt/harness/wptrunner/wptmanifest/backends/conditional.py
+++ /dev/null
@@ -1,331 +0,0 @@
-# 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 operator
-
-from ..node import NodeVisitor, DataNode, ConditionalNode, KeyValueNode, ListNode, ValueNode
-from ..parser import parse
-
-
-class ConditionalValue(object):
- def __init__(self, node, condition_func):
- self.node = node
- self.condition_func = condition_func
- if isinstance(node, ConditionalNode):
- assert len(node.children) == 2
- self.condition_node = self.node.children[0]
- self.value_node = self.node.children[1]
- else:
- assert isinstance(node, (ValueNode, ListNode))
- self.condition_node = None
- self.value_node = self.node
-
- @property
- def value(self):
- if isinstance(self.value_node, ValueNode):
- return self.value_node.data
- else:
- return [item.data for item in self.value_node.children]
-
- @value.setter
- def value(self, value):
- self.value_node.data = value
-
- def __call__(self, run_info):
- return self.condition_func(run_info)
-
- def set_value(self, value):
- self.value = value
-
- def remove(self):
- if len(self.node.parent.children) == 1:
- self.node.parent.remove()
- self.node.remove()
-
-
-class Compiler(NodeVisitor):
- def compile(self, tree, data_cls_getter=None, **kwargs):
- """Compile a raw AST into a form where conditional expressions
- are represented by ConditionalValue objects that can be evaluated
- at runtime.
-
- tree - The root node of the wptmanifest AST to compile
-
- data_cls_getter - A function taking two parameters; the previous
- output node and the current ast node and returning
- the class of the output node to use for the current
- ast node
- """
- if data_cls_getter is None:
- self.data_cls_getter = lambda x, y: ManifestItem
- else:
- self.data_cls_getter = data_cls_getter
-
- self.tree = tree
- self.output_node = self._initial_output_node(tree, **kwargs)
- self.visit(tree)
- assert self.output_node is not None
- return self.output_node
-
- def compile_condition(self, condition):
- """Compile a ConditionalNode into a ConditionalValue.
-
- condition: A ConditionalNode"""
- data_node = DataNode()
- key_value_node = KeyValueNode()
- key_value_node.append(condition.copy())
- data_node.append(key_value_node)
- manifest_item = self.compile(data_node)
- return manifest_item._data[None][0]
-
- def _initial_output_node(self, node, **kwargs):
- return self.data_cls_getter(None, None)(node, **kwargs)
-
- def visit_DataNode(self, node):
- if node != self.tree:
- output_parent = self.output_node
- self.output_node = self.data_cls_getter(self.output_node, node)(node)
- else:
- output_parent = None
-
- assert self.output_node is not None
-
- for child in node.children:
- self.visit(child)
-
- if output_parent is not None:
- # Append to the parent *after* processing all the node data
- output_parent.append(self.output_node)
- self.output_node = self.output_node.parent
-
- assert self.output_node is not None
-
- def visit_KeyValueNode(self, node):
- key_values = []
- for child in node.children:
- condition, value = self.visit(child)
- key_values.append(ConditionalValue(child, condition))
-
- self.output_node._add_key_value(node, key_values)
-
- def visit_ListNode(self, node):
- return (lambda x:True, [self.visit(child) for child in node.children])
-
- def visit_ValueNode(self, node):
- return (lambda x: True, node.data)
-
- def visit_AtomNode(self, node):
- return (lambda x: True, node.data)
-
- def visit_ConditionalNode(self, node):
- return self.visit(node.children[0]), self.visit(node.children[1])
-
- def visit_StringNode(self, node):
- indexes = [self.visit(child) for child in node.children]
-
- def value(x):
- rv = node.data
- for index in indexes:
- rv = rv[index(x)]
- return rv
- return value
-
- def visit_NumberNode(self, node):
- if "." in node.data:
- return lambda x: float(node.data)
- else:
- return lambda x: int(node.data)
-
- def visit_VariableNode(self, node):
- indexes = [self.visit(child) for child in node.children]
-
- def value(x):
- data = x[node.data]
- for index in indexes:
- data = data[index(x)]
- return data
- return value
-
- def visit_IndexNode(self, node):
- assert len(node.children) == 1
- return self.visit(node.children[0])
-
- def visit_UnaryExpressionNode(self, node):
- assert len(node.children) == 2
- operator = self.visit(node.children[0])
- operand = self.visit(node.children[1])
-
- return lambda x: operator(operand(x))
-
- def visit_BinaryExpressionNode(self, node):
- assert len(node.children) == 3
- operator = self.visit(node.children[0])
- operand_0 = self.visit(node.children[1])
- operand_1 = self.visit(node.children[2])
-
- assert operand_0 is not None
- assert operand_1 is not None
-
- return lambda x: operator(operand_0(x), operand_1(x))
-
- def visit_UnaryOperatorNode(self, node):
- return {"not": operator.not_}[node.data]
-
- def visit_BinaryOperatorNode(self, node):
- return {"and": operator.and_,
- "or": operator.or_,
- "==": operator.eq,
- "!=": operator.ne}[node.data]
-
-
-class ManifestItem(object):
- def __init__(self, node=None, **kwargs):
- self.node = node
- self.parent = None
- self.children = []
- self._data = {}
-
- def __repr__(self):
- return "<ManifestItem %s>" % (self.node.data)
-
- def __str__(self):
- rv = [repr(self)]
- for item in self.children:
- rv.extend(" %s" % line for line in str(item).split("\n"))
- return "\n".join(rv)
-
- @property
- def is_empty(self):
- if self._data:
- return False
- return all(child.is_empty for child in self.children)
-
- @property
- def root(self):
- node = self
- while node.parent is not None:
- node = node.parent
- return node
-
- @property
- def name(self):
- return self.node.data
-
- def has_key(self, key):
- for node in [self, self.root]:
- if key in node._data:
- return True
- return False
-
- def get(self, key, run_info=None):
- if run_info is None:
- run_info = {}
-
- for node in [self, self.root]:
- if key in node._data:
- for cond_value in node._data[key]:
- try:
- matches = cond_value(run_info)
- except KeyError:
- matches = False
- if matches:
- return cond_value.value
- raise KeyError
-
- def set(self, key, value, condition=None):
- # First try to update the existing value
- if key in self._data:
- cond_values = self._data[key]
- for cond_value in cond_values:
- if cond_value.condition_node == condition:
- cond_value.value = value
- return
- # If there isn't a conditional match reuse the existing KeyValueNode as the
- # parent
- node = None
- for child in self.node.children:
- if child.data == key:
- node = child
- break
- assert node is not None
-
- else:
- node = KeyValueNode(key)
- self.node.append(node)
-
- value_node = ValueNode(value)
- if condition is not None:
- conditional_node = ConditionalNode()
- conditional_node.append(condition)
- conditional_node.append(value_node)
- node.append(conditional_node)
- cond_value = Compiler().compile_condition(conditional_node)
- else:
- node.append(value_node)
- cond_value = ConditionalValue(value_node, lambda x: True)
-
- # Update the cache of child values. This is pretty annoying and maybe
- # it should just work directly on the tree
- if key not in self._data:
- self._data[key] = []
- if self._data[key] and self._data[key][-1].condition_node is None:
- self._data[key].insert(len(self._data[key]) - 1, cond_value)
- else:
- self._data[key].append(cond_value)
-
- def _add_key_value(self, node, values):
- """Called during construction to set a key-value node"""
- self._data[node.data] = values
-
- def append(self, child):
- self.children.append(child)
- child.parent = self
- if child.node.parent != self.node:
- self.node.append(child.node)
- return child
-
- def remove(self):
- if self.parent:
- self.parent._remove_child(self)
-
- def _remove_child(self, child):
- self.children.remove(child)
- child.parent = None
-
- def iterchildren(self, name=None):
- for item in self.children:
- if item.name == name or name is None:
- yield item
-
- def _flatten(self):
- rv = {}
- for node in [self, self.root]:
- for name, value in node._data.iteritems():
- if name not in rv:
- rv[name] = value
- return rv
-
- def iteritems(self):
- for item in self._flatten().iteritems():
- yield item
-
- def iterkeys(self):
- for item in self._flatten().iterkeys():
- yield item
-
- def remove_value(self, key, value):
- self._data[key].remove(value)
- if not self._data[key]:
- del self._data[key]
- value.remove()
-
-
-def compile_ast(ast, data_cls_getter=None, **kwargs):
- return Compiler().compile(ast, data_cls_getter=data_cls_getter, **kwargs)
-
-
-def compile(stream, data_cls_getter=None, **kwargs):
- return compile_ast(parse(stream),
- data_cls_getter=data_cls_getter,
- **kwargs)
diff --git a/tests/wpt/harness/wptrunner/wptmanifest/backends/static.py b/tests/wpt/harness/wptrunner/wptmanifest/backends/static.py
deleted file mode 100644
index 7221fce7246..00000000000
--- a/tests/wpt/harness/wptrunner/wptmanifest/backends/static.py
+++ /dev/null
@@ -1,224 +0,0 @@
-# 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 operator
-
-from ..node import NodeVisitor
-from ..parser import parse
-
-
-class Compiler(NodeVisitor):
- """Compiler backend that evaluates conditional expressions
- to give static output"""
-
- def compile(self, tree, expr_data, data_cls_getter=None, **kwargs):
- """Compile a raw AST into a form with conditional expressions
- evaluated.
-
- tree - The root node of the wptmanifest AST to compile
-
- expr_data - A dictionary of key / value pairs to use when
- evaluating conditional expressions
-
- data_cls_getter - A function taking two parameters; the previous
- output node and the current ast node and returning
- the class of the output node to use for the current
- ast node
- """
-
- self._kwargs = kwargs
- self.expr_data = expr_data
-
- if data_cls_getter is None:
- self.data_cls_getter = lambda x, y: ManifestItem
- else:
- self.data_cls_getter = data_cls_getter
-
- self.output_node = None
- self.visit(tree)
- return self.output_node
-
- def visit_DataNode(self, node):
- output_parent = self.output_node
- if self.output_node is None:
- assert node.parent is None
- self.output_node = self.data_cls_getter(None, None)(None, **self._kwargs)
- else:
- self.output_node = self.data_cls_getter(self.output_node, node)(node.data)
-
- for child in node.children:
- self.visit(child)
-
- if output_parent is not None:
- output_parent.append(self.output_node)
- self.output_node = self.output_node.parent
-
- def visit_KeyValueNode(self, node):
- key_name = node.data
- key_value = None
- for child in node.children:
- value = self.visit(child)
- if value is not None:
- key_value = value
- break
- if key_value is not None:
- self.output_node.set(key_name, key_value)
-
- def visit_ValueNode(self, node):
- return node.data
-
- def visit_AtomNode(self, node):
- return node.data
-
- def visit_ListNode(self, node):
- return [self.visit(child) for child in node.children]
-
- def visit_ConditionalNode(self, node):
- assert len(node.children) == 2
- if self.visit(node.children[0]):
- return self.visit(node.children[1])
-
- def visit_StringNode(self, node):
- value = node.data
- for child in node.children:
- value = self.visit(child)(value)
- return value
-
- def visit_NumberNode(self, node):
- if "." in node.data:
- return float(node.data)
- else:
- return int(node.data)
-
- def visit_VariableNode(self, node):
- value = self.expr_data[node.data]
- for child in node.children:
- value = self.visit(child)(value)
- return value
-
- def visit_IndexNode(self, node):
- assert len(node.children) == 1
- index = self.visit(node.children[0])
- return lambda x: x[index]
-
- def visit_UnaryExpressionNode(self, node):
- assert len(node.children) == 2
- operator = self.visit(node.children[0])
- operand = self.visit(node.children[1])
-
- return operator(operand)
-
- def visit_BinaryExpressionNode(self, node):
- assert len(node.children) == 3
- operator = self.visit(node.children[0])
- operand_0 = self.visit(node.children[1])
- operand_1 = self.visit(node.children[2])
-
- return operator(operand_0, operand_1)
-
- def visit_UnaryOperatorNode(self, node):
- return {"not": operator.not_}[node.data]
-
- def visit_BinaryOperatorNode(self, node):
- return {"and": operator.and_,
- "or": operator.or_,
- "==": operator.eq,
- "!=": operator.ne}[node.data]
-
-
-class ManifestItem(object):
- def __init__(self, name, **kwargs):
- self.parent = None
- self.name = name
- self.children = []
- self._data = {}
-
- def __repr__(self):
- return "<ManifestItem %s>" % (self.name)
-
- def __str__(self):
- rv = [repr(self)]
- for item in self.children:
- rv.extend(" %s" % line for line in str(item).split("\n"))
- return "\n".join(rv)
-
- @property
- def is_empty(self):
- if self._data:
- return False
- return all(child.is_empty for child in self.children)
-
- @property
- def root(self):
- node = self
- while node.parent is not None:
- node = node.parent
- return node
-
- def has_key(self, key):
- for node in [self, self.root]:
- if key in node._data:
- return True
- return False
-
- def get(self, key):
- for node in [self, self.root]:
- if key in node._data:
- return node._data[key]
- raise KeyError
-
- def set(self, name, value):
- self._data[name] = value
-
- def remove(self):
- if self.parent:
- self.parent._remove_child(self)
-
- def _remove_child(self, child):
- self.children.remove(child)
- child.parent = None
-
- def iterchildren(self, name=None):
- for item in self.children:
- if item.name == name or name is None:
- yield item
-
- def _flatten(self):
- rv = {}
- for node in [self, self.root]:
- for name, value in node._data.iteritems():
- if name not in rv:
- rv[name] = value
- return rv
-
- def iteritems(self):
- for item in self._flatten().iteritems():
- yield item
-
- def iterkeys(self):
- for item in self._flatten().iterkeys():
- yield item
-
- def itervalues(self):
- for item in self._flatten().itervalues():
- yield item
-
- def append(self, child):
- child.parent = self
- self.children.append(child)
- return child
-
-
-def compile_ast(ast, expr_data, data_cls_getter=None, **kwargs):
- return Compiler().compile(ast,
- expr_data,
- data_cls_getter=data_cls_getter,
- **kwargs)
-
-
-def compile(stream, expr_data, data_cls_getter=None, **kwargs):
- return compile_ast(parse(stream),
- expr_data,
- data_cls_getter=data_cls_getter,
- **kwargs)
diff --git a/tests/wpt/harness/wptrunner/wptmanifest/node.py b/tests/wpt/harness/wptrunner/wptmanifest/node.py
deleted file mode 100644
index e260eeaf765..00000000000
--- a/tests/wpt/harness/wptrunner/wptmanifest/node.py
+++ /dev/null
@@ -1,161 +0,0 @@
-# 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/.
-
-class NodeVisitor(object):
- def visit(self, node):
- # This is ugly as hell, but we don't have multimethods and
- # they aren't trivial to fake without access to the class
- # object from the class body
- func = getattr(self, "visit_%s" % (node.__class__.__name__))
- return func(node)
-
-
-class Node(object):
- def __init__(self, data=None):
- self.data = data
- self.parent = None
- self.children = []
-
- def append(self, other):
- other.parent = self
- self.children.append(other)
-
- def remove(self):
- self.parent.children.remove(self)
-
- def __repr__(self):
- return "<%s %s>" % (self.__class__.__name__, self.data)
-
- def __str__(self):
- rv = [repr(self)]
- for item in self.children:
- rv.extend(" %s" % line for line in str(item).split("\n"))
- return "\n".join(rv)
-
- def __eq__(self, other):
- if not (self.__class__ == other.__class__ and
- self.data == other.data and
- len(self.children) == len(other.children)):
- return False
- for child, other_child in zip(self.children, other.children):
- if not child == other_child:
- return False
- return True
-
- def copy(self):
- new = self.__class__(self.data)
- for item in self.children:
- new.append(item.copy())
- return new
-
-
-class DataNode(Node):
- def append(self, other):
- # Append that retains the invariant that child data nodes
- # come after child nodes of other types
- other.parent = self
- if isinstance(other, DataNode):
- self.children.append(other)
- else:
- index = len(self.children)
- while index > 0 and isinstance(self.children[index - 1], DataNode):
- index -= 1
- for i in xrange(index):
- assert other.data != self.children[i].data
- self.children.insert(index, other)
-
-
-class KeyValueNode(Node):
- def append(self, other):
- # Append that retains the invariant that conditional nodes
- # come before unconditional nodes
- other.parent = self
- if isinstance(other, ValueNode):
- if self.children:
- assert not isinstance(self.children[-1], ValueNode)
- self.children.append(other)
- else:
- if self.children and isinstance(self.children[-1], ValueNode):
- self.children.insert(len(self.children) - 1, other)
- else:
- self.children.append(other)
-
-
-class ListNode(Node):
- def append(self, other):
- other.parent = self
- self.children.append(other)
-
-
-class ValueNode(Node):
- def append(self, other):
- raise TypeError
-
-
-class AtomNode(ValueNode):
- pass
-
-
-class ConditionalNode(Node):
- pass
-
-
-class UnaryExpressionNode(Node):
- def __init__(self, operator, operand):
- Node.__init__(self)
- self.append(operator)
- self.append(operand)
-
- def append(self, other):
- Node.append(self, other)
- assert len(self.children) <= 2
-
- def copy(self):
- new = self.__class__(self.children[0].copy(),
- self.children[1].copy())
- return new
-
-
-class BinaryExpressionNode(Node):
- def __init__(self, operator, operand_0, operand_1):
- Node.__init__(self)
- self.append(operator)
- self.append(operand_0)
- self.append(operand_1)
-
- def append(self, other):
- Node.append(self, other)
- assert len(self.children) <= 3
-
- def copy(self):
- new = self.__class__(self.children[0].copy(),
- self.children[1].copy(),
- self.children[2].copy())
- return new
-
-
-class UnaryOperatorNode(Node):
- def append(self, other):
- raise TypeError
-
-
-class BinaryOperatorNode(Node):
- def append(self, other):
- raise TypeError
-
-
-class IndexNode(Node):
- pass
-
-
-class VariableNode(Node):
- pass
-
-
-class StringNode(Node):
- pass
-
-
-class NumberNode(ValueNode):
- pass
diff --git a/tests/wpt/harness/wptrunner/wptmanifest/parser.py b/tests/wpt/harness/wptrunner/wptmanifest/parser.py
deleted file mode 100644
index f52deb9c124..00000000000
--- a/tests/wpt/harness/wptrunner/wptmanifest/parser.py
+++ /dev/null
@@ -1,750 +0,0 @@
-# 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/.
-
-#default_value:foo
-#include: other.manifest
-#
-#[test_name.js]
-# expected: ERROR
-#
-# [subtest 1]
-# expected:
-# os == win: FAIL #This is a comment
-# PASS
-#
-
-# TODO: keep comments in the tree
-
-from __future__ import unicode_literals
-
-import types
-from cStringIO import StringIO
-
-from node import *
-
-
-class ParseError(Exception):
- def __init__(self, filename, line, detail):
- self.line = line
- self.filename = filename
- self.detail = detail
- self.message = "%s: %s line %s" % (self.detail, self.filename, self.line)
- Exception.__init__(self, self.message)
-
-eol = object
-group_start = object
-group_end = object
-digits = "0123456789"
-open_parens = "[("
-close_parens = "])"
-parens = open_parens + close_parens
-operator_chars = "=!"
-
-unary_operators = ["not"]
-binary_operators = ["==", "!=", "and", "or"]
-
-operators = ["==", "!=", "not", "and", "or"]
-
-atoms = {"True": True,
- "False": False,
- "Reset": object()}
-
-def decode(s):
- assert isinstance(s, unicode)
- return s
-
-
-def precedence(operator_node):
- return len(operators) - operators.index(operator_node.data)
-
-
-class TokenTypes(object):
- def __init__(self):
- for type in ["group_start", "group_end", "paren", "list_start", "list_end", "separator", "ident", "string", "number", "atom", "eof"]:
- setattr(self, type, type)
-
-token_types = TokenTypes()
-
-
-class Tokenizer(object):
- def __init__(self):
- self.reset()
-
- def reset(self):
- self.indent_levels = [0]
- self.state = self.line_start_state
- self.next_state = self.data_line_state
- self.line_number = 0
-
- def tokenize(self, stream):
- self.reset()
- assert not isinstance(stream, unicode)
- if isinstance(stream, str):
- stream = StringIO(stream)
- if not hasattr(stream, "name"):
- self.filename = ""
- else:
- self.filename = stream.name
-
- self.next_line_state = self.line_start_state
- for i, line in enumerate(stream):
- assert isinstance(line, str)
- self.state = self.next_line_state
- assert self.state is not None
- states = []
- self.next_line_state = None
- self.line_number = i + 1
- self.index = 0
- self.line = line.decode('utf-8').rstrip()
- assert isinstance(self.line, unicode)
- while self.state != self.eol_state:
- states.append(self.state)
- tokens = self.state()
- if tokens:
- for token in tokens:
- yield token
- self.state()
- while True:
- yield (token_types.eof, None)
-
- def char(self):
- if self.index == len(self.line):
- return eol
- return self.line[self.index]
-
- def consume(self):
- if self.index < len(self.line):
- self.index += 1
-
- def peek(self, length):
- return self.line[self.index:self.index + length]
-
- def skip_whitespace(self):
- while self.char() == " ":
- self.consume()
-
- def eol_state(self):
- if self.next_line_state is None:
- self.next_line_state = self.line_start_state
-
- def line_start_state(self):
- self.skip_whitespace()
- if self.char() == eol:
- self.state = self.eol_state
- return
- if self.index > self.indent_levels[-1]:
- self.indent_levels.append(self.index)
- yield (token_types.group_start, None)
- else:
- while self.index < self.indent_levels[-1]:
- self.indent_levels.pop()
- yield (token_types.group_end, None)
- # This is terrible; if we were parsing an expression
- # then the next_state will be expr_or_value but when we deindent
- # it must always be a heading or key next so we go back to data_line_state
- self.next_state = self.data_line_state
- if self.index != self.indent_levels[-1]:
- raise ParseError(self.filename, self.line_number, "Unexpected indent")
-
- self.state = self.next_state
-
- def data_line_state(self):
- if self.char() == "[":
- yield (token_types.paren, self.char())
- self.consume()
- self.state = self.heading_state
- else:
- self.state = self.key_state
-
- def heading_state(self):
- rv = ""
- while True:
- c = self.char()
- if c == "\\":
- rv += self.consume_escape()
- elif c == "]":
- break
- elif c == eol:
- raise ParseError(self.filename, self.line_number, "EOL in heading")
- else:
- rv += c
- self.consume()
-
- yield (token_types.string, decode(rv))
- yield (token_types.paren, "]")
- self.consume()
- self.state = self.line_end_state
- self.next_state = self.data_line_state
-
- def key_state(self):
- rv = ""
- while True:
- c = self.char()
- if c == " ":
- self.skip_whitespace()
- if self.char() != ":":
- raise ParseError(self.filename, self.line_number, "Space in key name")
- break
- elif c == ":":
- break
- elif c == eol:
- raise ParseError(self.filename, self.line_number, "EOL in key name (missing ':'?)")
- elif c == "\\":
- rv += self.consume_escape()
- else:
- rv += c
- self.consume()
- yield (token_types.string, decode(rv))
- yield (token_types.separator, ":")
- self.consume()
- self.state = self.after_key_state
-
- def after_key_state(self):
- self.skip_whitespace()
- c = self.char()
- if c == "#":
- self.next_state = self.expr_or_value_state
- self.state = self.comment_state
- elif c == eol:
- self.next_state = self.expr_or_value_state
- self.state = self.eol_state
- elif c == "[":
- self.state = self.list_start_state
- else:
- self.state = self.value_state
-
- def list_start_state(self):
- yield (token_types.list_start, "[")
- self.consume()
- self.state = self.list_value_start_state
-
- def list_value_start_state(self):
- self.skip_whitespace()
- if self.char() == "]":
- self.state = self.list_end_state
- elif self.char() in ("'", '"'):
- quote_char = self.char()
- self.consume()
- yield (token_types.string, self.consume_string(quote_char))
- self.skip_whitespace()
- if self.char() == "]":
- self.state = self.list_end_state
- elif self.char() != ",":
- raise ParseError(self.filename, self.line_number, "Junk after quoted string")
- self.consume()
- elif self.char() == "#":
- self.state = self.comment_state
- self.next_line_state = self.list_value_start_state
- elif self.char() == eol:
- self.next_line_state = self.list_value_start_state
- self.state = self.eol_state
- elif self.char() == ",":
- raise ParseError(self.filename, self.line_number, "List item started with separator")
- elif self.char() == "@":
- self.state = self.list_value_atom_state
- else:
- self.state = self.list_value_state
-
- def list_value_state(self):
- rv = ""
- spaces = 0
- while True:
- c = self.char()
- if c == "\\":
- escape = self.consume_escape()
- rv += escape
- elif c == eol:
- raise ParseError(self.filename, self.line_number, "EOL in list value")
- elif c == "#":
- raise ParseError(self.filename, self.line_number, "EOL in list value (comment)")
- elif c == ",":
- self.state = self.list_value_start_state
- self.consume()
- break
- elif c == " ":
- spaces += 1
- self.consume()
- elif c == "]":
- self.state = self.list_end_state
- self.consume()
- break
- else:
- rv += " " * spaces
- spaces = 0
- rv += c
- self.consume()
-
- if rv:
- yield (token_types.string, decode(rv))
-
- def list_value_atom_state(self):
- self.consume()
- for _, value in self.list_value_state():
- yield token_types.atom, value
-
- def list_end_state(self):
- self.consume()
- yield (token_types.list_end, "]")
- self.state = self.line_end_state
-
- def value_state(self):
- self.skip_whitespace()
- if self.char() in ("'", '"'):
- quote_char = self.char()
- self.consume()
- yield (token_types.string, self.consume_string(quote_char))
- if self.char() == "#":
- self.state = self.comment_state
- else:
- self.state = self.line_end_state
- elif self.char() == "@":
- self.consume()
- for _, value in self.value_inner_state():
- yield token_types.atom, value
- else:
- self.state = self.value_inner_state
-
- def value_inner_state(self):
- rv = ""
- spaces = 0
- while True:
- c = self.char()
- if c == "\\":
- rv += self.consume_escape()
- elif c == "#":
- self.state = self.comment_state
- break
- elif c == " ":
- # prevent whitespace before comments from being included in the value
- spaces += 1
- self.consume()
- elif c == eol:
- self.state = self.line_end_state
- break
- else:
- rv += " " * spaces
- spaces = 0
- rv += c
- self.consume()
- yield (token_types.string, decode(rv))
-
- def comment_state(self):
- while self.char() is not eol:
- self.consume()
- self.state = self.eol_state
-
- def line_end_state(self):
- self.skip_whitespace()
- c = self.char()
- if c == "#":
- self.state = self.comment_state
- elif c == eol:
- self.state = self.eol_state
- else:
- raise ParseError(self.filename, self.line_number, "Junk before EOL %s" % c)
-
- def consume_string(self, quote_char):
- rv = ""
- while True:
- c = self.char()
- if c == "\\":
- rv += self.consume_escape()
- elif c == quote_char:
- self.consume()
- break
- elif c == eol:
- raise ParseError(self.filename, self.line_number, "EOL in quoted string")
- else:
- rv += c
- self.consume()
-
- return decode(rv)
-
- def expr_or_value_state(self):
- if self.peek(3) == "if ":
- self.state = self.expr_state
- else:
- self.state = self.value_state
-
- def expr_state(self):
- self.skip_whitespace()
- c = self.char()
- if c == eol:
- raise ParseError(self.filename, self.line_number, "EOL in expression")
- elif c in "'\"":
- self.consume()
- yield (token_types.string, self.consume_string(c))
- elif c == "#":
- raise ParseError(self.filename, self.line_number, "Comment before end of expression")
- elif c == ":":
- yield (token_types.separator, c)
- self.consume()
- self.state = self.value_state
- elif c in parens:
- self.consume()
- yield (token_types.paren, c)
- elif c in ("!", "="):
- self.state = self.operator_state
- elif c in digits:
- self.state = self.digit_state
- else:
- self.state = self.ident_state
-
- def operator_state(self):
- # Only symbolic operators
- index_0 = self.index
- while True:
- c = self.char()
- if c == eol:
- break
- elif c in operator_chars:
- self.consume()
- else:
- self.state = self.expr_state
- break
- yield (token_types.ident, self.line[index_0:self.index])
-
- def digit_state(self):
- index_0 = self.index
- seen_dot = False
- while True:
- c = self.char()
- if c == eol:
- break
- elif c in digits:
- self.consume()
- elif c == ".":
- if seen_dot:
- raise ParseError(self.filename, self.line_number, "Invalid number")
- self.consume()
- seen_dot = True
- elif c in parens:
- break
- elif c in operator_chars:
- break
- elif c == " ":
- break
- elif c == ":":
- break
- else:
- raise ParseError(self.filename, self.line_number, "Invalid character in number")
-
- self.state = self.expr_state
- yield (token_types.number, self.line[index_0:self.index])
-
- def ident_state(self):
- index_0 = self.index
- while True:
- c = self.char()
- if c == eol:
- break
- elif c == ".":
- break
- elif c in parens:
- break
- elif c in operator_chars:
- break
- elif c == " ":
- break
- elif c == ":":
- break
- else:
- self.consume()
- self.state = self.expr_state
- yield (token_types.ident, self.line[index_0:self.index])
-
- def consume_escape(self):
- assert self.char() == "\\"
- self.consume()
- c = self.char()
- self.consume()
- if c == "x":
- return self.decode_escape(2)
- elif c == "u":
- return self.decode_escape(4)
- elif c == "U":
- return self.decode_escape(6)
- elif c in ["a", "b", "f", "n", "r", "t", "v"]:
- return eval("'\%s'" % c)
- elif c is eol:
- raise ParseError(self.filename, self.line_number, "EOL in escape")
- else:
- return c
-
- def decode_escape(self, length):
- value = 0
- for i in xrange(length):
- c = self.char()
- value *= 16
- value += self.escape_value(c)
- self.consume()
-
- return unichr(value)
-
- def escape_value(self, c):
- if '0' <= c <= '9':
- return ord(c) - ord('0')
- elif 'a' <= c <= 'f':
- return ord(c) - ord('a') + 10
- elif 'A' <= c <= 'F':
- return ord(c) - ord('A') + 10
- else:
- raise ParseError(self.filename, self.line_number, "Invalid character escape")
-
-
-class Parser(object):
- def __init__(self):
- self.reset()
-
- def reset(self):
- self.token = None
- self.unary_operators = "!"
- self.binary_operators = frozenset(["&&", "||", "=="])
- self.tokenizer = Tokenizer()
- self.token_generator = None
- self.tree = Treebuilder(DataNode(None))
- self.expr_builder = None
- self.expr_builders = []
-
- def parse(self, input):
- self.reset()
- self.token_generator = self.tokenizer.tokenize(input)
- self.consume()
- self.manifest()
- return self.tree.node
-
- def consume(self):
- self.token = self.token_generator.next()
-
- def expect(self, type, value=None):
- if self.token[0] != type:
- raise ParseError
- if value is not None:
- if self.token[1] != value:
- raise ParseError
-
- self.consume()
-
- def manifest(self):
- self.data_block()
- self.expect(token_types.eof)
-
- def data_block(self):
- while self.token[0] == token_types.string:
- self.tree.append(KeyValueNode(self.token[1]))
- self.consume()
- self.expect(token_types.separator)
- self.value_block()
- self.tree.pop()
-
- while self.token == (token_types.paren, "["):
- self.consume()
- if self.token[0] != token_types.string:
- raise ParseError
- self.tree.append(DataNode(self.token[1]))
- self.consume()
- self.expect(token_types.paren, "]")
- if self.token[0] == token_types.group_start:
- self.consume()
- self.data_block()
- self.eof_or_end_group()
- self.tree.pop()
-
- def eof_or_end_group(self):
- if self.token[0] != token_types.eof:
- self.expect(token_types.group_end)
-
- def value_block(self):
- if self.token[0] == token_types.list_start:
- self.consume()
- self.list_value()
- elif self.token[0] == token_types.string:
- self.value()
- elif self.token[0] == token_types.group_start:
- self.consume()
- self.expression_values()
- if self.token[0] == token_types.string:
- self.value()
- self.eof_or_end_group()
- elif self.token[0] == token_types.atom:
- self.atom()
- else:
- raise ParseError
-
- def list_value(self):
- self.tree.append(ListNode())
- while self.token[0] in (token_types.atom, token_types.string):
- if self.token[0] == token_types.atom:
- self.atom()
- else:
- self.value()
- self.expect(token_types.list_end)
- self.tree.pop()
-
- def expression_values(self):
- while self.token == (token_types.ident, "if"):
- self.consume()
- self.tree.append(ConditionalNode())
- self.expr_start()
- self.expect(token_types.separator)
- if self.token[0] == token_types.string:
- self.value()
- else:
- raise ParseError
- self.tree.pop()
-
- def value(self):
- self.tree.append(ValueNode(self.token[1]))
- self.consume()
- self.tree.pop()
-
- def atom(self):
- if self.token[1] not in atoms:
- raise ParseError(self.tokenizer.filename, self.tokenizer.line_number, "Unrecognised symbol @%s" % self.token[1])
- self.tree.append(AtomNode(atoms[self.token[1]]))
- self.consume()
- self.tree.pop()
-
- def expr_start(self):
- self.expr_builder = ExpressionBuilder(self.tokenizer)
- self.expr_builders.append(self.expr_builder)
- self.expr()
- expression = self.expr_builder.finish()
- self.expr_builders.pop()
- self.expr_builder = self.expr_builders[-1] if self.expr_builders else None
- if self.expr_builder:
- self.expr_builder.operands[-1].children[-1].append(expression)
- else:
- self.tree.append(expression)
- self.tree.pop()
-
- def expr(self):
- self.expr_operand()
- while (self.token[0] == token_types.ident and self.token[1] in binary_operators):
- self.expr_bin_op()
- self.expr_operand()
-
- def expr_operand(self):
- if self.token == (token_types.paren, "("):
- self.consume()
- self.expr_builder.left_paren()
- self.expr()
- self.expect(token_types.paren, ")")
- self.expr_builder.right_paren()
- elif self.token[0] == token_types.ident and self.token[1] in unary_operators:
- self.expr_unary_op()
- self.expr_operand()
- elif self.token[0] in [token_types.string, token_types.ident]:
- self.expr_value()
- elif self.token[0] == token_types.number:
- self.expr_number()
- else:
- raise ParseError(self.tokenizer.filename, self.tokenizer.line_number, "Unrecognised operand")
-
- def expr_unary_op(self):
- if self.token[1] in unary_operators:
- self.expr_builder.push_operator(UnaryOperatorNode(self.token[1]))
- self.consume()
- else:
- raise ParseError(self.tokenizer.filename, self.tokenizer.line_number, "Expected unary operator")
-
- def expr_bin_op(self):
- if self.token[1] in binary_operators:
- self.expr_builder.push_operator(BinaryOperatorNode(self.token[1]))
- self.consume()
- else:
- raise ParseError(self.tokenizer.filename, self.tokenizer.line_number, "Expected binary operator")
-
- def expr_value(self):
- node_type = {token_types.string: StringNode,
- token_types.ident: VariableNode}[self.token[0]]
- self.expr_builder.push_operand(node_type(self.token[1]))
- self.consume()
- if self.token == (token_types.paren, "["):
- self.consume()
- self.expr_builder.operands[-1].append(IndexNode())
- self.expr_start()
- self.expect(token_types.paren, "]")
-
- def expr_number(self):
- self.expr_builder.push_operand(NumberNode(self.token[1]))
- self.consume()
-
-
-class Treebuilder(object):
- def __init__(self, root):
- self.root = root
- self.node = root
-
- def append(self, node):
- self.node.append(node)
- self.node = node
- return node
-
- def pop(self):
- node = self.node
- self.node = self.node.parent
- return node
-
-
-class ExpressionBuilder(object):
- def __init__(self, tokenizer):
- self.operands = []
- self.operators = [None]
- self.tokenizer = tokenizer
-
- def finish(self):
- while self.operators[-1] is not None:
- self.pop_operator()
- rv = self.pop_operand()
- assert self.is_empty()
- return rv
-
- def left_paren(self):
- self.operators.append(None)
-
- def right_paren(self):
- while self.operators[-1] is not None:
- self.pop_operator()
- if not self.operators:
- raise ParseError(self.tokenizer.filename, self.tokenizer.line,
- "Unbalanced parens")
-
- assert self.operators.pop() is None
-
- def push_operator(self, operator):
- assert operator is not None
- while self.precedence(self.operators[-1]) > self.precedence(operator):
- self.pop_operator()
-
- self.operators.append(operator)
-
- def pop_operator(self):
- operator = self.operators.pop()
- if isinstance(operator, BinaryOperatorNode):
- operand_1 = self.operands.pop()
- operand_0 = self.operands.pop()
- self.operands.append(BinaryExpressionNode(operator, operand_0, operand_1))
- else:
- operand_0 = self.operands.pop()
- self.operands.append(UnaryExpressionNode(operator, operand_0))
-
- def push_operand(self, node):
- self.operands.append(node)
-
- def pop_operand(self):
- return self.operands.pop()
-
- def is_empty(self):
- return len(self.operands) == 0 and all(item is None for item in self.operators)
-
- def precedence(self, operator):
- if operator is None:
- return 0
- return precedence(operator)
-
-
-def parse(stream):
- p = Parser()
- return p.parse(stream)
diff --git a/tests/wpt/harness/wptrunner/wptmanifest/serializer.py b/tests/wpt/harness/wptrunner/wptmanifest/serializer.py
deleted file mode 100644
index efa839d8dbf..00000000000
--- a/tests/wpt/harness/wptrunner/wptmanifest/serializer.py
+++ /dev/null
@@ -1,140 +0,0 @@
-# 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/.
-
-from node import NodeVisitor, ValueNode, ListNode, BinaryExpressionNode
-from parser import atoms, precedence
-
-atom_names = {v:"@%s" % k for (k,v) in atoms.iteritems()}
-
-named_escapes = set(["\a", "\b", "\f", "\n", "\r", "\t", "\v"])
-
-def escape(string, extras=""):
- rv = ""
- for c in string:
- if c in named_escapes:
- rv += c.encode("unicode_escape")
- elif c == "\\":
- rv += "\\\\"
- elif c < '\x20':
- rv += "\\x%02x" % ord(c)
- elif c in extras:
- rv += "\\" + c
- else:
- rv += c
- return rv.encode("utf8")
-
-
-class ManifestSerializer(NodeVisitor):
- def __init__(self, skip_empty_data=False):
- self.skip_empty_data = skip_empty_data
-
- def serialize(self, root):
- self.indent = 2
- rv = "\n".join(self.visit(root))
- if rv[-1] != "\n":
- rv = rv + "\n"
- return rv
-
- def visit_DataNode(self, node):
- rv = []
- if not self.skip_empty_data or node.children:
- if node.data:
- rv.append("[%s]" % escape(node.data, extras="]"))
- indent = self.indent * " "
- else:
- indent = ""
-
- for child in node.children:
- rv.extend("%s%s" % (indent if item else "", item) for item in self.visit(child))
-
- if node.parent:
- rv.append("")
-
- return rv
-
- def visit_KeyValueNode(self, node):
- rv = [escape(node.data, ":") + ":"]
- indent = " " * self.indent
-
- if len(node.children) == 1 and isinstance(node.children[0], (ValueNode, ListNode)):
- rv[0] += " %s" % self.visit(node.children[0])[0]
- else:
- for child in node.children:
- rv.append(indent + self.visit(child)[0])
-
- return rv
-
- def visit_ListNode(self, node):
- rv = ["["]
- rv.extend(", ".join(self.visit(child)[0] for child in node.children))
- rv.append("]")
- return ["".join(rv)]
-
- def visit_ValueNode(self, node):
- if "#" in node.data or (isinstance(node.parent, ListNode) and
- ("," in node.data or "]" in node.data)):
- if "\"" in node.data:
- quote = "'"
- else:
- quote = "\""
- else:
- quote = ""
- return [quote + escape(node.data, extras=quote) + quote]
-
- def visit_AtomNode(self, node):
- return [atom_names[node.data]]
-
- def visit_ConditionalNode(self, node):
- return ["if %s: %s" % tuple(self.visit(item)[0] for item in node.children)]
-
- def visit_StringNode(self, node):
- rv = ["\"%s\"" % escape(node.data, extras="\"")]
- for child in node.children:
- rv[0] += self.visit(child)[0]
- return rv
-
- def visit_NumberNode(self, node):
- return [str(node.data)]
-
- def visit_VariableNode(self, node):
- rv = escape(node.data)
- for child in node.children:
- rv += self.visit(child)
- return [rv]
-
- def visit_IndexNode(self, node):
- assert len(node.children) == 1
- return ["[%s]" % self.visit(node.children[0])[0]]
-
- def visit_UnaryExpressionNode(self, node):
- children = []
- for child in node.children:
- child_str = self.visit(child)[0]
- if isinstance(child, BinaryExpressionNode):
- child_str = "(%s)" % child_str
- children.append(child_str)
- return [" ".join(children)]
-
- def visit_BinaryExpressionNode(self, node):
- assert len(node.children) == 3
- children = []
- for child_index in [1, 0, 2]:
- child = node.children[child_index]
- child_str = self.visit(child)[0]
- if (isinstance(child, BinaryExpressionNode) and
- precedence(node.children[0]) < precedence(child.children[0])):
- child_str = "(%s)" % child_str
- children.append(child_str)
- return [" ".join(children)]
-
- def visit_UnaryOperatorNode(self, node):
- return [str(node.data)]
-
- def visit_BinaryOperatorNode(self, node):
- return [str(node.data)]
-
-
-def serialize(tree, *args, **kwargs):
- s = ManifestSerializer(*args, **kwargs)
- return s.serialize(tree)
diff --git a/tests/wpt/harness/wptrunner/wptmanifest/tests/__init__.py b/tests/wpt/harness/wptrunner/wptmanifest/tests/__init__.py
deleted file mode 100644
index c580d191c1b..00000000000
--- a/tests/wpt/harness/wptrunner/wptmanifest/tests/__init__.py
+++ /dev/null
@@ -1,3 +0,0 @@
-# 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/.
diff --git a/tests/wpt/harness/wptrunner/wptmanifest/tests/test_conditional.py b/tests/wpt/harness/wptrunner/wptmanifest/tests/test_conditional.py
deleted file mode 100644
index 628e8a4c663..00000000000
--- a/tests/wpt/harness/wptrunner/wptmanifest/tests/test_conditional.py
+++ /dev/null
@@ -1,147 +0,0 @@
-# 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 unittest
-
-from cStringIO import StringIO
-
-from ..backends import conditional
-from ..node import BinaryExpressionNode, BinaryOperatorNode, VariableNode, NumberNode
-
-
-class TestConditional(unittest.TestCase):
- def compile(self, input_text):
- return conditional.compile(input_text)
-
- def test_get_0(self):
- data = """
-key: value
-
-[Heading 1]
- other_key:
- if a == 1: value_1
- if a == 2: value_2
- value_3
-"""
-
- manifest = self.compile(data)
-
- self.assertEquals(manifest.get("key"), "value")
- children = list(item for item in manifest.iterchildren())
- self.assertEquals(len(children), 1)
- section = children[0]
- self.assertEquals(section.name, "Heading 1")
-
- self.assertEquals(section.get("other_key", {"a": 1}), "value_1")
- self.assertEquals(section.get("other_key", {"a": 2}), "value_2")
- self.assertEquals(section.get("other_key", {"a": 7}), "value_3")
- self.assertEquals(section.get("key"), "value")
-
- def test_get_1(self):
- data = """
-key: value
-
-[Heading 1]
- other_key:
- if a == "1": value_1
- if a == 2: value_2
- value_3
-"""
-
- manifest = self.compile(data)
-
- children = list(item for item in manifest.iterchildren())
- section = children[0]
-
- self.assertEquals(section.get("other_key", {"a": "1"}), "value_1")
- self.assertEquals(section.get("other_key", {"a": 1}), "value_3")
-
- def test_get_2(self):
- data = """
-key:
- if a[1] == "b": value_1
- if a[1] == 2: value_2
- value_3
-"""
-
- manifest = self.compile(data)
-
- self.assertEquals(manifest.get("key", {"a": "ab"}), "value_1")
- self.assertEquals(manifest.get("key", {"a": [1, 2]}), "value_2")
-
- def test_get_3(self):
- data = """
-key:
- if a[1] == "ab"[1]: value_1
- if a[1] == 2: value_2
- value_3
-"""
-
- manifest = self.compile(data)
-
- self.assertEquals(manifest.get("key", {"a": "ab"}), "value_1")
- self.assertEquals(manifest.get("key", {"a": [1, 2]}), "value_2")
-
- def test_set_0(self):
- data = """
-key:
- if a == "a": value_1
- if a == "b": value_2
- value_3
-"""
- manifest = self.compile(data)
-
- manifest.set("new_key", "value_new")
-
- self.assertEquals(manifest.get("new_key"), "value_new")
-
- def test_set_1(self):
- data = """
-key:
- if a == "a": value_1
- if a == "b": value_2
- value_3
-"""
-
- manifest = self.compile(data)
-
- manifest.set("key", "value_new")
-
- self.assertEquals(manifest.get("key"), "value_new")
- self.assertEquals(manifest.get("key", {"a": "a"}), "value_1")
-
- def test_set_2(self):
- data = """
-key:
- if a == "a": value_1
- if a == "b": value_2
- value_3
-"""
-
- manifest = self.compile(data)
-
- expr = BinaryExpressionNode(BinaryOperatorNode("=="),
- VariableNode("a"),
- NumberNode("1"))
-
- manifest.set("key", "value_new", expr)
-
- self.assertEquals(manifest.get("key", {"a": 1}), "value_new")
- self.assertEquals(manifest.get("key", {"a": "a"}), "value_1")
-
- def test_api_0(self):
- data = """
-key:
- if a == 1.5: value_1
- value_2
-key_1: other_value
-"""
- manifest = self.compile(data)
-
- self.assertFalse(manifest.is_empty)
- self.assertEquals(manifest.root, manifest)
- self.assertTrue(manifest.has_key("key_1"))
- self.assertFalse(manifest.has_key("key_2"))
-
- self.assertEquals(set(manifest.iterkeys()), set(["key", "key_1"]))
diff --git a/tests/wpt/harness/wptrunner/wptmanifest/tests/test_parser.py b/tests/wpt/harness/wptrunner/wptmanifest/tests/test_parser.py
deleted file mode 100644
index 6e8e6e6bea9..00000000000
--- a/tests/wpt/harness/wptrunner/wptmanifest/tests/test_parser.py
+++ /dev/null
@@ -1,79 +0,0 @@
-# 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 unittest
-
-from cStringIO import StringIO
-
-from .. import parser
-
-# There aren't many tests here because it turns out to be way more convenient to
-# use test_serializer for the majority of cases
-
-
-class TestExpression(unittest.TestCase):
- def setUp(self):
- self.parser = parser.Parser()
-
- def parse(self, input_str):
- return self.parser.parse(StringIO(input_str))
-
- def compare(self, input_text, expected):
- actual = self.parse(input_text)
- self.match(expected, actual)
-
- def match(self, expected_node, actual_node):
- self.assertEquals(expected_node[0], actual_node.__class__.__name__)
- self.assertEquals(expected_node[1], actual_node.data)
- self.assertEquals(len(expected_node[2]), len(actual_node.children))
- for expected_child, actual_child in zip(expected_node[2], actual_node.children):
- self.match(expected_child, actual_child)
-
- def test_expr_0(self):
- self.compare(
- """
-key:
- if x == 1 : value""",
- ["DataNode", None,
- [["KeyValueNode", "key",
- [["ConditionalNode", None,
- [["BinaryExpressionNode", None,
- [["BinaryOperatorNode", "==", []],
- ["VariableNode", "x", []],
- ["NumberNode", "1", []]
- ]],
- ["ValueNode", "value", []],
- ]]]]]]
- )
-
- def test_expr_1(self):
- self.compare(
- """
-key:
- if not x and y : value""",
- ["DataNode", None,
- [["KeyValueNode", "key",
- [["ConditionalNode", None,
- [["BinaryExpressionNode", None,
- [["BinaryOperatorNode", "and", []],
- ["UnaryExpressionNode", None,
- [["UnaryOperatorNode", "not", []],
- ["VariableNode", "x", []]
- ]],
- ["VariableNode", "y", []]
- ]],
- ["ValueNode", "value", []],
- ]]]]]]
- )
-
- def test_atom_0(self):
- with self.assertRaises(parser.ParseError):
- self.parse("key: @Unknown")
-
- def test_atom_1(self):
- with self.assertRaises(parser.ParseError):
- self.parse("key: @true")
-
-if __name__ == "__main__":
- unittest.main()
diff --git a/tests/wpt/harness/wptrunner/wptmanifest/tests/test_serializer.py b/tests/wpt/harness/wptrunner/wptmanifest/tests/test_serializer.py
deleted file mode 100644
index 62a462c44e7..00000000000
--- a/tests/wpt/harness/wptrunner/wptmanifest/tests/test_serializer.py
+++ /dev/null
@@ -1,231 +0,0 @@
-# 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 sys
-import unittest
-
-from cStringIO import StringIO
-
-import pytest
-
-from .. import parser, serializer
-
-
-class TokenizerTest(unittest.TestCase):
- def setUp(self):
- self.serializer = serializer.ManifestSerializer()
- self.parser = parser.Parser()
-
- def serialize(self, input_str):
- return self.serializer.serialize(self.parser.parse(input_str))
-
- def compare(self, input_str, expected=None):
- if expected is None:
- expected = input_str
- expected = expected.encode("utf8")
- actual = self.serialize(input_str)
- self.assertEquals(actual, expected)
-
- def test_0(self):
- self.compare("""key: value
-[Heading 1]
- other_key: other_value
-""")
-
- def test_1(self):
- self.compare("""key: value
-[Heading 1]
- other_key:
- if a or b: other_value
-""")
-
- def test_2(self):
- self.compare("""key: value
-[Heading 1]
- other_key:
- if a or b: other_value
- fallback_value
-""")
-
- def test_3(self):
- self.compare("""key: value
-[Heading 1]
- other_key:
- if a == 1: other_value
- fallback_value
-""")
-
- def test_4(self):
- self.compare("""key: value
-[Heading 1]
- other_key:
- if a == "1": other_value
- fallback_value
-""")
-
- def test_5(self):
- self.compare("""key: value
-[Heading 1]
- other_key:
- if a == "abc"[1]: other_value
- fallback_value
-""")
-
- def test_6(self):
- self.compare("""key: value
-[Heading 1]
- other_key:
- if a == "abc"[c]: other_value
- fallback_value
-""")
-
- def test_7(self):
- self.compare("""key: value
-[Heading 1]
- other_key:
- if (a or b) and c: other_value
- fallback_value
-""",
-"""key: value
-[Heading 1]
- other_key:
- if a or b and c: other_value
- fallback_value
-""")
-
- def test_8(self):
- self.compare("""key: value
-[Heading 1]
- other_key:
- if a or (b and c): other_value
- fallback_value
-""")
-
- def test_9(self):
- self.compare("""key: value
-[Heading 1]
- other_key:
- if not (a and b): other_value
- fallback_value
-""")
-
- def test_10(self):
- self.compare("""key: value
-[Heading 1]
- some_key: some_value
-
-[Heading 2]
- other_key: other_value
-""")
-
- def test_11(self):
- self.compare("""key:
- if not a and b and c and d: true
-""")
-
- def test_12(self):
- self.compare("""[Heading 1]
- key: [a:1, b:2]
-""")
-
- def test_13(self):
- self.compare("""key: [a:1, "b:#"]
-""")
-
- def test_14(self):
- self.compare("""key: [","]
-""")
-
- def test_15(self):
- self.compare("""key: ,
-""")
-
- def test_16(self):
- self.compare("""key: ["]", b]
-""")
-
- def test_17(self):
- self.compare("""key: ]
-""")
-
- def test_18(self):
- self.compare("""key: \]
- """, """key: ]
-""")
-
- def test_escape_0(self):
- self.compare(r"""k\t\:y: \a\b\f\n\r\t\v""",
- r"""k\t\:y: \x07\x08\x0c\n\r\t\x0b
-""")
-
- def test_escape_1(self):
- self.compare(r"""k\x00: \x12A\x45""",
- r"""k\x00: \x12AE
-""")
-
- def test_escape_2(self):
- self.compare(r"""k\u0045y: \u1234A\uABc6""",
- u"""kEy: \u1234A\uabc6
-""")
-
- def test_escape_3(self):
- self.compare(r"""k\u0045y: \u1234A\uABc6""",
- u"""kEy: \u1234A\uabc6
-""")
-
- def test_escape_4(self):
- self.compare(r"""key: '\u1234A\uABc6'""",
- u"""key: \u1234A\uabc6
-""")
-
- def test_escape_5(self):
- self.compare(r"""key: [\u1234A\uABc6]""",
- u"""key: [\u1234A\uabc6]
-""")
-
- def test_escape_6(self):
- self.compare(r"""key: [\u1234A\uABc6\,]""",
- u"""key: ["\u1234A\uabc6,"]
-""")
-
- def test_escape_7(self):
- self.compare(r"""key: [\,\]\#]""",
- r"""key: [",]#"]
-""")
-
- def test_escape_8(self):
- self.compare(r"""key: \#""",
- r"""key: "#"
-""")
-
- @pytest.mark.xfail(sys.maxunicode == 0xFFFF, reason="narrow unicode")
- def test_escape_9(self):
- self.compare(r"""key: \U10FFFFabc""",
- u"""key: \U0010FFFFabc
-""")
-
- def test_escape_10(self):
- self.compare(r"""key: \u10FFab""",
- u"""key: \u10FFab
-""")
-
- def test_escape_11(self):
- self.compare(r"""key: \\ab
-""")
-
- def test_atom_1(self):
- self.compare(r"""key: @True
-""")
-
- def test_atom_2(self):
- self.compare(r"""key: @False
-""")
-
- def test_atom_3(self):
- self.compare(r"""key: @Reset
-""")
-
- def test_atom_4(self):
- self.compare(r"""key: [a, @Reset, b]
-""")
diff --git a/tests/wpt/harness/wptrunner/wptmanifest/tests/test_static.py b/tests/wpt/harness/wptrunner/wptmanifest/tests/test_static.py
deleted file mode 100644
index d28765edac9..00000000000
--- a/tests/wpt/harness/wptrunner/wptmanifest/tests/test_static.py
+++ /dev/null
@@ -1,102 +0,0 @@
-# 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 unittest
-
-from cStringIO import StringIO
-
-from ..backends import static
-
-# There aren't many tests here because it turns out to be way more convenient to
-# use test_serializer for the majority of cases
-
-
-class TestStatic(unittest.TestCase):
- def compile(self, input_text, input_data):
- return static.compile(input_text, input_data)
-
- def test_get_0(self):
- data = """
-key: value
-
-[Heading 1]
- other_key:
- if a == 1: value_1
- if a == 2: value_2
- value_3
-"""
-
- manifest = self.compile(data, {"a": 2})
-
- self.assertEquals(manifest.get("key"), "value")
- children = list(item for item in manifest.iterchildren())
- self.assertEquals(len(children), 1)
- section = children[0]
- self.assertEquals(section.name, "Heading 1")
-
- self.assertEquals(section.get("other_key"), "value_2")
- self.assertEquals(section.get("key"), "value")
-
- def test_get_1(self):
- data = """
-key: value
-
-[Heading 1]
- other_key:
- if a == 1: value_1
- if a == 2: value_2
- value_3
-"""
- manifest = self.compile(data, {"a": 3})
-
- children = list(item for item in manifest.iterchildren())
- section = children[0]
- self.assertEquals(section.get("other_key"), "value_3")
-
- def test_get_3(self):
- data = """key:
- if a == "1": value_1
- if a[0] == "ab"[0]: value_2
-"""
- manifest = self.compile(data, {"a": "1"})
- self.assertEquals(manifest.get("key"), "value_1")
-
- manifest = self.compile(data, {"a": "ac"})
- self.assertEquals(manifest.get("key"), "value_2")
-
- def test_get_4(self):
- data = """key:
- if not a: value_1
- value_2
-"""
- manifest = self.compile(data, {"a": True})
- self.assertEquals(manifest.get("key"), "value_2")
-
- manifest = self.compile(data, {"a": False})
- self.assertEquals(manifest.get("key"), "value_1")
-
- def test_api(self):
- data = """key:
- if a == 1.5: value_1
- value_2
-key_1: other_value
-"""
- manifest = self.compile(data, {"a": 1.5})
-
- self.assertFalse(manifest.is_empty)
- self.assertEquals(manifest.root, manifest)
- self.assertTrue(manifest.has_key("key_1"))
- self.assertFalse(manifest.has_key("key_2"))
-
- self.assertEquals(set(manifest.iterkeys()), set(["key", "key_1"]))
- self.assertEquals(set(manifest.itervalues()), set(["value_1", "other_value"]))
-
- def test_is_empty_1(self):
- data = """
-[Section]
- [Subsection]
-"""
- manifest = self.compile(data, {})
-
- self.assertTrue(manifest.is_empty)
diff --git a/tests/wpt/harness/wptrunner/wptmanifest/tests/test_tokenizer.py b/tests/wpt/harness/wptrunner/wptmanifest/tests/test_tokenizer.py
deleted file mode 100644
index 9395677135c..00000000000
--- a/tests/wpt/harness/wptrunner/wptmanifest/tests/test_tokenizer.py
+++ /dev/null
@@ -1,361 +0,0 @@
-# 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 sys
-import os
-import unittest
-
-sys.path.insert(0, os.path.abspath(".."))
-from cStringIO import StringIO
-
-from .. import parser
-from ..parser import token_types
-
-
-class TokenizerTest(unittest.TestCase):
- def setUp(self):
- self.tokenizer = parser.Tokenizer()
-
- def tokenize(self, input_str):
- rv = []
- for item in self.tokenizer.tokenize(StringIO(input_str)):
- rv.append(item)
- if item[0] == token_types.eof:
- break
- return rv
-
- def compare(self, input_text, expected):
- expected = expected + [(token_types.eof, None)]
- actual = self.tokenize(input_text)
- self.assertEquals(actual, expected)
-
- def test_heading_0(self):
- self.compare("""[Heading text]""",
- [(token_types.paren, "["),
- (token_types.string, "Heading text"),
- (token_types.paren, "]")])
-
- def test_heading_1(self):
- self.compare("""[Heading [text\]]""",
- [(token_types.paren, "["),
- (token_types.string, "Heading [text]"),
- (token_types.paren, "]")])
-
- def test_heading_2(self):
- self.compare("""[Heading #text]""",
- [(token_types.paren, "["),
- (token_types.string, "Heading #text"),
- (token_types.paren, "]")])
-
- def test_heading_3(self):
- self.compare("""[Heading [\]text]""",
- [(token_types.paren, "["),
- (token_types.string, "Heading []text"),
- (token_types.paren, "]")])
-
- def test_heading_4(self):
- with self.assertRaises(parser.ParseError):
- self.tokenize("[Heading")
-
- def test_heading_5(self):
- self.compare("""[Heading [\]text] #comment""",
- [(token_types.paren, "["),
- (token_types.string, "Heading []text"),
- (token_types.paren, "]")])
-
- def test_heading_6(self):
- self.compare(r"""[Heading \ttext]""",
- [(token_types.paren, "["),
- (token_types.string, "Heading \ttext"),
- (token_types.paren, "]")])
-
- def test_key_0(self):
- self.compare("""key:value""",
- [(token_types.string, "key"),
- (token_types.separator, ":"),
- (token_types.string, "value")])
-
- def test_key_1(self):
- self.compare("""key : value""",
- [(token_types.string, "key"),
- (token_types.separator, ":"),
- (token_types.string, "value")])
-
- def test_key_2(self):
- self.compare("""key : val ue""",
- [(token_types.string, "key"),
- (token_types.separator, ":"),
- (token_types.string, "val ue")])
-
- def test_key_3(self):
- self.compare("""key: value#comment""",
- [(token_types.string, "key"),
- (token_types.separator, ":"),
- (token_types.string, "value")])
-
- def test_key_4(self):
- with self.assertRaises(parser.ParseError):
- self.tokenize("""ke y: value""")
-
- def test_key_5(self):
- with self.assertRaises(parser.ParseError):
- self.tokenize("""key""")
-
- def test_key_6(self):
- self.compare("""key: "value\"""",
- [(token_types.string, "key"),
- (token_types.separator, ":"),
- (token_types.string, "value")])
-
- def test_key_7(self):
- self.compare("""key: 'value'""",
- [(token_types.string, "key"),
- (token_types.separator, ":"),
- (token_types.string, "value")])
-
- def test_key_8(self):
- self.compare("""key: "#value\"""",
- [(token_types.string, "key"),
- (token_types.separator, ":"),
- (token_types.string, "#value")])
-
- def test_key_9(self):
- self.compare("""key: '#value\'""",
- [(token_types.string, "key"),
- (token_types.separator, ":"),
- (token_types.string, "#value")])
-
- def test_key_10(self):
- with self.assertRaises(parser.ParseError):
- self.tokenize("""key: "value""")
-
- def test_key_11(self):
- with self.assertRaises(parser.ParseError):
- self.tokenize("""key: 'value""")
-
- def test_key_12(self):
- with self.assertRaises(parser.ParseError):
- self.tokenize("""key: 'value""")
-
- def test_key_13(self):
- with self.assertRaises(parser.ParseError):
- self.tokenize("""key: 'value' abc""")
-
- def test_key_14(self):
- self.compare(r"""key: \\nb""",
- [(token_types.string, "key"),
- (token_types.separator, ":"),
- (token_types.string, r"\nb")])
-
- def test_list_0(self):
- self.compare(
-"""
-key: []""",
- [(token_types.string, "key"),
- (token_types.separator, ":"),
- (token_types.list_start, "["),
- (token_types.list_end, "]")])
-
- def test_list_1(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, "]")])
-
- def test_list_2(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, "]")])
-
- def test_list_3(self):
- self.compare(
-"""
-key: [a, #b]
- c]""",
- [(token_types.string, "key"),
- (token_types.separator, ":"),
- (token_types.list_start, "["),
- (token_types.string, "a"),
- (token_types.string, "c"),
- (token_types.list_end, "]")])
-
- def test_list_4(self):
- with self.assertRaises(parser.ParseError):
- self.tokenize("""key: [a #b]
- c]""")
-
- def test_list_5(self):
- with self.assertRaises(parser.ParseError):
- self.tokenize("""key: [a \\
- 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, "]")])
-
- def test_expr_0(self):
- self.compare(
-"""
-key:
- if cond == 1: value""",
- [(token_types.string, "key"),
- (token_types.separator, ":"),
- (token_types.group_start, None),
- (token_types.ident, "if"),
- (token_types.ident, "cond"),
- (token_types.ident, "=="),
- (token_types.number, "1"),
- (token_types.separator, ":"),
- (token_types.string, "value")])
-
- def test_expr_1(self):
- self.compare(
-"""
-key:
- if cond == 1: value1
- value2""",
- [(token_types.string, "key"),
- (token_types.separator, ":"),
- (token_types.group_start, None),
- (token_types.ident, "if"),
- (token_types.ident, "cond"),
- (token_types.ident, "=="),
- (token_types.number, "1"),
- (token_types.separator, ":"),
- (token_types.string, "value1"),
- (token_types.string, "value2")])
-
- def test_expr_2(self):
- self.compare(
-"""
-key:
- if cond=="1": value""",
- [(token_types.string, "key"),
- (token_types.separator, ":"),
- (token_types.group_start, None),
- (token_types.ident, "if"),
- (token_types.ident, "cond"),
- (token_types.ident, "=="),
- (token_types.string, "1"),
- (token_types.separator, ":"),
- (token_types.string, "value")])
-
- def test_expr_3(self):
- self.compare(
-"""
-key:
- if cond==1.1: value""",
- [(token_types.string, "key"),
- (token_types.separator, ":"),
- (token_types.group_start, None),
- (token_types.ident, "if"),
- (token_types.ident, "cond"),
- (token_types.ident, "=="),
- (token_types.number, "1.1"),
- (token_types.separator, ":"),
- (token_types.string, "value")])
-
- def test_expr_4(self):
- self.compare(
- """
-key:
- if cond==1.1 and cond2 == "a": value""",
- [(token_types.string, "key"),
- (token_types.separator, ":"),
- (token_types.group_start, None),
- (token_types.ident, "if"),
- (token_types.ident, "cond"),
- (token_types.ident, "=="),
- (token_types.number, "1.1"),
- (token_types.ident, "and"),
- (token_types.ident, "cond2"),
- (token_types.ident, "=="),
- (token_types.string, "a"),
- (token_types.separator, ":"),
- (token_types.string, "value")])
-
- def test_expr_5(self):
- self.compare(
-"""
-key:
- if (cond==1.1 ): value""",
- [(token_types.string, "key"),
- (token_types.separator, ":"),
- (token_types.group_start, None),
- (token_types.ident, "if"),
- (token_types.paren, "("),
- (token_types.ident, "cond"),
- (token_types.ident, "=="),
- (token_types.number, "1.1"),
- (token_types.paren, ")"),
- (token_types.separator, ":"),
- (token_types.string, "value")])
-
- def test_expr_6(self):
- self.compare(
-"""
-key:
- if "\\ttest": value""",
- [(token_types.string, "key"),
- (token_types.separator, ":"),
- (token_types.group_start, None),
- (token_types.ident, "if"),
- (token_types.string, "\ttest"),
- (token_types.separator, ":"),
- (token_types.string, "value")])
-
- 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(
-"""
-key:
- if 1.: value""",
- [(token_types.string, "key"),
- (token_types.separator, ":"),
- (token_types.group_start, None),
- (token_types.ident, "if"),
- (token_types.number, "1."),
- (token_types.separator, ":"),
- (token_types.string, "value")])
-
-if __name__ == "__main__":
- unittest.main()
diff --git a/tests/wpt/harness/wptrunner/wptrunner.py b/tests/wpt/harness/wptrunner/wptrunner.py
deleted file mode 100644
index d955131c581..00000000000
--- a/tests/wpt/harness/wptrunner/wptrunner.py
+++ /dev/null
@@ -1,248 +0,0 @@
-# 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/.
-
-from __future__ import unicode_literals
-
-import json
-import os
-import sys
-
-import environment as env
-import products
-import testloader
-import wptcommandline
-import wptlogging
-import wpttest
-from testrunner import ManagerGroup
-
-here = os.path.split(__file__)[0]
-
-logger = None
-
-"""Runner for web-platform-tests
-
-The runner has several design goals:
-
-* Tests should run with no modification from upstream.
-
-* Tests should be regarded as "untrusted" so that errors, timeouts and even
- crashes in the tests can be handled without failing the entire test run.
-
-* For performance tests can be run in multiple browsers in parallel.
-
-The upstream repository has the facility for creating a test manifest in JSON
-format. This manifest is used directly to determine which tests exist. Local
-metadata files are used to store the expected test results.
-"""
-
-def setup_logging(*args, **kwargs):
- global logger
- logger = wptlogging.setup(*args, **kwargs)
-
-def get_loader(test_paths, product, ssl_env, debug=None, run_info_extras=None, **kwargs):
- if run_info_extras is None:
- run_info_extras = {}
-
- run_info = wpttest.get_run_info(kwargs["run_info"], product, debug=debug,
- extras=run_info_extras)
-
- test_manifests = testloader.ManifestLoader(test_paths, force_manifest_update=kwargs["manifest_update"]).load()
-
- manifest_filters = []
- meta_filters = []
-
- if kwargs["include"] or kwargs["exclude"] or kwargs["include_manifest"]:
- manifest_filters.append(testloader.TestFilter(include=kwargs["include"],
- exclude=kwargs["exclude"],
- manifest_path=kwargs["include_manifest"],
- test_manifests=test_manifests))
- if kwargs["tags"]:
- meta_filters.append(testloader.TagFilter(tags=kwargs["tags"]))
-
- test_loader = testloader.TestLoader(test_manifests,
- kwargs["test_types"],
- run_info,
- manifest_filters=manifest_filters,
- meta_filters=meta_filters,
- chunk_type=kwargs["chunk_type"],
- total_chunks=kwargs["total_chunks"],
- chunk_number=kwargs["this_chunk"],
- include_https=ssl_env.ssl_enabled)
- return run_info, test_loader
-
-def list_test_groups(test_paths, product, **kwargs):
- env.do_delayed_imports(logger, test_paths)
-
- ssl_env = env.ssl_env(logger, **kwargs)
-
- run_info, test_loader = get_loader(test_paths, product, ssl_env,
- **kwargs)
-
- for item in sorted(test_loader.groups(kwargs["test_types"])):
- print item
-
-
-def list_disabled(test_paths, product, **kwargs):
- env.do_delayed_imports(logger, test_paths)
-
- rv = []
-
- ssl_env = env.ssl_env(logger, **kwargs)
-
- run_info, test_loader = get_loader(test_paths, product, ssl_env,
- **kwargs)
-
- for test_type, tests in test_loader.disabled_tests.iteritems():
- for test in tests:
- rv.append({"test": test.id, "reason": test.disabled()})
- print json.dumps(rv, indent=2)
-
-
-def get_pause_after_test(test_loader, **kwargs):
- total_tests = sum(len(item) for item in test_loader.tests.itervalues())
- if kwargs["pause_after_test"] is None:
- if kwargs["repeat_until_unexpected"]:
- return False
- if kwargs["repeat"] == 1 and total_tests == 1:
- return True
- return False
- return kwargs["pause_after_test"]
-
-
-def run_tests(config, test_paths, product, **kwargs):
- with wptlogging.CaptureIO(logger, not kwargs["no_capture_stdio"]):
- env.do_delayed_imports(logger, test_paths)
-
- (check_args,
- browser_cls, get_browser_kwargs,
- executor_classes, get_executor_kwargs,
- env_options, run_info_extras) = products.load_product(config, product)
-
- ssl_env = env.ssl_env(logger, **kwargs)
-
- check_args(**kwargs)
-
- if "test_loader" in kwargs:
- run_info = wpttest.get_run_info(kwargs["run_info"], product, debug=None,
- extras=run_info_extras(**kwargs))
- test_loader = kwargs["test_loader"]
- else:
- run_info, test_loader = get_loader(test_paths,
- product,
- ssl_env,
- run_info_extras=run_info_extras(**kwargs),
- **kwargs)
-
- if kwargs["run_by_dir"] is False:
- test_source_cls = testloader.SingleTestSource
- test_source_kwargs = {}
- else:
- # A value of None indicates infinite depth
- test_source_cls = testloader.PathGroupedSource
- test_source_kwargs = {"depth": kwargs["run_by_dir"]}
-
- logger.info("Using %i client processes" % kwargs["processes"])
-
- unexpected_total = 0
-
- kwargs["pause_after_test"] = get_pause_after_test(test_loader, **kwargs)
-
- with env.TestEnvironment(test_paths,
- ssl_env,
- kwargs["pause_after_test"],
- kwargs["debug_info"],
- env_options) as test_environment:
- try:
- test_environment.ensure_started()
- except env.TestEnvironmentError as e:
- logger.critical("Error starting test environment: %s" % e.message)
- raise
-
- browser_kwargs = get_browser_kwargs(ssl_env=ssl_env, **kwargs)
-
- repeat = kwargs["repeat"]
- repeat_count = 0
- repeat_until_unexpected = kwargs["repeat_until_unexpected"]
-
- while repeat_count < repeat or repeat_until_unexpected:
- repeat_count += 1
- if repeat_until_unexpected:
- logger.info("Repetition %i" % (repeat_count))
- elif repeat > 1:
- logger.info("Repetition %i / %i" % (repeat_count, repeat))
-
- unexpected_count = 0
- logger.suite_start(test_loader.test_ids, run_info)
- for test_type in kwargs["test_types"]:
- logger.info("Running %s tests" % test_type)
-
- for test in test_loader.disabled_tests[test_type]:
- logger.test_start(test.id)
- logger.test_end(test.id, status="SKIP")
-
- executor_cls = executor_classes.get(test_type)
- executor_kwargs = get_executor_kwargs(test_type,
- test_environment.external_config,
- test_environment.cache_manager,
- run_info,
- **kwargs)
-
- if executor_cls is None:
- logger.error("Unsupported test type %s for product %s" %
- (test_type, product))
- continue
-
-
- with ManagerGroup("web-platform-tests",
- kwargs["processes"],
- test_source_cls,
- test_source_kwargs,
- browser_cls,
- browser_kwargs,
- executor_cls,
- executor_kwargs,
- kwargs["pause_after_test"],
- kwargs["pause_on_unexpected"],
- kwargs["restart_on_unexpected"],
- kwargs["debug_info"]) as manager_group:
- try:
- manager_group.run(test_type, test_loader.tests)
- except KeyboardInterrupt:
- logger.critical("Main thread got signal")
- manager_group.stop()
- raise
- unexpected_count += manager_group.unexpected_count()
-
- unexpected_total += unexpected_count
- logger.info("Got %i unexpected results" % unexpected_count)
- if repeat_until_unexpected and unexpected_total > 0:
- break
- logger.suite_end()
-
- return unexpected_total == 0
-
-
-def main():
- """Main entry point when calling from the command line"""
- kwargs = wptcommandline.parse_args()
-
- try:
- if kwargs["prefs_root"] is None:
- kwargs["prefs_root"] = os.path.abspath(os.path.join(here, "prefs"))
-
- setup_logging(kwargs, {"raw": sys.stdout})
-
- if kwargs["list_test_groups"]:
- list_test_groups(**kwargs)
- elif kwargs["list_disabled"]:
- list_disabled(**kwargs)
- else:
- return not run_tests(**kwargs)
- except Exception:
- if kwargs["pdb"]:
- import pdb, traceback
- print traceback.format_exc()
- pdb.post_mortem()
- else:
- raise
diff --git a/tests/wpt/harness/wptrunner/wpttest.py b/tests/wpt/harness/wptrunner/wpttest.py
deleted file mode 100644
index 97dd11bae9a..00000000000
--- a/tests/wpt/harness/wptrunner/wpttest.py
+++ /dev/null
@@ -1,329 +0,0 @@
-# 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/.
-
-DEFAULT_TIMEOUT = 10 # seconds
-LONG_TIMEOUT = 60 # seconds
-
-import os
-
-import mozinfo
-
-from wptmanifest.parser import atoms
-
-atom_reset = atoms["Reset"]
-enabled_tests = set(["testharness", "reftest", "wdspec"])
-
-
-class Result(object):
- def __init__(self, status, message, expected=None, extra=None):
- if status not in self.statuses:
- raise ValueError("Unrecognised status %s" % status)
- self.status = status
- self.message = message
- self.expected = expected
- self.extra = extra
-
- def __repr__(self):
- return "<%s.%s %s>" % (self.__module__, self.__class__.__name__, self.status)
-
-
-class SubtestResult(object):
- def __init__(self, name, status, message, stack=None, expected=None):
- self.name = name
- if status not in self.statuses:
- raise ValueError("Unrecognised status %s" % status)
- self.status = status
- self.message = message
- self.stack = stack
- self.expected = expected
-
- def __repr__(self):
- return "<%s.%s %s %s>" % (self.__module__, self.__class__.__name__, self.name, self.status)
-
-
-class TestharnessResult(Result):
- default_expected = "OK"
- statuses = set(["OK", "ERROR", "TIMEOUT", "EXTERNAL-TIMEOUT", "CRASH"])
-
-
-class TestharnessSubtestResult(SubtestResult):
- default_expected = "PASS"
- statuses = set(["PASS", "FAIL", "TIMEOUT", "NOTRUN"])
-
-
-class ReftestResult(Result):
- default_expected = "PASS"
- statuses = set(["PASS", "FAIL", "ERROR", "TIMEOUT", "EXTERNAL-TIMEOUT", "CRASH"])
-
-
-class WdspecResult(Result):
- default_expected = "OK"
- statuses = set(["OK", "ERROR", "TIMEOUT", "EXTERNAL-TIMEOUT", "CRASH"])
-
-
-class WdspecSubtestResult(SubtestResult):
- default_expected = "PASS"
- statuses = set(["PASS", "FAIL", "ERROR"])
-
-
-def get_run_info(metadata_root, product, **kwargs):
- return RunInfo(metadata_root, product, **kwargs)
-
-
-class RunInfo(dict):
- def __init__(self, metadata_root, product, debug, extras=None):
- self._update_mozinfo(metadata_root)
- self.update(mozinfo.info)
- self["product"] = product
- if debug is not None:
- self["debug"] = debug
- elif "debug" not in self:
- # Default to release
- self["debug"] = False
- if extras is not None:
- self.update(extras)
-
- def _update_mozinfo(self, metadata_root):
- """Add extra build information from a mozinfo.json file in a parent
- directory"""
- path = metadata_root
- dirs = set()
- while path != os.path.expanduser('~'):
- if path in dirs:
- break
- dirs.add(str(path))
- path = os.path.split(path)[0]
-
- mozinfo.find_and_update_from_json(*dirs)
-
-
-class Test(object):
- result_cls = None
- subtest_result_cls = None
- test_type = None
-
- def __init__(self, url, inherit_metadata, test_metadata, timeout=DEFAULT_TIMEOUT, path=None,
- protocol="http"):
- self.url = url
- self._inherit_metadata = inherit_metadata
- self._test_metadata = test_metadata
- self.timeout = timeout
- self.path = path
- self.environment = {"protocol": protocol, "prefs": self.prefs}
-
- def __eq__(self, other):
- return self.id == other.id
-
- @classmethod
- def from_manifest(cls, manifest_item, inherit_metadata, test_metadata):
- timeout = LONG_TIMEOUT if manifest_item.timeout == "long" else DEFAULT_TIMEOUT
- return cls(manifest_item.url,
- inherit_metadata,
- test_metadata,
- timeout=timeout,
- path=manifest_item.source_file.path,
- protocol="https" if hasattr(manifest_item, "https") and manifest_item.https else "http")
-
- @property
- def id(self):
- return self.url
-
- @property
- def keys(self):
- return tuple()
-
- def _get_metadata(self, subtest=None):
- if self._test_metadata is not None and subtest is not None:
- return self._test_metadata.get_subtest(subtest)
- else:
- return self._test_metadata
-
- def itermeta(self, subtest=None):
- for metadata in self._inherit_metadata:
- yield metadata
-
- if self._test_metadata is not None:
- yield self._get_metadata()
- if subtest is not None:
- subtest_meta = self._get_metadata(subtest)
- if subtest_meta is not None:
- yield subtest_meta
-
- def disabled(self, subtest=None):
- for meta in self.itermeta(subtest):
- disabled = meta.disabled
- if disabled is not None:
- return disabled
- return None
-
- @property
- def restart_after(self):
- for meta in self.itermeta(None):
- restart_after = meta.restart_after
- if restart_after is not None:
- return True
- return False
-
- @property
- def tags(self):
- tags = set()
- for meta in self.itermeta():
- meta_tags = meta.tags
- if atom_reset in meta_tags:
- tags = meta_tags.copy()
- tags.remove(atom_reset)
- else:
- tags |= meta_tags
-
- tags.add("dir:%s" % self.id.lstrip("/").split("/")[0])
-
- return tags
-
- @property
- def prefs(self):
- prefs = {}
- for meta in self.itermeta():
- meta_prefs = meta.prefs
- if atom_reset in prefs:
- prefs = meta_prefs.copy()
- del prefs[atom_reset]
- else:
- prefs.update(meta_prefs)
- return prefs
-
- def expected(self, subtest=None):
- if subtest is None:
- default = self.result_cls.default_expected
- else:
- default = self.subtest_result_cls.default_expected
-
- metadata = self._get_metadata(subtest)
- if metadata is None:
- return default
-
- try:
- return metadata.get("expected")
- except KeyError:
- return default
-
- def __repr__(self):
- return "<%s.%s %s>" % (self.__module__, self.__class__.__name__, self.id)
-
-
-class TestharnessTest(Test):
- result_cls = TestharnessResult
- subtest_result_cls = TestharnessSubtestResult
- test_type = "testharness"
-
- @property
- def id(self):
- return self.url
-
-
-class ManualTest(Test):
- test_type = "manual"
-
- @property
- def id(self):
- return self.url
-
-
-class ReftestTest(Test):
- result_cls = ReftestResult
- test_type = "reftest"
-
- def __init__(self, url, inherit_metadata, test_metadata, references,
- timeout=DEFAULT_TIMEOUT, path=None, viewport_size=None,
- dpi=None, protocol="http"):
- Test.__init__(self, url, inherit_metadata, test_metadata, timeout, path, protocol)
-
- for _, ref_type in references:
- if ref_type not in ("==", "!="):
- raise ValueError
-
- self.references = references
- self.viewport_size = viewport_size
- self.dpi = dpi
-
- @classmethod
- def from_manifest(cls,
- manifest_test,
- inherit_metadata,
- test_metadata,
- nodes=None,
- references_seen=None):
-
- timeout = LONG_TIMEOUT if manifest_test.timeout == "long" else DEFAULT_TIMEOUT
-
- if nodes is None:
- nodes = {}
- if references_seen is None:
- references_seen = set()
-
- url = manifest_test.url
-
- node = cls(manifest_test.url,
- inherit_metadata,
- test_metadata,
- [],
- timeout=timeout,
- path=manifest_test.path,
- viewport_size=manifest_test.viewport_size,
- dpi=manifest_test.dpi,
- protocol="https" if hasattr(manifest_test, "https") and manifest_test.https else "http")
-
- nodes[url] = node
-
- for ref_url, ref_type in manifest_test.references:
- comparison_key = (ref_type,) + tuple(sorted([url, ref_url]))
- if ref_url in nodes:
- manifest_node = ref_url
- if comparison_key in references_seen:
- # We have reached a cycle so stop here
- # Note that just seeing a node for the second time is not
- # enough to detect a cycle because
- # A != B != C != A must include C != A
- # but A == B == A should not include the redundant B == A.
- continue
-
- references_seen.add(comparison_key)
-
- manifest_node = manifest_test.manifest.get_reference(ref_url)
- if manifest_node:
- reference = ReftestTest.from_manifest(manifest_node,
- [],
- None,
- nodes,
- references_seen)
- else:
- reference = ReftestTest(ref_url, [], None, [])
-
- node.references.append((reference, ref_type))
-
- return node
-
- @property
- def id(self):
- return self.url
-
- @property
- def keys(self):
- return ("reftype", "refurl")
-
-
-class WdspecTest(Test):
- result_cls = WdspecResult
- subtest_result_cls = WdspecSubtestResult
- test_type = "wdspec"
-
-
-manifest_test_cls = {"reftest": ReftestTest,
- "testharness": TestharnessTest,
- "manual": ManualTest,
- "wdspec": WdspecTest}
-
-
-def from_manifest(manifest_test, inherit_metadata, test_metadata):
- test_cls = manifest_test_cls[manifest_test.item_type]
- return test_cls.from_manifest(manifest_test, inherit_metadata, test_metadata)
diff --git a/tests/wpt/run.py b/tests/wpt/run.py
index c795220876c..1c3d07b95ad 100644
--- a/tests/wpt/run.py
+++ b/tests/wpt/run.py
@@ -20,7 +20,7 @@ def servo_path(*args):
return os.path.join(servo_root, *args)
# Imports
-sys.path.append(wpt_path("harness"))
+sys.path.append(wpt_path("web-platform-tests", "tools", "wptrunner"))
from wptrunner import wptrunner, wptcommandline
diff --git a/tests/wpt/update/__init__.py b/tests/wpt/update/__init__.py
index 0cd536d4c35..9b8e8d0d393 100644
--- a/tests/wpt/update/__init__.py
+++ b/tests/wpt/update/__init__.py
@@ -11,7 +11,7 @@ from mozlog.structured import structuredlog
here = os.path.split(__file__)[0]
-sys.path.insert(0, os.path.abspath(os.path.join(here, os.pardir, "harness")))
+sys.path.insert(0, os.path.abspath(os.path.join(here, os.pardir, "web-platform-tests", "tools", "wptrunner")))
sys.path.insert(0, os.path.abspath(os.path.join(here, os.pardir, "tests", "tools", "scripts")))
from wptrunner.update import setup_logging, WPTUpdate
diff --git a/tests/wpt/update_css.py b/tests/wpt/update_css.py
index 0ee4bdb0277..8e5f1d5759a 100644
--- a/tests/wpt/update_css.py
+++ b/tests/wpt/update_css.py
@@ -12,7 +12,7 @@ def wpt_path(*args):
return os.path.join(here, *args)
# Imports
-sys.path.append(wpt_path("harness"))
+sys.path.append(wpt_path("web-platform-tests", "tools", "wptrunner"))
from wptrunner import wptcommandline
diff --git a/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/executors/executorservo.py b/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/executors/executorservo.py
index eca35b179c0..5f05500d2d3 100644
--- a/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/executors/executorservo.py
+++ b/tests/wpt/web-platform-tests/tools/wptrunner/wptrunner/executors/executorservo.py
@@ -180,7 +180,6 @@ class ServoRefTestExecutor(ProcessTestExecutor):
def __init__(self, browser, server_config, binary=None, timeout_multiplier=1,
screenshot_cache=None, debug_info=None, pause_after_test=False):
- do_delayed_imports()
ProcessTestExecutor.__init__(self,
browser,
server_config,