diff options
-rw-r--r-- | .travis.yml | 1 | ||||
-rw-r--r-- | docs/development/installation.rst | 46 | ||||
-rw-r--r-- | patchwork/tests/browser.py | 176 | ||||
-rw-r--r-- | patchwork/tests/test_user_browser.py | 41 | ||||
-rw-r--r-- | tools/docker/Dockerfile | 9 | ||||
-rwxr-xr-x | tools/docker/entrypoint.sh | 14 | ||||
-rw-r--r-- | tox.ini | 3 |
7 files changed, 17 insertions, 273 deletions
diff --git a/.travis.yml b/.travis.yml index 7e871da..6cb983f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,7 +22,6 @@ env: - PW_TEST_DB_TYPE=mysql PW_TEST_DB_USER=root global: - PW_TEST_DB_PASS="" - - PW_SKIP_BROWSER_TESTS=yes before_script: - mysql -e 'create database patchwork character set utf8;' diff --git a/docs/development/installation.rst b/docs/development/installation.rst index a1bee1d..f2ed0f2 100644 --- a/docs/development/installation.rst +++ b/docs/development/installation.rst @@ -41,7 +41,8 @@ To run a shell within this environment, run: $ docker-compose run --rm web --shell -To run `django-manage` commands, such as `createsuperuser` or `migrate`, run: +To run ``django-manage`` commands, such as ``createsuperuser`` or ``migrate``, +run: .. code-block:: shell @@ -53,48 +54,17 @@ To access the SQL command-line client, run: $ docker-compose run --rm web python manage.py dbshell -To run unit tests, excluding Selenium UI interaction tests, using only the -package versions installed during container initialization, run: - -.. code-block:: shell - - $ docker-compose run --rm web --quick-test - -To run the same against all supported versions of Django (via tox), run: - -.. code-block:: shell - - $ docker-compose run --rm web --quick-tox - -To run specific tox targets or tests, pass arguments to the above: +To run unit tests against the system Python packages, run: .. code-block:: shell - $ docker-compose run --rm web --quick-tox -e py27-django18 \ - patchwork.tests.test_bundles + $ docker-compose run --rm web python manage.py test -To run all tests, including Selenium UI interaction tests, using only the -package versions installed container initialization, run: - -.. code-block:: shell - - $ docker-compose run --rm web --test - -To run the same against all supported versions of Django (via tox), run: - -.. code-block:: shell - - $ docker-compose run --rm web --tox - -To run all tests, including Selenium UI interaction tests in non-headless mode, -run: +To run unit tests for multiple versions using ``tox``, run: .. code-block:: shell - $ docker run -it --rm -v (pwd):/home/patchwork/patchwork/ \ - --link patchwork_db_1:db -p 8000:8000 \ - -v /tmp/.X11-unix:/tmp/.X11-unix \ - -e PW_TEST_DB_HOST=db -e DISPLAY patchwork_web bash + $ docker-compose run --rm web tox To reset the database before any of these commands, add ``--reset`` to the command line after ``web`` and before any other arguments. Conversely, to @@ -102,8 +72,8 @@ backup the database at any stage, run: .. code-block:: shell - $ docker exec DATABASECONTAINER /usr/bin/mysqldump -u DATABASEUSER \ - --password=DATABASEPASSWORD DATABASE > backup.sql + $ docker exec DATABASECONTAINER /usr/bin/mysqldump -u DATABASEUSER \ + --password=DATABASEPASSWORD DATABASE > backup.sql where ``DATABASECONTAINER`` is found by ``docker ps -a`` and the other settings are the same as those defined in ``patchwork/settings/dev.py``. To restore this diff --git a/patchwork/tests/browser.py b/patchwork/tests/browser.py deleted file mode 100644 index 1939def..0000000 --- a/patchwork/tests/browser.py +++ /dev/null @@ -1,176 +0,0 @@ -# Patchwork - automated patch tracking system -# Copyright (C) 2015 Intel Corporation -# -# This file is part of the Patchwork package. -# -# Patchwork is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# Patchwork is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Patchwork; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -import errno -import os -import time - -from django.contrib.staticfiles.testing import StaticLiveServerTestCase -from selenium.common.exceptions import ( - NoSuchElementException, StaleElementReferenceException, - TimeoutException) -from selenium import webdriver -from selenium.webdriver.support.ui import WebDriverWait -from selenium.webdriver.chrome.options import Options - - -class Wait(WebDriverWait): - - """Subclass of WebDriverWait. - - Includes a predetermined timeout and poll frequency. Also deals with a - wider variety of exceptions. - """ - _TIMEOUT = 10 - _POLL_FREQUENCY = 0.5 - - def __init__(self, driver): - super(Wait, self).__init__(driver, self._TIMEOUT, self._POLL_FREQUENCY) - - def until(self, method, message=''): - """Call method with driver until it returns True.""" - end_time = time.time() + self._timeout - - while True: - try: - value = method(self._driver) - if value: - return value - except NoSuchElementException: - pass - except StaleElementReferenceException: - pass - - time.sleep(self._poll) - if(time.time() > end_time): - break - - raise TimeoutException(message) - - def until_not(self, method, message=''): - """Call method with driver until it returns True.""" - end_time = time.time() + self._timeout - while(True): - try: - value = method(self._driver) - if not value: - return value - except NoSuchElementException: - return True - except StaleElementReferenceException: - pass - - time.sleep(self._poll) - if(time.time() > end_time): - break - - raise TimeoutException(message) - - -def mkdir(path): - try: - os.makedirs(path) - except OSError as error: - if error.errno == errno.EEXIST and os.path.isdir(path): - pass - else: - raise - - -class SeleniumTestCase(StaticLiveServerTestCase): - # TODO(stephenfin): This should handle non-UNIX paths - _SCREENSHOT_DIR = os.path.dirname(__file__) + '/../../selenium_screenshots' - - def setUp(self): - self.skip = os.getenv('PW_SKIP_BROWSER_TESTS', None) - if self.skip: - self.skipTest('Disabled by environment variable') - - super(SeleniumTestCase, self).setUp() - - self.browser = os.getenv('SELENIUM_BROWSER', 'chrome') - if self.browser == 'firefox': - self.selenium = webdriver.Firefox() - if self.browser == 'chrome': - chrome_options = Options() - # chrome's aggressive sandboxing doesn't work well with - # docker so disable the sandbox. We're only looking at our - # own site so it should be safe enough - chrome_options.add_argument("--no-sandbox") - self.selenium = webdriver.Chrome( - service_args=['--verbose', '--log-path=selenium.log'], - chrome_options=chrome_options - ) - - mkdir(self._SCREENSHOT_DIR) - self._screenshot_number = 1 - - def tearDown(self): - self.selenium.quit() - super(SeleniumTestCase, self).tearDown() - - def screenshot(self): - name = '%s_%d.png' % (self._testMethodName, self._screenshot_number) - path = os.path.join(self._SCREENSHOT_DIR, name) - self.selenium.get_screenshot_as_file(path) - self._screenshot_number += 1 - - def get(self, relative_url): - self.selenium.get('%s%s' % (self.live_server_url, relative_url)) - self.screenshot() - - def find(self, selector): - return self.selenium.find_element_by_css_selector(selector) - - def focused_element(self): - return self.selenium.switch_to.active_element - - def wait_until_present(self, name): - def is_present(driver): - return driver.find_element_by_name(name) - msg = "An element named '%s' should be on the page" % name - element = Wait(self.selenium).until(is_present, msg) - self.screenshot() - return element - - def wait_until_visible(self, selector): - def is_visible(driver): - return self.find(selector).is_displayed() - msg = "The element matching '%s' should be visible" % selector - Wait(self.selenium).until(is_visible, msg) - self.screenshot() - return self.find(selector) - - def wait_until_focused(self, selector): - def is_focused(driver): - return self.find(selector) == self.focused_element() - msg = "The element matching '%s' should be focused" % selector - Wait(self.selenium).until(is_focused, msg) - self.screenshot() - return self.find(selector) - - def enter_text(self, name, value): - field = self.wait_until_present(name) - field.send_keys(value) - return field - - def click(self, selector): - element = self.wait_until_visible(selector) - element.click() - return element diff --git a/patchwork/tests/test_user_browser.py b/patchwork/tests/test_user_browser.py deleted file mode 100644 index ad4143f..0000000 --- a/patchwork/tests/test_user_browser.py +++ /dev/null @@ -1,41 +0,0 @@ -# Patchwork - automated patch tracking system -# Copyright (C) 2015 Intel Corporation -# -# This file is part of the Patchwork package. -# -# Patchwork is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# Patchwork is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Patchwork; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -from patchwork.compat import reverse -from patchwork.tests.browser import SeleniumTestCase -from patchwork.tests.utils import create_user - - -class LoginTestCase(SeleniumTestCase): - - def setUp(self): - super(LoginTestCase, self).setUp() - self.user = create_user() - - def test_default_focus(self): - self.get(reverse('auth_login')) - self.wait_until_focused('#id_username') - - def test_login(self): - self.get(reverse('auth_login')) - self.enter_text('username', self.user.username) - self.enter_text('password', self.user.username) - self.click('input[value="Login"]') - dropdown = self.wait_until_visible('a.dropdown-toggle strong') - self.assertEqual(dropdown.text, self.user.username) diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile index 31b2aae..68a62e1 100644 --- a/tools/docker/Dockerfile +++ b/tools/docker/Dockerfile @@ -13,8 +13,8 @@ ENV DEBIAN_FRONTEND noninteractive ENV PYTHONUNBUFFERED 1 # System -# trusty and findutils is for python3.4 -# xenial is for python3.5 +# trusty and findutils is for python3.4; xenial is for python3.5 +# TODO(stephenfin): Are curl, unzip required? COPY tools/docker/trusty.list /etc/apt/sources.list.d/trusty.list COPY tools/docker/xenial.list /etc/apt/sources.list.d/xenial.list RUN apt-get update -qq && \ @@ -22,9 +22,8 @@ RUN apt-get update -qq && \ python-dev python-pip python-setuptools python-wheel \ python3.5-dev python3-pip python3-setuptools python3-wheel \ python3.4-dev findutils=4.4.2-7 python3.6-dev \ - libmysqlclient-dev mysql-client curl unzip xvfb chromium-chromedriver \ - chromium-browser build-essential git postgresql-client tzdata && \ - ln -s /usr/lib/chromium-browser/chromedriver /usr/bin/ + libmysqlclient-dev mysql-client curl unzip build-essential \ + git postgresql-client tzdata # User RUN useradd --uid=$UID --create-home patchwork diff --git a/tools/docker/entrypoint.sh b/tools/docker/entrypoint.sh index 4a89978..997b876 100755 --- a/tools/docker/entrypoint.sh +++ b/tools/docker/entrypoint.sh @@ -106,26 +106,20 @@ elif ! test_database; then reset_data fi +# TODO(stephenfin): Deprecated the --test, --tox, --quick-test and --quick-tox +# flags in a future release if [ $# -eq 0 ]; then # we probably ran with --reset and nothing else # just exit cleanly exit 0 elif [ "$1" == "--shell" ]; then exec bash -elif [ "$1" == "--quick-test" ]; then +elif [ "$1" == "--test" ] || [ "$1" == "--quick-test" ]; then shift - export PW_SKIP_BROWSER_TESTS=yes python3 manage.py test $@ -elif [ "$1" == "--test" ]; then +elif [ "$1" == "--tox" ] || [ "$1" == "--quick-tox" ]; then shift - xvfb-run --server-args='-screen 0, 1024x768x16' python3 manage.py test $@ -elif [ "$1" == "--quick-tox" ]; then - shift - export PW_SKIP_BROWSER_TESTS=yes tox $@ -elif [ "$1" == "--tox" ]; then - shift - xvfb-run --server-args='-screen 0, 1024x768x16' tox $@ else # run whatever CMD is set to $@ fi @@ -20,8 +20,7 @@ setenv = passenv = http_proxy HTTP_PROXY https_proxy HTTPS_PROXY no_proxy NO_PROXY PW_TEST_DB_TYPE PW_TEST_DB_USER PW_TEST_DB_PASS PW_TEST_DB_HOST - PW_TEST_DB_PORT DISPLAY SELENIUM_BROWSER PW_SKIP_BROWSER_TESTS - DISPLAY HOME XAUTHORITY + PW_TEST_DB_PORT commands = python -Wonce {toxinidir}/manage.py test --noinput '{posargs:patchwork}' |