Merge pull request #1818 from chrismeyersfsu/fix-parallel_failures

isolate test cache
This commit is contained in:
Chris Meyers
2018-05-17 13:24:40 -04:00
committed by GitHub
11 changed files with 92 additions and 63 deletions

View File

View File

@@ -0,0 +1,6 @@
# Ensure that our autouse overwrites are working
def test_cache(settings):
assert settings.CACHES['default']['BACKEND'] == 'django.core.cache.backends.locmem.LocMemCache'
assert settings.CACHES['default']['LOCATION'].startswith('unique-')

View File

@@ -106,3 +106,21 @@ def get_ssh_version(mocker):
@pytest.fixture @pytest.fixture
def job_template_with_survey_passwords_unit(job_template_with_survey_passwords_factory): def job_template_with_survey_passwords_unit(job_template_with_survey_passwords_factory):
return job_template_with_survey_passwords_factory(persisted=False) return job_template_with_survey_passwords_factory(persisted=False)
@pytest.fixture
def mock_cache():
class MockCache(object):
cache = {}
def get(self, key, default=None):
return self.cache.get(key, default)
def set(self, key, value, timeout=60):
self.cache[key] = value
def delete(self, key):
del self.cache[key]
return MockCache()

View File

@@ -9,7 +9,6 @@ from six.moves import xrange
# Django # Django
from django.core.urlresolvers import resolve from django.core.urlresolvers import resolve
from django.core.cache import cache
from django.utils.six.moves.urllib.parse import urlparse from django.utils.six.moves.urllib.parse import urlparse
from django.utils import timezone from django.utils import timezone
from django.contrib.auth.models import User from django.contrib.auth.models import User
@@ -57,14 +56,6 @@ def swagger_autogen(requests=__SWAGGER_REQUESTS__):
return requests return requests
@pytest.fixture(autouse=True)
def clear_cache():
'''
Clear cache (local memory) for each test to prevent using cached settings.
'''
cache.clear()
@pytest.fixture(scope="session", autouse=True) @pytest.fixture(scope="session", autouse=True)
def celery_memory_broker(): def celery_memory_broker():
''' '''

View File

