Added docker compose files, updated Dockerfile command and tests.

* Added new docker-compose files to aid with ui test development as
as well as running ui tests against upstream.

* Changed the tests to use pytest base url. This allows us to use
the verify option to wait for the server to be created and setup
before beginning the tests.

* Added setup-docker.sh script to config the docker redash databases
and setup the redash instance for testing.

* Added a docker entrypoint to allow for calling test command from
the command line. This will help with CI.
This commit is contained in:
Benjamin Forehand Jr 2018-05-18 17:35:09 -04:00
Родитель f71277c6a5
Коммит 3ced2428a5
10 изменённых файлов: 151 добавлений и 63 удалений

Просмотреть файл

@ -57,4 +57,4 @@ RUN pipenv install --python=$(which python3.6)
ENTRYPOINT [ "pipenv", "run" ]
CMD ["pytest", "--driver", "Firefox", "--variables", "variables.json", "--html", "report.html"]
CMD ["pytest", "--driver", "Firefox", "--base-url", "http://redash:5000", "--verify-base-url", "--variables", "variables.json", "--html", "report.html"]

Просмотреть файл

@ -5,6 +5,7 @@ name = "pypi"
[packages]
pytest = "*"
pytest-base-url = "*"
pytest-selenium = "*"
pypom = "*"
pytest-variables = "*"

82
Pipfile.lock сгенерированный
Просмотреть файл

