Updated UI-tests to run inside of docker and switched to circleci 2.0 (#6457)

* Updated config to use circleci as well as configure ui-tests to run within docker

* Removed hacky certifi installs

* Update requirements to master versions

Fixes #4697 (though not only that)
This commit is contained in:
Benjamin Forehand Jr 2017-10-05 04:14:08 -07:00 коммит произвёл Christopher Grebs
Родитель 7a4f43e1a6
Коммит d6bb402a44
19 изменённых файлов: 538 добавлений и 464 удалений

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

@ -6,7 +6,6 @@ python:
env:
global:
- DISPLAY=:99.0
- secure: "bYe6WOTAnlS8Ru4ODWSSOnHffxcN23NkKZh4M0eO510HvZGCMB4zZn8afiVKGXd1YqsoRfMXTBZJ0yBcFEvWnyH7S4kd+7d1PpNS4kgLVKtLCW5d7Wc5GA6uh1jWLS+zKFBNN5sZ8OVc7rCsLCBRDEoI94wBKYwDX2Kk1WKylz8="
matrix:
- TOXENV=flake8
@ -19,7 +18,6 @@ env:
- TOXENV=amo
- TOXENV=users
- TOXENV=main
- TOXENV=ui-tests
cache:
pip: true
@ -40,7 +38,6 @@ addons:
- oracle-java8-set-default
- elasticsearch
- gettext
firefox: latest
before_install:
- mysql -e 'create database olympia;'
@ -57,16 +54,6 @@ before_script:
- node --version
- java -version
- curl -v http://localhost:9200/
- |
if [[ $TOXENV == "ui-tests" ]]; then
wget -O /tmp/geckodriver.tar.gz https://github.com/mozilla/geckodriver/releases/download/v0.16.1/geckodriver-v0.16.1-linux64.tar.gz
mkdir $HOME/geckodriver && tar xvf /tmp/geckodriver.tar.gz -C $HOME/geckodriver
export PATH=$HOME/geckodriver:$PATH
firefox --version
geckodriver --version
sh -e /etc/init.d/xvfb start
sleep 10
fi
script:
- |

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

@ -125,4 +125,19 @@ update: update_deps update_db update_assets
reindex:
python manage.py reindex $(ARGS)
ui-tests:
rm -rf ./user-media/* ./tmp/*
python manage.py reset_db --noinput
python manage.py syncdb --noinput
python manage.py loaddata initial.json
python manage.py import_prod_versions
schematic --fake src/olympia/migrations/
python manage.py loaddata zadmin/users
python manage.py update_permissions_from_mc
python manage.py loaddata src/olympia/access/fixtures/initial.json
python manage.py waffle_switch super-create-accounts on
python manage.py createsuperuser --email=uitest@mozilla.com --username=uitest --noinput --add-to-supercreate-group --save-api-credentials=tests/ui/variables.json --hostname=olympia.dev
python manage.py reindex --wipe --force --noinput
python manage.py generate_ui_test_addons
initialize: update_deps initialize_db update_assets populate_data

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

@ -1,38 +1,109 @@
machine:
services:
- docker
hosts:
olympia.dev: 127.0.0.1
version: 2.0
dependencies:
override:
- docker version
- >
printf '{"commit":"%s","version":"%s","source":"https://github.com/%s/%s","build":"%s"}\n'
"$CIRCLE_SHA1"
"$CIRCLE_TAG"
"$CIRCLE_PROJECT_USERNAME"
"$CIRCLE_PROJECT_REPONAME"
"$CIRCLE_BUILD_URL"
> version.json
- docker build -t app:build -f Dockerfile.deploy .
test:
override:
- echo "UI Tests are run on Travis CI. https://travis-ci.org/mozilla/addons-server/"
deployment:
latest:
branch: master
commands:
- docker tag app:build ${DOCKERHUB_REPO}:latest
- docker login -e $DOCKERHUB_EMAIL -u $DOCKERHUB_USER -p $DOCKERHUB_PASS
- docker push ${DOCKERHUB_REPO}:latest
releases:
# push all tags
tag: /.*/
commands:
- docker tag app:build ${DOCKERHUB_REPO}:${CIRCLE_TAG}
- docker login -e $DOCKERHUB_EMAIL -u $DOCKERHUB_USER -p $DOCKERHUB_PASS
- docker push ${DOCKERHUB_REPO}:${CIRCLE_TAG}
jobs:
build:
machine: true
working_directory: ~/addons-server
steps:
- checkout
- run: >
printf '{"commit":"%s","version":"%s","source":"https://github.com/%s/%s","build":"%s"}\n'
"$CIRCLE_SHA1"
"$CIRCLE_TAG"
"$CIRCLE_PROJECT_USERNAME"
"$CIRCLE_PROJECT_REPONAME"
"$CIRCLE_BUILD_URL"
> version.json
- run: docker build -t app:build -f Dockerfile.deploy .
- persist_to_workspace:
root: .
paths: .
integration_test:
working_directory: ~/addons-server
machine: true
steps:
- checkout
- restore_cache:
keys:
- uitest-cache-{{ checksum "requirements/docs.txt" }}
- uitest-cache-{{ checksum "requirements/prod.txt" }}
- uitest-cache-{{ checksum "requirements/dev.txt" }}
- uitest-cache-{{ checksum "requirements/uitests.txt" }}
- uitest-cache-
- run:
name: Install Docker Compose
command: |
set -x
sudo pip install docker-compose
- run:
name: Start container, verify it's running and start tests
command: |
set -x
sudo sysctl -w vm.max_map_count=262144
docker-compose up -d
sleep 10
docker-compose exec web bash /code/scripts/ui-test.sh
- store_artifacts:
path: ui-test-results
- save_cache:
key: uitest-cache-{{ checksum "requirements/docs.txt" }}
paths:
- .tox
- save_cache:
key: uitest-cache-{{ checksum "requirements/prod.txt" }}
paths:
- .tox
- save_cache:
key: uitest-cache-{{ checksum "requirements/dev.txt" }}
paths:
- .tox
- save_cache:
key: uitest-cache-{{ checksum "requirements/uitests.txt" }}
paths:
- .tox
- save_cache:
key: uitest-cache-
paths:
- .tox
deploy:
machine: true
steps:
- attach_workspace:
at: ~/addons-server
- run:
name: Dockerfile deploy
command: |
docker tag app:build ${DOCKERHUB_REPO}:latest
docker login -e $DOCKERHUB_EMAIL -u $DOCKERHUB_USER -p $DOCKERHUB_PASS
docker push ${DOCKERHUB_REPO}:latest
release:
machine: true
steps:
- attach_workspace:
at: ~/addons-server
- run:
Name: Release
command: |
docker tag app:build ${DOCKERHUB_REPO}:${CIRCLE_TAG}
docker login -e $DOCKERHUB_EMAIL -u $DOCKERHUB_USER -p $DOCKERHUB_PASS
docker push ${DOCKERHUB_REPO}:${CIRCLE_TAG}
workflows:
version: 2
build_test_deploy_release:
jobs:
- build
- integration_test
- deploy:
requires:
- build
filters:
branches:
only: master
- release:
requires:
- build
filters:
tags:
only: /.*/
branches:
ignore: /.*/

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

@ -1,7 +1,10 @@
nginx:
ports:
- "80:80"
version: "2"
web:
ports:
- "8000:8000"
services:
nginx:
ports:
- "80:80"
web:
ports:
- "8000:8000"

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

@ -1,69 +1,74 @@
worker: &worker
image: addons/addons-server
command: supervisord -n -c /code/docker/supervisor-celery.conf
entrypoint: ./scripts/start-docker.sh
volumes:
- .:/code
links:
- memcached
- mysqld
- elasticsearch
- redis
- rabbitmq
environment:
- BROKER_URL=amqp://olympia:olympia@rabbitmq/olympia
- CELERY_RESULT_BACKEND=redis://redis:6379/1
- DATABASE_URL=mysql://root:@mysqld/olympia
- ELASTICSEARCH_LOCATION=elasticsearch:9200
- MEMCACHE_LOCATION=memcached:11211
- MYSQL_DATABASE=olympia
- MYSQL_ROOT_PASSWORD=docker
- OLYMPIA_SITE_URL=http://olympia.dev
- PYTHONDONTWRITEBYTECODE=1
- PYTHONUNBUFFERED=1
- RECURSION_LIMIT=10000
- REDIS_LOCATION=redis://redis:6379/0?socket_timeout=0.5
- TERM=xterm-256color
version: "2"
web:
<<: *worker
command: supervisord -n -c /code/docker/supervisor.conf
services:
worker: &worker
image: addons/addons-server
command: supervisord -n -c /code/docker/supervisor-celery.conf
entrypoint: ./scripts/start-docker.sh
volumes:
- .:/code
environment:
- BROKER_URL=amqp://olympia:olympia@rabbitmq/olympia
- CELERY_RESULT_BACKEND=redis://redis:6379/1
- DATABASE_URL=mysql://root:@mysqld/olympia
- ELASTICSEARCH_LOCATION=elasticsearch:9200
- MEMCACHE_LOCATION=memcached:11211
- MYSQL_DATABASE=olympia
- MYSQL_ROOT_PASSWORD=docker
- OLYMPIA_SITE_URL=http://olympia.dev
- PYTHONDONTWRITEBYTECODE=1
- PYTHONUNBUFFERED=1
- RECURSION_LIMIT=10000
- REDIS_LOCATION=redis://redis:6379/0?socket_timeout=0.5
- TERM=xterm-256color
extra_hosts:
- "olympia.dev:127.0.0.1"
nginx:
image: addons/addons-nginx
volumes:
- ./static:/srv/static
- ./site-static:/srv/site-static
links:
- web:web
web:
<<: *worker
command: supervisord -n -c /code/docker/supervisor.conf
memcached:
image: memcached:1.4
nginx:
image: addons/addons-nginx
volumes:
- ./static:/srv/static
- ./site-static:/srv/site-static
mysqld:
image: mysql:5.7
environment:
- MYSQL_ALLOW_EMPTY_PASSWORD=yes
- MYSQL_DATABASE=olympia
volumes:
- ./docker/etc/mysql/conf.d/:/etc/mysql/conf.d/
memcached:
image: memcached:1.4
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:5.4.1
environment:
- xpack.security.enabled=false
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
mem_limit: 2g
mysqld:
image: mysql:5.7
environment:
- MYSQL_ALLOW_EMPTY_PASSWORD=yes
- MYSQL_DATABASE=olympia
redis:
image: redis:2.8
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:5.4.1
environment:
- xpack.security.enabled=false
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
mem_limit: 2g
rabbitmq:
image: rabbitmq:3.5
hostname: olympia
expose:
- "5672"
environment:
- RABBITMQ_DEFAULT_USER=olympia
- RABBITMQ_DEFAULT_PASS=olympia
- RABBITMQ_DEFAULT_VHOST=olympia
redis:
image: redis:2.8
rabbitmq:
image: rabbitmq:3.5
hostname: olympia
expose:
- "5672"
environment:
- RABBITMQ_DEFAULT_USER=olympia
- RABBITMQ_DEFAULT_PASS=olympia
- RABBITMQ_DEFAULT_VHOST=olympia
selenium-firefox:
image: selenium/standalone-firefox-debug
expose:
- "4444"
ports:
- "5900"
shm_size: 2g
links:
- "web:olympia.dev"

91
requirements/uitests.txt Normal file
Просмотреть файл

@ -0,0 +1,91 @@
fxapom==1.10.1 \
--hash=sha256:2d3c6cb8182b6d0f525628c6cf84cfe7d8f9dbd1dad487e8514cc2f5461e5009 \
--hash=sha256:062c114b16281774470fffbbe80772f3fa9976cb4d2fe9db1a81d2028243a82c
hawkauthlib==0.1.1 \
--hash=sha256:7ac93c892e7629721dde196193c9af3bde1f20540945569f7c7d34d3ea92680a
PyBrowserID==0.12.0 \
--hash=sha256:40cfec78212d79af67ca8744c563dc029d30196585e4848b03e01bbbd36cf53e
PyFxA==0.3.0 \
--hash=sha256:e5963db092b71bff0f51e0695eeeb59405e5646c51998c2d3f06b96d5aca6ace \
--hash=sha256:783d798168a8df3d5c72829a3cf62210635626047baabebe409ccd4a0a16d0d1
PyJWT==1.5.3 \
--hash=sha256:a4e5f1441e3ca7b382fd0c0b416777ced1f97c64ef0c33bfa39daf38505cfd2f \
--hash=sha256:500be75b17a63f70072416843dc80c8821109030be824f4d14758f114978bae7
PyPOM==1.2.0 \
--hash=sha256:f3b0e8af86fda2a05361b1862dcb3267ed316ad49c5a7410981b270e0754d525 \
--hash=sha256:068abbeffee51fcb703357a5db1e7d2b3e8e4ccd9828b8bbe64b0fae6db99365
pytest==3.2.2 \
--hash=sha256:b84f554f8ddc23add65c411bf112b2d88e2489fd45f753b1cae5936358bdf314 \
--hash=sha256:f46e49e0340a532764991c498244a60e3a37d7424a532b3ff1a6a7653f1a403a
pytest-base-url==1.2.0 \
--hash=sha256:cbb117787d7327dde0d50b9b9be4203a831986ec0dc658317815bbd24a039ca9 \
--hash=sha256:248dae2e3e7bb2c69d10101724b68fe756853e4ece4d9feb8bf09b38c027f65b
pytest-html==1.14.0 \
--hash=sha256:9d35d1c6431329458f9d45cc2f51456a9365c82ccae629e5c5b3f08f2a8b89cf \
--hash=sha256:fcd90a13d41abcc69a0388bf5da8b81c78ed07f92789f8058a1b9da6d2cedb59
pytest-instafail==0.3.0 \
--hash=sha256:b4d5fc3ca81e530a8d0e15a7771dc14b06fc9a0930c4b3909a7f4527040572c3
pytest-metadata==1.5.0 \
--hash=sha256:f962d1a2ecb57162a3067ba41958e726ed6eb017f69648cb9439e7635f841bc8 \
--hash=sha256:d5788ced96426bf5ac890a7684ec24480782fda932cbdf9dbb073a4a2980770b
pytest-selenium==1.11.1 \
--hash=sha256:b98f97f7fc1f24b9806ab369df3077cf43cce0884e427ad7a21b9239ac8bef47 \
--hash=sha256:91a94a1221d180c7d455b5b1bd50d5cbce797f0ca81d28239075048abbf416b4
pytest-variables==1.7.0 \
--hash=sha256:d333e1df272f9ef4bf45d8665ee46a4901b11ab52bf661e83174f42f2f83df39 \
--hash=sha256:61a6098175a59af5dbabf4c93ceee81a75f045868078903c44e2edb9582d5d6e
pytest-xdist==1.20.0 \
--hash=sha256:7924d45c2430191fe3679a58116c74ceea13307d7822c169d65fd59a24b3a4fe
selenium==3.5.0 \
--hash=sha256:69b479bdfa1ab2fee86a75086f7d5c6ef93cdad8cb6521cb0596554c6722f3eb \
--hash=sha256:267418f5fde1a4f8c180e5b8f45bd57c6d45b1f7d8fa5ad699a48e9a98fa79a3
WebOb==1.7.3 \
--hash=sha256:0ef6a10fc04a9e699fe0260b3af9b3518e239d35e2942c6fdc2959c193730a2d \
--hash=sha256:e65ca14b9f5ae5b031988ffc93f8b7f305ddfcf17a4c774ae0db47bcb3b87283
zope.component==4.4.0 \
--hash=sha256:de06dd4b311f84f8f2662c7bb0cc615ad40cb8e8e42ab62cf082700b8e25e7f1 \
--hash=sha256:2a53e184026d63ef4073dd3722b34f104fbc702329b61182bf65e1152ef5038a
zope.event==4.3.0 \
--hash=sha256:57b5fefd1d92774a7c26d7307b7ad9d0eac2181fd320b2061e69216e2a3b3a07 \
--hash=sha256:e0ecea24247a837c71c106b0341a7a997e3653da820d21ef6c08b32548f733e7
zope.interface==4.4.2 \
--hash=sha256:0effab9d51933e35ccd01f4c8c6d72f8040df78deacb2ec9176a7519722ce9ba \
--hash=sha256:5c14d72a86df23bc473efa8567a2f04fc94d1ba84a8ba651e3a9991e8b20a15a \
--hash=sha256:74eba4f1d2100424d51956103836d7c07bc8e5bf17fcf34a59b784e1fcedeaf2 \
--hash=sha256:17873e481cd2dce1db4fc15bbcb59400c100771354bddad8302fadb7dd2a0f0e \
--hash=sha256:fd56bbded257c0da54e98dce7a030e76cc018b8c3eaeb8ce8f35487fb1c859e3 \
--hash=sha256:2bcd66cc16dccf8b1cca37abe8ce947d38b54f78c244fd45102fc00997c7446a \
--hash=sha256:8aa8f86fb2c7a7cab830fc871a2bd19af18dabb0e940ec9adb658136eb12ebae \
--hash=sha256:c55003bf2ab1046dbc0e79a4a9ac7af2f5800ed6ec4cb8e35fc3c99a21f380a8 \
--hash=sha256:21c506b586ab17e7d353e5597683112285b0889330c9bd4f374e4f8b387d3348 \
--hash=sha256:13119a6ab5cd1d9b28b85ac9c7e1dadd4e0b743016a5b77a374ce51b3d26f339 \
--hash=sha256:dac9c7d45f8ab94f6f1a0dd167398a633924c85238cc8d76a6a04e6eac04def7 \
--hash=sha256:fbe4140cc7743c541c302a0bf31dca432b0c0a914053809a9338237d54c3b6ca \
--hash=sha256:40026b28cbf065ae54dcfdb1f95f14d6d07c4f38a4293a3bb663f2bee620fd4e \
--hash=sha256:0e9fa25e4786d02e88a17f0b1152ab3e901ab47a44b05a6c711e253836d4698c \
--hash=sha256:8adee390aaeeae7d5858f023e552bdb631ff4f129900ea1e8bb62c3722af12f5 \
--hash=sha256:fae7b143aea7248cbbed9ed3977e8198fa82805d1643556b03d23df28ffdf99b \
--hash=sha256:0d1e1f3a816b5b4774c0a7cf46adf399d298f44c4de71ecab6ea83b9b71b9bc7 \
--hash=sha256:74f2a8c466124f852cb78bbb6bf8306340af1885e77870abc5418cbfeb54fece \
--hash=sha256:9a567f17f3f41e955bc87cfa39cbd5713ba3077dfd8a06a360605ec45407e357 \
--hash=sha256:f7cbfd9698c16cb2ed164e7b9e4b3a24217e51fccfd95c3fd3dcca9bc1e7c9e9 \
--hash=sha256:6c9e61ac24ed84d9c6a20155d979bd08f278c76450d7ab65a107057780457aac \
--hash=sha256:0b84b11b828770f9d711be99d037bb076ed0291a343fd910b683a9bd7866e0f2 \
--hash=sha256:aeeff785ba7cd5cad4b2cfd2930bf5c2431e0fdfdf7ffc0b3af44827f1007611 \
--hash=sha256:3c87138213b2a3896adcbf4fcc3dd916c68cef405cadcb9327d0f08949e10194 \
--hash=sha256:5e0c85069a508835b192d5fd304aef4a7b23a325f2cd58e8953ae1c1eb1a8570 \
--hash=sha256:7cc6f03a905094983f92cd6a97244de05e9293f7b09e110ce4c7c81de8a26a3a \
--hash=sha256:b2467ebf96561f022265cf0e1920d19ab1178deb3f0bb9fbd81bd90e995251c1 \
--hash=sha256:6522348b2df4821f575117722c928feae140708cafa70a80272659db7bff6cbe \
--hash=sha256:8b6b3574a4471f15e63476cffb3528b7eadd325736dfc128abb33ff5602bb260 \
--hash=sha256:f4cfa59fe02ab708cd586f4051824d199118bff893252c0538e64171b21c1871 \
--hash=sha256:a7dca9e23887b449b11e849954bf2f58bf0585c312759d95dfcc12e2f4f62166 \
--hash=sha256:c7fe0182a96b241ee4e0684eb9d845daec0601efe221960c265311ed43ae3328 \
--hash=sha256:6477aa23a0a5e56a5b04579f66f3271276164355a8f097f4b0bf5323f2c87c0d \
--hash=sha256:4e59e427200201f69ef82956ddf9e527891becf5b7cde8ec3ce39e1d0e262eb0 \
--hash=sha256:b694b9ce4b434565a90a0ced8e80f7d3ab6d06ae84b8a6c084fcafc9fb3e8f95 \
--hash=sha256:84eb3fad9402372b66f544a536a201665e69923a7e897c49b76ea033f7d1e7c5 \
--hash=sha256:41fac9e2b43ef6e47c21b66b1646155b1c8e6de8c0e8ffb615bebe7d9c1f063c \
--hash=sha256:576bb6efc56aa21807f61aaa138c4686b7ae272b854c0ad4ef9358ae2ee12062 \
--hash=sha256:d015fb90214dccbfc8260df89a72fab29a52cb6389b3298c8e54c70aa9ac6746 \
--hash=sha256:f8e0b9a41ad54402785fc1ceb40b29a630779b61755ef51cd00c0bba3d2e5d4e

10
scripts/ui-test.sh Normal file
Просмотреть файл

@ -0,0 +1,10 @@
#!/bin/sh
echo 127.0.0.1 olympia.dev | tee -a /etc/hosts
yum -y install curl
curl https://raw.githubusercontent.com/creationix/nvm/v0.30.2/install.sh > install-nvm.sh
sh install-nvm.sh
source ~/.bash_profile
nvm install node
unset NPM_CONFIG_PREFIX
pip install tox
tox -e ui-tests

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

@ -0,0 +1,32 @@
from django.core.cache import cache
from django.core.management.base import BaseCommand
from django.core.management import call_command
from django.utils import translation
from olympia.landfill.serializers import GenerateAddonsSerializer
class Command(BaseCommand):
"""
Generate addons used specifically for the Integration Tests.
This will generate 10 addons with the name Ui-Addon, 1 Addon named
Ui-Addon-Test, 1 Featured theme, 4 featured collections, and 6 themes that
will not be marked as featured.
Usage:
python manage.py generate_ui_test_addons
"""
def handle(self, *args, **kwargs):
translation.activate('en-US')
serializer = GenerateAddonsSerializer()
serializer.create_generic_featured_addons()
serializer.create_featured_addon_with_version()
serializer.create_featured_theme()
serializer.create_featured_collections()
serializer.create_featured_themes()
cache.clear()
call_command('clear_cache')

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

@ -0,0 +1,154 @@
import random
from rest_framework import serializers
from olympia.amo.tests import user_factory, addon_factory
from olympia import amo
from olympia.addons.forms import icons
from olympia.addons.models import AddonUser, Preview
from olympia.addons.utils import generate_addon_guid
from olympia.amo.tests import version_factory
from olympia.constants.applications import APPS, FIREFOX
from olympia.constants.base import (
ADDON_EXTENSION,
ADDON_PERSONA,
STATUS_PUBLIC
)
from olympia.landfill.collection import generate_collection
from olympia.landfill.generators import generate_themes
from olympia.reviews.models import Review
from olympia.users.models import UserProfile
class GenerateAddonsSerializer(serializers.Serializer):
count = serializers.IntegerField(default=10)
def create_generic_featured_addons(self):
"""Creates 10 addons.
Creates exactly 10 random addons with users that are also randomly
generated.
"""
for _ in range(10):
AddonUser.objects.create(
user=user_factory(), addon=addon_factory())
def create_featured_addon_with_version(self):
"""Creates a custom addon named 'Ui-Addon'.
This addon will be a featured addon and will have a featured collecton
attatched to it. It will belong to the user uitest.
It has 1 preview, 5 reviews, and 2 authors. The second author is named
'ui-tester2'. It has a version number as well as a beta version.
"""
default_icons = [x[0] for x in icons() if x[0].startswith('icon/')]
addon = addon_factory(
status=STATUS_PUBLIC,
type=ADDON_EXTENSION,
average_daily_users=5000,
users=[UserProfile.objects.get(username='uitest')],
average_rating=5,
description=u'My Addon description',
file_kw={
'hash': 'fakehash',
'platform': amo.PLATFORM_ALL.id,
'size': 42,
},
guid=generate_addon_guid(),
icon_type=random.choice(default_icons),
name=u'Ui-Addon',
public_stats=True,
slug='ui-test-2',
summary=u'My Addon summary',
tags=['some_tag', 'another_tag', 'ui-testing',
'selenium', 'python'],
total_reviews=500,
weekly_downloads=9999999,
developer_comments='This is a testing addon.',
)
Preview.objects.create(addon=addon, position=1)
Review.objects.create(addon=addon, rating=5, user=user_factory())
Review.objects.create(addon=addon, rating=5, user=user_factory())
Review.objects.create(addon=addon, rating=5, user=user_factory())
Review.objects.create(addon=addon, rating=5, user=user_factory())
Review.objects.create(addon=addon, rating=5, user=user_factory())
Review.objects.create(addon=addon, rating=5, user=user_factory())
Review.objects.create(addon=addon, rating=5, user=user_factory())
Review.objects.create(addon=addon, rating=5, user=user_factory())
AddonUser.objects.create(user=user_factory(username='ui-tester2'),
addon=addon, listed=True)
version_factory(addon=addon, file_kw={'status': amo.STATUS_BETA},
version='1.1beta')
addon.save()
generate_collection(addon, app=FIREFOX)
print(
'Created addon {0} for testing successfully'
.format(addon.name))
def create_featured_theme(self):
"""Creates a custom theme named 'Ui-Test Theme'.
This theme will be a featured theme and will belong to the uitest user.
It has one author.
"""
addon = addon_factory(
status=STATUS_PUBLIC,
type=ADDON_PERSONA,
average_daily_users=4242,
users=[UserProfile.objects.get(username='uitest')],
average_rating=5,
description=u'My UI Theme description',
file_kw={
'hash': 'fakehash',
'platform': amo.PLATFORM_ALL.id,
'size': 42,
},
guid=generate_addon_guid(),
homepage=u'https://www.example.org/',
name=u'Ui-Test Theme',
public_stats=True,
slug='ui-test',
summary=u'My UI theme summary',
support_email=u'support@example.org',
support_url=u'https://support.example.org/support/ui-theme-addon/',
tags=['some_tag', 'another_tag', 'ui-testing',
'selenium', 'python'],
total_reviews=777,
weekly_downloads=123456,
developer_comments='This is a testing theme, used within pytest.',
)
addon.save()
generate_collection(
addon,
app=FIREFOX,
type=amo.COLLECTION_FEATURED)
print('Created Theme {0} for testing successfully'.format(addon.name))
def create_featured_collections(self):
"""Creates exactly 4 collections that are featured.
This fixture uses the generate_collection function from olympia.
"""
for _ in range(4):
addon = addon_factory(type=amo.ADDON_EXTENSION)
generate_collection(
addon, APPS['firefox'], type=amo.COLLECTION_FEATURED)
def create_featured_themes(self):
"""Creates exactly 6 themes that will be not featured.
These belong to the user uitest.
It will also create 6 themes that are featured with random authors.
"""
generate_themes(6, 'uitest@mozilla.com')
for _ in range(6):
addon = addon_factory(status=STATUS_PUBLIC, type=ADDON_PERSONA)
generate_collection(addon, app=FIREFOX)

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

@ -1,48 +1,13 @@
import datetime
import json
import os
import random
import urlparse
import jwt
import pytest
import requests
from django.core.management import call_command
from django.conf import settings
from fxapom.fxapom import DEV_URL, PROD_URL, FxATestAccount
from olympia import amo
from olympia.addons.forms import icons
from olympia.addons.models import AddonUser, Preview
from olympia.addons.utils import generate_addon_guid
from olympia.amo.tests import (
addon_factory,
create_switch,
user_factory,
version_factory,
)
from olympia.constants.applications import APPS, FIREFOX
from olympia.constants.base import (
ADDON_EXTENSION,
ADDON_PERSONA,
STATUS_PUBLIC
)
from olympia.landfill.collection import generate_collection
from olympia.landfill.generators import generate_themes
from olympia.reviews.models import Review
from olympia.users.models import UserProfile
from pytest_django import live_server_helper
# TODO: Change imports to allow running tests against deployed instances.
@pytest.fixture(scope='function')
def my_base_url(base_url, request, pytestconfig):
"""Base URL used to start the 'live_server'."""
if base_url:
pytestconfig.option.usingliveserver = False
return base_url
else:
return request.getfixturevalue("live_server").url
@pytest.fixture
@ -53,9 +18,9 @@ def capabilities(capabilities):
@pytest.fixture
def fxa_account(my_base_url):
def fxa_account(base_url):
"""Account used to login to the AMO site."""
url = DEV_URL if 'dev' or 'localhost' in my_base_url else PROD_URL
url = DEV_URL if 'dev' or 'localhost' in base_url else PROD_URL
return FxATestAccount(url)
@ -80,226 +45,10 @@ def jwt_secret(base_url, variables):
@pytest.fixture
def initial_data(transactional_db, pytestconfig):
"""Fixture used to fill database will dummy addons.
Creates exactly 10 random addons with users that are also randomly
generated.
"""
if not pytestconfig.option.usingliveserver:
return
for _ in range(10):
AddonUser.objects.create(user=user_factory(), addon=addon_factory())
@pytest.fixture
def theme(transactional_db, create_superuser, pytestconfig):
"""Creates a custom theme named 'Ui-Test Theme'.
This theme will be a featured theme and will belong to the user created by
the 'create_superuser' fixture.
It has one author.
"""
if not pytestconfig.option.usingliveserver:
return
addon = addon_factory(
status=STATUS_PUBLIC,
type=ADDON_PERSONA,
average_daily_users=4242,
users=[UserProfile.objects.get(username='uitest')],
average_rating=5,
description=u'My UI Theme description',
file_kw={
'hash': 'fakehash',
'platform': amo.PLATFORM_ALL.id,
'size': 42,
},
guid=generate_addon_guid(),
homepage=u'https://www.example.org/',
name=u'Ui-Test Theme',
public_stats=True,
slug='ui-test',
summary=u'My UI theme summary',
support_email=u'support@example.org',
support_url=u'https://support.example.org/support/ui-theme-addon/',
tags=['some_tag', 'another_tag', 'ui-testing',
'selenium', 'python'],
total_reviews=777,
weekly_downloads=123456,
developer_comments='This is a testing theme, used within pytest.',
)
addon.save()
generate_collection(addon, app=FIREFOX,
author=UserProfile.objects.get(username='uitest'))
print('Created Theme {0} for testing successfully'.format(addon.name))
return addon
@pytest.fixture
def addon(transactional_db, create_superuser, pytestconfig):
"""Creates a custom addon named 'Ui-Addon'.
This addon will be a featured addon and will have a featured collecton
attatched to it. It will belong to the user created by the
'create_superuser' fixture.
It has 1 preview, 5 reviews, and 2 authors. The second author is named
'ui-tester2'. It has a version number as well as a beta version.
"""
if not pytestconfig.option.usingliveserver:
return
default_icons = [x[0] for x in icons() if x[0].startswith('icon/')]
addon = addon_factory(
status=STATUS_PUBLIC,
type=ADDON_EXTENSION,
average_daily_users=5567,
users=[UserProfile.objects.get(username='uitest')],
average_rating=5,
description=u'My Addon description',
file_kw={
'hash': 'fakehash',
'platform': amo.PLATFORM_ALL.id,
'size': 42,
},
guid=generate_addon_guid(),
homepage=u'https://www.example.org/',
icon_type=random.choice(default_icons),
name=u'Ui-Addon',
public_stats=True,
slug='ui-test',
summary=u'My Addon summary',
support_email=u'support@example.org',
support_url=u'https://support.example.org/support/ui-test-addon/',
tags=['some_tag', 'another_tag', 'ui-testing',
'selenium', 'python'],
total_reviews=888,
weekly_downloads=2147483647,
developer_comments='This is a testing addon, used within pytest.',
is_experimental=True,
)
Preview.objects.create(addon=addon, position=1)
Review.objects.create(addon=addon, rating=5, user=user_factory())
Review.objects.create(addon=addon, rating=3, user=user_factory())
Review.objects.create(addon=addon, rating=2, user=user_factory())
Review.objects.create(addon=addon, rating=1, user=user_factory())
addon.reload()
AddonUser.objects.create(user=user_factory(username='ui-tester2'),
addon=addon, listed=True)
version_factory(addon=addon, file_kw={'status': amo.STATUS_BETA},
version='1.1beta')
addon.save()
generate_collection(addon, app=FIREFOX)
print('Created addon {0} for testing successfully'.format(addon.name))
return addon
@pytest.fixture
def minimal_addon(transactional_db, create_superuser, pytestconfig):
"""Creates a custom addon named 'Ui-Addon-2'.
It will belong to the user created by the 'create_superuser' fixture.
It has 1 preview, and 2 reviews.
"""
if not pytestconfig.option.usingliveserver:
return
default_icons = [x[0] for x in icons() if x[0].startswith('icon/')]
addon = addon_factory(
status=STATUS_PUBLIC,
type=ADDON_EXTENSION,
average_daily_users=7000,
users=[UserProfile.objects.get(username='uitest')],
average_rating=3,
description=u'My Addon description',
file_kw={
'hash': 'fakehash',
'platform': amo.PLATFORM_ALL.id,
'size': 42,
},
guid=generate_addon_guid(),
icon_type=random.choice(default_icons),
name=u'Ui-Addon-2',
public_stats=True,
slug='ui-test-2',
summary=u'My Addon summary',
tags=['some_tag', 'another_tag', 'ui-testing',
'selenium', 'python'],
total_reviews=777,
weekly_downloads=22233879,
developer_comments='This is a testing addon, used within pytest.',
)
Preview.objects.create(addon=addon, position=1)
Review.objects.create(addon=addon, rating=5, user=user_factory())
Review.objects.create(addon=addon, rating=3, user=user_factory())
addon.reload()
addon.save()
generate_collection(addon, app=FIREFOX, type=amo.COLLECTION_FEATURED)
print('Created addon {0} for testing successfully'.format(addon.name))
return addon
@pytest.fixture
def themes(transactional_db, create_superuser, pytestconfig):
"""Creates exactly 6 themes that will be not featured.
These belong to the user created by the 'create_superuser' fixture.
It will also create 6 themes that are featured with random authors.
"""
if not pytestconfig.option.usingliveserver:
return
owner = UserProfile.objects.get(username='uitest')
generate_themes(6, owner)
for _ in range(6):
addon = addon_factory(status=STATUS_PUBLIC, type=ADDON_PERSONA)
generate_collection(addon, app=FIREFOX)
@pytest.fixture
def collections(transactional_db, pytestconfig):
"""Creates exactly 4 collections that are featured.
This fixture uses the generate_collection function from olympia.
"""
if not pytestconfig.option.usingliveserver:
return
for _ in range(4):
addon = addon_factory(type=amo.ADDON_EXTENSION)
generate_collection(
addon, APPS['firefox'], type=amo.COLLECTION_FEATURED)
@pytest.fixture
def create_superuser(transactional_db, my_base_url, tmpdir, variables):
"""Creates a superuser."""
create_switch('super-create-accounts')
call_command('loaddata', 'initial.json')
call_command(
'createsuperuser',
interactive=False,
username='uitest',
email='uitester@mozilla.org',
add_to_supercreate_group=True,
save_api_credentials=str(tmpdir.join('variables.json')),
hostname=urlparse.urlsplit(my_base_url).hostname
)
with tmpdir.join('variables.json').open() as f:
variables.update(json.load(f))
@pytest.fixture
def user(create_superuser, my_base_url, fxa_account, jwt_token):
def user(base_url, fxa_account, jwt_token):
"""This creates a user for logging into the AMO site."""
url = '{base_url}/api/v3/accounts/super-create/'.format(
base_url=my_base_url)
base_url=base_url)
params = {
'email': fxa_account.email,
@ -312,48 +61,8 @@ def user(create_superuser, my_base_url, fxa_account, jwt_token):
return params
@pytest.fixture(scope='function')
def live_server(request, transactional_db, pytestconfig):
"""This fixture overrides the live_server fixture provided by pytest_django.
live_server allows us to create a running version of the
addons django application within pytest for testing.
cgrebs:
From what I found out was that the `live_server` fixture (in our setup,
couldn't reproduce in a fresh project) apparently starts up the
LiveServerThread way too early before pytest-django configures the
settings correctly.
That resulted in the LiveServerThread querying the 'default' database
which was different from what the other fixtures and tests were using
which resulted in the problem that the just created api keys could not
be found in the api methods in the live-server.
I worked around that by implementing the live_server fixture ourselfs
and make it function-scoped so that it now runs in a proper
database-transaction.
This is a HACK and I'll work on a more permanent solution but for now
it should be enough to continue working on porting tests...
Also investigating if there are any problems in pytest-django directly.
"""
addr = (request.config.getvalue('liveserver') or
os.getenv('DJANGO_LIVE_TEST_SERVER_ADDRESS'))
if not addr:
addr = 'localhost:8081,8100-8200'
server = live_server_helper.LiveServer(addr)
pytestconfig.option.usingliveserver = True
yield server
server.stop()
@pytest.fixture
def jwt_token(base_url, jwt_issuer, jwt_secret):
@pytest.fixture(scope='session')
def jwt_token(jwt_issuer, jwt_secret):
"""This creates a JWT Token"""
payload = {
'iss': jwt_issuer,

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

@ -6,7 +6,7 @@ from base import Base
class Collections(Base):
"""Collections page."""
_item_locator = (By.CSS_SELECTOR, '.item')
_item_locator = (By.CSS_SELECTOR, '.items > div')
def wait_for_page_to_load(self):
self.wait.until(lambda _: len(self.collections) > 0 and

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

@ -40,6 +40,13 @@ class Home(Base):
def __repr__(self):
return '{0.name} ({0.users:,} users)'.format(self)
def click(self):
"""Clicks on the addon."""
self.find_element(*self._name_locator).click()
from pages.desktop.details import Details
return Details(
self.selenium, self.page.base_url).wait_for_page_to_load()
@property
def name(self):
"""Extension name"""
@ -54,7 +61,7 @@ class Home(Base):
class FeaturedExtensions(Region):
"""Featured Extension region"""
_root_locator = (By.ID, 'featured-extensions')
_extension_locator = (By.CSS_SELECTOR, 'section > li > div')
_extension_locator = (By.CSS_SELECTOR, 'section > li > .addon')
_see_all_locator = (By.CSS_SELECTOR, 'h2 > a')
@property
@ -65,10 +72,10 @@ class Home(Base):
class Extension(Region):
_name_locator = (By.CSS_SELECTOR, 'h3')
_link_locator = (By.TAG_NAME, 'a')
_link_locator = (By.CSS_SELECTOR, '.addon .summary a')
def see_all(self):
"""Clicks the 'See All' link"""
def click(self):
"""Clicks the addon link"""
self.find_element(*self._link_locator).click()
from pages.desktop.details import Details
return Details(

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

@ -27,8 +27,8 @@ class SearchResultList(Base):
class SearchResultItem(Region):
"""Represents individual results on the search page."""
_name_locator = (By.CSS_SELECTOR, 'h3 > a')
_rating_locator = (By.CSS_SELECTOR, '.rating > .stars')
_users_sort_locator = (By.CSS_SELECTOR, '.vitals > .adu')
_rating_locator = (By.CSS_SELECTOR, '.rating .stars')
_users_sort_locator = (By.CSS_SELECTOR, '.vitals .adu')
@property
def name(self):

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

@ -1,9 +0,0 @@
fxapom==1.10.1
PyJWT==1.5.3
PyPOM==1.2.0
pytest==3.2.2
pytest-instafail==0.3.0
pytest-selenium==1.11.1
pytest-variables==1.7.0
pytest-xdist==1.20.0
selenium==3.6.0

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

@ -1,5 +1,6 @@
[tool:pytest]
addopts = -r=a --verbose
addopts = -r=a -vs --showlocals --tb=short
sensitive_url = mozilla\.(com|org)
xfail_strict = true
DJANGO_SETTINGS_MODULE = settings_test
base_url = http://olympia.dev:8000

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

@ -5,17 +5,17 @@ from pages.desktop.home import Home
@pytest.mark.nondestructive
def test_there_are_ten_most_popular_extensions(
my_base_url, selenium, initial_data):
base_url, selenium):
"""Ten most popular add-ons are listed"""
page = Home(selenium, my_base_url).open()
page = Home(selenium, base_url).open()
assert len(page.most_popular.extensions) == 10
@pytest.mark.nondestructive
def test_most_popular_extensions_are_sorted_by_users(
my_base_url, selenium, initial_data):
base_url, selenium):
"""Most popular add-ons are sorted by popularity"""
page = Home(selenium, my_base_url).open()
page = Home(selenium, base_url).open()
extensions_page = page.most_popular.extensions
sorted_by_users = sorted(extensions_page,
key=lambda e: e.users, reverse=True)
@ -25,28 +25,28 @@ def test_most_popular_extensions_are_sorted_by_users(
@pytest.mark.smoke
@pytest.mark.nondestructive
def test_that_clicking_on_addon_name_loads_details_page(
my_base_url, selenium, addon):
base_url, selenium):
"""Details page addon name matches clicked addon"""
page = Home(selenium, my_base_url).open()
name = page.featured_extensions.extensions[0].name
extension_page = page.featured_extensions.extensions[0].see_all()
page = Home(selenium, base_url).open()
name = page.most_popular.extensions[0].name
extension_page = page.most_popular.extensions[0].click()
assert name in extension_page.description_header.name
@pytest.mark.smoke
@pytest.mark.nondestructive
def test_that_featured_themes_exist_on_the_home(
my_base_url, selenium, themes):
base_url, selenium):
"""Featured themes are displayed"""
page = Home(selenium, my_base_url).open()
page = Home(selenium, base_url).open()
assert len(page.featured_themes.themes) == 6
@pytest.mark.nondestructive
def test_that_clicking_see_all_themes_link_works(
my_base_url, selenium, theme, themes):
base_url, selenium):
"""Amount of featured themes matches on both pages"""
page = Home(selenium, my_base_url).open()
page = Home(selenium, base_url).open()
themes = page.featured_themes.themes
theme_page = page.featured_themes.see_all()
assert len(themes) == len(theme_page.featured.themes)
@ -54,17 +54,17 @@ def test_that_clicking_see_all_themes_link_works(
@pytest.mark.nondestructive
def test_that_featured_extensions_exist_on_the_home(
my_base_url, selenium, addon):
base_url, selenium):
"""Featured extensions exist on home page"""
page = Home(selenium, my_base_url).open()
page = Home(selenium, base_url).open()
assert len(page.featured_extensions.extensions) >= 1
@pytest.mark.nondestructive
def test_that_clicking_see_all_collections_link_works(
my_base_url, selenium, collections):
base_url, selenium):
"""Amount of featured themes matches on both pages"""
page = Home(selenium, my_base_url).open()
page = Home(selenium, base_url).open()
collections = page.featured_collections.collections
collections_page = page.featured_collections.see_all()
assert len(collections) == len(collections_page.collections)

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