@@ -241,15 +241,16 @@ def test_shared_dependencies_launch(default_instance_group, job_template_factory
@pytest.mark.django_db @pytest.mark.django_db
def test_cleanup_interval(): def test_cleanup_interval(mock_cache):
assert cache.get('last_celery_task_cleanup') is None with mock.patch.multiple('awx.main.scheduler.task_manager.cache', get=mock_cache.get, set=mock_cache.set):
assert mock_cache.get('last_celery_task_cleanup') is None
TaskManager().cleanup_inconsistent_celery_tasks() TaskManager().cleanup_inconsistent_celery_tasks()
last_cleanup = cache.get('last_celery_task_cleanup') last_cleanup = mock_cache.get('last_celery_task_cleanup')
assert isinstance(last_cleanup, datetime) assert isinstance(last_cleanup, datetime)
TaskManager().cleanup_inconsistent_celery_tasks() TaskManager().cleanup_inconsistent_celery_tasks()
assert cache.get('last_celery_task_cleanup') == last_cleanup assert cache.get('last_celery_task_cleanup') == last_cleanup
class TestReaper(): class TestReaper():
@@ -326,7 +327,8 @@ class TestReaper():
@pytest.mark.django_db @pytest.mark.django_db
@mock.patch.object(JobNotificationMixin, 'send_notification_templates') @mock.patch.object(JobNotificationMixin, 'send_notification_templates')
@mock.patch.object(TaskManager, 'get_active_tasks', lambda self: ([], [])) @mock.patch.object(TaskManager, 'get_active_tasks', lambda self: ([], []))
def test_cleanup_inconsistent_task(self, notify, active_tasks, considered_jobs, reapable_jobs, running_tasks, waiting_tasks, mocker): def test_cleanup_inconsistent_task(self, notify, active_tasks, considered_jobs, reapable_jobs, running_tasks, waiting_tasks, mocker, settings):
settings.AWX_INCONSISTENT_TASK_INTERVAL = 0
tm = TaskManager() tm = TaskManager()
tm.get_running_tasks = mocker.Mock(return_value=(running_tasks, waiting_tasks)) tm.get_running_tasks = mocker.Mock(return_value=(running_tasks, waiting_tasks))

View File

@@ -0,0 +1,6 @@
# Ensure that our autouse overwrites are working
def test_cache(settings):
assert settings.CACHES['default']['BACKEND'] == 'django.core.cache.backends.locmem.LocMemCache'
assert settings.CACHES['default']['LOCATION'].startswith('unique-')

View File

@@ -7,10 +7,10 @@ import pytest
from uuid import uuid4 from uuid import uuid4
import json import json
import yaml import yaml
import mock
from backports.tempfile import TemporaryDirectory from backports.tempfile import TemporaryDirectory
from django.conf import settings from django.conf import settings
from django.core.cache import cache
from rest_framework.exceptions import ParseError from rest_framework.exceptions import ParseError
@@ -26,14 +26,6 @@ from awx.main.models import (
) )
@pytest.fixture(autouse=True)
def clear_cache():
'''
Clear cache (local memory) for each test to prevent using cached settings.
'''
cache.clear()
@pytest.mark.parametrize('input_, output', [ @pytest.mark.parametrize('input_, output', [
({"foo": "bar"}, {"foo": "bar"}), ({"foo": "bar"}, {"foo": "bar"}),
('{"foo": "bar"}', {"foo": "bar"}), ('{"foo": "bar"}', {"foo": "bar"}),
@@ -114,46 +106,48 @@ def test_get_type_for_model(model, name):
@pytest.fixture @pytest.fixture
def memoized_function(mocker): def memoized_function(mocker, mock_cache):
@common.memoize(track_function=True) with mock.patch('awx.main.utils.common.get_memoize_cache', return_value=mock_cache):
def myfunction(key, value): @common.memoize(track_function=True)
if key not in myfunction.calls: def myfunction(key, value):
myfunction.calls[key] = 0 if key not in myfunction.calls:
myfunction.calls[key] = 0
myfunction.calls[key] += 1 myfunction.calls[key] += 1
if myfunction.calls[key] == 1: if myfunction.calls[key] == 1:
return value return value
else: else:
return '%s called %s times' % (value, myfunction.calls[key]) return '%s called %s times' % (value, myfunction.calls[key])
myfunction.calls = dict() myfunction.calls = dict()
return myfunction return myfunction
def test_memoize_track_function(memoized_function): def test_memoize_track_function(memoized_function, mock_cache):
assert memoized_function('scott', 'scotterson') == 'scotterson' assert memoized_function('scott', 'scotterson') == 'scotterson'
assert cache.get('myfunction') == {u'scott-scotterson': 'scotterson'} assert mock_cache.get('myfunction') == {u'scott-scotterson': 'scotterson'}
assert memoized_function('scott', 'scotterson') == 'scotterson' assert memoized_function('scott', 'scotterson') == 'scotterson'
assert memoized_function.calls['scott'] == 1 assert memoized_function.calls['scott'] == 1
assert memoized_function('john', 'smith') == 'smith' assert memoized_function('john', 'smith') == 'smith'
assert cache.get('myfunction') == {u'scott-scotterson': 'scotterson', u'john-smith': 'smith'} assert mock_cache.get('myfunction') == {u'scott-scotterson': 'scotterson', u'john-smith': 'smith'}
assert memoized_function('john', 'smith') == 'smith' assert memoized_function('john', 'smith') == 'smith'
assert memoized_function.calls['john'] == 1 assert memoized_function.calls['john'] == 1
def test_memoize_delete(memoized_function): def test_memoize_delete(memoized_function, mock_cache):
assert memoized_function('john', 'smith') == 'smith' assert memoized_function('john', 'smith') == 'smith'
assert memoized_function('john', 'smith') == 'smith' assert memoized_function('john', 'smith') == 'smith'
assert memoized_function.calls['john'] == 1 assert memoized_function.calls['john'] == 1
assert cache.get('myfunction') == {u'john-smith': 'smith'} assert mock_cache.get('myfunction') == {u'john-smith': 'smith'}
common.memoize_delete('myfunction') with mock.patch('awx.main.utils.common.memoize_delete', side_effect=mock_cache.delete):
common.memoize_delete('myfunction')
assert cache.get('myfunction') is None assert mock_cache.get('myfunction') is None
assert memoized_function('john', 'smith') == 'smith called 2 times' assert memoized_function('john', 'smith') == 'smith called 2 times'
assert memoized_function.calls['john'] == 2 assert memoized_function.calls['john'] == 2

View File

@@ -127,12 +127,16 @@ class IllegalArgumentError(ValueError):
pass pass
def get_memoize_cache():
from django.core.cache import cache
return cache
def memoize(ttl=60, cache_key=None, track_function=False): def memoize(ttl=60, cache_key=None, track_function=False):
''' '''
Decorator to wrap a function and cache its result. Decorator to wrap a function and cache its result.
''' '''
from django.core.cache import cache cache = get_memoize_cache()
def _memoizer(f, *args, **kwargs): def _memoizer(f, *args, **kwargs):
if cache_key and track_function: if cache_key and track_function:
@@ -160,8 +164,7 @@ def memoize(ttl=60, cache_key=None, track_function=False):
def memoize_delete(function_name): def memoize_delete(function_name):
from django.core.cache import cache cache = get_memoize_cache()
return cache.delete(function_name) return cache.delete(function_name)

View File

@@ -537,19 +537,12 @@ ASGI_AMQP = {
} }
# Django Caching Configuration # Django Caching Configuration
if is_testing(): CACHES = {
CACHES = { 'default': {
'default': { 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', 'LOCATION': 'memcached:11211',
}, },
} }
else:
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': 'memcached:11211',
},
}
# Social Auth configuration. # Social Auth configuration.
SOCIAL_AUTH_STRATEGY = 'social_django.strategy.DjangoStrategy' SOCIAL_AUTH_STRATEGY = 'social_django.strategy.DjangoStrategy'

View File

@@ -9,6 +9,7 @@ import socket
import copy import copy
import sys import sys
import traceback import traceback
import random
# Centos-7 doesn't include the svg mime type # Centos-7 doesn't include the svg mime type
# /usr/lib64/python/mimetypes.py # /usr/lib64/python/mimetypes.py
@@ -20,6 +21,15 @@ from split_settings.tools import optional, include
# Load default settings. # Load default settings.
from defaults import * # NOQA from defaults import * # NOQA
# don't use memcache when running tests
if "pytest" in sys.modules:
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
'LOCATION': 'unique-{}'.format(random.randint(0, sys.maxint)),
},
}
# awx-manage shell_plus --notebook # awx-manage shell_plus --notebook
NOTEBOOK_ARGUMENTS = [ NOTEBOOK_ARGUMENTS = [
'--NotebookApp.token=', '--NotebookApp.token=',

View File

@@ -0,0 +1,6 @@
# Ensure that our autouse overwrites are working
def test_cache(settings):
assert settings.CACHES['default']['BACKEND'] == 'django.core.cache.backends.locmem.LocMemCache'
assert settings.CACHES['default']['LOCATION'].startswith('unique-')