Run PolyGerrit tests with Buck
Since Buck has no native support for web tests, wrap the tests in a
Python shim that calls wct. As in other Polymer cases, we need to
prepare a set of inputs and create a directory containing exactly what
wct expects to be there. Buck exposes resources to python_tests using
the pkg_resources API, which is cumbersome to use, and easier just to
ship around zip files as we do elsewhere.
Unlike other npm binaries we've encountered, the web-component-tester
module has numerous native dependencies, up to and including Selenium.
Rather than get in the game of distributing platform-specific
binaries, punt and require `wct` to be on the user's $PATH for now.
Tests are currently excluded in .buckconfig but can be run directly
with either:
buck test //polygerrit-ui/app:polygerrit_tests
buck test --include web
Change-Id: Ia314213925ac27ff271374a96ed539fb2acf0187
diff --git a/.buckconfig b/.buckconfig
index 38fcc58..fc51e19 100644
--- a/.buckconfig
+++ b/.buckconfig
@@ -28,3 +28,6 @@
[cache]
mode = dir
dir = ~/.gerritcodereview/buck-cache/locally-built-artifacts
+
+[test]
+ excluded_labels = manual
diff --git a/lib/js/BUCK b/lib/js/BUCK
index c683128..9f5390f 100644
--- a/lib/js/BUCK
+++ b/lib/js/BUCK
@@ -114,6 +114,16 @@
)
bower_component(
+ name = 'iron-test-helpers',
+ package = 'PolymerElements/iron-test-helpers',
+ version = '1.0.6',
+ semver = '~1.0.6',
+ deps = [':polymer'],
+ license = 'DO_NOT_DISTRIBUTE',
+ sha1 = 'c0f7c7f010ca3c63fb08ae0d9462e400380cde2c',
+)
+
+bower_component(
name = 'iron-validatable-behavior',
package = 'PolymerElements/iron-validatable-behavior',
version = '1.0.5',
@@ -152,6 +162,15 @@
)
bower_component(
+ name = 'test-fixture',
+ package = 'PolymerElements/test-fixture',
+ version = '1.0.3',
+ semver = '^1.0.0',
+ license = 'DO_NOT_DISTRIBUTE',
+ sha1 = '21192d554ff6ad7eea894ca751c73b6bc46867dc',
+)
+
+bower_component(
name = 'webcomponentsjs',
package = 'webcomponentsjs',
version = '0.7.17',
diff --git a/polygerrit-ui/README.md b/polygerrit-ui/README.md
index 00ff612..c2cd4bd 100644
--- a/polygerrit-ui/README.md
+++ b/polygerrit-ui/README.md
@@ -1,5 +1,18 @@
# PolyGerrit
+## Installing [Node.js](https://nodejs.org/en/download/)
+
+```sh
+# Debian/Ubuntu
+sudo apt-get install nodejs-legacy
+
+# OS X with Homebrew
+brew install node
+```
+
+All other platforms: [download from
+nodejs.org](https://nodejs.org/en/download/).
+
## Local UI, Production Data
To test the local UI against gerrit-review.googlesource.com:
@@ -31,7 +44,27 @@
## Running Tests
+One-time setup:
+
```sh
-npm install -g web-component-tester
-wct
+# Debian/Ubuntu
+sudo apt-get install npm
+
+# OS X with Homebrew
+brew install npm
+
+# All platforms (including those above)
+sudo npm install -g web-component-tester
+```
+
+Run all web tests:
+
+```sh
+buck test --include web
+```
+
+If you need to pass additional arguments to `wct`:
+
+```sh
+WCT_ARGS='-p --some-flag="foo bar"' buck test --no-results-cache --include web
```
diff --git a/polygerrit-ui/app/BUCK b/polygerrit-ui/app/BUCK
index 9da030d..317d6b2 100644
--- a/polygerrit-ui/app/BUCK
+++ b/polygerrit-ui/app/BUCK
@@ -1,5 +1,9 @@
include_defs('//lib/js.defs')
+WCT_TEST_PATTERNS = ['test/**']
+PY_TEST_PATTERNS = ['polygerrit_wct_tests.py']
+APP_SRCS = glob(['**'], excludes = WCT_TEST_PATTERNS + PY_TEST_PATTERNS)
+
WEBJS = 'bower_components/webcomponentsjs/webcomponents-lite.js'
# TODO(dborowitz): Putting these rules in this package avoids having to handle
@@ -38,7 +42,38 @@
vulcanize(
name = 'polygerrit',
app = 'elements/gr-app.html',
- srcs = glob(['**'], excludes = ['index.html']),
+ srcs = APP_SRCS,
components = ['//polygerrit-ui:polygerrit_components'],
)
+
+bower_components(
+ name = 'test_components',
+ deps = [
+ '//polygerrit-ui:polygerrit_components',
+ '//lib/js:iron-test-helpers',
+ '//lib/js:test-fixture',
+ ],
+)
+
+genrule(
+ name = 'test_resources',
+ cmd = ' && '.join([
+ 'cd $TMP',
+ 'unzip -q $(location :test_components)',
+ 'cp -rL $SRCDIR/* .',
+ 'zip -r $OUT .',
+ ]),
+ srcs = APP_SRCS + glob(WCT_TEST_PATTERNS),
+ out = 'test_resources.zip',
+)
+
+python_test(
+ name = 'polygerrit_tests',
+ srcs = glob(PY_TEST_PATTERNS),
+ resources = [':test_resources'],
+ labels = [
+ 'manual',
+ 'web',
+ ],
+)
diff --git a/polygerrit-ui/app/polygerrit_wct_tests.py b/polygerrit-ui/app/polygerrit_wct_tests.py
new file mode 100644
index 0000000..571dcb8
--- /dev/null
+++ b/polygerrit-ui/app/polygerrit_wct_tests.py
@@ -0,0 +1,105 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from __future__ import print_function
+
+import atexit
+from distutils import spawn
+import json
+import os
+import pkg_resources
+import shlex
+import shutil
+import subprocess
+import sys
+import tempfile
+import unittest
+import zipfile
+
+
+def _write_wct_conf(root, exports):
+ with open(os.path.join(root, 'wct.conf.js'), 'w') as f:
+ f.write('module.exports = %s;\n' % json.dumps(exports))
+
+
+def _wct_cmd():
+ return ['wct'] + shlex.split(os.environ.get('WCT_ARGS', ''))
+
+
+class PolyGerritWctTests(unittest.TestCase):
+
+ # Should really be setUpClass/tearDownClass, but Buck's test runner doesn't
+ # produce sane stack traces from those methods. There's only one test method
+ # anyway, so just use setUp.
+
+ def _check_wct(self):
+ self.assertTrue(
+ spawn.find_executable('wct'),
+ msg='wct not found; try `npm install -g web-component-tester`')
+
+ def _extract_resources(self):
+ tmpdir = tempfile.mkdtemp()
+ atexit.register(lambda: shutil.rmtree(tmpdir))
+ root = os.path.join(tmpdir, 'polygerrit')
+ os.mkdir(root)
+
+ tr = 'test_resources.zip'
+ zip_path = os.path.join(tmpdir, tr)
+ s = pkg_resources.resource_stream(__name__, tr)
+ with open(zip_path, 'w') as f:
+ shutil.copyfileobj(s, f)
+
+ with zipfile.ZipFile(zip_path, 'r') as z:
+ z.extractall(root)
+
+ return tmpdir, root
+
+ def test_wct(self):
+ self._check_wct()
+ tmpdir, root = self._extract_resources()
+
+ cmd = _wct_cmd()
+ print('Running %s in %s' % (cmd, root), file=sys.stderr)
+
+ _write_wct_conf(root, {
+ 'suites': ['test'],
+ 'webserver': {
+ 'pathMappings': [
+ {'/components/bower_components': 'bower_components'},
+ ],
+ },
+ 'plugins': {
+ 'local': {
+ # For some reason wct tries to install selenium into its node_modules
+ # directory on first run. If you've installed into /usr/local and
+ # aren't running wct as root, you're screwed. Turning this option off
+ # seems to still work, so there's that.
+ 'skipSeleniumInstall': True,
+ },
+ },
+ })
+
+ p = subprocess.Popen(cmd, cwd=root,
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ out, err = p.communicate()
+ sys.stdout.write(out)
+ sys.stderr.write(err)
+ self.assertEquals(0, p.returncode)
+
+ # Only remove tmpdir if successful, to allow debugging.
+ shutil.rmtree(tmpdir)
+
+
+if __name__ == '__main__':
+ unittest.main()