506 lines
21 KiB
Python
506 lines
21 KiB
Python
import mock
|
|
from webtest import TestApp
|
|
|
|
import datetime
|
|
import json
|
|
import pytest
|
|
import os
|
|
import urllib
|
|
from urlparse import urlparse
|
|
|
|
from django.conf import settings
|
|
from django.core.urlresolvers import reverse
|
|
from django.test import override_settings
|
|
|
|
from combo.wsgi import application
|
|
from combo.data.models import (Page, CellBase, TextCell, ParentContentCell,
|
|
FeedCell, LinkCell, ConfigJsonCell)
|
|
from combo.apps.family.models import FamilyInfosCell
|
|
|
|
pytestmark = pytest.mark.django_db
|
|
|
|
from test_manager import admin_user, login
|
|
|
|
def test_missing_index(app):
|
|
Page.objects.all().delete()
|
|
resp = app.get('/', status=200)
|
|
assert 'Welcome' in resp.body
|
|
|
|
def test_index(app):
|
|
Page.objects.all().delete()
|
|
page = Page(title='Home', slug='index', template_name='standard')
|
|
page.save()
|
|
resp = app.get('/index', status=301)
|
|
assert urlparse(resp.location).path == '/'
|
|
resp = app.get('/', status=200)
|
|
|
|
# check {% now %} inside a skeleton_extra_placeholder is interpreted
|
|
assert str(datetime.datetime.now().year) in resp.body
|
|
|
|
def test_page_contents(app):
|
|
Page.objects.all().delete()
|
|
page = Page(title='Home', slug='index', template_name='standard')
|
|
page.save()
|
|
cell = TextCell(page=page, placeholder='content', text='Foobar', order=0)
|
|
cell.save()
|
|
resp = app.get('/', status=200)
|
|
assert 'Foobar' in resp.body
|
|
|
|
def test_page_contents_unlogged_only(app, admin_user):
|
|
Page.objects.all().delete()
|
|
page = Page(title='Home', slug='index', template_name='standard')
|
|
page.save()
|
|
cell = TextCell(page=page, placeholder='content', text='Foobar', order=0,
|
|
restricted_to_unlogged=True)
|
|
cell.save()
|
|
resp = app.get('/', status=200)
|
|
assert 'Foobar' in resp.body
|
|
|
|
app = login(app)
|
|
resp = app.get('/', status=200)
|
|
assert not 'Foobar' in resp.body
|
|
|
|
def test_page_footer_acquisition(app):
|
|
Page.objects.all().delete()
|
|
page = Page(title='Home', slug='index', template_name='standard')
|
|
page.save()
|
|
cell = TextCell(page=page, placeholder='footer', text='BARFOO', order=0)
|
|
cell.save()
|
|
resp = app.get('/', status=200)
|
|
assert 'BARFOO' in resp.body
|
|
|
|
page = Page(title='Second', slug='second', template_name='standard')
|
|
page.save()
|
|
ParentContentCell(page=page, placeholder='footer', order=0).save()
|
|
resp = app.get('/second', status=301)
|
|
assert urlparse(resp.location).path == '/second/'
|
|
resp = app.get('/second/', status=200)
|
|
assert 'BARFOO' in resp.body
|
|
|
|
def test_page_redirect(app):
|
|
Page.objects.all().delete()
|
|
page = Page(title='Elsewhere', slug='elsewhere', template_name='standard',
|
|
redirect_url='http://example.net')
|
|
page.save()
|
|
resp = app.get('/elsewhere/', status=302)
|
|
assert resp.location == 'http://example.net'
|
|
|
|
def test_page_templated_redirect(app):
|
|
Page.objects.all().delete()
|
|
with override_settings(TEMPLATE_VARS={'test_url': 'http://example.net'}):
|
|
page = Page(title='Elsewhere', slug='elsewhere', template_name='standard',
|
|
redirect_url='[test_url]')
|
|
page.save()
|
|
resp = app.get('/elsewhere/', status=302)
|
|
assert resp.location == 'http://example.net'
|
|
|
|
def test_page_private_unlogged(app):
|
|
Page.objects.all().delete()
|
|
page = Page(title='Home', slug='index', template_name='standard', public=False)
|
|
page.save()
|
|
resp = app.get('/', status=302)
|
|
assert resp.location.endswith('/login/?next=http%3A//testserver/')
|
|
|
|
def test_page_private_logged_in(app, admin_user):
|
|
Page.objects.all().delete()
|
|
page = Page(title='Home', slug='index', template_name='standard', public=False)
|
|
page.save()
|
|
app = login(app)
|
|
resp = app.get('/', status=200)
|
|
|
|
def test_page_skeleton(app):
|
|
Page.objects.all().delete()
|
|
page = Page(title='Elsewhere', slug='elsewhere', template_name='standard',
|
|
redirect_url='http://example.net/foo/')
|
|
page.save()
|
|
|
|
# url prefix match
|
|
resp = app.get('/__skeleton__/?source=%s' % urllib.quote('http://example.net/foo/bar'))
|
|
assert '{% block placeholder-content %}{% block content %}{% endblock %}{% endblock %}' in resp.body
|
|
assert '{% block placeholder-footer %}{% block footer %}{% endblock %}{% endblock %}' in resp.body
|
|
|
|
# url netloc match
|
|
resp = app.get('/__skeleton__/?source=%s' % urllib.quote('http://example.net'))
|
|
assert '{% block placeholder-content %}{% block content %}{% endblock %}{% endblock %}' in resp.body
|
|
assert '{% block placeholder-footer %}{% block footer %}{% endblock %}{% endblock %}' in resp.body
|
|
|
|
# settings.KNOWN_SERVICES match
|
|
resp = app.get('/__skeleton__/?source=%s' % urllib.quote('http://127.0.0.1:8999/'))
|
|
assert '{% block placeholder-content %}{% block content %}{% endblock %}{% endblock %}' in resp.body
|
|
|
|
# no match
|
|
resp = app.get('/__skeleton__/?source=%s' % urllib.quote('http://example.com/foo/bar'), status=403)
|
|
|
|
# check with a footer cell
|
|
cell = TextCell(page=page, placeholder='footer', text='Foobar', order=0)
|
|
cell.save()
|
|
resp = app.get('/__skeleton__/?source=%s' % urllib.quote('http://example.net'))
|
|
assert '{% block placeholder-content %}{% block content %}{% endblock %}{% endblock %}' in resp.body
|
|
assert not '{% block placeholder-footer %}{% block footer %}{% endblock %}{% endblock %}' in resp.body
|
|
assert 'Foobar' in resp.body
|
|
|
|
# check {% now %} inside a skeleton_extra_placeholder is not interpreted
|
|
assert '{%now' in resp.body
|
|
|
|
# check cells in footer are present even if there's no redirection page
|
|
page.slug = 'index'
|
|
page.save()
|
|
resp = app.get('/__skeleton__/?source=%s' % urllib.quote('http://127.0.0.1:8999/'))
|
|
assert '{% block placeholder-content %}{% block content %}{% endblock %}{% endblock %}' in resp.body
|
|
assert not '{% block placeholder-footer %}{% block footer %}{% endblock %}{% endblock %}' in resp.body
|
|
assert 'Foobar' in resp.body
|
|
|
|
# check link cells provide a full URL
|
|
other_page = Page(title='Plop', slug='plop', template_name='standard')
|
|
other_page.save()
|
|
cell = LinkCell(page=page, placeholder='footer', link_page=other_page, order=0)
|
|
cell.save()
|
|
resp = app.get('/__skeleton__/?source=%s' % urllib.quote('http://127.0.0.1:8999/'))
|
|
assert 'http://testserver/plop' in resp.body
|
|
|
|
def test_subpage_location(app):
|
|
Page.objects.all().delete()
|
|
|
|
page_index = Page(title='Home Page', slug='index', template_name='standard')
|
|
page_index.save()
|
|
|
|
page_sibling = Page(title='Second top level page', slug='second', template_name='standard')
|
|
page_sibling.save()
|
|
|
|
page = Page(title='Child of Home', slug='child-home',
|
|
template_name='standard', parent=page_index)
|
|
page.save()
|
|
|
|
page = Page(title='Grand child of home', slug='grand-child-home',
|
|
template_name='standard', parent=page)
|
|
page.save()
|
|
|
|
page = Page(title='Child of second', slug='child-second',
|
|
template_name='standard', parent=page_sibling)
|
|
page.save()
|
|
|
|
page = Page(title='Grand child of second', slug='grand-child-second',
|
|
template_name='standard', parent=page)
|
|
page.save()
|
|
|
|
resp = app.get('/', status=200)
|
|
assert 'Home Page' in resp.body
|
|
|
|
resp = app.get('/child-home/', status=200)
|
|
assert 'Child of Home' in resp.body
|
|
|
|
resp = app.get('/child-home/grand-child-home/', status=200)
|
|
assert 'Grand child of home' in resp.body
|
|
|
|
assert urlparse(app.get('/child-home/grand-child-home', status=301).location
|
|
).path == '/child-home/grand-child-home/'
|
|
app.get('/grand-child-home/', status=404)
|
|
|
|
resp = app.get('/second/', status=200)
|
|
assert 'Second top level page' in resp.body
|
|
|
|
resp = app.get('/second/child-second/', status=200)
|
|
assert 'Child of second' in resp.body
|
|
|
|
resp = app.get('/second/child-second/grand-child-second/', status=200)
|
|
assert 'Grand child of second' in resp.body
|
|
|
|
def test_404(app):
|
|
Page.objects.all().delete()
|
|
resp = app.get('/foobar/', status=404)
|
|
assert "This page doesn't exist" in resp.body
|
|
|
|
def test_style_demo(app, admin_user):
|
|
TextCell.objects.all().delete()
|
|
Page.objects.all().delete()
|
|
app = login(app)
|
|
with override_settings(DEBUG=True):
|
|
resp = app.get('/__style__/', status=200)
|
|
assert 'Lorem ipsum' in resp.body
|
|
assert TextCell.objects.count() == 0
|
|
assert Page.objects.count() == 0
|
|
|
|
def test_page_async_cell(app):
|
|
Page.objects.all().delete()
|
|
page = Page(title='Home', slug='index', template_name='standard')
|
|
page.save()
|
|
cell = FeedCell(page=page, placeholder='content', url='http://example.net',
|
|
order=1)
|
|
cell.save()
|
|
resp = app.get('/', status=200)
|
|
assert 'data-ajax-cell-must-load="true"' in resp.body
|
|
|
|
def test_ajax_cell(app):
|
|
Page.objects.all().delete()
|
|
page = Page(title='Home', slug='index', template_name='standard')
|
|
page.save()
|
|
page2 = Page(title='Other', slug='other', template_name='standard')
|
|
page2.save()
|
|
cell = TextCell(page=page, placeholder='content', text='<p>Foobar</p>', order=0)
|
|
cell.save()
|
|
resp = app.get(reverse('combo-public-ajax-page-cell',
|
|
kwargs={'page_pk': page.id, 'cell_reference': cell.get_reference()}))
|
|
assert resp.body.strip() == '<p>Foobar</p>'
|
|
|
|
resp = app.get(reverse('combo-public-ajax-page-cell',
|
|
kwargs={'page_pk': page2.id, 'cell_reference': cell.get_reference()}),
|
|
status=404)
|
|
|
|
resp = app.get(reverse('combo-public-ajax-page-cell',
|
|
kwargs={'page_pk': '100', 'cell_reference': cell.get_reference()}),
|
|
status=404)
|
|
|
|
page.public = False
|
|
page.save()
|
|
resp = app.get(reverse('combo-public-ajax-page-cell',
|
|
kwargs={'page_pk': page.id, 'cell_reference': cell.get_reference()}),
|
|
status=403)
|
|
|
|
page.public = True
|
|
page.save()
|
|
cell.public = False
|
|
cell.save()
|
|
resp = app.get('/', status=200)
|
|
assert not 'FOOBAR' in resp.body
|
|
|
|
resp = app.get(reverse('combo-public-ajax-page-cell',
|
|
kwargs={'page_pk': page.id, 'cell_reference': cell.get_reference()}),
|
|
status=403)
|
|
|
|
|
|
def test_initial_login_page(app, admin_user):
|
|
Page.objects.all().delete()
|
|
page = Page(title='Home', slug='index', template_name='standard')
|
|
page.save()
|
|
page = Page(title='Initial Login', slug='initial-login', template_name='standard', public=False)
|
|
page.save()
|
|
|
|
with override_settings(COMBO_INITIAL_LOGIN_PAGE_PATH='/initial-login/'):
|
|
resp = app.get('/', status=200)
|
|
|
|
# first visit
|
|
app = login(app)
|
|
resp = app.get('/', status=302)
|
|
assert urlparse(resp.location).path == '/initial-login/'
|
|
|
|
# visit again
|
|
resp = app.get('/', status=200)
|
|
|
|
|
|
def test_welcome_page(app, admin_user):
|
|
Page.objects.all().delete()
|
|
page = Page(title='Home', slug='index', template_name='standard')
|
|
page.save()
|
|
page = Page(title='Welcome', slug='welcome', template_name='standard')
|
|
page.save()
|
|
|
|
with override_settings(COMBO_WELCOME_PAGE_PATH='/welcome/'):
|
|
app.cookiejar.clear()
|
|
resp = app.get('/', status=302)
|
|
assert urlparse(resp.location).path == '/welcome/'
|
|
|
|
resp = app.get('/', status=200)
|
|
|
|
app.cookiejar.clear()
|
|
resp = app.get('/', status=302)
|
|
assert urlparse(resp.location).path == '/welcome/'
|
|
|
|
app.cookiejar.clear()
|
|
app = login(app)
|
|
resp = app.get('/', status=200)
|
|
|
|
|
|
def test_post_cell(app):
|
|
Page.objects.all().delete()
|
|
page = Page(title='Home', slug='index', template_name='standard')
|
|
page.save()
|
|
cell = TextCell(page=page, placeholder='content', text='<p>Foobar</p>', order=0)
|
|
cell.save()
|
|
|
|
# check it's not possible to post to cell that doesn't have POST support.
|
|
resp = app.post(reverse('combo-public-ajax-page-cell',
|
|
kwargs={'page_pk': page.id, 'cell_reference': cell.get_reference()}),
|
|
params={'hello': 'world'},
|
|
status=403)
|
|
|
|
templates_settings = [settings.TEMPLATES[0].copy()]
|
|
templates_settings[0]['DIRS'] = ['%s/templates-1' % os.path.abspath(os.path.dirname(__file__))]
|
|
with override_settings(JSON_CELL_TYPES={
|
|
'test-post-cell': {
|
|
'name': 'Foobar',
|
|
'url': 'http://test-post-cell/',
|
|
'actions': {
|
|
'create': {
|
|
'url': 'http://test-post-cell/create/',
|
|
}
|
|
}
|
|
}},
|
|
TEMPLATES=templates_settings
|
|
):
|
|
cell = ConfigJsonCell(page=page, placeholder='content', order=0)
|
|
cell.key = 'test-post-cell'
|
|
cell.save()
|
|
|
|
with mock.patch('combo.utils.requests.get') as requests_get:
|
|
requests_get.return_value = mock.Mock(content=json.dumps({'hello': 'world'}), status_code=200)
|
|
|
|
resp = app.get('/', status=200)
|
|
resp.form['value'] = 'plop'
|
|
|
|
with mock.patch('combo.utils.requests.post') as requests_post:
|
|
requests_post.return_value = mock.Mock(content=json.dumps({'err': 0}), status_code=200)
|
|
resp2 = resp.form.submit()
|
|
assert requests_post.call_args[0][0] == 'http://test-post-cell/create/'
|
|
assert requests_post.call_args[1]['json'] == {'value': 'plop'}
|
|
assert urlparse(resp2.location).path == '/'
|
|
|
|
# check ajax call
|
|
with mock.patch('combo.utils.requests.post') as requests_post:
|
|
requests_post.return_value = mock.Mock(content=json.dumps({'err': 0}), status_code=200)
|
|
resp2 = resp.form.submit(headers={'x-requested-with': 'XMLHttpRequest'})
|
|
assert requests_post.call_args[0][0] == 'http://test-post-cell/create/'
|
|
assert requests_post.call_args[1]['json'] == {'value': 'plop'}
|
|
assert resp2.content.startswith('<form')
|
|
|
|
# check error on POST
|
|
with mock.patch('combo.utils.requests.post') as requests_post:
|
|
requests_post.return_value = mock.Mock(content=json.dumps({'err': 0}), status_code=400)
|
|
resp2 = resp.form.submit()
|
|
assert urlparse(resp2.location).path == '/'
|
|
resp2 = resp2.follow()
|
|
assert 'Error sending data.' in resp2.content
|
|
|
|
settings.JSON_CELL_TYPES['test-post-cell']['actions']['create']['error-message'] = 'Failed to create stuff.'
|
|
resp2 = resp.form.submit()
|
|
assert urlparse(resp2.location).path == '/'
|
|
resp2 = resp2.follow()
|
|
assert 'Failed to create stuff.' in resp2.content
|
|
|
|
with mock.patch('combo.utils.requests.post') as requests_post:
|
|
requests_post.return_value = mock.Mock(content=json.dumps({'err': 0}), status_code=400)
|
|
resp2 = resp.form.submit(headers={'x-requested-with': 'XMLHttpRequest'})
|
|
assert resp2.content.startswith('<form')
|
|
assert resp2.headers['x-error-message'] == 'Failed to create stuff.'
|
|
|
|
# check variable substitution in URL
|
|
with mock.patch('combo.utils.requests.post') as requests_post:
|
|
settings.JSON_CELL_TYPES['test-post-cell']['actions']['create'] = {
|
|
'url': 'http://test-post-cell/[value]/delete'}
|
|
resp2 = resp.form.submit()
|
|
assert requests_post.call_args[0][0] == 'http://test-post-cell/plop/delete'
|
|
|
|
def test_familyinfos_cell_with_placeholders(app, admin_user):
|
|
Page.objects.all().delete()
|
|
page = Page(title='Family', slug='index', template_name='standard')
|
|
page.save()
|
|
family_cell = FamilyInfosCell(page=page, placeholder='content', order=0)
|
|
family_cell.save()
|
|
TextCell(page=page, placeholder='family_unlinked_user', text='<p>Hello anonymous user</p>', order=0,
|
|
restricted_to_unlogged=True, public=True).save()
|
|
TextCell(page=page, placeholder='family_unlinked_user', text='<p>You are not linked</p>',
|
|
order=1, public=False, restricted_to_unlogged=False).save()
|
|
|
|
with override_settings(FAMILY_SERVICE={'root': '/family/'}):
|
|
with mock.patch('combo.utils.requests.send') as requests_send:
|
|
resp = app.get('/')
|
|
assert "<p>Hello anonymous user</p>" in resp.content
|
|
assert "<p>You are not linked</p>" not in resp.content
|
|
|
|
app = login(app)
|
|
data = {'err': 0, 'data': None}
|
|
requests_send.return_value = mock.Mock(json=lambda: data, content=json.dumps(data), status_code=200)
|
|
# make sure no data are loaded
|
|
resp = app.get('/')
|
|
resp.html.body.find('div', {'class': 'familyinfoscell'}).text.strip() == 'Loading...'
|
|
# put data in cache
|
|
resp = app.get(reverse('combo-public-ajax-page-cell',
|
|
kwargs={'page_pk': page.pk, 'cell_reference': family_cell.get_reference()}))
|
|
resp = app.get('/')
|
|
assert "<p>Hello anonymous user</p>" not in resp.content
|
|
assert "<p>You are not linked</p>" in resp.content
|
|
|
|
|
|
@mock.patch('combo.utils.requests.get')
|
|
def test_familycell_link(requests_get, app, settings, admin_user):
|
|
settings.FAMILY_SERVICE = {'root': '/family/'}
|
|
Page.objects.all().delete()
|
|
page = Page(title='Family', slug='index', template_name='standard')
|
|
page.save()
|
|
family_cell = FamilyInfosCell(page=page, placeholder='content', order=0)
|
|
family_cell.save()
|
|
TextCell(page=page, placeholder='family_unlinked_user', text='<p>Hello anonymous user</p>', order=0,
|
|
restricted_to_unlogged=True, public=True).save()
|
|
TextCell(page=page, placeholder='family_unlinked_user', text='<p>You are not linked</p>',
|
|
order=1, public=False, restricted_to_unlogged=False).save()
|
|
app = login(app)
|
|
# when linking fails
|
|
requests_get.return_value = mock.Mock(ok=False, json=lambda: {'err': 102})
|
|
resp = app.get('/family/link/')
|
|
resp.form['family_id'] = '123'
|
|
resp.form['family_code'] = 'l33t'
|
|
resp = resp.form.submit().follow()
|
|
messages = resp.context['messages']
|
|
assert len(messages._loaded_messages) == 1
|
|
assert messages._loaded_messages[0].message == 'Failed to link to family. Please check your credentials and retry later.'
|
|
requests_get.return_value = mock.Mock(ok=True, json=lambda: {})
|
|
resp.form['family_id'] = '123'
|
|
resp.form['family_code'] = 'l33t'
|
|
resp = resp.form.submit().follow()
|
|
messages = resp.context['messages']
|
|
assert len(messages._loaded_messages) == 2
|
|
assert messages._loaded_messages[1].message == 'Your account was successfully linked.'
|
|
|
|
|
|
@mock.patch('combo.utils.requests.get')
|
|
def test_familycell_unlink(requests_get, app, settings, admin_user):
|
|
settings.FAMILY_SERVICE = {'root': '/family/'}
|
|
Page.objects.all().delete()
|
|
page = Page(title='Family', slug='index', template_name='standard')
|
|
page.save()
|
|
family_cell = FamilyInfosCell(page=page, placeholder='content', order=0)
|
|
family_cell.save()
|
|
TextCell(page=page, placeholder='family_unlinked_user', text='<p>Hello anonymous user</p>', order=0,
|
|
restricted_to_unlogged=True, public=True).save()
|
|
TextCell(page=page, placeholder='family_unlinked_user', text='<p>You are not linked</p>',
|
|
order=1, public=False, restricted_to_unlogged=False).save()
|
|
app = login(app)
|
|
requests_get.return_value = mock.Mock(ok=False, json=lambda: {'err': 102})
|
|
resp = app.get('/family/unlink/')
|
|
resp = resp.form.submit().follow()
|
|
messages = resp.context['messages']
|
|
assert len(messages._loaded_messages) == 1
|
|
assert messages._loaded_messages[0].message == 'An error occured when unlinking.'
|
|
requests_get.return_value = mock.Mock(ok=True, json=lambda: {})
|
|
resp = app.get('/family/unlink/')
|
|
resp = resp.form.submit().follow()
|
|
messages = resp.context['messages']
|
|
assert len(messages._loaded_messages) == 2
|
|
assert messages._loaded_messages[1].message == 'Your account was successfully unlinked.'
|
|
|
|
|
|
def test_synchronous_placeholder(app):
|
|
page = Page(title=u'foo', slug='foo', template_name='standard', order=0)
|
|
page.save()
|
|
cell = FeedCell(page=page, placeholder='content', url='http://example.net', order=1)
|
|
cell.save()
|
|
|
|
templates_settings = [settings.TEMPLATES[0].copy()]
|
|
templates_settings[0]['DIRS'] = ['%s/templates-1' % os.path.abspath(os.path.dirname(__file__))]
|
|
with override_settings(COMBO_PUBLIC_TEMPLATES={
|
|
'standard': {
|
|
'name': 'Test',
|
|
'template': 'combo/page_template_synchronous_placeholder.html',
|
|
}},
|
|
TEMPLATES=templates_settings
|
|
):
|
|
with mock.patch('requests.get') as requests_get:
|
|
requests_get.return_value = mock.Mock(content='', status_code=200)
|
|
resp = app.get('/foo/', status=200)
|
|
assert not 'data-ajax-cell-must-load="true"' in resp.body
|
|
|
|
cell = FeedCell(page=page, placeholder='sidebar', url='http://example.org', order=1)
|
|
cell.save()
|
|
|
|
resp = app.get('/foo/', status=200)
|
|
assert resp.body.count('data-ajax-cell-must-load="true"') == 1
|