2018-08-21 18:13:25 +03:00
|
|
|
"""
|
|
|
|
pytest hooks and fixtures used for our unittests.
|
|
|
|
|
|
|
|
Please note that there should not be any Django/Olympia related imports
|
|
|
|
on module-level, they should instead be added to hooks or fixtures directly.
|
|
|
|
"""
|
2018-10-15 18:30:02 +03:00
|
|
|
import os
|
2018-07-27 14:39:35 +03:00
|
|
|
import uuid
|
2019-01-23 08:01:09 +03:00
|
|
|
import warnings
|
2015-08-26 20:33:42 +03:00
|
|
|
|
2014-11-19 19:36:40 +03:00
|
|
|
import pytest
|
2019-01-08 13:48:42 +03:00
|
|
|
import responses
|
2019-01-23 08:01:09 +03:00
|
|
|
import six
|
Default to 'and' operator for match queries. Remove slug search, prioritize exact matches more. (#7303)
* Default to 'and' operator for match queries. Remove slug search, prioritize exact matches more.
References many "component: search" issues. What I tested with a
database of all public add-ons:
Example searches:
tab center redux - should find "Tab Center Redux" while "Tab Mix Plus" is probably second and "Redux DevTools" 4th or so
Open Image in New Tab -> should find "Open Image in New Tab" while "Open Bookmarks in New Tab" should be 2nd or 3rd
CoinHive -> Finds "Coinhive Blocker", "CoinBlock" (prefix search) and "NoMiners" (description)
Privacy -> Finds "Privacy Badger", "Privacy Pass", "Privacy Settings", "Google Privacy" (probably 4th or so) and "Blur" (summary + description + many users). Scores "Ghostery" on the first page but ranks it in the middle
firebu -> Finds "Firebug", "Firebug Autocompleter", "Firefinder for Firebug"
fireb -> Scores "Fire Drag" first, puts "Firebug" approximately 3rd or so
Menu Wizzard -> Finds "Menu Wizard" (fuzzy, typo) first, then "Add-ons Manager Context Menu" apparently because it matches good in the title and has many users
Frame Demolition -> Finds "Frame Demolition"
Demolition -> Finds only "Frame Demolition", same for "Demolation" (typo)
reStyle -> Finds "reStyle" and scores a few add-ons that match on "restore" next since the term is similar
MegaUpload DownloadHelper -> finds "MegaUpload DownloadHelper" first, scores "Video DownloadHelper" and "RadpidShare DownloadHelper" next. Doesn't find "Popup Blocker" anymore as currently happening on -prod
MegaUpload -> only finds "MegaUpload DownloadHelper" and nothing else
No Flash -> Scores "No Flash" first, then depending on users "Download Flash and Video", "YouTube Flash Video Player" and "YouTube Flash Player" (not necessarily in that order)
Disable Hello, Pocket & Reader+ -> finds "Disable Hello, Pocket & Reader+" first (yeay!), then scores "Reader", "Disable WebRTC" and "In My Pocket" next similarly to what's happening on -prod currently
Not working yet:
privacybadger -> "Privacy Badger" -> will probably need some kind of ngram filtering and analyzing (#591)
eyes -> 'decentraleyes' -> Not sure this should actually work, will probably need some more analyzing too (#591)
Not sure if it's specifically only because of these changes but #3248 is fixed.
This potentially fixes #7244, #6891, #6837, #6417, mozilla/addons#359.
Not sure if this fixes #mozilla/addons#567 but the results look much more promising and the amount of results doesn't explode here. I only have 2.8k add-ons for testing though so I'm not too sure.
And might be relevant to #6137.
This is a big step towards #2661, I doubt we can call this fixed though.
* Fix name tests
* Speed up ES tests, make scoring results more predictable by using only one shard and one replica
* Add tests
* Only test on new apiv3 based search.
* Fixup 'get_results'
* Remove debug print
* Isort imports
* Fix test settings, I'm blind.
* Adapt number of shards to what we define in settings_test
* Test search for grapple
* Remove property filtering in legacy api search, fix tests, fix flake8
* Add comment explaining shard config
* Fix tests again, add default platform, fix total counts again.
* Try to do some fixture cleanup, let's see...
* More test refactoring, make use of dfs-query-then-fetch during tests, allow us to test this later too via a waffle flag.
* Don't use waffle flag for legacy search, only for apiv3 searches.
* Fix unused import, fix usage of 'params'
* Use query-then-fetch in a regular addons-view tool, fix a few more tests to be able to handle the waffle-flag
* Create the dfs query then fetch flag only in ESTestCase, delete it properly. More serializer fixes
* precache the waffle flag for autocomplete tests too
* Minor cleanups
* Add docs, fix code style
* Add a todo
* Fix codestyle
2018-01-30 08:26:30 +03:00
|
|
|
|
2014-11-19 19:36:40 +03:00
|
|
|
|
2015-08-31 10:22:37 +03:00
|
|
|
@pytest.fixture(autouse=True)
|
|
|
|
def unpin_db(request):
|
|
|
|
"""Unpin the database from master in the current DB.
|
|
|
|
|
|
|
|
The `multidb` middleware pins the current thread to master for 15 seconds
|
|
|
|
after any POST request, which can lead to unexpected results for tests
|
|
|
|
of DB slave functionality."""
|
2018-08-21 18:13:25 +03:00
|
|
|
from multidb import pinning
|
2015-08-31 10:22:37 +03:00
|
|
|
|
|
|
|
request.addfinalizer(pinning.unpin_this_thread)
|
|
|
|
|
|
|
|
|
2017-02-06 20:13:18 +03:00
|
|
|
@pytest.fixture(autouse=True)
|
|
|
|
def mock_elasticsearch():
|
|
|
|
"""Mock ElasticSearch in tests by default.
|
|
|
|
|
|
|
|
Tests that do need ES should inherit from ESTestCase, which will stop the
|
|
|
|
mock at setup time."""
|
2018-08-21 18:13:25 +03:00
|
|
|
from olympia.amo.tests import start_es_mocks, stop_es_mocks
|
|
|
|
|
2017-02-06 20:13:18 +03:00
|
|
|
start_es_mocks()
|
|
|
|
|
|
|
|
yield
|
|
|
|
|
|
|
|
stop_es_mocks()
|
|
|
|
|
|
|
|
|
2019-01-16 14:26:45 +03:00
|
|
|
@pytest.fixture(autouse=True)
|
|
|
|
def start_responses_mocking(request):
|
|
|
|
"""Enable ``responses`` this enforcing us to explicitly mark tests
|
|
|
|
that require internet usage.
|
|
|
|
"""
|
|
|
|
marker = request.node.get_closest_marker('allow_external_http_requests')
|
|
|
|
|
|
|
|
if not marker:
|
|
|
|
responses.start()
|
|
|
|
|
|
|
|
yield
|
|
|
|
|
|
|
|
try:
|
|
|
|
if not marker:
|
|
|
|
responses.stop()
|
|
|
|
responses.reset()
|
|
|
|
except RuntimeError:
|
|
|
|
# responses patcher was already uninstalled
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
2018-05-09 18:53:35 +03:00
|
|
|
@pytest.fixture(autouse=True)
|
|
|
|
def mock_basket(settings):
|
|
|
|
"""Mock Basket in tests by default.
|
|
|
|
|
|
|
|
Tests that do need basket to work should disable `responses`
|
|
|
|
and add a passthrough.
|
|
|
|
"""
|
|
|
|
USER_TOKEN = u'13f64f64-1de7-42f6-8c7f-a19e2fae5021'
|
|
|
|
responses.add(
|
|
|
|
responses.GET,
|
|
|
|
settings.BASKET_URL + '/news/lookup-user/',
|
|
|
|
json={'status': 'ok', 'newsletters': [], 'token': USER_TOKEN})
|
|
|
|
responses.add(
|
|
|
|
responses.POST,
|
|
|
|
settings.BASKET_URL + '/news/subscribe/',
|
|
|
|
json={'status': 'ok', 'token': USER_TOKEN})
|
|
|
|
responses.add(
|
|
|
|
responses.POST,
|
|
|
|
settings.BASKET_URL + '/news/unsubscribe/{}/'.format(USER_TOKEN),
|
|
|
|
json={'status': 'ok', 'token': USER_TOKEN})
|
|
|
|
|
|
|
|
|
2015-08-23 12:14:51 +03:00
|
|
|
def pytest_configure(config):
|
2018-08-21 18:13:25 +03:00
|
|
|
import django
|
|
|
|
# Forcefully call `django.setup`, pytest-django tries to be very lazy
|
|
|
|
# and doesn't call it if it has already been setup.
|
|
|
|
# That is problematic for us since we overwrite our logging config
|
|
|
|
# in settings_test and it can happen that django get's initialized
|
|
|
|
# with the wrong configuration. So let's forcefully re-initialize
|
|
|
|
# to setup the correct logging config since at this point
|
|
|
|
# DJANGO_SETTINGS_MODULE should be `settings_test` every time.
|
|
|
|
django.setup()
|
|
|
|
|
2017-05-30 08:30:46 +03:00
|
|
|
from olympia.amo.tests import prefix_indexes
|
2015-08-23 12:14:51 +03:00
|
|
|
prefix_indexes(config)
|
2015-08-26 20:33:42 +03:00
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture(autouse=True, scope='session')
|
|
|
|
def instrument_jinja():
|
|
|
|
"""Make sure the "templates" list in a response is properly updated, even
|
|
|
|
though we're using Jinja2 and not the default django template engine."""
|
|
|
|
import jinja2
|
2018-08-21 18:13:25 +03:00
|
|
|
from django import test
|
|
|
|
|
2015-08-26 20:33:42 +03:00
|
|
|
old_render = jinja2.Template.render
|
|
|
|
|
|
|
|
def instrumented_render(self, *args, **kwargs):
|
|
|
|
context = dict(*args, **kwargs)
|
|
|
|
test.signals.template_rendered.send(
|
|
|
|
sender=self, template=self, context=context)
|
|
|
|
return old_render(self, *args, **kwargs)
|
|
|
|
|
|
|
|
jinja2.Template.render = instrumented_render
|
|
|
|
|
|
|
|
|
2018-02-02 14:47:50 +03:00
|
|
|
def default_prefixer(settings):
|
2015-08-26 20:33:42 +03:00
|
|
|
"""Make sure each test starts with a default URL prefixer."""
|
2018-08-21 18:13:25 +03:00
|
|
|
from django import http
|
|
|
|
from olympia import amo
|
|
|
|
|
2015-08-26 20:33:42 +03:00
|
|
|
request = http.HttpRequest()
|
|
|
|
request.META['SCRIPT_NAME'] = ''
|
|
|
|
prefixer = amo.urlresolvers.Prefixer(request)
|
|
|
|
prefixer.app = settings.DEFAULT_APP
|
|
|
|
prefixer.locale = settings.LANGUAGE_CODE
|
|
|
|
amo.urlresolvers.set_url_prefix(prefixer)
|
|
|
|
|
|
|
|
|
2018-02-02 14:47:50 +03:00
|
|
|
@pytest.yield_fixture(autouse=True)
|
|
|
|
def test_pre_setup(request, tmpdir, settings):
|
2018-08-21 18:13:25 +03:00
|
|
|
from django.core.cache import caches
|
|
|
|
from django.utils import translation
|
|
|
|
from olympia import amo, core
|
|
|
|
from olympia.translations.hold import clean_translations
|
2018-07-27 14:39:35 +03:00
|
|
|
from waffle.utils import get_cache as waffle_get_cache
|
|
|
|
from waffle import models as waffle_models
|
|
|
|
|
2019-01-23 08:01:09 +03:00
|
|
|
# Ignore ResourceWarning for now. It's a Python 3 thing so it's done
|
|
|
|
# dynamically here.
|
|
|
|
if six.PY3:
|
|
|
|
warnings.filterwarnings('ignore', category=ResourceWarning) # noqa
|
|
|
|
|
2018-07-27 14:39:35 +03:00
|
|
|
# Clear all cache-instances. They'll be re-initialized by Django
|
|
|
|
# This will make sure that our random `KEY_PREFIX` is applied
|
|
|
|
# appropriately.
|
|
|
|
# This is done by Django too whenever `settings` is changed
|
|
|
|
# directly but because we're using the `settings` fixture
|
|
|
|
# here this is not detected correctly.
|
|
|
|
caches._caches.caches = {}
|
|
|
|
|
|
|
|
# Randomize the cache key prefix to keep
|
|
|
|
# tests isolated from each other.
|
|
|
|
prefix = uuid.uuid4().hex
|
|
|
|
settings.CACHES['default']['KEY_PREFIX'] = 'amo:{0}:'.format(prefix)
|
|
|
|
|
|
|
|
# Reset global django-waffle cache instance to make sure it's properly
|
|
|
|
# using our new key prefix
|
|
|
|
waffle_models.cache = waffle_get_cache()
|
2015-08-26 20:33:42 +03:00
|
|
|
|
|
|
|
translation.trans_real.deactivate()
|
|
|
|
# Django fails to clear this cache.
|
|
|
|
translation.trans_real._translations = {}
|
|
|
|
translation.trans_real.activate(settings.LANGUAGE_CODE)
|
|
|
|
|
2018-10-15 18:30:02 +03:00
|
|
|
def _path(*args):
|
|
|
|
path = str(os.path.join(*args))
|
|
|
|
if not os.path.exists(path):
|
|
|
|
os.makedirs(path)
|
|
|
|
return path
|
|
|
|
|
2019-01-16 14:09:35 +03:00
|
|
|
settings.STORAGE_ROOT = storage_root = _path(str(tmpdir.mkdir('storage')))
|
2018-10-15 18:30:02 +03:00
|
|
|
settings.SHARED_STORAGE = shared_storage = _path(
|
|
|
|
storage_root, 'shared_storage')
|
|
|
|
|
|
|
|
settings.ADDONS_PATH = _path(storage_root, 'files')
|
|
|
|
settings.GUARDED_ADDONS_PATH = _path(storage_root, 'guarded-addons')
|
|
|
|
settings.GIT_FILE_STORAGE_PATH = _path(storage_root, 'git-storage')
|
|
|
|
settings.MEDIA_ROOT = _path(shared_storage, 'uploads')
|
|
|
|
settings.TMP_PATH = _path(shared_storage, 'tmp')
|
2018-01-04 12:12:56 +03:00
|
|
|
|
2018-02-02 14:47:50 +03:00
|
|
|
# Reset the prefixer and urlconf after updating media root
|
|
|
|
default_prefixer(settings)
|
|
|
|
|
2018-09-17 10:24:14 +03:00
|
|
|
from django.urls import clear_url_caches, set_urlconf
|
2018-02-02 14:47:50 +03:00
|
|
|
|
|
|
|
def _clear_urlconf():
|
|
|
|
clear_url_caches()
|
|
|
|
set_urlconf(None)
|
|
|
|
|
|
|
|
_clear_urlconf()
|
|
|
|
|
|
|
|
request.addfinalizer(_clear_urlconf)
|
|
|
|
|
|
|
|
yield
|
2015-08-26 20:33:42 +03:00
|
|
|
|
2017-03-06 19:19:34 +03:00
|
|
|
core.set_user(None)
|
2015-08-26 20:33:42 +03:00
|
|
|
clean_translations(None) # Make sure queued translations are removed.
|
|
|
|
|
|
|
|
# Make sure we revert everything we might have changed to prefixers.
|
|
|
|
amo.urlresolvers.clean_url_prefixes()
|
2015-09-10 13:32:58 +03:00
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture
|
|
|
|
def admin_group(db):
|
|
|
|
"""Create the Admins group."""
|
2018-08-21 18:13:25 +03:00
|
|
|
from olympia.access.models import Group
|
2015-09-10 13:32:58 +03:00
|
|
|
return Group.objects.create(name='Admins', rules='*:*')
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture
|
2018-02-02 14:47:50 +03:00
|
|
|
def mozilla_user(admin_group, settings):
|
2015-09-10 13:32:58 +03:00
|
|
|
"""Create a "Mozilla User"."""
|
2018-08-21 18:13:25 +03:00
|
|
|
from olympia.access.models import GroupUser
|
|
|
|
from olympia.users.models import UserProfile
|
|
|
|
|
2015-09-10 13:32:58 +03:00
|
|
|
user = UserProfile.objects.create(pk=settings.TASK_USER_ID,
|
|
|
|
email='admin@mozilla.com',
|
|
|
|
username='admin')
|
|
|
|
user.save()
|
|
|
|
GroupUser.objects.create(user=user, group=admin_group)
|
|
|
|
return user
|