@ -6,9 +6,9 @@ from pages.desktop.home import Home
@pytest.mark.skipif(os.environ.get('PYTEST_BASE_URL') is None,
reason='Live Server login currently not functioning')
def test_login(my_base_url, selenium, user):
def test_login(base_url, selenium, user):
"""User can login"""
page = Home(selenium, my_base_url).open()
page = Home(selenium, base_url).open()
assert not page.logged_in
page.login(user['email'], user['password'])
assert page.logged_in
@ -16,9 +16,9 @@ def test_login(my_base_url, selenium, user):
@pytest.mark.skip(
reason='https://github.com/mozilla/geckodriver/issues/233')
def test_logout(my_base_url, selenium, user):
def test_logout(base_url, selenium, user):
"""User can logout"""
page = Home(selenium, my_base_url).open()
page = Home(selenium, base_url).open()
page.login(user['email'], user['password'])
page.logout()
assert not page.logged_in

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

@ -6,11 +6,10 @@ from pages.desktop.home import Home
@pytest.mark.smoke
@pytest.mark.nondestructive
def test_that_searching_for_addon_returns_addon_as_first_result(
my_base_url, es_test, selenium, addon):
base_url, es_test, selenium):
"""Test searching for an addon returns the addon."""
page = Home(selenium, my_base_url).open()
name = str(
getattr(addon, 'name', page.featured_extensions.extensions[0].name))
page = Home(selenium, base_url).open()
name = page.most_popular.extensions[0].name
search_page = page.search_for(name)
assert name in search_page.results[0].name
assert name in selenium.title
@ -22,12 +21,10 @@ def test_that_searching_for_addon_returns_addon_as_first_result(
['Most Users', 'users'],
['Top Rated', 'rating']])
def test_sorting_by(
transactional_db, es_test, my_base_url, selenium, addon,
minimal_addon, category, sort_attr):
base_url, selenium, es_test, category, sort_attr):
"""Test searching for an addon and sorting."""
page = Home(selenium, my_base_url).open()
name = str(
getattr(addon, 'name', page.featured_extensions.extensions[0].name))
page = Home(selenium, base_url).open()
name = page.most_popular.extensions[0].name
search_page = page.search_for(name)
search_page.sort_by(category, sort_attr)
results = [getattr(i, sort_attr) for i in search_page.results]

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

@ -56,11 +56,12 @@ commands =
py.test -n 2 -m 'not es_tests' -v src/olympia/ --ignore src/olympia/addons/ --ignore src/olympia/devhub/ --ignore src/olympia/editors/ --ignore src/olympia/amo/ --ignore src/olympia/users/ {posargs}
[testenv:ui-tests]
passenv = DISPLAY PYTEST_ADDOPTS PYTEST_BASE_URL ELASTICSEARCH_LOCATION
passenv = *
commands =
make -f Makefile-docker update_deps
pip install --exists-action=w -r tests/ui/requirements.txt
pytest --boxed --driver Firefox -v tests/ui/ {posargs}
pip install --no-deps -r requirements/uitests.txt
make -f Makefile-docker ui-tests
pytest --driver Remote --host selenium-firefox --port 4444 --capability browserName firefox --variables tests/ui/variables.json --self-contained-html tests/ui {posargs}
[testenv:assets]
commands =