@ -1,7 +1,20 @@
{
"_meta": {
"hash": {
"sha256": "d6131fc6bb32a8212eeebf2348c457d8e2b3ee816f4efb0603666c850ffd8da6"
"sha256": "965c019e00fe38782f6b122d2615c37c079098f1084feaab10a760063b171b3f"
},
"host-environment-markers": {
"implementation_name": "cpython",
"implementation_version": "3.6.1",
"os_name": "posix",
"platform_machine": "x86_64",
"platform_python_implementation": "CPython",
"platform_release": "17.5.0",
"platform_system": "Darwin",
"platform_version": "Darwin Kernel Version 17.5.0: Fri Apr 13 19:32:32 PDT 2018; root:xnu-4570.51.2~1/RELEASE_X86_64",
"python_full_version": "3.6.1",
"python_version": "3.6",
"sys_platform": "darwin"
},
"pipfile-spec": 6,
"requires": {
@ -18,52 +31,52 @@
"default": {
"attrs": {
"hashes": [
"sha256:1c7960ccfd6a005cd9f7ba884e6316b5e430a3f1a6c37c5f87d8b43f83b54ec9",
"sha256:a17a9573a6f475c99b551c0e0a812707ddda1ec9653bed04c13841404ed6f450"
"sha256:4b90b09eeeb9b88c35bc642cbac057e45a5fd85367b985bd2809c62b7b939265",
"sha256:e0d0eb91441a3b53dab4d9b743eafc1ac44476296a2053b6ca3af0b139faf87b"
],
"version": "==17.4.0"
"version": "==18.1.0"
},
"certifi": {
"hashes": [
"sha256:13e698f54293db9f89122b0581843a782ad0934a4fe0172d2a980ba77fc61bb7",
"sha256:9fa520c1bacfb634fa7af20a76bcbd3d5fb390481724c597da32c719a7dca4b0"
"sha256:9fa520c1bacfb634fa7af20a76bcbd3d5fb390481724c597da32c719a7dca4b0",
"sha256:13e698f54293db9f89122b0581843a782ad0934a4fe0172d2a980ba77fc61bb7"
],
"version": "==2018.4.16"
},
"chardet": {
"hashes": [
"sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae",
"sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"
"sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691",
"sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae"
],
"version": "==3.0.4"
},
"idna": {
"hashes": [
"sha256:2c6a5de3089009e3da7c5dde64a141dbc8551d5b7f6cf4ed7c2568d0cc520a8f",
"sha256:8c7309c718f94b3a625cb648ace320157ad16ff131ae0af362c9f21b80ef6ec4"
"sha256:8c7309c718f94b3a625cb648ace320157ad16ff131ae0af362c9f21b80ef6ec4",
"sha256:2c6a5de3089009e3da7c5dde64a141dbc8551d5b7f6cf4ed7c2568d0cc520a8f"
],
"version": "==2.6"
},
"more-itertools": {
"hashes": [
"sha256:0dd8f72eeab0d2c3bd489025bb2f6a1b8342f9b198f6fc37b52d15cfa4531fea",
"sha256:11a625025954c20145b37ff6309cd54e39ca94f72f6bb9576d1195db6fa2442e",
"sha256:0dd8f72eeab0d2c3bd489025bb2f6a1b8342f9b198f6fc37b52d15cfa4531fea",
"sha256:c9ce7eccdcb901a2c75d326ea134e0886abfbea5f93e91cc95de9507c0816c44"
],
"version": "==4.1.0"
},
"pluggy": {
"hashes": [
"sha256:7f8ae7f5bdf75671a718d2daf0a64b7885f74510bcd98b1a0bb420eb9a9d0cff",
"sha256:d345c8fe681115900d6da8d048ba67c25df42973bda370783cd58826442dcd7c",
"sha256:e160a7fcf25762bb60efc7e171d4497ff1d8d2d75a3d0df7a21b76821ecbf5c5"
"sha256:e160a7fcf25762bb60efc7e171d4497ff1d8d2d75a3d0df7a21b76821ecbf5c5",
"sha256:7f8ae7f5bdf75671a718d2daf0a64b7885f74510bcd98b1a0bb420eb9a9d0cff"
],
"version": "==0.6.0"
},
"py": {
"hashes": [
"sha256:29c9fab495d7528e80ba1e343b958684f4ace687327e6f789a94bf3d1915f881",
"sha256:983f77f3331356039fdd792e9220b7b8ee1aa6bd2b25f567a963ff1de5a64f6a"
"sha256:983f77f3331356039fdd792e9220b7b8ee1aa6bd2b25f567a963ff1de5a64f6a",
"sha256:29c9fab495d7528e80ba1e343b958684f4ace687327e6f789a94bf3d1915f881"
],
"version": "==1.5.3"
},
@ -72,15 +85,13 @@
"sha256:ea1d3b0297fdeccc47d034a005e6cd16e206ad32258aeffbca47f0c516a63082",
"sha256:ece35948abcb65f4dc230bd7464323bc83e7c02d35aaaeea53fd728effc0df14"
],
"index": "pypi",
"version": "==2.0.0"
},
"pytest": {
"hashes": [
"sha256:54713b26c97538db6ff0703a12b19aeaeb60b5e599de542e7fca0ec83b9038e8",
"sha256:829230122facf05a5f81a6d4dfe6454a04978ea3746853b2b84567ecf8e5c526"
"sha256:829230122facf05a5f81a6d4dfe6454a04978ea3746853b2b84567ecf8e5c526",
"sha256:54713b26c97538db6ff0703a12b19aeaeb60b5e599de542e7fca0ec83b9038e8"
],
"index": "pypi",
"version": "==3.5.1"
},
"pytest-base-url": {
@ -95,13 +106,12 @@
"sha256:23bf611f3048decc1cf5281238574155d07190e0d1370f91318eec6b8031a6c1",
"sha256:bbb6cb7936bc4944cd8122f72e9981157149714648d3596ec1ff2b2ed9baeac1"
],
"index": "pypi",
"version": "==1.17.0"
},
"pytest-metadata": {
"hashes": [
"sha256:2d495b61542cb25dfc52fbf40c7a02220c7c127b7ba8974e6c72d6c9593c547a",
"sha256:ec37c48f44e7973cc6d06b36a148d3a3432e5dda8b8a40239fb52099b202907f"
"sha256:ec37c48f44e7973cc6d06b36a148d3a3432e5dda8b8a40239fb52099b202907f",
"sha256:2d495b61542cb25dfc52fbf40c7a02220c7c127b7ba8974e6c72d6c9593c547a"
],
"version": "==1.7.0"
},
@ -110,7 +120,6 @@
"sha256:050a357a8bc9d38241052a277a5da3d67ff4801a807e8918113a88defee11c97",
"sha256:b3c36a212d0b5a3ba61fccbf9f754aa2286840dc2ae910a04b67c72685a1bca7"
],
"index": "pypi",
"version": "==1.12.0"
},
"pytest-variables": {
@ -118,7 +127,6 @@
"sha256:59c00b95779657532ac5f8209b28b5d447c8b4bc4210c1d6bdf9a42aa201f9b0",
"sha256:7808b77b643b9f8a24f1ee1c32132648b1c62ab93956f20fe101dde66db6d09a"
],
"index": "pypi",
"version": "==1.7.1"
},
"requests": {
@ -130,15 +138,15 @@
},
"selenium": {
"hashes": [
"sha256:2b6f018e55f50e9c67a67caec2f73f806f72c162fb38cf3ea79e0a8f6506bf56",
"sha256:5841fb30c3965866220c34d16de8e3d091e2833fcac385160a63db0c3522a297"
"sha256:1372101ad23798462038481f92ba1c7fab8385c788b05da6b44318f10ea52422",
"sha256:b8a2630fd858636c894960726ca3c94d8277e516ea3a9d81614fb819a5844764"
],
"version": "==3.11.0"
"version": "==3.12.0"
},
"six": {
"hashes": [
"sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9",
"sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb"
"sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb",
"sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9"
],
"version": "==1.11.0"
},
@ -151,8 +159,8 @@
},
"zope.component": {
"hashes": [
"sha256:1b29aa65413f6dda29e64e2352a6aa13d9ba70078f6b91f328573488788d531c",
"sha256:2776ab93945c8df3781fdcc2126dc7080e9a1d64fef5f76a21550473cbb505bf"
"sha256:2776ab93945c8df3781fdcc2126dc7080e9a1d64fef5f76a21550473cbb505bf",
"sha256:1b29aa65413f6dda29e64e2352a6aa13d9ba70078f6b91f328573488788d531c"
],
"version": "==4.4.1"
},
@ -165,15 +173,15 @@
},
"zope.interface": {
"hashes": [
"sha256:21506674d30c009271fe68a242d330c83b1b9d76d62d03d87e1e9528c61beea6",
"sha256:3d184aff0756c44fff7de69eb4cd5b5311b6f452d4de28cb08343b3f21993763",
"sha256:467d364b24cb398f76ad5e90398d71b9325eb4232be9e8a50d6a3b3c7a1c8789",
"sha256:57c38470d9f57e37afb460c399eb254e7193ac7fb8042bd09bdc001981a9c74c",
"sha256:3d184aff0756c44fff7de69eb4cd5b5311b6f452d4de28cb08343b3f21993763",
"sha256:21506674d30c009271fe68a242d330c83b1b9d76d62d03d87e1e9528c61beea6",
"sha256:f41037260deaacb875db250021fe883bf536bf6414a4fd25b25059b02e31b120",
"sha256:9ada83f4384bbb12dedc152bcdd46a3ac9f5f7720d43ac3ce3e8e8b91d733c10",
"sha256:a1daf9c5120f3cc6f2b5fef8e1d2a3fb7bbbb20ed4bfdc25bc8364bc62dcf54b",
"sha256:e6b77ae84f2b8502d99a7855fa33334a1eb6159de45626905cb3e454c023f339",
"sha256:e881ef610ff48aece2f4ee2af03d2db1a146dc7c705561bd6089b2356f61641f",
"sha256:f41037260deaacb875db250021fe883bf536bf6414a4fd25b25059b02e31b120"
"sha256:e6b77ae84f2b8502d99a7855fa33334a1eb6159de45626905cb3e454c023f339",
"sha256:a1daf9c5120f3cc6f2b5fef8e1d2a3fb7bbbb20ed4bfdc25bc8364bc62dcf54b",
"sha256:57c38470d9f57e37afb460c399eb254e7193ac7fb8042bd09bdc001981a9c74c"
],
"version": "==4.5.0"
}

