diff --git a/app/__init__.py b/app/__init__.py index 8f45d5b1d..0a2ef8724 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -25,9 +25,6 @@ from functools import partial from notifications_python_client.errors import HTTPError from notifications_utils import logging, request_helper, formatters -from notifications_utils.clients.antivirus.antivirus_client import AntivirusClient -from notifications_utils.clients.zendesk.zendesk_client import ZendeskClient -from notifications_utils.clients.statsd.statsd_client import StatsdClient from notifications_utils.recipients import ( validate_phone_number, InvalidPhoneError, @@ -42,6 +39,12 @@ from werkzeug.local import LocalProxy from app import proxy_fix from app.config import configs from app.asset_fingerprinter import asset_fingerprinter +from app.extensions import ( + antivirus_client, + statsd_client, + zendesk_client, + redis_client, +) from app.models.service import Service from app.models.user import AnonymousUser from app.navigation import ( @@ -75,9 +78,6 @@ from app.utils import get_logo_cdn_domain, id_safe login_manager = LoginManager() csrf = CSRFProtect() -antivirus_client = AntivirusClient() -statsd_client = StatsdClient() -zendesk_client = ZendeskClient() # The current service attached to the request stack. @@ -116,8 +116,7 @@ def create_app(application): proxy_fix, request_helper, - # Internal API clients - antivirus_client, + # API clients api_key_api_client, billing_api_client, complaint_api_client, @@ -140,8 +139,10 @@ def create_app(application): user_api_client, # External API clients + antivirus_client, statsd_client, zendesk_client, + redis_client ): client.init_app(application) @@ -153,6 +154,9 @@ def create_app(application): login_manager.session_protection = None login_manager.anonymous_user = AnonymousUser + # make sure we handle unicode correctly + redis_client.redis_store.decode_responses = True + from app.main import main as main_blueprint application.register_blueprint(main_blueprint) diff --git a/app/config.py b/app/config.py index 27926e011..47620b253 100644 --- a/app/config.py +++ b/app/config.py @@ -97,6 +97,8 @@ class Development(Config): ASSET_PATH = '/static/' + REDIS_URL = 'redis://localhost:6379/0' + class Test(Development): DEBUG = True diff --git a/app/extensions.py b/app/extensions.py new file mode 100644 index 000000000..935dfd7c4 --- /dev/null +++ b/app/extensions.py @@ -0,0 +1,11 @@ +from notifications_utils.clients.antivirus.antivirus_client import ( + AntivirusClient, +) +from notifications_utils.clients.redis.redis_client import RedisClient +from notifications_utils.clients.statsd.statsd_client import StatsdClient +from notifications_utils.clients.zendesk.zendesk_client import ZendeskClient + +antivirus_client = AntivirusClient() +statsd_client = StatsdClient() +zendesk_client = ZendeskClient() +redis_client = RedisClient() diff --git a/app/main/forms.py b/app/main/forms.py index 399705c24..525e20737 100644 --- a/app/main/forms.py +++ b/app/main/forms.py @@ -1281,3 +1281,10 @@ class TemplateAndFoldersSelectionForm(Form): required_for_ops('add-new-template'), Optional(), ], required_message='Select the type of template you want to add') + + +class ClearCacheForm(StripWhitespaceForm): + model_type = RadioField( + 'What do you want to clear today', + validators=[DataRequired()] + ) diff --git a/app/main/views/feedback.py b/app/main/views/feedback.py index 8b7b36f65..bfba526bb 100644 --- a/app/main/views/feedback.py +++ b/app/main/views/feedback.py @@ -4,12 +4,8 @@ import pytz from flask import abort, redirect, render_template, request, session, url_for from flask_login import current_user -from app import ( - convert_to_boolean, - current_service, - service_api_client, - zendesk_client, -) +from app import convert_to_boolean, current_service, service_api_client +from app.extensions import zendesk_client from app.main import main from app.main.forms import Feedback, Problem, SupportType, Triage diff --git a/app/main/views/platform_admin.py b/app/main/views/platform_admin.py index d2eebb061..1029bba3c 100644 --- a/app/main/views/platform_admin.py +++ b/app/main/views/platform_admin.py @@ -1,5 +1,6 @@ import itertools import re +from collections import OrderedDict from datetime import datetime from flask import abort, flash, redirect, render_template, request, url_for @@ -8,14 +9,19 @@ from notifications_python_client.errors import HTTPError from requests import RequestException from app import ( - antivirus_client, complaint_api_client, letter_jobs_client, platform_stats_api_client, service_api_client, ) +from app.extensions import antivirus_client, redis_client from app.main import main -from app.main.forms import DateFilterForm, PDFUploadForm, ReturnedLettersForm +from app.main.forms import ( + ClearCacheForm, + DateFilterForm, + PDFUploadForm, + ReturnedLettersForm, +) from app.statistics_utils import ( get_formatted_percentage, get_formatted_percentage_two_dp, @@ -281,6 +287,56 @@ def platform_admin_letter_validation_preview(): ) +@main.route("/platform-admin/clear-cache", methods=['GET', 'POST']) +@login_required +@user_is_platform_admin +def clear_cache(): + # note: `service-{uuid}-templates` cache is cleared for both services and templates. + CACHE_KEYS = OrderedDict([ + ('user', [ + 'user-????????-????-????-????-????????????', + ]), + ('service', [ + 'has_jobs-????????-????-????-????-????????????', + 'service-????????-????-????-????-????????????', + 'service-????????-????-????-????-????????????-templates', + 'service-????????-????-????-????-????????????-data-retention', + 'service-????????-????-????-????-????????????-template-folders', + ]), + ('template', [ + 'service-????????-????-????-????-????????????-templates', + 'template-????????-????-????-????-????????????-version-*', + 'template-????????-????-????-????-????????????-versions', + ]), + ('email_branding', [ + 'email_branding', + 'email_branding-????????-????-????-????-????????????', + ]), + ('letter_branding', [ + 'letter_branding', + 'letter_branding-????????-????-????-????-????????????', + ]) + ]) + + form = ClearCacheForm() + form.model_type.choices = [(key, key.replace('_', ' ').title()) for key in CACHE_KEYS] + + if form.validate_on_submit(): + to_delete = form.model_type.data + + num_deleted = max( + redis_client.delete_cache_keys_by_pattern(pattern) + for pattern in CACHE_KEYS[to_delete] + ) + msg = 'Removed {} {} object{} from redis' + flash(msg.format(num_deleted, to_delete, 's' if num_deleted != 1 else ''), category='default') + + return render_template( + 'views/platform-admin/clear-cache.html', + form=form + ) + + def sum_service_usage(service): total = 0 for notification_type in service['statistics'].keys(): diff --git a/app/main/views/service_settings.py b/app/main/views/service_settings.py index 063c8730a..c797ea373 100644 --- a/app/main/views/service_settings.py +++ b/app/main/views/service_settings.py @@ -23,8 +23,8 @@ from app import ( organisations_client, service_api_client, user_api_client, - zendesk_client, ) +from app.extensions import zendesk_client from app.main import main from app.main.forms import ( BrandingOptionsEmail, diff --git a/app/navigation.py b/app/navigation.py index 69a5814ca..e5dbca7ab 100644 --- a/app/navigation.py +++ b/app/navigation.py @@ -74,6 +74,7 @@ class HeaderNavigation(Navigation): }, 'platform-admin': { 'add_organisation', + 'clear_cache', 'create_email_branding', 'create_letter_branding', 'email_branding', @@ -403,6 +404,7 @@ class MainNavigation(Navigation): 'check_notification_preview', 'choose_account', 'choose_service', + 'clear_cache', 'confirm_edit_organisation_name', 'conversation_reply_with_template', 'conversation_updates', @@ -579,6 +581,7 @@ class CaseworkNavigation(Navigation): 'choose_account', 'choose_service', 'choose_template_to_copy', + 'clear_cache', 'confirm_edit_organisation_name', 'confirm_redact_template', 'conversation', @@ -818,6 +821,7 @@ class OrgNavigation(Navigation): 'choose_service', 'choose_template', 'choose_template_to_copy', + 'clear_cache', 'confirm_redact_template', 'conversation', 'conversation_reply', diff --git a/app/notify_client/__init__.py b/app/notify_client/__init__.py index bcd9f8fb9..ffcf55e23 100644 --- a/app/notify_client/__init__.py +++ b/app/notify_client/__init__.py @@ -2,7 +2,6 @@ from flask_login import current_user from flask import has_request_context, request, abort from notifications_python_client.base import BaseAPIClient from notifications_python_client import __version__ -from notifications_utils.clients.redis.redis_client import RedisClient def _attach_current_user(data): @@ -14,8 +13,6 @@ def _attach_current_user(data): class NotifyAdminAPIClient(BaseAPIClient): - redis_client = RedisClient() - def __init__(self): super().__init__("a" * 73, "b") @@ -24,8 +21,6 @@ class NotifyAdminAPIClient(BaseAPIClient): self.service_id = app.config['ADMIN_CLIENT_USER_NAME'] self.api_key = app.config['ADMIN_CLIENT_SECRET'] self.route_secret = app.config['ROUTE_SECRET_KEY_1'] - self.redis_client.init_app(app) - self.redis_client.redis_store.decode_responses = True def generate_headers(self, api_token): headers = { diff --git a/app/notify_client/cache.py b/app/notify_client/cache.py index 85bcd54ab..36d769df2 100644 --- a/app/notify_client/cache.py +++ b/app/notify_client/cache.py @@ -4,6 +4,8 @@ from datetime import timedelta from functools import wraps from inspect import signature +from app.extensions import redis_client + TTL = int(timedelta(days=7).total_seconds()) @@ -38,11 +40,11 @@ def set(key_format): @wraps(client_method) def new_client_method(client_instance, *args, **kwargs): redis_key = _make_key(key_format, client_method, args, kwargs) - cached = client_instance.redis_client.get(redis_key) + cached = redis_client.get(redis_key) if cached: return json.loads(cached.decode('utf-8')) api_response = client_method(client_instance, *args, **kwargs) - client_instance.redis_client.set( + redis_client.set( redis_key, json.dumps(api_response), ex=TTL, @@ -60,7 +62,7 @@ def delete(key_format): @wraps(client_method) def new_client_method(client_instance, *args, **kwargs): redis_key = _make_key(key_format, client_method, args, kwargs) - client_instance.redis_client.delete(redis_key) + redis_client.delete(redis_key) return client_method(client_instance, *args, **kwargs) return new_client_method diff --git a/app/notify_client/job_api_client.py b/app/notify_client/job_api_client.py index e835ac601..b6e8fd97d 100644 --- a/app/notify_client/job_api_client.py +++ b/app/notify_client/job_api_client.py @@ -1,5 +1,6 @@ from collections import defaultdict +from app.extensions import redis_client from app.notify_client import NotifyAdminAPIClient, _attach_current_user, cache @@ -96,8 +97,7 @@ class JobApiClient(NotifyAdminAPIClient): return bool(self.get_jobs(service_id)['data']) def create_job(self, job_id, service_id, scheduled_for=None): - - self.redis_client.set( + redis_client.set( 'has_jobs-{}'.format(service_id), b'true', ex=cache.TTL, diff --git a/app/notify_client/template_folder_api_client.py b/app/notify_client/template_folder_api_client.py index 23044259a..d273b4dc8 100644 --- a/app/notify_client/template_folder_api_client.py +++ b/app/notify_client/template_folder_api_client.py @@ -1,3 +1,4 @@ +from app.extensions import redis_client from app.notify_client import NotifyAdminAPIClient, cache @@ -35,7 +36,7 @@ class TemplateFolderAPIClient(NotifyAdminAPIClient): }) if template_ids: - self.redis_client.delete(*map( + redis_client.delete(*map( 'template-{}-version-None'.format, template_ids, )) diff --git a/app/templates/views/platform-admin/_base_template.html b/app/templates/views/platform-admin/_base_template.html index 71d617dfc..90022f895 100644 --- a/app/templates/views/platform-admin/_base_template.html +++ b/app/templates/views/platform-admin/_base_template.html @@ -24,6 +24,7 @@ ('Email Complaints', url_for('main.platform_admin_list_complaints')), ('Returned letters', url_for('main.platform_admin_returned_letters')), ('Letter validation preview', url_for('main.platform_admin_letter_validation_preview')), + ('Clear cache', url_for('main.clear_cache')), ] %}
  • diff --git a/app/templates/views/platform-admin/clear-cache.html b/app/templates/views/platform-admin/clear-cache.html new file mode 100644 index 000000000..5cdc11b0a --- /dev/null +++ b/app/templates/views/platform-admin/clear-cache.html @@ -0,0 +1,21 @@ +{% extends "views/platform-admin/_base_template.html" %} +{% from "components/form.html" import form_wrapper %} +{% from "components/radios.html" import radios %} +{% from "components/page-footer.html" import page_footer %} + +{% block per_page_title %} + Clear Cache +{% endblock %} + +{% block platform_admin_content %} + +

    + Clear Cache +

    + + {% call form_wrapper() %} + {{ radios(form.model_type) }} + {{ page_footer('Clear') }} + {% endcall %} + +{% endblock %} diff --git a/requirements-app.txt b/requirements-app.txt index 07a25835f..4b2101f14 100644 --- a/requirements-app.txt +++ b/requirements-app.txt @@ -23,4 +23,4 @@ awscli-cwlogs>=1.4,<1.5 # Putting upgrade on hold due to v1.0.0 using sha512 instead of sha1 by default itsdangerous==0.24 # pyup: <1.0.0 -git+https://github.com/alphagov/notifications-utils.git@31.0.0#egg=notifications-utils==31.0.0 +git+https://github.com/alphagov/notifications-utils.git@31.2.0#egg=notifications-utils==31.2.0 diff --git a/requirements.txt b/requirements.txt index 629d88224..f1b58d0cf 100644 --- a/requirements.txt +++ b/requirements.txt @@ -25,13 +25,13 @@ awscli-cwlogs>=1.4,<1.5 # Putting upgrade on hold due to v1.0.0 using sha512 instead of sha1 by default itsdangerous==0.24 # pyup: <1.0.0 -git+https://github.com/alphagov/notifications-utils.git@31.0.0#egg=notifications-utils==31.0.0 +git+https://github.com/alphagov/notifications-utils.git@31.2.0#egg=notifications-utils==31.2.0 ## The following requirements were added by pip freeze: -awscli==1.16.100 +awscli==1.16.105 bleach==3.0.2 boto3==1.6.16 -botocore==1.12.90 +botocore==1.12.95 certifi==2018.11.29 chardet==3.0.4 Click==7.0 @@ -48,7 +48,7 @@ jdcal==1.4 Jinja2==2.10 jmespath==0.9.3 lml==0.0.9 -lxml==4.3.0 +lxml==4.3.1 MarkupSafe==1.1.0 mistune==0.8.4 monotonic==1.5 diff --git a/tests/app/main/views/test_platform_admin.py b/tests/app/main/views/test_platform_admin.py index 719f83ef3..7fba52400 100644 --- a/tests/app/main/views/test_platform_admin.py +++ b/tests/app/main/views/test_platform_admin.py @@ -2,7 +2,7 @@ import datetime import re import uuid from functools import partial -from unittest.mock import ANY +from unittest.mock import ANY, call import pytest import requests_mock @@ -858,3 +858,42 @@ def test_letter_validation_preview_doesnt_call_template_preview_when_file_doesnt page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser') assert page.find('div', class_='banner-dangerous').text.strip() == "Document didn't pass the virus scan" + + +def test_clear_cache_shows_form(client_request, platform_admin_user, mocker): + redis = mocker.patch('app.main.views.platform_admin.redis_client') + client_request.login(platform_admin_user) + + page = client_request.get('main.clear_cache') + + assert page.select('input[type=radio]')[0]['value'] == 'user' + assert page.select('input[type=radio]')[1]['value'] == 'service' + assert page.select('input[type=radio]')[2]['value'] == 'template' + assert not redis.delete_cache_keys_by_pattern.called + + +def test_clear_cache_submits_and_tells_you_how_many_things_were_deleted(client_request, platform_admin_user, mocker): + redis = mocker.patch('app.main.views.platform_admin.redis_client') + redis.delete_cache_keys_by_pattern.side_effect = [0, 3, 1] + client_request.login(platform_admin_user) + + page = client_request.post('main.clear_cache', _data={'model_type': 'template'}, _expected_status=200) + + assert redis.delete_cache_keys_by_pattern.call_args_list == [ + call('service-????????-????-????-????-????????????-templates'), + call('template-????????-????-????-????-????????????-version-*'), + call('template-????????-????-????-????-????????????-versions'), + ] + + flash_banner = page.find('div', class_='banner-default') + assert flash_banner.text.strip() == 'Removed 3 template objects from redis' + + +def test_clear_cache_requires_option(client_request, platform_admin_user, mocker): + redis = mocker.patch('app.main.views.platform_admin.redis_client') + client_request.login(platform_admin_user) + + page = client_request.post('main.clear_cache', _data={}, _expected_status=200) + + assert normalize_spaces(page.find('span', class_='error-message').text) == 'Not a valid choice' + assert not redis.delete_cache_keys_by_pattern.called diff --git a/tests/app/notify_client/test_email_branding_client.py b/tests/app/notify_client/test_email_branding_client.py index bfef92971..ef1b48587 100644 --- a/tests/app/notify_client/test_email_branding_client.py +++ b/tests/app/notify_client/test_email_branding_client.py @@ -9,11 +9,11 @@ def test_get_email_branding(mocker, fake_uuid): return_value={'foo': 'bar'} ) mock_redis_get = mocker.patch( - 'app.notify_client.RedisClient.get', + 'app.extensions.RedisClient.get', return_value=None, ) mock_redis_set = mocker.patch( - 'app.notify_client.RedisClient.set', + 'app.extensions.RedisClient.set', ) EmailBrandingClient().get_email_branding(fake_uuid) mock_get.assert_called_once_with( @@ -33,11 +33,11 @@ def test_get_all_email_branding(mocker): return_value={'email_branding': [1, 2, 3]} ) mock_redis_get = mocker.patch( - 'app.notify_client.RedisClient.get', + 'app.extensions.RedisClient.get', return_value=None, ) mock_redis_set = mocker.patch( - 'app.notify_client.RedisClient.set', + 'app.extensions.RedisClient.set', ) EmailBrandingClient().get_all_email_branding() mock_get.assert_called_once_with( @@ -56,7 +56,7 @@ def test_create_email_branding(mocker): 'domain': 'sample.com', 'brand_type': 'org'} mock_post = mocker.patch('app.notify_client.email_branding_client.EmailBrandingClient.post') - mock_redis_delete = mocker.patch('app.notify_client.RedisClient.delete') + mock_redis_delete = mocker.patch('app.extensions.RedisClient.delete') EmailBrandingClient().create_email_branding( logo=org_data['logo'], name=org_data['name'], text=org_data['text'], colour=org_data['colour'], domain=org_data['domain'], brand_type='org' @@ -75,7 +75,7 @@ def test_update_email_branding(mocker, fake_uuid): 'domain': 'sample.com', 'brand_type': 'org'} mock_post = mocker.patch('app.notify_client.email_branding_client.EmailBrandingClient.post') - mock_redis_delete = mocker.patch('app.notify_client.RedisClient.delete') + mock_redis_delete = mocker.patch('app.extensions.RedisClient.delete') EmailBrandingClient().update_email_branding( branding_id=fake_uuid, logo=org_data['logo'], name=org_data['name'], text=org_data['text'], colour=org_data['colour'], domain=org_data['domain'], brand_type='org') diff --git a/tests/app/notify_client/test_job_client.py b/tests/app/notify_client/test_job_client.py index 58c457f35..b12322168 100644 --- a/tests/app/notify_client/test_job_client.py +++ b/tests/app/notify_client/test_job_client.py @@ -10,7 +10,7 @@ def test_client_creates_job_data_correctly(mocker, fake_uuid): job_id = fake_uuid service_id = fake_uuid mocker.patch('app.notify_client.current_user', id='1') - mock_redis_set = mocker.patch('app.notify_client.RedisClient.set') + mock_redis_set = mocker.patch('app.extensions.RedisClient.set') expected_data = { "id": job_id, @@ -330,7 +330,7 @@ def test_has_jobs_sets_cache( 'app.notify_client.job_api_client.JobApiClient.get', return_value={'data': job_data} ) - mock_redis_set = mocker.patch('app.notify_client.RedisClient.set') + mock_redis_set = mocker.patch('app.extensions.RedisClient.set') JobApiClient().has_jobs(fake_uuid) @@ -359,7 +359,7 @@ def test_has_jobs_returns_from_cache( 'app.notify_client.job_api_client.JobApiClient.get' ) mock_redis_get = mocker.patch( - 'app.notify_client.RedisClient.get', + 'app.extensions.RedisClient.get', return_value=cache_value, ) diff --git a/tests/app/notify_client/test_letter_branding_client.py b/tests/app/notify_client/test_letter_branding_client.py index 232d55fa8..a6e9db49d 100644 --- a/tests/app/notify_client/test_letter_branding_client.py +++ b/tests/app/notify_client/test_letter_branding_client.py @@ -8,8 +8,8 @@ def test_get_letter_branding(mocker, fake_uuid): 'app.notify_client.letter_branding_client.LetterBrandingClient.get', return_value={'foo': 'bar'} ) - mock_redis_get = mocker.patch('app.notify_client.RedisClient.get', return_value=None) - mock_redis_set = mocker.patch('app.notify_client.RedisClient.set') + mock_redis_get = mocker.patch('app.extensions.RedisClient.get', return_value=None) + mock_redis_set = mocker.patch('app.extensions.RedisClient.set') LetterBrandingClient().get_letter_branding(fake_uuid) @@ -24,8 +24,8 @@ def test_get_letter_branding(mocker, fake_uuid): def test_get_all_letter_branding(mocker): mock_get = mocker.patch('app.notify_client.letter_branding_client.LetterBrandingClient.get', return_value=[1, 2, 3]) - mock_redis_get = mocker.patch('app.notify_client.RedisClient.get', return_value=None) - mock_redis_set = mocker.patch('app.notify_client.RedisClient.set') + mock_redis_get = mocker.patch('app.extensions.RedisClient.get', return_value=None) + mock_redis_set = mocker.patch('app.extensions.RedisClient.set') LetterBrandingClient().get_all_letter_branding() @@ -42,7 +42,7 @@ def test_create_letter_branding(mocker): new_branding = {'filename': 'uuid-test', 'name': 'my letters', 'domain': 'example.com'} mock_post = mocker.patch('app.notify_client.letter_branding_client.LetterBrandingClient.post') - mock_redis_delete = mocker.patch('app.notify_client.RedisClient.delete') + mock_redis_delete = mocker.patch('app.extensions.RedisClient.delete') LetterBrandingClient().create_letter_branding( filename=new_branding['filename'], name=new_branding['name'], domain=new_branding['domain'] @@ -59,7 +59,7 @@ def test_update_letter_branding(mocker, fake_uuid): branding = {'filename': 'uuid-test', 'name': 'my letters', 'domain': 'example.com'} mock_post = mocker.patch('app.notify_client.letter_branding_client.LetterBrandingClient.post') - mock_redis_delete = mocker.patch('app.notify_client.RedisClient.delete') + mock_redis_delete = mocker.patch('app.extensions.RedisClient.delete') LetterBrandingClient().update_letter_branding( branding_id=fake_uuid, filename=branding['filename'], name=branding['name'], domain=branding['domain']) diff --git a/tests/app/notify_client/test_service_api_client.py b/tests/app/notify_client/test_service_api_client.py index f809259db..f8e58dec4 100644 --- a/tests/app/notify_client/test_service_api_client.py +++ b/tests/app/notify_client/test_service_api_client.py @@ -324,7 +324,7 @@ def test_returns_value_from_cache( ): mock_redis_get = mocker.patch( - 'app.notify_client.RedisClient.get', + 'app.extensions.RedisClient.get', return_value=cache_value, ) mock_api_get = mocker.patch( @@ -332,7 +332,7 @@ def test_returns_value_from_cache( return_value={'data_from': 'api'}, ) mock_redis_set = mocker.patch( - 'app.notify_client.RedisClient.set', + 'app.extensions.RedisClient.set', ) assert client_method(*extra_args) == expected_return_value @@ -375,7 +375,7 @@ def test_deletes_service_cache( extra_kwargs, ): mocker.patch('app.notify_client.current_user', id='1') - mock_redis_delete = mocker.patch('app.notify_client.RedisClient.delete') + mock_redis_delete = mocker.patch('app.extensions.RedisClient.delete') mock_request = mocker.patch('notifications_python_client.base.BaseAPIClient.request') getattr(client, method)(*extra_args, **extra_kwargs) @@ -423,7 +423,7 @@ def test_deletes_caches_when_modifying_templates( expected_cache_deletes, ): mocker.patch('app.notify_client.current_user', id='1') - mock_redis_delete = mocker.patch('app.notify_client.RedisClient.delete') + mock_redis_delete = mocker.patch('app.extensions.RedisClient.delete') mock_request = mocker.patch('notifications_python_client.base.BaseAPIClient.request') getattr(service_api_client, method)(*extra_args) diff --git a/tests/app/notify_client/test_template_folder_client.py b/tests/app/notify_client/test_template_folder_client.py index 3ab808930..bfd615e2f 100644 --- a/tests/app/notify_client/test_template_folder_client.py +++ b/tests/app/notify_client/test_template_folder_client.py @@ -9,7 +9,7 @@ from app.notify_client.template_folder_api_client import TemplateFolderAPIClient @pytest.mark.parametrize('parent_id', [uuid.uuid4(), None]) def test_create_template_folder_calls_correct_api_endpoint(mocker, parent_id): - mock_redis_delete = mocker.patch('app.notify_client.RedisClient.delete') + mock_redis_delete = mocker.patch('app.extensions.RedisClient.delete') some_service_id = uuid.uuid4() expected_url = '/service/{}/template-folder'.format(some_service_id) @@ -26,8 +26,8 @@ def test_create_template_folder_calls_correct_api_endpoint(mocker, parent_id): def test_get_template_folders_calls_correct_api_endpoint(mocker): - mock_redis_get = mocker.patch('app.notify_client.RedisClient.get', return_value=None) - mock_redis_set = mocker.patch('app.notify_client.RedisClient.set') + mock_redis_get = mocker.patch('app.extensions.RedisClient.get', return_value=None) + mock_redis_set = mocker.patch('app.extensions.RedisClient.set') mock_api_get = mocker.patch( 'app.notify_client.NotifyAdminAPIClient.get', return_value={'template_folders': {'a': 'b'}} @@ -50,7 +50,7 @@ def test_get_template_folders_calls_correct_api_endpoint(mocker): def test_move_templates_and_folders(mocker): - mock_redis_delete = mocker.patch('app.notify_client.RedisClient.delete') + mock_redis_delete = mocker.patch('app.extensions.RedisClient.delete') mock_api_post = mocker.patch('app.notify_client.NotifyAdminAPIClient.post') some_service_id = uuid.uuid4() @@ -106,7 +106,7 @@ def test_move_templates_and_folders_to_root(mocker): def test_update_template_folder_calls_correct_api_endpoint(mocker): - mock_redis_delete = mocker.patch('app.notify_client.RedisClient.delete') + mock_redis_delete = mocker.patch('app.extensions.RedisClient.delete') some_service_id = uuid.uuid4() template_folder_id = uuid.uuid4() @@ -124,7 +124,7 @@ def test_update_template_folder_calls_correct_api_endpoint(mocker): def test_delete_template_folder_calls_correct_api_endpoint(mocker): - mock_redis_delete = mocker.patch('app.notify_client.RedisClient.delete') + mock_redis_delete = mocker.patch('app.extensions.RedisClient.delete') some_service_id = uuid.uuid4() template_folder_id = uuid.uuid4() diff --git a/tests/app/notify_client/test_user_client.py b/tests/app/notify_client/test_user_client.py index c3b93cd2b..f76338e75 100644 --- a/tests/app/notify_client/test_user_client.py +++ b/tests/app/notify_client/test_user_client.py @@ -210,7 +210,7 @@ def test_returns_value_from_cache( ): mock_redis_get = mocker.patch( - 'app.notify_client.RedisClient.get', + 'app.extensions.RedisClient.get', return_value=cache_value, ) mock_api_get = mocker.patch( @@ -218,7 +218,7 @@ def test_returns_value_from_cache( return_value={'data': 'from api'}, ) mock_redis_set = mocker.patch( - 'app.notify_client.RedisClient.set', + 'app.extensions.RedisClient.set', ) mock_model = mocker.patch( 'app.models.user.User.__init__', @@ -262,7 +262,7 @@ def test_deletes_user_cache( extra_kwargs, ): mocker.patch('app.notify_client.current_user', id='1') - mock_redis_delete = mocker.patch('app.notify_client.RedisClient.delete') + mock_redis_delete = mocker.patch('app.extensions.RedisClient.delete') mock_request = mocker.patch('notifications_python_client.base.BaseAPIClient.request') getattr(client, method)(*extra_args, **extra_kwargs)