diff --git a/README b/README index 06ba0ffe..86b69784 100644 --- a/README +++ b/README @@ -88,12 +88,6 @@ Unit tests are written using py.test, and its pytest-django support library. DJANGO_SETTINGS_MODULE=combo.settings COMBO_SETTINGS_FILE=tests/settings.py py.test -Tests for w.c.s. cells do require access to the wcsctl script, its location has -to be given in a WCSCTL environment variable, this give a full command line: - - WCSCTL=$(pwd)/wcs/wcsctl.py \ - DJANGO_SETTINGS_MODULE=combo.settings COMBO_SETTINGS_FILE=tests/settings.py py.test - License ------- diff --git a/get_wcs.sh b/get_wcs.sh deleted file mode 100755 index 47c234b3..00000000 --- a/get_wcs.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh -xue - -cd $TOX_WORK_DIR -test -d wcs || git clone http://git.entrouvert.org/wcs.git -(cd wcs && git pull) -rm -rf wcs/tests diff --git a/tests/test_wcs.py b/tests/test_wcs.py index 9b894f61..5e62ea02 100644 --- a/tests/test_wcs.py +++ b/tests/test_wcs.py @@ -2,22 +2,15 @@ import pytest +import copy import json import re -import requests -import subprocess -import shutil -import sys -import tempfile -import time -import os from django.apps import apps from django.conf import settings from django.core.cache import cache from django.urls import reverse from django.db import connection -from django.test import override_settings from django.test.client import RequestFactory from django.test.utils import CaptureQueriesContext from django.utils.six.moves.urllib import parse as urlparse @@ -27,14 +20,14 @@ import mock from combo.data.library import get_cell_classes from combo.data.models import CellBase, LinkListCell, Page, ValidityInfo from combo.apps.search.engines import engines -from combo.apps.wcs.models import (WcsFormCell, WcsCurrentFormsCell, - WcsFormsOfCategoryCell, WcsCurrentDraftsCell, WcsCategoryCell, - TrackingCodeInputCell, BackofficeSubmissionCell, WcsCareFormsCell) +from combo.apps.wcs.models import ( + WcsFormCell, WcsCurrentFormsCell, + WcsFormsOfCategoryCell, WcsCurrentDraftsCell, WcsCategoryCell, + TrackingCodeInputCell, BackofficeSubmissionCell, WcsCareFormsCell) -from combo.apps.search.models import SearchCell, IndexedCell +from combo.apps.search.models import SearchCell from combo.apps.search.utils import index_site, search_site from django.contrib.auth.models import AnonymousUser -from django.test.client import RequestFactory from combo.utils import NothingInCacheException @@ -42,137 +35,51 @@ from .test_manager import login pytestmark = pytest.mark.django_db -wcs_present = pytest.mark.skipif('WCS_MANAGE' not in os.environ or not os.path.exists(os.environ['WCS_MANAGE']), - reason='WCS_MANAGE not defined in environment') -WCS_MANAGE = os.environ.get('WCS_MANAGE') - -WCS_SCRIPTS = { - 'setup-auth': """ -from quixote import get_publisher - -get_publisher().cfg['identification'] = {'methods': ['password']} -get_publisher().cfg['debug'] = {'display_exceptions': 'text'} -get_publisher().write_cfg() -""", - 'create-user': """ -from quixote import get_publisher -from qommon.ident.password_accounts import PasswordAccount - -user = get_publisher().user_class() -user.name = 'foo bar' -user.email = 'foo@example.net' -user.store() -account = PasswordAccount(id='user') -account.set_password('user') -account.user_id = user.id -account.store() -""", - 'create-data': """ -import datetime -from quixote import get_publisher - -from wcs.categories import Category -from wcs.formdef import FormDef -from wcs.roles import Role -from wcs import fields - -cats = [] -for i in range(1, 10): - cat = Category() - cat.name = 'Test %d' % i - cat.description = 'Hello world' - cat.store() - cats.append(cat) - -formdef = FormDef() -formdef.name = 'form title' -formdef.category_id = cat.id -formdef.keywords = 'foo, bar' -formdef.fields = [ - fields.StringField(id='1', label='1st field', type='string'), - fields.ItemField(id='2', label='2nd field', type='item', - items=['foo', 'bar', 'baz']), +WCS_FORMDEFS_DATA = [ + {'slug': 'form-title', 'title': 'form title', 'url': '/form-title/', 'keywords': ['foo', 'bar']}, + {'slug': 'a-second-form-title', 'title': 'a second form title', 'url': '/a-second-form-title/'}, + {'slug': 'a-private-form', 'title': 'a private form', 'url': '/a-private-form/'}, + {'slug': 'third-form-title', 'title': 'third form title', 'url': '/third-form-title/'}, ] -formdef.store() -user = get_publisher().user_class.select()[0] +WCS_CATEGORIES_DATA = [ + {'slug': 'test-%s' % i, 'title': 'Test %s' % i, 'url': '/test-%s/' % i} + for i in [3, 9] +] -for i in range(50): - formdata = formdef.data_class()() - formdata.just_created() - formdata.receipt_time = datetime.datetime(2015, 1, 1).timetuple() - formdata.data = {'1': 'FOO BAR %d' % i} - if i%4 == 0: - formdata.data['2'] = 'foo' - formdata.data['2_display'] = 'foo' - elif i%4 == 1: - formdata.data['2'] = 'bar' - formdata.data['2_display'] = 'bar' - else: - formdata.data['2'] = 'baz' - formdata.data['2_display'] = 'baz' - if i%3 == 0: - formdata.jump_status('new') - else: - formdata.jump_status('finished') - if i%7 == 0: - formdata.user_id = user.id - formdata.store() +WCS_CATEGORIES_FORMDEFS_DATA = [ + {'slug': 'form-title', 'title': 'form title', 'url': '/form-title/', 'keywords': ['foo', 'bar'], 'count': 42}, + {'slug': 'a-second-form-title', 'title': 'a second form title', 'url': '/a-second-form-title/', 'count': 35}, +] -# another formdef in same category -formdef = FormDef() -formdef.name = 'a second form title' -formdef.category_id = cat.id -formdef.fields = [] -formdef.store() +WCS_USER_FORMS_DATA = [ + {'name': 'name', 'title': 'Title', 'url': '/form/1/', 'form_receipt_datetime': '2015-01-01T00:00:00', 'readable': True, + 'category_slug': 'test-9'}, + {'name': 'name', 'url': '/form/2/', 'form_receipt_datetime': '2015-01-01T00:00:00', 'readable': True}, + {'name': 'name', 'title': 'Title', 'url': '/form/3/', 'form_receipt_datetime': '2015-01-01T00:00:00'}, + {'name': 'name', 'title': 'Title', 'url': '/form/4/', 'form_receipt_datetime': '2015-01-01T00:00:00', 'readable': True, + 'form_status_is_endpoint': True, 'category_slug': 'test-9'}, +] -# a formdef in another category -formdef = FormDef() -formdef.name = 'third form title' -formdef.category_id = cats[2].id -formdef.fields = [] -formdef.enable_tracking_codes = True -formdef.store() +WCS_FORMS_DATA = [ + { + 'form_receipt_datetime': '2019-10-17T16:46:03', + 'form_url_backoffice': '/backoffice/management/foobar/1/', + }, + { + 'form_receipt_datetime': '2019-10-17T16:46:04', + 'form_url_backoffice': '/backoffice/management/foobar/2/', + }, +] -# a draft of that formdef -formdata = formdef.data_class()() -formdata.data = {} -formdata.page_no = 1 -formdata.status = 'draft' -formdata.receipt_time = datetime.datetime(2015, 1, 1).timetuple() -formdata.user_id = user.id -formdata.store() - -if '127.0.0.2' in get_publisher().get_frontoffice_url(): - # create a tracking code on second website only - code = get_publisher().tracking_code_class() - code.id = 'CNPHNTFB' - code.formdata = formdata - -# a private formdef -role = Role(name='Blah') -role.store() - -formdef = FormDef() -formdef.name = 'a private form' -formdef.category_id = cats[2].id -formdef.roles = [role.id] -formdef.backoffice_submission_roles = [role.id] -formdef.fields = [] -formdef.store() - -user2 = get_publisher().user_class() # agent -user2.name = 'foo2 bar2' -user2.email = 'foo2@example.net' -user2.roles = [role.id] -user2.store() -""", - -} - -WCS_DIR = tempfile.mkdtemp() -WCS_PID = None +WCS_USER_DRAFTS_DATA = [ + {'name': 'name', 'title': 'Title', 'url': '/form/1/', 'form_receipt_datetime': '2015-01-01T00:00:00', 'category_slug': 'test-9'}, + {'name': 'name', 'url': '/form/2/', 'form_receipt_datetime': '2015-01-01T00:00:00'}, + {'name': 'name', 'title': 'Title', 'url': '/form/3/', 'form_receipt_datetime': '2015-01-01T00:00:00'}, + {'name': 'name', 'title': 'Title', 'url': '/form/4/', 'form_receipt_datetime': '2015-01-01T00:00:00', + 'form_status_is_endpoint': True, 'category_slug': 'test-9'}, +] class MockUser(object): @@ -191,70 +98,40 @@ class MockUserWithNameId(object): return 'xyz' -def run_wcs_script(script, hostname): - script_path = os.path.join(WCS_DIR, script + '.py') - fd = open(script_path, 'w') - fd.write(WCS_SCRIPTS[script]) - fd.close() - subprocess.check_call([sys.executable, WCS_MANAGE, 'runscript', '--app-dir', WCS_DIR, - '--vhost', hostname, script_path], - env={'DJANGO_SETTINGS_MODULE': 'wcs.settings'}) +class MockedRequestResponse(mock.Mock): + status_code = 200 + + def json(self): + return json.loads(self.content) -def setup_module(module): - global WCS_PID - - if not WCS_MANAGE: - return - - for hostname in ['127.0.0.1', '127.0.0.2']: - os.mkdir(os.path.join(WCS_DIR, hostname)) - - run_wcs_script('setup-auth', hostname) - run_wcs_script('create-user', hostname) - run_wcs_script('create-data', hostname) - - fd = open(os.path.join(WCS_DIR, hostname, 'site-options.cfg'), 'w') - fd.write('''[api-secrets] -combo = combo -''') - fd.close() - - with open(os.path.join(WCS_DIR, 'wcs.cfg'), 'w') as fd: - fd.write('''[main] -app_dir = %s\n''' % WCS_DIR) - - with open(os.path.join(WCS_DIR, 'local_settings.py'), 'w') as fd: - fd.write(''' -WCS_LEGACY_CONFIG_FILE = '%s/wcs.cfg' -THEMES_DIRECTORY = '/' -ALLOWED_HOSTS = ['127.0.0.1', '127.0.0.2'] -''' % WCS_DIR) - - WCS_PID = os.fork() - if not WCS_PID: - os.chdir(os.path.dirname(WCS_MANAGE)) - os.environ['DJANGO_SETTINGS_MODULE'] = 'wcs.settings' - os.environ['WCS_SETTINGS_FILE'] = os.path.join(WCS_DIR, 'local_settings.py') - os.execvp('python', [sys.executable, 'manage.py', 'runserver', '--noreload', '0.0.0.0:8999']) - sys.exit(0) - - time.sleep(5) - -def teardown_module(module): - if WCS_PID: - os.kill(WCS_PID, 9) - shutil.rmtree(WCS_DIR) +def get_data_from_url(url): + if '/api/formdefs/' in url: + return WCS_FORMDEFS_DATA + if '/api/categories/' in url: + if '/formdefs/' in url: + return WCS_CATEGORIES_FORMDEFS_DATA + return WCS_CATEGORIES_DATA + if '/api/user/forms' in url: + return WCS_USER_FORMS_DATA + if '/api/forms' in url: + return WCS_FORMS_DATA + if '/api/user/drafts' in url: + return WCS_USER_DRAFTS_DATA + return [] -def check_wcs_open(url): - session = requests.Session() - scheme, netloc, path, query, fragment = urlparse.urlsplit(url) - path = '/login/' - login_url = urlparse.urlunsplit((scheme, netloc, path, query, fragment)) - resp = session.post(login_url, data={'username': 'user', 'password': 'user'}) - resp = session.get(url) - assert resp.status_code == 200 +def mocked_requests_send(request, **kwargs): + request_url = urlparse.urlparse(request.url) + data = copy.deepcopy(get_data_from_url(request_url.path)) + for elem in data: + for key in ['url', 'form_url_backoffice']: + if key not in elem: + continue + elem_url = elem[key] + elem[key] = '{scheme}://{netloc}{url}'.format(scheme=request_url.scheme, netloc=request_url.netloc, url=elem_url) + + return MockedRequestResponse(content=json.dumps({'data': data})) @pytest.fixture @@ -264,8 +141,9 @@ def context(): ctx['request'].session = {} return ctx -@wcs_present -def test_form_cell_setup(): + +@mock.patch('combo.apps.wcs.utils.requests.send', side_effect=mocked_requests_send) +def test_form_cell_setup(mock_send): cell = WcsFormCell() form_class = cell.get_default_form_class() form = form_class() @@ -280,8 +158,8 @@ def test_form_cell_setup(): (u'other:third-form-title', u'test2 : third form title')] -@wcs_present -def test_form_cell_save_cache(): +@mock.patch('combo.apps.wcs.utils.requests.send', side_effect=mocked_requests_send) +def test_form_cell_save_cache(mock_send): page = Page(title='xxx', slug='test_form_cell_save_cache', template_name='standard') page.save() cell = WcsFormCell(page=page, placeholder='content', order=0) @@ -291,7 +169,7 @@ def test_form_cell_save_cache(): assert cell.cached_title == 'form title' assert cell.get_additional_label() == 'form title' # make sure cached attributes are removed from serialized pages - assert not 'cached_' in json.dumps(page.get_serialized_page()) + assert 'cached_' not in json.dumps(page.get_serialized_page()) # check content provided to search engine assert cell.render_for_search() == '' @@ -309,7 +187,6 @@ def test_form_cell_save_cache(): assert WcsFormCell.objects.get(id=cell.id).cached_title == 'form title' -@wcs_present def test_form_cell_validity(): page = Page.objects.create(title='xxx', slug='test_form_cell_save_cache', template_name='standard') cell = WcsFormCell.objects.create(page=page, placeholder='content', order=0) @@ -335,7 +212,6 @@ def test_form_cell_validity(): assert validity_info.invalid_since is not None -@wcs_present def test_form_cell_load(): page = Page(title='xxx', slug='test_form_cell_save_cache', template_name='standard') page.save() @@ -353,8 +229,8 @@ def test_form_cell_load(): assert cell.cached_title == 'form title' -@wcs_present -def test_category_cell_save_cache(): +@mock.patch('combo.apps.wcs.utils.requests.send', side_effect=mocked_requests_send) +def test_category_cell_save_cache(mock_send): page = Page(title='xxx', slug='test_category_cell_save_cache', template_name='standard') page.save() cell = WcsCategoryCell(page=page, placeholder='content', order=0) @@ -365,7 +241,6 @@ def test_category_cell_save_cache(): assert cell.get_additional_label() == 'Test 3' -@wcs_present def test_category_cell_validity(): page = Page.objects.create(title='xxx', slug='test_category_cell_save_cache', template_name='standard') cell = WcsCategoryCell.objects.create(page=page, placeholder='content', order=0) @@ -391,8 +266,8 @@ def test_category_cell_validity(): assert validity_info.invalid_since is not None -@wcs_present -def test_form_cell_render(): +@mock.patch('combo.apps.wcs.utils.requests.send', side_effect=mocked_requests_send) +def test_form_cell_render(mock_send): page = Page(title='xxx', slug='test_form_cell_render', template_name='standard') page.save() cell = WcsFormCell(page=page, placeholder='content', order=0) @@ -402,8 +277,9 @@ def test_form_cell_render(): assert 'http://127.0.0.1:8999/form-title/tryauth' in result assert 'form title' in result -@wcs_present -def test_current_forms_cell_setup(): + +@mock.patch('combo.apps.wcs.utils.requests.send', side_effect=mocked_requests_send) +def test_current_forms_cell_setup(mock_send): cell = WcsCurrentFormsCell() form_class = cell.get_default_form_class() form = form_class() @@ -423,8 +299,9 @@ def test_current_forms_cell_setup(): cell.done_forms = True assert cell.get_additional_label() == 'All Sites - Done Forms' -@wcs_present -def test_current_forms_cell_render(context): + +@mock.patch('combo.apps.wcs.utils.requests.send', side_effect=mocked_requests_send) +def test_current_forms_cell_render(mock_send, context): page = Page(title='xxx', slug='test_current_forms_cell_render', template_name='standard') page.save() cell = WcsCurrentFormsCell(page=page, placeholder='content', order=0) @@ -437,15 +314,18 @@ def test_current_forms_cell_render(context): with pytest.raises(NothingInCacheException): result = cell.render(context) - context['synchronous'] = True # to get fresh content + context['synchronous'] = True # to get fresh content # default is to get current forms from all wcs sites result = cell.render(context) - assert 'http://127.0.0.1:8999/form-title/1/' in result - assert 'http://127.0.0.1:8999/form-title/22/' in result - assert not 'http://127.0.0.1:8999/form-title/8/' in result - assert 'http://127.0.0.2:8999/form-title/1/' in result - assert 'http://127.0.0.2:8999/form-title/22/' in result + assert 'http://127.0.0.1:8999/form/1/' in result + assert 'http://127.0.0.1:8999/form/2/' not in result # no title + assert 'http://127.0.0.1:8999/form/3/' not in result # not readable + assert 'http://127.0.0.1:8999/form/4/' not in result # done + assert 'http://127.0.0.2:8999/form/1/' in result + assert 'http://127.0.0.2:8999/form/2/' not in result + assert 'http://127.0.0.2:8999/form/3/' not in result + assert 'http://127.0.0.2:8999/form/4/' not in result # done forms cell.current_forms = False @@ -453,18 +333,10 @@ def test_current_forms_cell_render(context): cell.include_drafts = False cell.save() result = cell.render(context) - assert not 'http://127.0.0.1:8999/form-title/1/' in result - assert 'http://127.0.0.1:8999/form-title/8/' in result - - data = cell.get_data(context) - assert data['default']['data'][0]['site_slug'] == 'default' - assert data['other']['data'][0]['site_slug'] == 'other' - - # check flat list - extra_context = cell.get_cell_extra_context(context) - assert len(extra_context['forms']) == 10 - assert len([x for x in extra_context['forms'] if x['site_slug'] == 'default']) == 5 - assert len([x for x in extra_context['forms'] if x['site_slug'] == 'other']) == 5 + assert 'http://127.0.0.1:8999/form/1/' not in result # wip + assert 'http://127.0.0.1:8999/form/4/' in result # done + assert 'http://127.0.0.2:8999/form/1/' not in result # wip + assert 'http://127.0.0.2:8999/form/4/' in result # done # limit to a category cell.categories = {'data': ['default:test-3']} @@ -472,13 +344,13 @@ def test_current_forms_cell_render(context): assert len(extra_context['forms']) == 0 cell.categories = {'data': ['default:test-9']} extra_context = cell.get_cell_extra_context(context) - assert len(extra_context['forms']) == 5 + assert len(extra_context['forms']) == 1 # check both category limit and all forms cell.current_forms = True cell.done_forms = True extra_context = cell.get_cell_extra_context(context) - assert len(extra_context['forms']) == 8 + assert len(extra_context['forms']) == 2 # check both category limit and no forms cell.current_forms = False @@ -516,8 +388,8 @@ def test_current_forms_cell_render(context): assert 'There are no done forms' in result -@wcs_present -def test_current_forms_cell_validity(context): +@mock.patch('combo.apps.wcs.utils.requests.send', side_effect=mocked_requests_send) +def test_current_forms_cell_validity(mock_send, context): page = Page.objects.create(title='xxx', slug='test_current_forms_cell_render', template_name='standard') cell = WcsCurrentFormsCell.objects.create(page=page, placeholder='content', order=0) context['request'].user = MockUser() @@ -533,8 +405,8 @@ def test_current_forms_cell_validity(context): assert ValidityInfo.objects.exists() is False -@wcs_present -def test_current_forms_cell_check_validity(context): +@mock.patch('combo.apps.wcs.utils.requests.send', side_effect=mocked_requests_send) +def test_current_forms_cell_check_validity(mock_send, context): page = Page.objects.create(title='xxx', slug='test_current_forms_cell_render', template_name='standard') cell = WcsCurrentFormsCell.objects.create(page=page, placeholder='content', order=0) @@ -564,8 +436,8 @@ def test_current_forms_cell_check_validity(context): assert validity_info.invalid_since is not None -@wcs_present -def test_current_forms_cell_render_single_site(context): +@mock.patch('combo.apps.wcs.utils.requests.send', side_effect=mocked_requests_send) +def test_current_forms_cell_render_single_site(mock_send, context): page = Page(title='xxx', slug='test_current_forms_cell_render', template_name='standard') page.save() cell = WcsCurrentFormsCell(page=page, placeholder='content', order=0) @@ -579,16 +451,14 @@ def test_current_forms_cell_render_single_site(context): with pytest.raises(NothingInCacheException): result = cell.render(context) - context['synchronous'] = True # to get fresh content + context['synchronous'] = True # to get fresh content result = cell.render(context) - assert 'http://127.0.0.1:8999/form-title/1/' in result - assert 'http://127.0.0.1:8999/form-title/22/' in result - assert 'http://127.0.0.2:8999/form-title/1/' not in result - assert 'http://127.0.0.2:8999/form-title/22/' not in result + assert 'http://127.0.0.1:8999/form/1/' in result + assert 'http://127.0.0.2:8999/form/1/' not in result -@wcs_present -def test_current_forms_unknown_name_id(caplog, context): + +def test_current_forms_unknown_name_id(context): page = Page(title='xxx', slug='test_current_forms_cell_render', template_name='standard') page.save() cell = WcsCurrentFormsCell(page=page, placeholder='content', order=0) @@ -600,16 +470,17 @@ def test_current_forms_unknown_name_id(caplog, context): # query should fail as nothing is cached cache.clear() with pytest.raises(NothingInCacheException): - result = cell.render(context) + cell.render(context) - context['synchronous'] = True # to get fresh content + context['synchronous'] = True # to get fresh content - result = cell.render(context) - assert 'http://127.0.0.1:8999/' not in result - assert len(caplog.records) == 0 + with mock.patch('combo.apps.wcs.models.requests.get') as requests_get: + mock_json = mock.Mock(status_code=200) + requests_get.return_value = mock_json + cell.render(context) + assert requests_get.call_args_list[0][0][0] == '/api/users/xyz/forms?limit=100&sort=desc' -@wcs_present def test_care_forms_cell_setup(): cell = WcsCareFormsCell() form_class = cell.get_default_form_class() @@ -621,8 +492,8 @@ def test_care_forms_cell_setup(): assert cell.get_additional_label() == 'test' -@wcs_present -def test_care_forms_cell_render(context): +@mock.patch('combo.apps.wcs.utils.requests.send', side_effect=mocked_requests_send) +def test_care_forms_cell_render(mock_send, context): page = Page(title='xxx', slug='test_care_forms_cell_render', template_name='standard') page.save() cell = WcsCareFormsCell(page=page, placeholder='content', order=0) @@ -637,33 +508,13 @@ def test_care_forms_cell_render(context): context['synchronous'] = True # to get fresh content - with mock.patch('combo.apps.wcs.models.requests.get') as requests_get: - response1 = {'err': 0, 'data': [ - { - 'form_receipt_datetime': '2019-10-17T16:46:03', - 'form_url_backoffice': 'http://127.0.0.1:8999/backoffice/management/foobar/1/', - }, - { - 'form_receipt_datetime': '2019-10-17T16:46:04', - 'form_url_backoffice': 'http://127.0.0.1:8999/backoffice/management/foobar/2/', - }, - ]} - response2 = {'err': 0, 'data': [ - { - 'form_receipt_datetime': '2019-10-17T16:46:05', - 'form_url_backoffice': 'http://127.0.0.2:8999/backoffice/management/foobar/42/', - }, - ]} - mock_json = mock.Mock(status_code=200) - mock_json.json.side_effect = [response1, response2] - requests_get.return_value = mock_json - - result = cell.render(context) + result = cell.render(context) assert 'http://127.0.0.1:8999/backoffice/management/foobar/1' in result assert 'http://127.0.0.1:8999/backoffice/management/foobar/2' in result assert '"http://127.0.0.1:8999/backoffice/management/"' in result - assert 'http://127.0.0.2:8999/backoffice/management/foobar/42' in result + assert 'http://127.0.0.2:8999/backoffice/management/foobar/1' in result + assert 'http://127.0.0.2:8999/backoffice/management/foobar/2' in result assert '"http://127.0.0.2:8999/backoffice/management/"' in result data = cell.get_data(context) @@ -671,7 +522,6 @@ def test_care_forms_cell_render(context): assert 'other' in data -@wcs_present def test_care_forms_cell_validity(context): page = Page.objects.create(title='xxx', slug='test_care_forms_cell_render', template_name='standard') cell = WcsCareFormsCell.objects.create(page=page, placeholder='content', order=0) @@ -698,8 +548,8 @@ def test_care_forms_cell_validity(context): assert validity_info.invalid_since is not None -@wcs_present -def test_care_forms_cell_render_single_site(context): +@mock.patch('combo.apps.wcs.utils.requests.send', side_effect=mocked_requests_send) +def test_care_forms_cell_render_single_site(mock_send, context): page = Page(title='xxx', slug='test_care_forms_cell_render', template_name='standard') page.save() cell = WcsCareFormsCell(page=page, placeholder='content', order=0) @@ -724,8 +574,8 @@ def test_care_forms_cell_render_single_site(context): assert 'other' not in data -@wcs_present -def test_forms_of_category_cell_setup(): +@mock.patch('combo.apps.wcs.utils.requests.send', side_effect=mocked_requests_send) +def test_forms_of_category_cell_setup(mock_send): cell = WcsFormsOfCategoryCell() form_class = cell.get_default_form_class() form = form_class() @@ -736,8 +586,8 @@ def test_forms_of_category_cell_setup(): (u'other:test-9', u'test2 : Test 9')] -@wcs_present -def test_forms_of_category_cell_render(context): +@mock.patch('combo.apps.wcs.utils.requests.send', side_effect=mocked_requests_send) +def test_forms_of_category_cell_render(mock_send, context): page = Page(title='xxx', slug='test_forms_of_category_cell_render', template_name='standard') page.save() cell = WcsFormsOfCategoryCell(page=page, placeholder='content', order=0) @@ -785,17 +635,18 @@ def test_forms_of_category_cell_render(context): assert len(list(cell.get_external_links_data())) == 2 # existing category, but empty - cell.category_reference = 'default:test-1' - cell.save() - result = cell.render(context) - assert '