Просмотреть файл

@ -0,0 +1,11 @@
# This configuration file is for **development** setup. For production, refer to
# docker-compose.production.yml.
version: '2'
services:
ui-tests:
image: mozilla/redash-ui-tests:latest
environment:
REDASH_SERVER_URL: http://redash:5000
links:
- "server:redash"
entrypoint: ./docker-entrypoint.sh

49
docker-compose.yml Normal file
Просмотреть файл

@ -0,0 +1,49 @@
version: '2'
services:
ui-tests:
build: .
environment:
REDASH_SERVER_URL: http://redash:5000
links:
- "server:redash"
entrypoint: ./docker-entrypoint.sh
server:
image: redash/redash:latest
command: dev_server
depends_on:
- postgres
- redis
ports:
- "5000:5000"
environment:
PYTHONUNBUFFERED: 0
REDASH_LOG_LEVEL: "INFO"
REDASH_REDIS_URL: "redis://redis:6379/0"
REDASH_DATABASE_URL: "postgresql://postgres@postgres/postgres"
REDASH_GOOGLE_CLIENT_ID: "dummy"
REDASH_GOOGLE_CLIENT_SECRET: "dummy"
restart: always
worker:
image: redash/redash:latest
command: scheduler
volumes_from:
- server
depends_on:
- server
environment:
PYTHONUNBUFFERED: 0
REDASH_LOG_LEVEL: "INFO"
REDASH_REDIS_URL: "redis://redis:6379/0"
REDASH_DATABASE_URL: "postgresql://postgres@postgres/postgres"
QUEUES: "queries,scheduled_queries,celery"
WORKERS_COUNT: 2
redis:
image: redis:3.0-alpine
restart: unless-stopped
postgres:
image: postgres:9.5.6-alpine
# The following turns the DB into less durable, but gains significant performance improvements for the tests run (x3
# improvement on my personal machine). We should consider moving this into a dedicated Docker Compose configuration for
# tests.
command: "postgres -c fsync=off -c full_page_writes=off -c synchronous_commit=OFF"
restart: unless-stopped

