* Use docker-compose>=1.18 and minimal docker-compose config version to 2.3
* Starts ui-tests in Firefox docker container
* Let's the Firefox docker-container hit directly nginx
* makes use of https://github.com/jrbenny35/selenium-firefox/ firefox+selenium image
* makes use of /user-media/ serving directly via nginx for XPI installs
* Adds a helper that creates an installable add-on
* Update `firefox_options` fixture with all options needed to install add-ons with a test signing signature

Fixes #7270 
Fixes #2488
This commit is contained in:
Benjamin Forehand Jr 2018-01-11 21:58:00 -08:00 коммит произвёл Christopher Grebs
Родитель 0a7a2cd69f
Коммит 8a646cadc4
14 изменённых файлов: 200 добавлений и 54 удалений

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

@ -127,17 +127,28 @@ reindex:
ui-tests:
rm -rf ./user-media/* ./tmp/*
# Reset the database and fake database migrations
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/
# Let's load some initial data and import mozilla-product versions
python manage.py loaddata initial.json
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 import_prod_versions
python manage.py update_permissions_from_mc
# Create a proper superuser that can be used to access the API
python manage.py waffle_switch super-create-accounts on
python manage.py waffle_switch activate-autograph-signing 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
# Generate test add-ons and force a reindex to make sure things are updated
python manage.py generate_ui_test_addons
python manage.py reindex --force --noinput --wipe
pip install --no-deps -r requirements/uitests.txt
initialize: update_deps initialize_db update_assets populate_data

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

@ -59,7 +59,8 @@ jobs:
name: Install Docker Compose
command: |
set -x
sudo pip install docker-compose
pip install docker-compose>=1.18
docker-compose --version
- run:
name: Start container, verify it's running and start tests
command: |
@ -73,9 +74,10 @@ jobs:
docker-compose exec worker supervisorctl restart all
docker-compose exec web make -f Makefile-docker update_deps
docker-compose exec web supervisorctl restart all
docker-compose exec web bash /code/scripts/ui-test.sh
# Start Test in Firefox docker container
docker-compose exec selenium-firefox tox -e ui-tests
- store_artifacts:
path: ui-test-results
path: ui-test.html
- save_cache:
key: uitest-cache-{{ checksum "requirements/docs.txt" }}
paths:

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

@ -1,4 +1,4 @@
version: "2"
version: "2.3"
services:
nginx:

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

@ -1,26 +1,29 @@
version: "2"
version: "2.3"
x-env-mapping: &env
environment:
- CELERY_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
services:
worker: &worker
<<: *env
image: addons/addons-server
command: supervisord -n -c /code/docker/supervisor-celery.conf
entrypoint: ./scripts/start-docker.sh
volumes:
- .:/code
environment:
- CELERY_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"
@ -68,11 +71,14 @@ services:
image: mozilla/autograph:2.0.5
selenium-firefox:
image: selenium/standalone-firefox-debug
<<: *env
image: b4handjr/selenium-firefox
volumes:
- .:/code
expose:
- "4444"
ports:
- "5900"
shm_size: 2g
links:
- "web:olympia.dev"
- "nginx:olympia.dev"

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

@ -1,3 +1,6 @@
FoxPuppet==1.0.1 \
--hash=sha256:e912d18e15c202dd3bfe4b2b837411f267b231925feb170bc5af26787fccb4c2 \
--hash=sha256:a78918ea0b4846fe54cc853e3ab1bd11aa1c5ec6647a65eaa62c79a056b39581
fxapom==1.10.1 \
--hash=sha256:2d3c6cb8182b6d0f525628c6cf84cfe7d8f9dbd1dad487e8514cc2f5461e5009 \
--hash=sha256:062c114b16281774470fffbbe80772f3fa9976cb4d2fe9db1a81d2028243a82c
@ -23,6 +26,9 @@ pytest-base-url==1.4.1 \
pytest-html==1.16.1 \
--hash=sha256:135ea10b9ec0a5e370dc1820a5552d761aa3fec8400eabc0b06646f90f5c820e \
--hash=sha256:d6ae1ae5d10158d290b603ccf46b5d103e93cf7d67df42bb7d6516fb4f1317f3
pytest-firefox==0.1.1 \
--hash=sha256:d91ddd9b7090986d6e45df38830328d7178e95a846eafb1a975a12b7eb5a9fdb \
--hash=sha256:7c7acb4dc3d068a6d356797f18731b6ad2f64b5681043c0119f4b821bf20ea07
pytest-instafail==0.3.0 \
--hash=sha256:b4d5fc3ca81e530a8d0e15a7771dc14b06fc9a0930c4b3909a7f4527040572c3
pytest-metadata==1.5.1 \

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

@ -1,10 +0,0 @@
#!/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

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

@ -857,7 +857,7 @@ def version_factory(file_kw=None, **kw):
ApplicationsVersions.objects.get_or_create(application=application,
version=ver, min=av_min,
max=av_max)
if addon_type != amo.ADDON_PERSONA:
if addon_type != amo.ADDON_PERSONA and file_kw is not False:
file_kw = file_kw or {}
file_factory(version=ver, **file_kw)
return ver

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

@ -2,6 +2,7 @@ from django.core.cache import cache
from django.core.management import call_command
from django.core.management.base import BaseCommand
from django.utils import translation
from django.test.utils import override_settings
from olympia.landfill.serializers import GenerateAddonsSerializer
@ -21,12 +22,15 @@ class Command(BaseCommand):
"""
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()
with override_settings(CELERY_ALWAYS_EAGER=True):
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()
serializer.create_installable_addon()
cache.clear()
call_command('clear_cache')

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

@ -1,19 +1,29 @@
import mimetypes
import random
from django.conf import settings
from django.utils.translation import activate
from django.core.files.uploadedfile import SimpleUploadedFile
from rest_framework import serializers
from olympia.amo.tests import user_factory, addon_factory, copy_file_to_temp
from olympia import amo
from olympia.addons.forms import icons
from olympia.addons.models import AddonUser, Preview
from olympia.addons.models import AddonUser, Preview, Addon
from olympia.addons.utils import generate_addon_guid
from olympia.amo.tests import addon_factory, user_factory, version_factory
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)
ADDON_EXTENSION,
ADDON_PERSONA,
STATUS_PUBLIC
)
from olympia.landfill.collection import generate_collection
from olympia.landfill.generators import generate_themes
from olympia.files.tests.test_helpers import get_file
from olympia.ratings.models import Rating
from olympia.users.models import UserProfile
from olympia.devhub.tasks import create_version_for_upload
class GenerateAddonsSerializer(serializers.Serializer):
@ -84,6 +94,46 @@ class GenerateAddonsSerializer(serializers.Serializer):
'Created addon {0} for testing successfully'
.format(addon.name))
def create_featured_addon_with_version_for_install(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/')]
try:
addon = Addon.objects.get(guid='@webextension-guid')
except Addon.DoesNotExist:
addon = addon_factory(
status=STATUS_PUBLIC,
type=ADDON_EXTENSION,
file_kw=False,
average_daily_users=5000,
users=[UserProfile.objects.get(username='uitest')],
average_rating=5,
description=u'My Addon description',
guid='@webextension-guid',
icon_type=random.choice(default_icons),
name=u'Ui-Addon-Install',
public_stats=True,
slug='ui-test-install',
summary=u'My Addon summary',
tags=['some_tag', 'another_tag', 'ui-testing',
'selenium', 'python'],
weekly_downloads=9999999,
developer_comments='This is a testing addon.',
)
addon.save()
generate_collection(addon, app=FIREFOX)
print(
'Created addon {0} for testing successfully'
.format(addon.name))
return addon
def create_featured_theme(self):
"""Creates a custom theme named 'Ui-Test Theme'.
@ -148,3 +198,46 @@ class GenerateAddonsSerializer(serializers.Serializer):
for _ in range(6):
addon = addon_factory(status=STATUS_PUBLIC, type=ADDON_PERSONA)
generate_collection(addon, app=FIREFOX)
def create_installable_addon(self):
activate('en-US')
# using whatever add-on you already have should work imho, otherwise
# fall back to a new one for test purposes
addon = self.create_featured_addon_with_version_for_install()
# the user the add-on gets created with
user = UserProfile.objects.get(username='uitest')
user, _ = UserProfile.objects.get_or_create(
pk=settings.TASK_USER_ID,
defaults={'email': 'admin@mozilla.com', 'username': 'admin'})
# generate a proper uploaded file that simulates what django requires
# as request.POST
file_to_upload = 'webextension_signed_already.xpi'
file_path = get_file(file_to_upload)
# make sure we are not using the file in the source-tree but a
# temporary one to avoid the files get moved somewhere else and
# deleted from source tree
with copy_file_to_temp(file_path) as temporary_path:
data = open(temporary_path).read()
filedata = SimpleUploadedFile(
file_to_upload,
data,
content_type=mimetypes.guess_type(file_to_upload)[0])
# now, lets upload the file into the system
from olympia.devhub.views import handle_upload
upload = handle_upload(
filedata=filedata,
user=user,
channel=amo.RELEASE_CHANNEL_LISTED,
addon=addon,
)
# And let's create a new version for that upload.
create_version_for_upload(
upload.addon, upload, amo.RELEASE_CHANNEL_LISTED)

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

@ -11,10 +11,20 @@ from olympia import amo
@pytest.fixture
def capabilities(capabilities):
# In order to run these tests in Firefox 48, marionette is required
capabilities['marionette'] = True
return capabilities
def firefox_options(firefox_options):
firefox_options.set_preference(
'extensions.install.requireBuiltInCerts', False)
firefox_options.set_preference('xpinstall.signatures.required', False)
firefox_options.set_preference('extensions.webapi.testing', True)
firefox_options.set_preference('ui.popup.disable_autohide', True)
firefox_options.add_argument('-foreground')
firefox_options.log.level = 'trace'
return firefox_options
@pytest.fixture
def firefox_notifications(notifications):
return notifications
@pytest.fixture

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

@ -17,8 +17,13 @@ class Details(Base):
class DescriptionHeader(Region):
"""Represents the header of the detail page."""
_root_locator = (By.CLASS_NAME, 'addon-description-header')
_install_button_locator = (By.CLASS_NAME, 'add')
_name_locator = (By.TAG_NAME, 'h1')
@property
def name(self):
return self.find_element(*self._name_locator).text
@property
def install_button(self):
return self.find_element(*self._install_button_locator)

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

@ -2,5 +2,5 @@
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
DJANGO_SETTINGS_MODULE = settings
base_url = http://olympia.dev:80

20
tests/ui/test_install.py Normal file
Просмотреть файл

@ -0,0 +1,20 @@
import pytest
from pages.desktop.details import Details
@pytest.mark.nondestructive
def test_addon_install(
base_url, selenium, firefox, firefox_notifications):
"""Test that navigates to an addon and installs it."""
selenium.get('{}/firefox/addon/ui-test-install'.format(base_url))
addon = Details(selenium, base_url)
assert 'Ui-Addon-Install' in addon.description_header.name
addon.description_header.install_button.click()
firefox.browser.wait_for_notification(
firefox_notifications.AddOnInstallBlocked).allow()
firefox.browser.wait_for_notification(
firefox_notifications.AddOnInstallConfirmation).install()
firefox.browser.wait_for_notification(
firefox_notifications.AddOnInstallComplete).close()

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

@ -60,9 +60,8 @@ commands =
[testenv:ui-tests]
commands =
make -f Makefile-docker update_deps
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}
pytest --driver Firefox --variables tests/ui/variables.json --html=ui-test.html --self-contained-html tests/ui {posargs}
[testenv:assets]
commands =