' not in result - context['combo_display_even_empty_categories'] = True - result = cell.render(context) - assert '

' in result - context.pop('combo_display_even_empty_categories') + with mock.patch('combo.apps.wcs.models.requests.get') as requests_get: + mock_json = mock.Mock(status_code=200) + requests_get.return_value = mock_json + cell.render(context) + result = cell.render(context) + assert '

' not in result + context['combo_display_even_empty_categories'] = True + result = cell.render(context) + assert '

' in result + context.pop('combo_display_even_empty_categories') -@wcs_present def test_forms_of_category_cell_validity(context): page = Page.objects.create(title='xxx', slug='test_forms_of_category_cell_render', template_name='standard') cell = WcsFormsOfCategoryCell.objects.create(page=page, placeholder='content', order=0) @@ -836,7 +687,6 @@ def test_forms_of_category_cell_validity(context): assert validity_info.invalid_since is not None -@wcs_present def test_forms_of_category_cell_check_validity(context): page = Page.objects.create(title='xxx', slug='test_forms_of_category_cell_render', template_name='standard') cell = WcsFormsOfCategoryCell.objects.create(page=page, placeholder='content', order=0) @@ -856,54 +706,72 @@ def test_forms_of_category_cell_check_validity(context): assert validity_info.invalid_since is not None -@wcs_present def test_current_drafts_cell_render_unlogged(context): page = Page(title='xxx', slug='test_current_drafts_cell_render', template_name='standard') page.save() cell = WcsCurrentDraftsCell(page=page, placeholder='content', order=0) cell.save() - context['synchronous'] = True # to get fresh content - result = cell.render(context) - assert not 'http://127.0.0.1:8999/third-form-title' in result # no form + context['synchronous'] = True # to get fresh content + with mock.patch('combo.apps.wcs.models.requests.get') as requests_get: + mock_json = mock.Mock(status_code=200) + requests_get.return_value = mock_json + result = cell.render(context) + assert requests_get.call_args_list[0][0][0] == '/api/user/drafts' + assert 'http://127.0.0.1:8999/third-form-title' not in result # no form -@wcs_present -def test_current_drafts_cell_render_logged_in(context): +@mock.patch('combo.apps.wcs.utils.requests.send', side_effect=mocked_requests_send) +def test_current_drafts_cell_render_logged_in(mock_send, context): page = Page(title='xxx', slug='test_current_drafts_cell_render', template_name='standard') page.save() cell = WcsCurrentDraftsCell(page=page, placeholder='content', order=0) cell.save() - context['synchronous'] = True # to get fresh content + context['synchronous'] = True # to get fresh content context['request'].user = MockUser() # default is to get current forms from all wcs sites result = cell.render(context) - assert 'http://127.0.0.1:8999/third-form-title/1' in result - for url in re.findall(r'href=[\'"]?([^\'" >]+)', result): - check_wcs_open(url) + assert 'http://127.0.0.1:8999/form/1/' in result + assert 'http://127.0.0.1:8999/form/2/' not in result # no title + assert 'http://127.0.0.1:8999/form/3/' in result + assert 'http://127.0.0.1:8999/form/4/' not in result # done + assert 'http://127.0.0.2:8999/form/1/' in result + assert 'http://127.0.0.2:8999/form/2/' not in result + assert 'http://127.0.0.2:8999/form/3/' in result + assert 'http://127.0.0.2:8999/form/4/' not in result # check flat list extra_context = cell.get_cell_extra_context(context) - assert len(extra_context['drafts']) == 2 - assert len([x for x in extra_context['drafts'] if x['site_slug'] == 'default']) == 1 - assert len([x for x in extra_context['drafts'] if x['site_slug'] == 'other']) == 1 + assert len(extra_context['drafts']) == 8 + assert len([x for x in extra_context['drafts'] if x['site_slug'] == 'default']) == 4 + assert len([x for x in extra_context['drafts'] if x['site_slug'] == 'other']) == 4 # limit to a category cell.categories = {'data': ['default:test-3']} extra_context = cell.get_cell_extra_context(context) - assert len(extra_context['drafts']) == 1 + assert len(extra_context['drafts']) == 0 cell.categories = {'data': ['default:test-9']} extra_context = cell.get_cell_extra_context(context) - assert len(extra_context['drafts']) == 0 + assert len(extra_context['drafts']) == 2 # check empty message - result = cell.render(context) + with mock.patch('combo.apps.wcs.models.requests.get') as requests_get: + mock_json = mock.Mock(status_code=200) + requests_get.return_value = mock_json + result = cell.render(context) assert 'There are no current drafts.' in result + context['request'].user = MockUserWithNameId() + with mock.patch('combo.apps.wcs.models.requests.get') as requests_get: + mock_json = mock.Mock(status_code=200) + requests_get.return_value = mock_json + cell.render(context) + assert requests_get.call_args_list[0][0][0] == '/api/users/xyz/drafts' -@wcs_present -def test_current_drafts_cell_check_validity(context): + +@mock.patch('combo.apps.wcs.utils.requests.send', side_effect=mocked_requests_send) +def test_current_drafts_cell_check_validity(mock_send, context): page = Page.objects.create(title='xxx', slug='test_current_forms_cell_render', template_name='standard') cell = WcsCurrentDraftsCell.objects.create(page=page, placeholder='content', order=0) @@ -933,9 +801,8 @@ def test_current_drafts_cell_check_validity(context): assert validity_info.invalid_since is not None -@wcs_present -def test_manager_forms_of_category_cell(app, admin_user): - Page.objects.all().delete() +@mock.patch('combo.apps.wcs.utils.requests.send', side_effect=mocked_requests_send) +def test_manager_forms_of_category_cell(mock_send, app, admin_user): page = Page(title='One', slug='one', template_name='standard') page.save() app = login(app) @@ -953,9 +820,8 @@ def test_manager_forms_of_category_cell(app, admin_user): resp = resp.forms[0].submit() assert resp.status_int == 302 -@wcs_present + def test_manager_current_forms(app, admin_user): - Page.objects.all().delete() page = Page(title='One', slug='one', template_name='standard') page.save() app = login(app) @@ -990,9 +856,7 @@ def test_manager_current_forms(app, admin_user): settings.KNOWN_SERVICES = temp_settings -@wcs_present def test_tracking_code_cell(app, nocache): - Page.objects.all().delete() page = Page(title='One', slug='index', template_name='standard') page.save() cell = TrackingCodeInputCell(page=page, placeholder='content', order=0) @@ -1000,28 +864,49 @@ def test_tracking_code_cell(app, nocache): resp = app.get('/') resp.form['code'] = 'FOOBAR' - resp = resp.form.submit() + with mock.patch('combo.apps.wcs.models.requests.get') as requests_get: + mock_json = mock.Mock(status_code=200) + requests_get.return_value = mock_json + resp = resp.form.submit() + assert len(requests_get.call_args_list) == 2 + assert requests_get.call_args_list[0][0][0] == '/api/code/FOOBAR' + assert requests_get.call_args_list[1][0][0] == '/api/code/FOOBAR' + remote_service_urls = [c[1]['remote_service']['url'] for c in requests_get.call_args_list] + assert set(remote_service_urls) == set(['http://127.0.0.1:8999/', 'http://127.0.0.2:8999/']) assert resp.status_code == 302 resp = resp.follow() assert '
  • The tracking code could not been found.
  • ' in resp.text resp = app.get('/') resp.form['code'] = 'FOO?BAR?bad' - resp = resp.form.submit() + with mock.patch('combo.apps.wcs.models.requests.get') as requests_get: + mock_json = mock.Mock(status_code=200) + requests_get.return_value = mock_json + resp = resp.form.submit() + assert requests_get.call_args_list[0][0][0] == '/api/code/FOO%3FBAR%3FBAD%3CCODE%3E' assert resp.status_code == 302 resp = resp.follow() assert '
  • The tracking code could not been found.
  • ' in resp.text resp = app.get('/') resp.form['code'] = 'CNPHNTFB' - resp = resp.form.submit() + with mock.patch('combo.apps.wcs.models.requests.get') as requests_get: + requests_get.return_value = MockedRequestResponse(content=json.dumps({'err': 0, 'load_url': 'http://127.0.0.2:8999/code/CNPHNTFB/load'})) + resp = resp.form.submit() assert resp.status_code == 302 assert resp.location == 'http://127.0.0.2:8999/code/CNPHNTFB/load' # space/case resp = app.get('/') resp.form['code'] = ' cnphntfb' - resp = resp.form.submit() + with mock.patch('combo.apps.wcs.models.requests.get') as requests_get: + requests_get.side_effect = [ + mock.Mock(status_code=200), + MockedRequestResponse(content=json.dumps({'err': 0, 'load_url': 'http://127.0.0.2:8999/code/CNPHNTFB/load'})) + ] + resp = resp.form.submit() + assert requests_get.call_args_list[0][0][0] == '/api/code/CNPHNTFB' + assert requests_get.call_args_list[1][0][0] == '/api/code/CNPHNTFB' assert resp.status_code == 302 assert resp.location == 'http://127.0.0.2:8999/code/CNPHNTFB/load' @@ -1030,7 +915,12 @@ def test_tracking_code_cell(app, nocache): cell.save() resp = app.get('/') resp.form['code'] = 'CNPHNTFB' - resp = resp.form.submit() + with mock.patch('combo.apps.wcs.models.requests.get') as requests_get: + mock_json = mock.Mock(status_code=200) + requests_get.return_value = mock_json + resp = resp.form.submit() + assert len(requests_get.call_args_list) == 1 + assert requests_get.call_args_list[0][1]['remote_service']['url'] == 'http://127.0.0.1:8999/' resp = resp.follow() assert '
  • The tracking code could not been found.
  • ' in resp.text @@ -1038,13 +928,19 @@ def test_tracking_code_cell(app, nocache): resp = app.get('/') resp.form['url'] = 'http://example.org/' resp.form['code'] = 'CNPHNTFB' - resp = resp.form.submit() + with mock.patch('combo.apps.wcs.models.requests.get') as requests_get: + mock_json = mock.Mock(status_code=200) + requests_get.return_value = mock_json + resp = resp.form.submit() assert resp.location == 'http://example.org/?unknown-tracking-code' resp = app.get('/') resp.form['url'] = 'http://example.org/?foo=bar' resp.form['code'] = 'CNPHNTFB' - resp = resp.form.submit() + with mock.patch('combo.apps.wcs.models.requests.get') as requests_get: + mock_json = mock.Mock(status_code=200) + requests_get.return_value = mock_json + resp = resp.form.submit() assert resp.location == 'http://example.org/?foo=bar&unknown-tracking-code' # redirect to an unknown site @@ -1067,8 +963,8 @@ def test_tracking_code_cell(app, nocache): resp = app.post(reverse('wcs-tracking-code'), params={'cell': cell.id}, status=400) -@wcs_present -def test_cell_assets(settings, app, admin_user): +@mock.patch('combo.apps.wcs.utils.requests.send', side_effect=mocked_requests_send) +def test_cell_assets(mock_send, settings, app, admin_user): page = Page.objects.create(title='xxx', slug='test_cell_assets', template_name='standard') cell1 = WcsFormCell.objects.create(page=page, placeholder='content', order=0, formdef_reference=u'default:form-title') @@ -1117,36 +1013,62 @@ def test_cell_assets(settings, app, admin_user): assert u'>Picture — %s (test)<' % cell1.get_label_for_asset() in resp.text -@wcs_present -def test_tracking_code_search(app, nocache): +def test_tracking_code_search(settings, app, nocache): settings.TEMPLATE_VARS['is_portal_agent'] = True - assert len(app.get('/api/search/tracking-code/').json.get('data')) == 0 - assert app.get('/api/search/tracking-code/').json.get('err') == 0 - assert len(app.get('/api/search/tracking-code/?q=123').json.get('data')) == 0 - assert len(app.get('/api/search/tracking-code/?q=BBCCDFF').json.get('data')) == 0 - assert len(app.get('/api/search/tracking-code/?q=BBCCDDFF').json.get('data')) == 0 - assert len(app.get('/api/search/tracking-code/?q=CNPHNTFB').json.get('data')) == 1 - assert len(app.get('/api/search/tracking-code/?q=BBCCDDFFG').json.get('data')) == 0 - assert len(app.get('/api/search/tracking-code/?q= cnphntfb').json.get('data')) == 1 -@wcs_present -def test_tracking_code_search_rate_limit(app): + with mock.patch('combo.apps.wcs.models.requests.get') as requests_get: + result = app.get('/api/search/tracking-code/').json + assert len(result.get('data')) == 0 + assert result.get('err') == 0 + assert requests_get.called is False # no code + + with mock.patch('combo.apps.wcs.models.requests.get') as requests_get: + assert len(app.get('/api/search/tracking-code/?q=123').json.get('data')) == 0 + assert requests_get.called is False # no letters + + with mock.patch('combo.apps.wcs.models.requests.get') as requests_get: + assert len(app.get('/api/search/tracking-code/?q=BBCCDFF').json.get('data')) == 0 + assert requests_get.called is False # too short + + with mock.patch('combo.apps.wcs.models.requests.get') as requests_get: + mock_json = mock.Mock(status_code=200) + requests_get.return_value = mock_json + assert len(app.get('/api/search/tracking-code/?q=BBCCDDFF').json.get('data')) == 0 + assert len(requests_get.call_args_list) == 2 + assert requests_get.call_args_list[0][0][0] == '/api/code/BBCCDDFF' + assert requests_get.call_args_list[1][0][0] == '/api/code/BBCCDDFF' + remote_service_urls = [c[1]['remote_service']['url'] for c in requests_get.call_args_list] + assert set(remote_service_urls) == set(['http://127.0.0.1:8999/', 'http://127.0.0.2:8999/']) + + with mock.patch('combo.apps.wcs.models.requests.get') as requests_get: + requests_get.return_value = MockedRequestResponse(content=json.dumps({'err': 0, 'load_url': 'http://127.0.0.2:8999/code/CNPHNTFB/load'})) + assert len(app.get('/api/search/tracking-code/?q=CNPHNTFB').json.get('data')) == 1 + assert requests_get.call_args_list[0][0][0] == '/api/code/CNPHNTFB' + + with mock.patch('combo.apps.wcs.models.requests.get') as requests_get: + assert len(app.get('/api/search/tracking-code/?q=BBCCDDFFG').json.get('data')) == 0 + assert requests_get.called is False # too long + + with mock.patch('combo.apps.wcs.models.requests.get') as requests_get: + requests_get.side_effect = [ + mock.Mock(status_code=200), + MockedRequestResponse(content=json.dumps({'err': 0, 'load_url': 'http://127.0.0.2:8999/code/CNPHNTFB/load'})) + ] + assert len(app.get('/api/search/tracking-code/?q= cnphntfb').json.get('data')) == 1 + assert requests_get.call_args_list[0][0][0] == '/api/code/CNPHNTFB' + + +def test_tracking_code_search_rate_limit(settings, app): settings.TEMPLATE_VARS['is_portal_agent'] = True - for i in range(3): - assert app.get('/api/search/tracking-code/?q=BBCCDDFF').json.get('err') == 0 - for i in range(3): # make sure we hit ratelimit - app.get('/api/search/tracking-code/?q=BBCCDDFF') + settings.WCS_TRACKING_CODE_RATE_LIMIT = '0/s' assert app.get('/api/search/tracking-code/?q=BBCCDDFF').json.get('err') == 1 - Page.objects.all().delete() page = Page(title='One', slug='index', template_name='standard') page.save() cell = TrackingCodeInputCell(page=page, placeholder='content', order=0) cell.save() resp = app.get('/') - for i in range(3): # make sure we hit ratelimit - app.get('/api/search/tracking-code/?q=BBCCDDFF') resp.form['code'] = 'FOOBAR' resp = resp.form.submit() assert resp.status_code == 302 @@ -1154,14 +1076,11 @@ def test_tracking_code_search_rate_limit(app): assert '
  • Looking up tracking code is currently rate limited.
  • ' in resp.text resp = app.get('/') - for i in range(3): # make sure we hit ratelimit - app.get('/api/search/tracking-code/?q=BBCCDDFF') resp.form['code'] = 'FOOBAR' resp.form['url'] = 'http://example.org/' resp = resp.form.submit(status=403) -@wcs_present def test_wcs_search_engines(app): settings.TEMPLATE_VARS['is_portal_agent'] = True search_engines = engines.get_engines() @@ -1173,7 +1092,6 @@ def test_wcs_search_engines(app): assert len([x for x in search_engines.keys() if x.startswith('formdata:')]) == 0 -@wcs_present def test_backoffice_submission_cell_render(context): page = Page(title='xxx', slug='test_backoffice_submission_cell_render', template_name='standard') page.save() @@ -1183,36 +1101,23 @@ def test_backoffice_submission_cell_render(context): context['synchronous'] = True # to get fresh content - result = cell.render(context) - assert '/backoffice/submission/a-private-form/' not in result + with mock.patch('combo.apps.wcs.models.requests.get') as requests_get: + mock_json = mock.Mock(status_code=200) + requests_get.return_value = mock_json + result = cell.render(context) + assert requests_get.call_args_list[0][0][0] == '/api/formdefs/?backoffice-submission=on' assert context['all_formdefs'] == {} assert 'h2' not in result - context['request'].user = MockUser() - - result = cell.render(context) - assert '/backoffice/submission/a-private-form/' not in result - assert context['all_formdefs'] == {} - assert 'h2' not in result - - class MockUser2(MockUser): - email = 'foo2@example.net' - context['request'].user = MockUser2() - - result = cell.render(context) + with mock.patch('combo.apps.wcs.models.requests.get') as requests_get: + requests_get.return_value = MockedRequestResponse(content=json.dumps( + {'data': [{'backoffice_submission_url': '/backoffice/submission/a-private-form/', 'title': 'Foo'}]})) + result = cell.render(context) assert '/backoffice/submission/a-private-form/' in result assert list(context['all_formdefs'].keys()) == ['default'] assert 'h2' in result - with mock.patch('combo.apps.wcs.models.requests.get') as requests_get: - # empty response - mock_json = mock.Mock(status_code=200) - requests_get.return_value = mock_json - result = cell.render(context) - assert '/backoffice/submission/a-private-form/' not in result - -@wcs_present def test_manager_link_list_cell_duplicate(): page = Page.objects.create(title='xxx', slug='new', template_name='standard') cell = LinkListCell.objects.create(order=0, page=page) @@ -1236,9 +1141,8 @@ def test_manager_link_list_cell_duplicate(): assert new_item.cached_json == item.cached_json -@wcs_present -def test_manager_add_edit_delete_list_link_item(app, admin_user): - Page.objects.all().delete() +@mock.patch('combo.apps.wcs.utils.requests.send', side_effect=mocked_requests_send) +def test_manager_add_edit_delete_list_link_item(mock_send, app, admin_user): page = Page.objects.create(title='One', slug='one', template_name='standard') cell = LinkListCell.objects.create(order=0, placeholder='content', page=page) app = login(app) @@ -1273,7 +1177,6 @@ def test_manager_add_edit_delete_list_link_item(app, admin_user): assert WcsFormCell.objects.count() == 0 -@wcs_present def test_import_export_pages_with_links(): page = Page(title=u'bar', slug='bar', order=1) page.save() @@ -1289,7 +1192,6 @@ def test_import_export_pages_with_links(): ) site_export = [x.get_serialized_page() for x in Page.objects.all()] - Page.objects.all().delete() Page.load_serialized_pages(site_export) @@ -1322,7 +1224,6 @@ def test_list_of_links_with_form_render(app): assert 'keyword-bar' in resp -@wcs_present def test_view_page_with_wcs_cells_num_queries(app, admin_user): page = Page.objects.create(title=u'bar', slug='index', order=1) for i in range(0, 15): @@ -1342,7 +1243,6 @@ def test_view_page_with_wcs_cells_num_queries(app, admin_user): assert len(ctx.captured_queries) == 61 -@wcs_present def test_hourly(): appconfig = apps.get_app_config('wcs') page = Page.objects.create(title='xxx', slug='test_current_forms_cell_render', template_name='standard') @@ -1358,9 +1258,8 @@ def test_hourly(): assert hasattr(klass, 'check_validity') is False -@wcs_present -def test_search_external_forms_links(context): - +@mock.patch('combo.apps.wcs.utils.requests.send', side_effect=mocked_requests_send) +def test_search_external_forms_links(mock_send, context): page = Page(title='xxx', slug='test_forms_of_category_cell_search', template_name='standard') page.save() diff --git a/tox.ini b/tox.ini index 2c727b8f..1066464b 100644 --- a/tox.ini +++ b/tox.ini @@ -5,7 +5,6 @@ envlist = coverage-py3-django111-pylint,py3-django22 [testenv] usedevelop = True setenv = - WCS_MANAGE={toxworkdir}/wcs/wcsctl.py DJANGO_SETTINGS_MODULE=combo.settings COMBO_SETTINGS_FILE=tests/settings.py TOX_WORK_DIR={toxworkdir} @@ -32,7 +31,6 @@ deps = git+http://git.entrouvert.org/debian/django-ckeditor.git commands = ./getlasso3.sh - ./get_wcs.sh python manage.py compilemessages py.test {env:COVERAGE:} {posargs: --junitxml=junit-{envname}.xml tests/} pylint: ./pylint.sh combo/