From bab2895fcfbbe32f7d18b6a680111e675ddd73dd Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Tue, 17 Apr 2018 09:50:44 +0100 Subject: tests: Remove Selenium tests These were added quite some time ago in order to allow some level of UI testing. However, I've personally never used them, they're not used by the CI, and no one has shown any desire in extending them in their time here. It is time to bid these tests adieu. Removing these allows us to remove a whole load of wiring that existed just to enable these. Some of this, like the '--quick-tox' option for the Dockerfile, is retained so we don't need to use different commands for various versions of Patchwork, but the majority is just stripped out. Signed-off-by: Stephen Finucane Cc: Daniel Axtens --- .travis.yml | 1 - docs/development/installation.rst | 46 ++------- patchwork/tests/browser.py | 176 ----------------------------------- patchwork/tests/test_user_browser.py | 41 -------- tools/docker/Dockerfile | 9 +- tools/docker/entrypoint.sh | 14 +-- tox.ini | 3 +- 7 files changed, 17 insertions(+), 273 deletions(-) delete mode 100644 patchwork/tests/browser.py delete mode 100644 patchwork/tests/test_user_browser.py 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 diff --git a/tox.ini b/tox.ini index a7c6dfc..a64d958 100644 --- a/tox.ini +++ b/tox.ini @@ -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}' -- cgit v1.2.3