12
docker-entrypoint.sh Executable file
Просмотреть файл

@ -0,0 +1,12 @@
#!/bin/bash
set -e
case "$1" in
ui_test)
exec pipenv run pytest --driver=Firefox --base-url=http://redash:5000 --verify-base-url --variables=variables.json --html=report.html
;;
*)
exec "$@"
;;
esac

Просмотреть файл

@ -32,7 +32,7 @@ class LoginPage(Page):
"""Return the profile dropdown element."""
element = self.wait.until(expected.visibility_of_element_located((
By.CSS_SELECTOR,
".dropdown--profile__username",
".dropdown .dropdown--profile__username",
)))
return element.text

5
setup-docker.sh Executable file
Просмотреть файл

@ -0,0 +1,5 @@
#! /bin/bash
docker-compose -f docker-compose.yml run --rm server create_db
docker-compose -f docker-compose.yml run --rm postgres psql -h postgres -U postgres -c "create database tests"
wget localhost:5000/setup --post-data="name=Ashley McTest&email=ashley@example.com&password=REPLACE ME&org_name=default" -O /dev/null

Просмотреть файл

@ -6,6 +6,9 @@ import os
import attr
import pytest
import requests
from requests.packages.urllib3.util.retry import Retry
from requests.adapters import HTTPAdapter
from pages.login import LoginPage
@ -18,7 +21,22 @@ class User:
email = attr.ib(type=str)
@pytest.fixture(name='org')
@pytest.fixture(scope='session', autouse=True)
def _verify_url(request, base_url, user, org):
"""Verifies the base URL.
This will ping the base url until it returns a 200.
"""
verify = request.config.option.verify_base_url
if base_url and verify:
session = requests.Session()
retries = Retry(backoff_factor=0.1,
status_forcelist=[500, 502, 503, 504])
session.mount(base_url, HTTPAdapter(max_retries=retries))
session.get(base_url, verify=False)
@pytest.fixture(name='org', scope='session')
def fixture_org():
"""Return the slug of an org."""
return 'default'
@ -30,34 +48,14 @@ def fixture_unknown_user(variables, org):
return User(**variables[org]['users']['unknown'])
@pytest.fixture(name='user')
@pytest.fixture(name='user', scope='session')
def fixture_user(variables, org):
"""Return a registered user."""
return User(**variables[org]['users']['ashley'])
@pytest.fixture(name='server_url')
def fixture_server_url(request):
"""Return the URL to the Redash server."""
return request.config.option.server_url
@pytest.fixture(name='login_page')
def fixture_login_page(selenium, server_url, org):
def fixture_login_page(selenium, base_url, org):
"""Return a page object model for the login page."""
login_page = LoginPage(selenium, server_url, org=org)
login_page = LoginPage(selenium, base_url, org=org)
return login_page.open()
def pytest_addoption(parser):
"""Add custom options to pytest."""
group = parser.getgroup('redash')
group.addoption(
'--server-url',
action='store',
dest='server_url',
type=str,
default=os.getenv('REDASH_SERVER_URL', 'http://localhost:5000'),
help="URL to the Redash Server",
)

Просмотреть файл

@ -2,7 +2,10 @@
"""UI tests for the login page."""
import pytest
@pytest.mark.nondestructive
def test_login_wrong_user_credentials(login_page, unknown_user):
"""Test for a failed login attempt."""
assert login_page.title == 'Login to Redash'
@ -13,6 +16,7 @@ def test_login_wrong_user_credentials(login_page, unknown_user):
assert login_page.title == 'Login to Redash'
@pytest.mark.nondestructive
def test_login(login_page, user):
"""Test for a successful login attempt."""
assert login_page.title == 'Login to Redash'