[WIP] Tests for kfet views

This commit is contained in:
Aurélien Delobelle 2017-08-10 15:02:08 +02:00
parent 878c617cc7
commit c9aac8a49d
3 changed files with 585 additions and 22 deletions

View file

@ -1,26 +1,243 @@
import json
from decimal import Decimal
from unittest.mock import patch
from django.test import TestCase, Client
from django.contrib.auth.models import User
from django.contrib.auth.models import Group, Permission
from django.core.urlresolvers import reverse
from django.test import Client, TestCase
from django.utils import timezone
from ..models import Account, OperationGroup, Checkout, Operation
from ..models import Account, Checkout, Operation, OperationGroup
from .testcases import ViewTestCaseMixin
from .utils import create_team, create_user
class AccountTests(TestCase):
"""Account related views"""
class LoginGenericTeamViewTests(ViewTestCaseMixin, TestCase):
url_name = 'kfet.login.genericteam'
url_expected = '/k-fet/login/genericteam'
auth_user = 'team'
auth_forbidden = [None, 'user']
def test_ok(self):
r = self.client.get(self.url)
self.assertEqual(r.status_code, 200)
logged_in_username = r.wsgi_request.user.username
self.assertEqual(logged_in_username, 'kfet_genericteam')
class AccountListViewTests(ViewTestCaseMixin, TestCase):
url_name = 'kfet.account'
url_expected = '/k-fet/accounts/'
auth_user = 'team'
auth_forbidden = [None, 'user']
def test_ok(self):
r = self.client.get(self.url)
self.assertEqual(r.status_code, 200)
class AccountValidFreeTests(ViewTestCaseMixin, TestCase):
url_name = 'kfet.account.is_validandfree.ajax'
url_expected = '/k-fet/accounts/is_validandfree'
auth_user = 'team'
auth_forbidden = [None, 'user']
def test_ok_isvalid_isfree(self):
"""Upper case trigramme not taken is valid and free."""
r = self.client.get(self.url, {'trigramme': 'AAA'})
self.assertDictEqual(json.loads(r.content.decode('utf-8')), {
'is_valid': True,
'is_free': True,
})
def test_ok_isvalid_notfree(self):
"""Already taken trigramme is not free, but valid."""
r = self.client.get(self.url, {'trigramme': '000'})
self.assertDictEqual(json.loads(r.content.decode('utf-8')), {
'is_valid': True,
'is_free': False,
})
def test_ok_notvalid_isfree(self):
"""Lower case if forbidden but free."""
r = self.client.get(self.url, {'trigramme': 'aaa'})
self.assertDictEqual(json.loads(r.content.decode('utf-8')), {
'is_valid': False,
'is_free': True,
})
class AccountCreateViewTests(ViewTestCaseMixin, TestCase):
url_name = 'kfet.account.create'
url_expected = '/k-fet/accounts/new'
auth_user = 'team'
auth_forbidden = [None, 'user']
@property
def users_extra(self):
return {
'team__add_account': create_team(
'team__add_account', '101',
perms=['kfet.add_account'],
),
}
def test_get_ok(self):
r = self.client.get(self.url)
self.assertEqual(r.status_code, 200)
def test_post_ok(self):
post_data = {
'trigramme': 'AAA',
'username': 'plopplopplop',
'first_name': 'first',
'last_name': 'last',
'email': 'email@domain.net',
}
client = Client()
client.login(
username='team__add_account',
password='team__add_account',
)
r = client.post(self.url, post_data)
self.assertRedirects(r, self.url)
a = Account.objects.get(trigramme='AAA')
self.assertEqual(a.username, 'plopplopplop')
def test_post_forbidden(self):
post_data = {
'trigramme': 'AAA',
'username': 'plopplopplop',
'first_name': 'first',
'last_name': 'last',
'email': 'email@domain.net',
}
# A team member (without kfet.add_account) is authenticated with
# self.client.
r = self.client.post(self.url, post_data)
self.assertEqual(r.status_code, 200)
with self.assertRaises(Account.DoesNotExist):
Account.objects.get(trigramme='AAA')
class AccountCreateAjaxViewTests(ViewTestCaseMixin, TestCase):
urls_conf = [
{
'name': 'kfet.account.create.fromuser',
'kwargs': {'username': 'user'},
'expected': '/k-fet/accounts/new/user/user',
},
{
'name': 'kfet.account.create.fromclipper',
'kwargs': {
'login_clipper': 'myclipper',
'fullname': 'first last1 last2',
},
'expected': (
'/k-fet/accounts/new/clipper/myclipper/first%20last1%20last2'
),
},
{
'name': 'kfet.account.create.empty',
'expected': '/k-fet/accounts/new/empty',
},
]
auth_user = 'team'
auth_forbidden = [None, 'user']
def test_fromuser(self):
r = self.client.get(self.t_urls[0])
user = self.users['user']
self.assertEqual(r.status_code, 200)
self.assertEqual(r.context['user_form'].instance, user)
self.assertEqual(r.context['cof_form'].instance, user.profile)
self.assertIn('account_form', r.context)
def test_fromclipper(self):
r = self.client.get(self.t_urls[1])
self.assertEqual(r.status_code, 200)
self.assertIn('user_form', r.context)
self.assertIn('cof_form', r.context)
self.assertIn('account_form', r.context)
def test_empty(self):
r = self.client.get(self.t_urls[0])
self.assertEqual(r.status_code, 200)
self.assertIn('user_form', r.context)
self.assertIn('cof_form', r.context)
self.assertIn('account_form', r.context)
class AccountCreateAutocompleteViewTests(ViewTestCaseMixin, TestCase):
url_name = 'kfet.account.create.autocomplete'
url_expected = '/k-fet/autocomplete/account_new'
auth_user = 'team'
auth_forbidden = [None, 'user']
def test_ok(self):
r = self.client.get(self.url, {'q': 'first'})
self.assertEqual(r.status_code, 200)
self.assertListEqual(list(r.context['users_notcof']), [])
self.assertListEqual(list(r.context['users_cof']), [])
self.assertListEqual(
list(r.context['kfet']),
[(self.accounts['user'], self.users['user'])],
)
class AccountSearchViewTests(ViewTestCaseMixin, TestCase):
url_name = 'kfet.account.search.autocomplete'
url_expected = '/k-fet/autocomplete/account_search'
auth_user = 'team'
auth_forbidden = [None, 'user']
def test_ok(self):
r = self.client.get(self.url, {'q': 'first'})
self.assertEqual(r.status_code, 200)
self.assertListEqual(
list(r.context['accounts']),
[('000', 'first last')],
)
class AccountReadViewTests(ViewTestCaseMixin, TestCase):
url_name = 'kfet.account.read'
url_kwargs = {'trigramme': '001'}
url_expected = '/k-fet/accounts/001'
auth_user = 'team'
auth_forbidden = [None, 'user']
@property
def users_extra(self):
return {
'user1': create_user('user1', '001'),
}
def setUp(self):
# A user and its account
self.user = User.objects.create_user(username="foobar", password="foo")
acc = Account.objects.create(
trigramme="FOO", cofprofile=self.user.profile
)
super().setUp()
user1_acc = self.accounts['user1']
team_acc = self.accounts['team']
# Dummy operations and operation groups
checkout = Checkout.objects.create(
created_by=acc, name="checkout",
created_by=team_acc, name="checkout",
valid_from=timezone.now(),
valid_to=timezone.now() + timezone.timedelta(days=365)
)
@ -30,7 +247,7 @@ class AccountTests(TestCase):
]
OperationGroup.objects.bulk_create([
OperationGroup(
on_acc=acc, checkout=checkout, at=at, is_cof=False,
on_acc=user1_acc, checkout=checkout, at=at, is_cof=False,
amount=amount
)
for (at, amount) in opeg_data
@ -47,13 +264,112 @@ class AccountTests(TestCase):
amount=Decimal('3')
)
@patch('gestioncof.signals.messages')
def test_account_read(self, mock_messages):
"""We can query the "Account - Read" page."""
def test_ok(self):
"""We can query the "Account - Read" page."""
r = self.client.get(self.url)
self.assertEqual(r.status_code, 200)
def test_ok_self(self):
client = Client()
self.assertTrue(client.login(
username="foobar",
password="foo"
))
resp = client.get("/k-fet/accounts/FOO")
self.assertEqual(200, resp.status_code)
client.login(username='user1', password='user1')
r = client.get(self.url)
self.assertEqual(r.status_code, 200)
class AccountUpdateViewTests(ViewTestCaseMixin, TestCase):
url_name = 'kfet.account.update'
url_kwargs = {'trigramme': '001'}
url_expected = '/k-fet/accounts/001/edit'
auth_user = 'team'
auth_forbidden = [None, 'user']
@property
def users_extra(self):
return {
'user1': create_user('user1', '001'),
}
def test_ok(self):
r = self.client.get(self.url)
self.assertEqual(r.status_code, 200)
def test_ok_self(self):
client = Client()
client.login(username='user1', password='user1')
r = client.get(self.url)
self.assertEqual(r.status_code, 200)
class BaseAccountGroupViewTests(ViewTestCaseMixin):
auth_user = 'team__manage_perms'
auth_forbidden = [None, 'user', 'team']
@property
def users_extra(self):
return {
'team__manage_perms': create_team(
'team__manage_perms', '101',
perms=['kfet.manage_perms'],
),
}
class AccountGroupListViewTests(BaseAccountGroupViewTests, TestCase):
url_name = 'kfet.account.group'
url_expected = '/k-fet/accounts/groups'
def test_ok(self):
r = self.client.get(self.url)
self.assertEqual(r.status_code, 200)
self.assertQuerysetEqual(
r.context['groups'],
Group.objects.filter(name__icontains='K-Fêt'),
ordered=False,
)
class AccountGroupCreateViewTests(BaseAccountGroupViewTests, TestCase):
url_name = 'kfet.account.group.create'
url_expected = '/k-fet/accounts/groups/new'
def test_ok(self):
r = self.client.get(self.url)
self.assertEqual(r.status_code, 200)
class AccountGroupUpdateViewTests(BaseAccountGroupViewTests, TestCase):
url_name = 'kfet.account.group.update'
url_kwargs = {'pk': 42}
url_expected = '/k-fet/accounts/groups/42/edit'
def setUp(self):
super().setUp()
self.group1 = Group.objects.create(pk=42, name='K-Fêt - Group')
self.group1.permissions = [
Permission.objects.get(
content_type__app_label='kfet',
codename='is_team',
)
]
def test_get_ok(self):
r = self.client.get(self.url)
self.assertEqual(r.status_code, 200)
def test_post_ok(self):
post_data = {
'name': 'Group42',
'permissions': (
self.group1.permissions
.values_list('pk', flat=True)
),
}
r = self.client.post(self.url, post_data)
self.assertRedirects(r, reverse('kfet.account.group'))
self.group1.refresh_from_db()
self.assertEqual(self.group1.name, 'K-Fêt Group42')

142
kfet/tests/testcases.py Normal file
View file

@ -0,0 +1,142 @@
from unittest import mock
from django.core.urlresolvers import reverse
from django.http import QueryDict
from django.test import Client
from .utils import create_root, create_team, create_user
class ViewTestCaseMixin:
url_name = None
url_expected = None
auth_user = None
auth_forbidden = []
def setUp(self):
# Signals handlers on login/logout send messages.
# Due to the way the Django' test Client performs login, this raise an
# error. As workaround, we mock the Django' messages module.
patcher_messages = mock.patch('gestioncof.signals.messages')
patcher_messages.start()
self.addCleanup(patcher_messages.stop)
self.users = {}
self.accounts = {}
for label, user in {**self.users_base, **self.users_extra}.items():
self.register_user(label, user)
if self.auth_user:
# The wrapper is a sanity check.
self.assertTrue(
self.client.login(
username=self.auth_user,
password=self.auth_user,
)
)
@property
def users_base(self):
# Format desc: username, password, trigramme
return {
# user, user, 000
'user': create_user(),
# team, team, 100
'team': create_team(),
# root, root, 200
'root': create_root(),
}
@property
def users_extra(self):
return {}
def register_user(self, label, user):
self.users[label] = user
if hasattr(user.profile, 'account_kfet'):
self.accounts[label] = user.profile.account_kfet
@property
def urls_conf(self):
return [{
'name': self.url_name,
'args': getattr(self, 'url_args', []),
'kwargs': getattr(self, 'url_kwargs', {}),
'expected': self.url_expected,
}]
@property
def t_urls(self):
return [
reverse(
url_conf['name'],
args=url_conf.get('args', []),
kwargs=url_conf.get('kwargs', {}),
)
for url_conf in self.urls_conf]
@property
def url(self):
return self.t_urls[0]
def assertForbidden(self, response):
request = response.wsgi_request
try:
try:
# Is this an HTTP Forbidden response ?
self.assertEqual(response.status_code, 403)
except AssertionError:
# A redirection to the login view is fine too.
# Let's build the login url with the 'next' param on current
# page.
full_path = request.get_full_path()
querystring = QueryDict(mutable=True)
querystring['next'] = full_path
login_url = '/login?' + querystring.urlencode(safe='/')
# We don't focus on what the login view does.
# So don't fetch the redirect.
self.assertRedirects(
response, login_url,
fetch_redirect_response=False,
)
except AssertionError:
raise AssertionError(
"%(http_method)s request at %(path)s should be forbidden for "
"%(username)s user.\n"
"Response isn't 403, nor a redirect to login view. Instead, "
"response code is %(code)d." % {
'http_method': request.method,
'path': request.get_full_path(),
'username': (
"'{}'".format(request.user.username)
if request.user.username
else 'anonymous'
),
'code': response.status_code,
}
)
def assertForbiddenKfet(self, response):
self.assertEqual(response.status_code, 200)
form = response.context['form']
self.assertIn("Permission refusée", form.non_field_errors)
def test_urls(self):
for url, conf in zip(self.t_urls, self.urls_conf):
self.assertEqual(url, conf['expected'])
def test_forbidden(self):
for creds in self.auth_forbidden:
for url in self.t_urls:
client = Client()
if creds is not None:
client.login(username=creds, password=creds)
r = client.get(url)
self.assertForbidden(r)

105
kfet/tests/utils.py Normal file
View file

@ -0,0 +1,105 @@
from django.contrib.auth import get_user_model
from django.contrib.auth.models import Permission
from ..models import Account
User = get_user_model()
def user_add_perms(user, perms_labels):
"""
Add perms to a user.
Args:
user (User instance)
perms (list of str 'app.perm_name')
Returns:
The same user (refetched from DB to avoid missing perms)
"""
u_labels = set(perms_labels)
perms = []
for label in u_labels:
app_label, codename = label.split('.', 1)
perms.append(
Permission.objects.get(
content_type__app_label=app_label,
codename=codename,
)
)
user.user_permissions.add(*perms)
# If permissions have already been fetched for this user, we need to reload
# it to avoid using of the previous permissions cache.
# https://docs.djangoproject.com/en/1.11/topics/auth/default/#permission-caching
return User.objects.get(pk=user.pk)
def _create_user_and_account(user_attrs, account_attrs, perms=None):
user_attrs.setdefault('password', user_attrs['username'])
user = User.objects.create_user(**user_attrs)
account_attrs['cofprofile'] = user.profile
kfet_pwd = account_attrs.pop('password', None)
account = Account.objects.create(**account_attrs)
if perms is not None:
user = user_add_perms(user, perms)
if 'kfet.is_team' in perms:
if kfet_pwd is None:
kfet_pwd = 'kfetpwd_{}'.format(user_attrs['password'])
account.change_pwd(kfet_pwd)
account.save()
return user
def create_user(username='user', trigramme='000', **kwargs):
user_attrs = kwargs.setdefault('user_attrs', {})
user_attrs.setdefault('username', username)
user_attrs.setdefault('first_name', 'first')
user_attrs.setdefault('last_name', 'last')
user_attrs.setdefault('email', 'mail@user.net')
account_attrs = kwargs.setdefault('account_attrs', {})
account_attrs.setdefault('trigramme', trigramme)
return _create_user_and_account(**kwargs)
def create_team(username='team', trigramme='100', **kwargs):
user_attrs = kwargs.setdefault('user_attrs', {})
user_attrs.setdefault('username', username)
user_attrs.setdefault('first_name', 'team')
user_attrs.setdefault('last_name', 'member')
user_attrs.setdefault('email', 'mail@team.net')
account_attrs = kwargs.setdefault('account_attrs', {})
account_attrs.setdefault('trigramme', trigramme)
perms = kwargs.setdefault('perms', [])
perms.append('kfet.is_team')
return _create_user_and_account(**kwargs)
def create_root(username='root', trigramme='200', **kwargs):
user_attrs = kwargs.setdefault('user_attrs', {})
user_attrs.setdefault('username', username)
user_attrs.setdefault('first_name', 'super')
user_attrs.setdefault('last_name', 'user')
user_attrs.setdefault('email', 'mail@root.net')
account_attrs = kwargs.setdefault('account_attrs', {})
account_attrs.setdefault('trigramme', trigramme)
return _create_user_and_account(**kwargs)