New Test order.

* seperate unittests and integration tests
* moved old tests in seperat folder 'old'
* created a testrunner that does not create a testdatabase, if only unittests are run
* wrote some unit- and integration tests as examples
* fixed user.get_short_name() to use the sort order from config
* fixed wrong url_pattern in the user app
This commit is contained in:
Oskar Hahn 2015-01-22 18:29:12 +01:00
parent ea45469338
commit e7230b7391
82 changed files with 1172 additions and 509 deletions

View File

@ -8,6 +8,12 @@ install:
- "node_modules/.bin/bower install" - "node_modules/.bin/bower install"
- "node_modules/.bin/gulp --production" - "node_modules/.bin/gulp --production"
script: script:
- "DJANGO_SETTINGS_MODULE='tests.settings' coverage run ./manage.py test"
- "coverage report -m --fail-under=80"
- "flake8 --max-line-length=150 --statistics openslides tests" - "flake8 --max-line-length=150 --statistics openslides tests"
- "DJANGO_SETTINGS_MODULE='tests.settings' coverage run ./manage.py test tests.unit"
- "coverage report --show-missing --fail-under=35"
- "DJANGO_SETTINGS_MODULE='tests.settings' coverage run ./manage.py test tests.integration"
- "coverage report --show-missing --fail-under=45"
- "DJANGO_SETTINGS_MODULE='tests.old.settings' ./manage.py test tests.old"

View File

@ -2,6 +2,10 @@ import re
from parser import command, argument, call from parser import command, argument, call
FAIL = '\033[91m'
SUCCESS = '\033[92m'
RESET = '\033[0m'
@argument('module', nargs='?', default='') @argument('module', nargs='?', default='')
@command('test', help='runs the tests') @command('test', help='runs the tests')
@ -10,8 +14,8 @@ def test(args=None):
Runs the tests. Runs the tests.
""" """
module = getattr(args, 'module', '') module = getattr(args, 'module', '')
return call("DJANGO_SETTINGS_MODULE='tests.settings' coverage run " return call("DJANGO_SETTINGS_MODULE='tests.integration.settings' coverage run "
"./manage.py test %s" % module) "./manage.py test tests.%s" % module)
@argument('--plain', action='store_true') @argument('--plain', action='store_true')
@ -51,11 +55,17 @@ def travis(args=None):
if line == 'script:': if line == 'script:':
script_lines = True script_lines = True
continue continue
if not script_lines: if not script_lines or not line:
continue continue
match = re.search(r'"(.*)"', line) match = re.search(r'"(.*)"', line)
return_codes.append(call(match.group(1))) print('Run: %s' % match.group(1))
return_code = call(match.group(1))
return_codes.append(return_code)
if return_code:
print(FAIL + 'fail!\n' + RESET)
else:
print(SUCCESS + 'success!\n' + RESET)
# Retuns True if one command exited with a different statuscode then 1 # Retuns True if one command exited with a different statuscode then 1
return bool(list(filter(bool, return_codes))) return bool(list(filter(bool, return_codes)))
@ -81,3 +91,14 @@ def min_requirements(args=None):
yield '%s==%s' % (line.req.key, line.req.specs[0][1]) yield '%s==%s' % (line.req.key, line.req.specs[0][1])
print('pip install %s' % ' '.join(get_lowest_versions(args.requirements))) print('pip install %s' % ' '.join(get_lowest_versions(args.requirements)))
@command('clear',
help='Deletes unneeded files and folders')
def clear(args=None):
"""
Deletes all .pyc and .orig files and empty folders.
"""
call('find -name "*.pyc" -delete')
call('find -name "*.orig" -delete')
call('find -type d -empty -delete')

View File

@ -159,7 +159,7 @@
{{ field }} {{ field }}
<button class="btn btn-primary tooltip-bottom" type="submit" data-original-title="{% trans 'Apply' %}"><i class="icon-ok icon-white"></i></button> <button class="btn btn-primary tooltip-bottom" type="submit" data-original-title="{% trans 'Apply' %}"><i class="icon-ok icon-white"></i></button>
{% if perms.users.can_see and perms.users.can_manage %} {% if perms.users.can_see and perms.users.can_manage %}
<a href="{% url 'user_new' %}" class="btn" rel="tooltip" data-original-title="{% trans 'Add new user' %}"><i class="icon-add-user"></i></a> <a href="{% url 'user_create' %}" class="btn" rel="tooltip" data-original-title="{% trans 'Add new user' %}"><i class="icon-add-user"></i></a>
{% endif %} {% endif %}
{% if field.errors %} {% if field.errors %}
<span class="help-inline">{{ field.errors }}</span> <span class="help-inline">{{ field.errors }}</span>

View File

@ -149,7 +149,7 @@
<span class="glyphicon glyphicon-ok" aria-hidden="true"></span> <span class="glyphicon glyphicon-ok" aria-hidden="true"></span>
</button> </button>
{% if perms.users.can_see and perms.users.can_manage %} {% if perms.users.can_see and perms.users.can_manage %}
<a href="{% url 'user_new' %}" target="_blank" class="btn btn-default" <a href="{% url 'user_create' %}" target="_blank" class="btn btn-default"
rel="tooltip" data-original-title="{% trans 'Add new participant' %}"> rel="tooltip" data-original-title="{% trans 'Add new participant' %}">
<span class="glyphicon glyphicon-user" aria-hidden="true"></span> <span class="glyphicon glyphicon-user" aria-hidden="true"></span>
</a> </a>

View File

@ -173,3 +173,5 @@ CKEDITOR_CONFIGS = {
# Use small alternative with tornado as frontend or big alternative with a # Use small alternative with tornado as frontend or big alternative with a
# webserver as wsgi server. # webserver as wsgi server.
USE_TORNADO_AS_WSGI_SERVER = True USE_TORNADO_AS_WSGI_SERVER = True
TEST_RUNNER = 'openslides.utils.test.OpenSlidesDiscoverRunner'

View File

@ -162,6 +162,5 @@ def get_protected_perm():
Returns the permission to manage users. This function is a helper Returns the permission to manage users. This function is a helper
function used to protect manager users from locking out themselves. function used to protect manager users from locking out themselves.
""" """
return Permission.objects.get( return Permission.objects.get_by_natural_key(
content_type=ContentType.objects.get(app_label='users', model='user'), app_label='users', model='user', codename='can_manage')
codename='can_manage')

View File

@ -9,12 +9,17 @@ from django.core.urlresolvers import reverse
from django.db import models from django.db import models
from django.utils.translation import ugettext_lazy, ugettext_noop from django.utils.translation import ugettext_lazy, ugettext_noop
from openslides.config.api import config
from openslides.projector.models import SlideMixin from openslides.projector.models import SlideMixin
from openslides.utils.models import AbsoluteUrlMixin from openslides.utils.models import AbsoluteUrlMixin
from openslides.utils.rest_api import RESTModelMixin from openslides.utils.rest_api import RESTModelMixin
class UserManager(BaseUserManager): class UserManager(BaseUserManager):
"""
UserManager that creates new users only with a password and a username.
"""
def create_user(self, username, password, **kwargs): def create_user(self, username, password, **kwargs):
user = self.model(username=username, **kwargs) user = self.model(username=username, **kwargs)
user.set_password(password) user.set_password(password)
@ -87,9 +92,9 @@ class User(RESTModelMixin, SlideMixin, AbsoluteUrlMixin, PermissionsMixin, Abstr
Returns the URL to the user. Returns the URL to the user.
""" """
if link == 'detail': if link == 'detail':
url = reverse('user_view', args=[str(self.pk)]) url = reverse('user_detail', args=[str(self.pk)])
elif link == 'update': elif link == 'update':
url = reverse('user_edit', args=[str(self.pk)]) url = reverse('user_update', args=[str(self.pk)])
elif link == 'delete': elif link == 'delete':
url = reverse('user_delete', args=[str(self.pk)]) url = reverse('user_delete', args=[str(self.pk)])
else: else:
@ -111,10 +116,7 @@ class User(RESTModelMixin, SlideMixin, AbsoluteUrlMixin, PermissionsMixin, Abstr
E. g.: * Dr. Max Mustermann (Villingen) E. g.: * Dr. Max Mustermann (Villingen)
* Professor Dr. Enders, Christoph (Leipzig) * Professor Dr. Enders, Christoph (Leipzig)
""" """
if self.structure_level: structure = '(%s)' % self.structure_level if self.structure_level else ''
structure = '(%s)' % self.structure_level
else:
structure = ''
return ' '.join((self.title, self.get_short_name(), structure)).strip() return ' '.join((self.title, self.get_short_name(), structure)).strip()
@ -125,9 +127,21 @@ class User(RESTModelMixin, SlideMixin, AbsoluteUrlMixin, PermissionsMixin, Abstr
E. g.: * Max Mustermann E. g.: * Max Mustermann
* Enders, Christoph * Enders, Christoph
""" """
# TODO: Order of name. See config. # Strip white spaces from the name parts
name = ('%s %s' % (self.first_name, self.last_name)).strip() first_name = self.first_name.strip()
return name or self.username last_name = self.last_name.strip()
# The user has a last_name and a first_name
if first_name and last_name:
if config['users_sort_users_by_first_name']:
name = ' '.join((first_name, last_name))
else:
name = ', '.join((last_name, first_name))
# The user has only a first_name or a last_name or no name
else:
name = first_name or last_name or self.username
return name
def reset_password(self, password=None): def reset_password(self, password=None):
""" """

View File

@ -1,6 +1,7 @@
{% extends "base.html" %} {% extends "base.html" %}
{% load i18n %} {% load i18n %}
{% load tags %}
{% block title %}{{ shown_user }} {{ block.super }}{% endblock %} {% block title %}{{ shown_user }} {{ block.super }}{% endblock %}
@ -29,7 +30,7 @@
<ul class="dropdown-menu pull-right"> <ul class="dropdown-menu pull-right">
<!-- edit --> <!-- edit -->
<li> <li>
<a href="{% url 'user_edit' shown_user.id %}"> <a href="{{ user|absolute_url:'update' }}">
<i class="icon-pencil"></i> <i class="icon-pencil"></i>
{% trans 'Edit user' %} {% trans 'Edit user' %}
</a> </a>

View File

@ -20,11 +20,11 @@
{% trans "Users" %} {% trans "Users" %}
<small class="pull-right"> <small class="pull-right">
{% if perms.users.can_manage %} {% if perms.users.can_manage %}
<a href="{% url 'user_new' %}" class="btn btn-mini btn-primary" rel="tooltip" data-original-title="{% trans 'New user' %}"> <a href="{% url 'user_create' %}" class="btn btn-mini btn-primary" rel="tooltip" data-original-title="{% trans 'New user' %}">
<i class="icon-plus icon-white"></i> <i class="icon-plus icon-white"></i>
{% trans "New" %} {% trans "New" %}
</a> </a>
<a href="{% url 'user_new_multiple' %}" class="btn btn-mini" rel="tooltip" data-original-title="{% trans 'New multiple users' %}"> <a href="{% url 'user_create_multiple' %}" class="btn btn-mini" rel="tooltip" data-original-title="{% trans 'New multiple users' %}">
<i class="icon-plus"></i> <i class="icon-plus"></i>
{% trans 'New multiple' %} {% trans 'New multiple' %}
</a> </a>
@ -102,9 +102,9 @@
<td class="optional">{{ user.title }}</td> <td class="optional">{{ user.title }}</td>
<td> <td>
{% if 'users_sort_users_by_first_name'|get_config %} {% if 'users_sort_users_by_first_name'|get_config %}
<a href="{% url 'user_view' user.id %}">{{ user.first_name }} {{ user.last_name }}</a> <a href="{{ user|absolute_url }}">{{ user.first_name }} {{ user.last_name }}</a>
{% else %} {% else %}
<a href="{% url 'user_view' user.id %}">{{ user.last_name }}{% if user.last_name and user.first_name %},{% endif %} {{ user.first_name }}</a> <a href="{{ user|absolute_url }}">{{ user.last_name }}{% if user.last_name and user.first_name %},{% endif %} {{ user.first_name }}</a>
{% endif %} {% endif %}
</td> </td>
<td class="optional">{{ user.structure_level }}</td> <td class="optional">{{ user.structure_level }}</td>
@ -138,7 +138,7 @@
<i class="icon-facetime-video {% if user.is_active_slide %}icon-white{% endif %}"></i> <i class="icon-facetime-video {% if user.is_active_slide %}icon-white{% endif %}"></i>
</a> </a>
{% endif %} {% endif %}
<a href="{% url 'user_edit' user.id %}" rel="tooltip" data-original-title="{% trans 'Edit' %}" <a href="{{ user|absolute_url:'update' }}" rel="tooltip" data-original-title="{% trans 'Edit' %}"
class="btn btn-mini"> class="btn btn-mini">
<i class="icon-pencil"></i> <i class="icon-pencil"></i>
</a> </a>

View File

@ -11,19 +11,19 @@ urlpatterns = patterns(
url(r'^new/$', url(r'^new/$',
views.UserCreateView.as_view(), views.UserCreateView.as_view(),
name='user_new'), name='user_create'),
url(r'^new_multiple/$', url(r'^new_multiple/$',
views.UserMultipleCreateView.as_view(), views.UserMultipleCreateView.as_view(),
name='user_new_multiple'), name='user_create_multiple'),
url(r'^(?P<pk>\d+)/$', url(r'^(?P<pk>\d+)/$',
views.UserDetailView.as_view(), views.UserDetailView.as_view(),
name='user_view'), name='user_detail'),
url(r'^(?P<pk>\d+)/edit/$', url(r'^(?P<pk>\d+)/edit/$',
views.UserUpdateView.as_view(), views.UserUpdateView.as_view(),
name='user_edit'), name='user_update'),
url(r'^(?P<pk>\d+)/del/$', url(r'^(?P<pk>\d+)/del/$',
views.UserDeleteView.as_view(), views.UserDeleteView.as_view(),

View File

@ -251,7 +251,7 @@ class ResetPasswordView(SingleObjectMixin, QuestionView):
question_message = ugettext_lazy('Do you really want to reset the password?') question_message = ugettext_lazy('Do you really want to reset the password?')
def get_redirect_url(self, **kwargs): def get_redirect_url(self, **kwargs):
return reverse('user_edit', args=[self.get_object().id]) return self.get_object().get_absolute_url('update')
def on_clicked_yes(self): def on_clicked_yes(self):
self.get_object().reset_password() self.get_object().reset_password()

View File

@ -1,9 +1,32 @@
from django.core.management import call_command from django.core.management import call_command
from django.test import TestCase as _TestCase from django.test import TestCase as _TestCase
from django.test.runner import DiscoverRunner
from openslides.config.api import config from openslides.config.api import config
class OpenSlidesDiscoverRunner(DiscoverRunner):
def run_tests(self, test_labels, extra_tests=None, **kwargs):
"""
Test Runner which does not create a database, if only unittest are run.
"""
if len(test_labels) == 1 and test_labels[0].startswith('tests.unit'):
# Do not create a test database, if only unittests are tested
create_database = False
else:
create_database = True
self.setup_test_environment()
suite = self.build_suite(test_labels, extra_tests)
if create_database:
old_config = self.setup_databases()
result = self.run_suite(suite)
if create_database:
self.teardown_databases(old_config)
self.teardown_test_environment()
return self.suite_result(suite, result)
class TestCase(_TestCase): class TestCase(_TestCase):
""" """
Overwrites Django's TestCase class to refreshs the config cache. Overwrites Django's TestCase class to refreshs the config cache.

View File

@ -2,44 +2,15 @@ import difflib
import roman import roman
from django.contrib.auth.models import Permission from django.contrib.auth.models import Permission
from django.shortcuts import render_to_response
from django.template import RequestContext
from .signals import template_manipulation
def template(template_name):
"""
Decorator to set a template for a view.
Deprecated. Use class based views instead.
"""
# TODO: Write the login page an the usersettings page with class based views
# Remove this function afterwards
def renderer(func):
def wrapper(request, *args, **kwargs):
output = func(request, *args, **kwargs)
if not isinstance(output, dict):
return output
context = {}
template_manipulation.send(
sender='utils_template', request=request, context=context)
output.update(context)
response = render_to_response(
template_name, output, context_instance=RequestContext(request))
if 'cookie' in output:
response.set_cookie(output['cookie'][0], output['cookie'][1])
return response
return wrapper
return renderer
def delete_default_permissions(**kwargs): def delete_default_permissions(**kwargs):
""" """
Deletes the permissions, django creates by default for the admin. Deletes the permissions, django creates by default for the admin.
""" """
# TODO: Create an participant app which does not create the permissions. # TODO: Find a way not to create the permissions in the first place.
# Delete this function afterwards # Meta.default_permissions does not work, because django will
# nevertheless create permissions for its own models like "group"
for p in Permission.objects.all(): for p in Permission.objects.all():
if (p.codename.startswith('add') or if (p.codename.startswith('add') or
p.codename.startswith('delete') or p.codename.startswith('delete') or
@ -51,7 +22,7 @@ def html_strong(string):
""" """
Returns the text wrapped in an HTML-Strong element. Returns the text wrapped in an HTML-Strong element.
""" """
return u"<strong>%s</strong>" % string return "<strong>%s</strong>" % string
def htmldiff(text1, text2): def htmldiff(text1, text2):

View File

@ -33,7 +33,7 @@ class LoginMixin(object):
""" """
Check if the user is loged in. Check if the user is loged in.
""" """
return super(LoginMixin, self).dispatch(request, *args, **kwargs) return super().dispatch(request, *args, **kwargs)
class PermissionMixin(object): class PermissionMixin(object):
@ -68,7 +68,7 @@ class PermissionMixin(object):
"%s?next=%s" % (settings.LOGIN_URL, path)) "%s?next=%s" % (settings.LOGIN_URL, path))
else: else:
raise PermissionDenied raise PermissionDenied
return super(PermissionMixin, self).dispatch(request, *args, **kwargs) return super().dispatch(request, *args, **kwargs)
class AjaxMixin(object): class AjaxMixin(object):
@ -103,7 +103,7 @@ class ExtraContextMixin(object):
""" """
context = super(ExtraContextMixin, self).get_context_data(**kwargs) context = super(ExtraContextMixin, self).get_context_data(**kwargs)
template_manipulation.send( template_manipulation.send(
sender=self.__class__, request=self.request, context=context) sender=type(self), request=self.request, context=context)
return context return context
@ -130,11 +130,13 @@ class UrlMixin(object):
elif url: elif url:
value = url value = url
else: else:
if use_absolute_url_link is None:
get_absolute_url_args = []
else:
get_absolute_url_args = [use_absolute_url_link]
try: try:
if use_absolute_url_link is None: value = self.object.get_absolute_url(*get_absolute_url_args)
value = self.object.get_absolute_url()
else:
value = self.object.get_absolute_url(use_absolute_url_link)
except AttributeError: except AttributeError:
raise ImproperlyConfigured( raise ImproperlyConfigured(
'No url to redirect to. See openslides.utils.views.UrlMixin ' 'No url to redirect to. See openslides.utils.views.UrlMixin '
@ -155,10 +157,7 @@ class UrlMixin(object):
except AttributeError: except AttributeError:
value = [] value = []
else: else:
if pk: value = [pk] if pk else []
value = [pk]
else:
value = []
return value return value

View File

@ -0,0 +1,14 @@
from openslides.utils.test import TestCase
from django.test.client import Client
class UserViews(TestCase):
def setUp(self):
self.client = Client()
self.client.login(username='admin', password='admin')
def test_user_list(self):
response = self.client.get('/user/')
self.assertTemplateUsed(response, 'users/user_list.html')
self.assertEqual(response.status_code, 200)

View File

@ -5,6 +5,7 @@ from openslides.motion.csv_import import import_motions
from openslides.motion.models import Category, Motion from openslides.motion.models import Category, Motion
from openslides.users.models import User from openslides.users.models import User
from openslides.utils.test import TestCase from openslides.utils.test import TestCase
from openslides.config.api import config
class CSVImport(TestCase): class CSVImport(TestCase):
@ -20,6 +21,9 @@ class CSVImport(TestCase):
Category.objects.create(name='Bildung', prefix='B2') Category.objects.create(name='Bildung', prefix='B2')
def test_example_file_de(self): def test_example_file_de(self):
# Set config to sort names by first_name because the example csv-file
# expect this.
config['users_sort_users_by_first_name'] = True
special_user = User.objects.create_user(username='Harry_Holland', special_user = User.objects.create_user(username='Harry_Holland',
password='iegheeChaje7guthie4a', password='iegheeChaje7guthie4a',
first_name='Harry', first_name='Harry',
@ -31,7 +35,7 @@ class CSVImport(TestCase):
first_name='John', first_name='John',
last_name='Doe') last_name='Doe')
csv_dir = os.path.join(os.path.dirname(__file__), '..', '..', 'extras', 'csv-examples') csv_dir = os.path.join(os.path.dirname(__file__), '..', '..', '..', 'extras', 'csv-examples')
self.assertEqual(Motion.objects.count(), 0) self.assertEqual(Motion.objects.count(), 0)
with open(csv_dir + '/motions-demo_de.csv', 'rb') as f: with open(csv_dir + '/motions-demo_de.csv', 'rb') as f:
success_message, warning_message, error_message = import_motions( success_message, warning_message, error_message = import_motions(

View File

@ -7,7 +7,7 @@ from django.core.urlresolvers import clear_url_caches
from openslides.utils.test import TestCase from openslides.utils.test import TestCase
@override_settings(INSTALLED_PLUGINS=('tests.plugin_api.test_plugin_one',)) @override_settings(INSTALLED_PLUGINS=('tests.old.plugin_api.test_plugin_one',))
class TestPluginOne(TestCase): class TestPluginOne(TestCase):
def setUp(self): def setUp(self):
self.admin_client = Client() self.admin_client = Client()
@ -27,11 +27,11 @@ class TestPluginOne(TestCase):
self.assertRedirects(response, '/version/') self.assertRedirects(response, '/version/')
@override_settings(INSTALLED_PLUGINS=('tests.plugin_api.test_plugin_two',)) @override_settings(INSTALLED_PLUGINS=('tests.old.plugin_api.test_plugin_two',))
class TestPluginTwo(TestCase): class TestPluginTwo(TestCase):
def test_version_page(self): def test_version_page(self):
admin_client = Client() admin_client = Client()
admin_client.login(username='admin', password='admin') admin_client.login(username='admin', password='admin')
response = admin_client.get('/version/') response = admin_client.get('/version/')
self.assertContains(response, 'tests.plugin_api.test_plugin_two') self.assertContains(response, 'tests.old.plugin_api.test_plugin_two')
self.assertContains(response, ' Version unknown') self.assertContains(response, ' Version unknown')

View File

56
tests/old/settings.py Normal file
View File

@ -0,0 +1,56 @@
"""
Settings file for OpenSlides' tests
"""
import os
from openslides.global_settings import * # noqa
# Path to the directory for user specific data files
OPENSLIDES_USER_DATA_PATH = os.path.realpath(os.path.dirname(__file__))
# SECURITY WARNING: Keep the secret key used in production secret!
SECRET_KEY = 'secret'
# OpenSlides plugins
# Add plugins to this list.
INSTALLED_PLUGINS += (
'tests.old.utils',
)
INSTALLED_APPS += INSTALLED_PLUGINS
# Database
# Change this to use MySQL or PostgreSQL.
# See https://docs.djangoproject.com/en/1.7/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
}
}
# Some other settings
TIME_ZONE = 'Europe/Berlin'
MEDIA_ROOT = os.path.join(OPENSLIDES_USER_DATA_PATH, '')
TEMPLATE_DIRS = (
os.path.join(OPENSLIDES_USER_DATA_PATH, 'templates'),
)
STATICFILES_DIRS.insert(0, os.path.join(OPENSLIDES_USER_DATA_PATH, 'static'))
HAYSTACK_CONNECTIONS['default']['STORAGE'] = 'ram'
# Special test settings
# Use a faster password hasher.
PASSWORD_HASHERS = (
'django.contrib.auth.hashers.MD5PasswordHasher',
)

View File

View File

@ -85,10 +85,10 @@ class GroupViews(TestCase):
def test_detail(self): def test_detail(self):
response = self.client.get('/user/group/3/') response = self.client.get('/user/group/3/')
pattern = r'admins_first_name Administrator|aWei4ien6Se0vie0xeiv uquahx3Wohtieph9baer' pattern = r'Administrator, admins_first_name|uquahx3Wohtieph9baer, aWei4ien6Se0vie0xeiv'
match = re.findall(pattern, response.content.decode('utf8')) match = re.findall(pattern, response.content.decode('utf8'))
self.assertEqual(match[0], 'admins_first_name Administrator') self.assertEqual(match[0], 'Administrator, admins_first_name')
self.assertEqual(match[1], 'aWei4ien6Se0vie0xeiv uquahx3Wohtieph9baer') self.assertEqual(match[1], 'uquahx3Wohtieph9baer, aWei4ien6Se0vie0xeiv')
config['users_sort_users_by_first_name'] = True config['users_sort_users_by_first_name'] = True
self.assertTrue(config['users_sort_users_by_first_name']) self.assertTrue(config['users_sort_users_by_first_name'])

View File

View File

@ -27,12 +27,12 @@ class TestBaseTwo(object, metaclass=SignalConnectMetaClass):
class TestSignalConnectMetaClass(TestCase): class TestSignalConnectMetaClass(TestCase):
request_factory = RequestFactory() request_factory = RequestFactory()
@patch('tests.utils.test_dispatch.TestBaseOne.signal') @patch('tests.old.utils.test_dispatch.TestBaseOne.signal')
def test_call_signal_send(self, mock_signal): def test_call_signal_send(self, mock_signal):
TestBaseOne.get_all(self.request_factory.request) TestBaseOne.get_all(self.request_factory.request)
self.assertTrue(mock_signal.send.called) self.assertTrue(mock_signal.send.called)
@patch('tests.utils.test_dispatch.TestBaseOne.signal') @patch('tests.old.utils.test_dispatch.TestBaseOne.signal')
def test_call_signal_connect(self, mock_signal): def test_call_signal_connect(self, mock_signal):
class TestChildOne(TestBaseOne): class TestChildOne(TestBaseOne):
pass pass

View File

@ -6,20 +6,18 @@ import os
from openslides.global_settings import * # noqa from openslides.global_settings import * # noqa
# Path to the directory for user specific data files # Path to the directory for user specific data files
OPENSLIDES_USER_DATA_PATH = os.path.realpath(os.path.dirname(__file__)) OPENSLIDES_USER_DATA_PATH = os.path.realpath(os.path.dirname(__file__))
# SECURITY WARNING: Keep the secret key used in production secret! # SECURITY WARNING: Keep the secret key used in production secret!
SECRET_KEY = 'secret' SECRET_KEY = 'secret'
# OpenSlides plugins
# Add plugins to this list.
# Use 'DEBUG = True' to get more details for server errors. INSTALLED_PLUGINS += (
# SECURITY WARNING: Don't run with debug turned on in production! 'tests.old.utils',
)
DEBUG = True
TEMPLATE_DEBUG = DEBUG
INSTALLED_APPS += INSTALLED_PLUGINS INSTALLED_APPS += INSTALLED_PLUGINS
@ -31,7 +29,6 @@ INSTALLED_APPS += INSTALLED_PLUGINS
DATABASES = { DATABASES = {
'default': { 'default': {
'ENGINE': 'django.db.backends.sqlite3', 'ENGINE': 'django.db.backends.sqlite3',
'NAME': ''
} }
} }

0
tests/unit/__init__.py Normal file
View File

View File

View File

@ -0,0 +1,184 @@
from unittest import TestCase
from unittest.mock import patch, call, MagicMock
from openslides.users.api import (
gen_username,
gen_password,
get_registered_group,
create_or_reset_admin_user,
get_protected_perm)
@patch('openslides.users.api.User')
class UserGenUsername(TestCase):
"""
Tests for the function gen_username.
"""
def test_clear_strings(self, mock_user):
mock_user.objects.filter().exists.return_value = False
self.assertEqual(
gen_username('foo', 'bar'),
'foo bar')
def test_unstripped_strings(self, mock_user):
mock_user.objects.filter().exists.return_value = False
self.assertEqual(
gen_username('foo ', ' bar\n'),
'foo bar',
"The retuned value should only have one whitespace between the names")
def test_empty_second_string(self, mock_user):
mock_user.objects.filter().exists.return_value = False
self.assertEqual(
gen_username('foobar', ''),
'foobar',
"The returned value should not have whitespaces at the end")
def test_empty_first_string(self, mock_user):
mock_user.objects.filter().exists.return_value = False
self.assertEqual(
gen_username('', 'foobar'),
'foobar',
"The returned value should not have whitespaces at the beginning")
def test_two_empty_strings(self, mock_user):
mock_user.objects.filter().exists.return_value = False
with self.assertRaises(ValueError,
msg="A ValueError should be raised"):
gen_username('', '')
def test_used_username(self, mock_user):
mock_user.objects.filter().exists.side_effect = (True, False)
self.assertEqual(
gen_username('user', 'name'),
'user name 1',
"If the username already exist, a number should be added to the name")
def test_two_used_username(self, mock_user):
mock_user.objects.filter().exists.side_effect = (True, True, False)
self.assertEqual(
gen_username('user', 'name'),
'user name 2',
"If the username with a number already exist, a higher number should "
"be added to the name")
def test_umlauts(self, mock_user):
mock_user.objects.filter().exists.return_value = False
self.assertEqual(
gen_username('äöü', 'ßüäö'),
'äöü ßüäö',
"gen_username has also to work with umlauts")
@patch('openslides.users.api.choice')
class GenPassword(TestCase):
def test_normal(self, mock_choice):
"""
Test normal run of the function
"""
mock_choice.side_effect = tuple('test_password')
self.assertEqual(
gen_password(),
'test_pas')
# choice has to be called 8 times
mock_choice.assert_has_calls(
[call("abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789")
for _ in range(8)])
@patch('openslides.users.api.Group')
class GetRegisteredGroup(TestCase):
def test_normal(self, mock_group):
mock_group.objects.get.return_value = 'test_group'
self.assertEqual(
get_registered_group(),
'test_group')
mock_group.objects.getassert_called_once_with(pk=2)
@patch('openslides.users.api.Group')
@patch('openslides.users.api.User')
class CreateOrResetAdminUser(TestCase):
def test_get_admin_group(self, mock_user, mock_group):
"""
Tests, that the Group with pk4 is added to the admin
"""
admin_user = MagicMock(name='admin_user')
mock_user.objects.get.return_value = admin_user
mock_group.objects.get.return_value = 'admin_group'
create_or_reset_admin_user()
mock_group.objects.get.assert_called_once_with(pk=4)
admin_user.groups.add.assert_called_once_with('admin_group')
def test_password_set_to_admin(self, mock_user, mock_group):
"""
Tests, that the password of the admin is set to 'admin'.
"""
admin_user = MagicMock(name='admin_user')
mock_user.objects.get.return_value = admin_user
create_or_reset_admin_user()
self.assertEqual(
admin_user.default_password,
'admin')
admin_user.set_password.assert_called_once_with('admin')
admin_user.save.assert_called_once_with()
def test_return_value(self, mock_user, mock_group):
"""
Test, that the function retruns True, when a user is created.
"""
mock_user.DoesNotExist = Exception
mock_user.objects.get.side_effect = Exception
self.assertEqual(
create_or_reset_admin_user(),
True,
"create_or_reset_admin_user should return True when a new user is "
" created")
def test_attributes_of_created_user(self, mock_user, mock_group):
admin_user = MagicMock(name='admin_user')
mock_user.return_value = admin_user
mock_user.DoesNotExist = Exception
mock_user.objects.get.side_effect = Exception
create_or_reset_admin_user()
self.assertEqual(
admin_user.username,
'admin',
"The username of a new created admin should be 'admin'")
self.assertEqual(
admin_user.last_name,
'Administrator',
"The last_name of a new created admin should be 'Administrator'")
@patch('openslides.users.api.Permission')
class GetProtectedPerm(TestCase):
def test_normal(self, mock_permission):
mock_permission.objects.get_by_natural_key.return_value = 'test_permission'
value = get_protected_perm()
mock_permission.objects.get_by_natural_key.assert_called_once_with(
app_label='users', model='user', codename='can_manage')
self.assertEqual(
value,
'test_permission',
"The function should return the user.can_manage permission")

View File

@ -0,0 +1,140 @@
from unittest import TestCase
from unittest.mock import patch, MagicMock
from openslides.users.auth import AnonymousUser, get_user, auth
class TestAnonymousUser(TestCase):
def test_get_all_permissions_from_group_1(self):
"""
Tests, that get_all_permissions looks in the permissions of the group with
pk=1
"""
anonymous = AnonymousUser()
with patch('openslides.users.auth.Permission') as mock_permission:
anonymous.get_all_permissions()
mock_permission.objects.filter.assert_called_once_with(group__pk=1)
def test_has_perm_in_list(self):
anonymous = AnonymousUser()
anonymous.get_all_permissions = MagicMock(return_value=('p1', 'p2'))
self.assertTrue(
anonymous.has_perm('p1'),
"has_perm() should return True when the user has the permission")
def test_has_perm_not_in_list(self):
anonymous = AnonymousUser()
anonymous.get_all_permissions = MagicMock(return_value=('p1', 'p2'))
self.assertFalse(
anonymous.has_perm('p3'),
"has_perm() should return False when the user has not the permission")
def test_has_module_perms_in_list(self):
anonymous = AnonymousUser()
anonymous.get_all_permissions = MagicMock(return_value=('test_app.perm', ))
self.assertTrue(
anonymous.has_module_perms('test_app'),
"has_module_perms() should return True when the user has the "
"permission test_app.perm")
def test_has_module_perms_not_in_list(self):
anonymous = AnonymousUser()
anonymous.get_all_permissions = MagicMock(return_value=('test_otherapp.perm', ))
self.assertFalse(
anonymous.has_module_perms('test_app'),
"has_module_perms() should return False when the user does not have "
"the permission test_app.perm")
@patch('openslides.users.auth.config')
@patch('openslides.users.auth._get_user')
class TestGetUser(TestCase):
def test_not_in_cache(self, mock_get_user, mock_config):
mock_config.__getitem__.return_value = True
mock_get_user.return_value = AnonymousUser()
request = MagicMock()
del request._cached_user
user = get_user(request)
mock_get_user.assert_called_once_with(request)
self.assertEqual(user, AnonymousUser())
self.assertEqual(request._cached_user, AnonymousUser())
def test_in_cache(self, mock_get_user, mock_config):
request = MagicMock()
request._cached_user = 'my_user'
user = get_user(request)
self.assertFalse(
mock_get_user.called,
"_get_user should not have been called when the user object is in cache")
self.assertEqual(
user,
'my_user',
"The user in cache should be returned")
def test_disabled_anonymous_user(self, mock_get_user, mock_config):
mock_config.__getitem__.return_value = False
mock_get_user.return_value = 'django_anonymous_user'
request = MagicMock()
del request._cached_user
user = get_user(request)
mock_get_user.assert_called_once_with(request)
self.assertEqual(
user,
'django_anonymous_user',
"The django user should be returned")
self.assertEqual(
request._cached_user,
'django_anonymous_user',
"The django user should be cached")
@patch('openslides.users.auth.config')
@patch('openslides.users.auth._auth')
class TestAuth(TestCase):
def test_anonymous_enabled(self, mock_auth, mock_config):
mock_config.__getitem__.return_value = True
request = MagicMock()
mock_auth.return_value = {'user': AnonymousUser()}
context = auth(request)
self.assertEqual(
context,
{'user': AnonymousUser(),
'os_enable_anonymous_login': True})
def test_anonymous_disabled(self, mock_auth, mock_config):
mock_config.__getitem__.return_value = False
request = MagicMock()
mock_auth.return_value = {'user': AnonymousUser()}
context = auth(request)
self.assertEqual(
context,
{'user': AnonymousUser(),
'os_enable_anonymous_login': False})
def test_logged_in_user_in_request(self, mock_auth, mock_config):
mock_config.__getitem__.return_value = True
request = MagicMock()
mock_auth.return_value = {'user': 'logged_in_user'}
context = auth(request)
self.assertEqual(
context,
{'user': 'logged_in_user',
'os_enable_anonymous_login': True})

View File

@ -0,0 +1,312 @@
from unittest import TestCase
from unittest.mock import MagicMock, patch
from openslides.users.models import User, UserManager
class UserTest(TestCase):
def test_str(self):
"""
Tests, that the str representaion of a User object returns the same as
User.get_full_name().
"""
user = User()
user.get_full_name = MagicMock(return_value='Test Value')
self.assertEqual(
str(user),
'Test Value',
"The str representation of User is not user.get_full_name()")
def test_get_slide_context(self):
"""
Tests, that get_slide_context returns:
{'shown_user': self}
"""
user = User()
self.assertEqual(
user.get_slide_context(),
{'shown_user': user},
"User.get_slide_context returns a wrong context")
class UserGetAbsoluteUrlTest(TestCase):
def test_get_absolute_url_default(self):
"""
Tests get_absolute_url() with no argument.
It should return the url for the url-pattern of user_detail
"""
user = User(pk=5)
with patch('openslides.users.models.reverse') as mock_reverse:
mock_reverse.return_value = 'test url'
url = user.get_absolute_url()
self.assertEqual(
url,
'test url',
"User.get_absolute_url() does not return the result of reverse")
mock_reverse.assert_called_once_with('user_detail', args=['5'])
def test_get_absolute_url_detail(self):
"""
Tests get_absolute_url() with 'detail' as argument
"""
user = User(pk=5)
with patch('openslides.users.models.reverse') as mock_reverse:
mock_reverse.return_value = 'test url'
url = user.get_absolute_url('detail')
self.assertEqual(
url,
'test url',
"User.get_absolute_url('detail') does not return the result of reverse")
mock_reverse.assert_called_once_with('user_detail', args=['5'])
def test_get_absolute_url_update(self):
"""
Tests get_absolute_url() with 'update' as argument
"""
user = User(pk=5)
with patch('openslides.users.models.reverse') as mock_reverse:
mock_reverse.return_value = 'test url'
url = user.get_absolute_url('update')
self.assertEqual(
url,
'test url',
"User.get_absolute_url('update') does not return the result of reverse")
mock_reverse.assert_called_once_with('user_update', args=['5'])
def test_get_absolute_url_delete(self):
"""
Tests get_absolute_url() with 'delete' as argument
"""
user = User(pk=5)
with patch('openslides.users.models.reverse') as mock_reverse:
mock_reverse.return_value = 'test url'
url = user.get_absolute_url('delete')
self.assertEqual(
url,
'test url',
"User.get_absolute_url('delete') does not return the result of reverse")
mock_reverse.assert_called_once_with('user_delete', args=['5'])
def test_get_absolute_url_other(self):
"""
Tests get_absolute_url() with any other argument
"""
user = User(pk=5)
dummy_argument = MagicMock()
with patch('builtins.super') as mock_super:
mock_super().get_absolute_url.return_value = 'test url'
url = user.get_absolute_url(dummy_argument)
self.assertEqual(
url,
'test url',
"User.get_absolute_url(OTHER) does not return the result of reverse")
mock_super().get_absolute_url.assert_called_once_with(dummy_argument)
class UserGetFullName(TestCase):
def test_get_full_name_with_structure_level_and_title(self):
"""
Tests, that get_full_name returns the write string.
"""
user = User()
user.title = 'test_title'
user.structure_level = 'test_structure_level'
user.get_short_name = MagicMock(return_value='test_short_name')
self.assertEqual(
user.get_full_name(),
'test_title test_short_name (test_structure_level)',
"User.get_full_name() returns wrong string when it has a structure_level and title")
def test_get_full_name_without_structure_level_and_with_title(self):
"""
Tests, that get_full_name returns the write string.
"""
user = User()
user.title = 'test_title'
user.structure_level = ''
user.get_short_name = MagicMock(return_value='test_short_name')
self.assertEqual(
user.get_full_name(),
'test_title test_short_name',
"User.get_full_name() returns wrong string when it has no structure_level but a title")
def test_get_full_name_without_structure_level_and_without_title(self):
"""
Tests, that get_full_name returns the write string.
"""
user = User()
user.title = ''
user.structure_level = ''
user.get_short_name = MagicMock(return_value='test_short_name')
self.assertEqual(
user.get_full_name(),
'test_short_name',
"User.get_full_name() returns wrong string when it has no structure_level and no title")
class UserGetShortName(TestCase):
def test_get_short_name_sort_first_name_only_first_name(self):
"""
Tests the output of get_short_name.
"""
user = User()
user.first_name = 'test_first_name'
with patch('openslides.users.models.config') as mock_config:
mock_config.__getitem__.return_value = True
short_name = user.get_short_name()
self.assertEqual(
short_name,
'test_first_name',
"User.get_short_name() returns wrong string when it has only a "
"first_name and is sorted by first_name")
def test_get_short_name_sort_first_name_both_names(self):
"""
Tests the output of get_short_name.
"""
user = User()
user.first_name = 'test_first_name'
user.last_name = 'test_last_name'
with patch('openslides.users.models.config') as mock_config:
mock_config.__getitem__.return_value = True
short_name = user.get_short_name()
self.assertEqual(
short_name,
'test_first_name test_last_name',
"User.get_short_name() returns wrong string when it has a fist_name "
"and a last_name and is sorted by first_name")
def test_get_short_name_sort_last_name_only_first_name(self):
"""
Tests the output of get_short_name.
"""
user = User()
user.first_name = 'test_first_name'
with patch('openslides.users.models.config') as mock_config:
mock_config.__getitem__.return_value = False
short_name = user.get_short_name()
self.assertEqual(
short_name,
'test_first_name',
"User.get_short_name() returns wrong string when it has only a "
"first_name and is sorted by last_name")
def test_get_short_name_sort_last_name_both_names(self):
"""
Tests the output of get_short_name.
"""
user = User()
user.first_name = 'test_first_name'
user.last_name = 'test_last_name'
with patch('openslides.users.models.config') as mock_config:
mock_config.__getitem__.return_value = False
short_name = user.get_short_name()
self.assertEqual(
short_name,
'test_last_name, test_first_name',
"User.get_short_name() returns wrong string when it has a fist_name "
"and a last_name and is sorted by last_name")
def test_get_short_name_no_names(self):
"""
Tests the output of get_short_name.
"""
user = User(username='test_username')
with patch('openslides.users.models.config') as mock_config:
mock_config.__getitem__.return_value = False
short_name = user.get_short_name()
self.assertEqual(
short_name,
'test_username',
"User.get_short_name() returns wrong string when it has no fist_name "
"and no last_name and is sorted by last_name")
def test_while_spaces_in_name_parts(self):
"""
Tests the output if the name parts have white spaces at the begin or
end.
"""
user = User()
user.first_name = ' test_first_name\n '
user.last_name = ' test_last_name \n'
with patch('openslides.users.models.config') as mock_config:
mock_config.__getitem__.return_value = True
short_name = user.get_short_name()
self.assertEqual(
short_name,
'test_first_name test_last_name',
"User.get_short_name() has to strip whitespaces from the name parts")
class UserResetPassword(TestCase):
def test_reset_password_no_attribute(self):
"""
Tests reset_password with no attribute.
"""
user = User(default_password='test_default_password')
user.set_password = MagicMock()
user.reset_password()
user.set_password.assert_called_once_with('test_default_password')
def test_reset_password_with_attribute(self):
"""
Tests reset_password with no attribute.
"""
user = User(default_password='test_default_password')
user.set_password = MagicMock()
user.reset_password('test_password')
user.set_password.assert_called_once_with('test_password')
class UserManagerTest(TestCase):
def test_create_user(self):
"""
Tests, that create_user saves a new user with a set password.
"""
user = MagicMock()
user_manager = UserManager()
user_manager.model = MagicMock(return_value=user)
user_manager._db = 'my_test_db'
return_user = user_manager.create_user('test_username', 'test_password', test_kwarg='test_kwarg')
user_manager.model.assert_called_once_with(username='test_username', test_kwarg='test_kwarg')
user.set_password.assert_called_once_with('test_password')
user.save.assert_called_once_with(using='my_test_db')
self.assertEqual(
return_user,
user,
"The returned user is not the created user")

View File

View File

@ -0,0 +1,16 @@
from unittest import TestCase
from openslides.utils.models import AbsoluteUrlMixin
class TestAbsoluteUrlMixin(TestCase):
def test_get_absolute_url(self):
"""
Tests, that AbsoluteUrlMixin raises a ValueError if called.
"""
object = AbsoluteUrlMixin()
with self.assertRaisesRegex(
ValueError,
'Unknown Link "argument" for model "<class \'openslides.utils.models.AbsoluteUrlMixin\'>"'):
object.get_absolute_url('argument')

View File

@ -1,9 +1,10 @@
from openslides.utils.test import TestCase from unittest import TestCase
from openslides.utils.utils import html_strong, int_or_none from openslides.utils.utils import html_strong, int_or_none
class Test_functions(TestCase): class Test_functions(TestCase):
def test_string(self): def test_html_strong(self):
self.assertEqual(html_strong('some text'), '<strong>some text</strong>') self.assertEqual(html_strong('some text'), '<strong>some text</strong>')
def test_int_or_none(self): def test_int_or_none(self):

View File

@ -0,0 +1,318 @@
from unittest import TestCase
from unittest.mock import patch, MagicMock
from django.core.exceptions import ImproperlyConfigured, PermissionDenied
from openslides.utils import views
@patch('builtins.super')
class LoginMixinTest(TestCase):
def test_dispatch(self, mock_super):
"""
Tests that the function calls super
"""
# TODO: find a way to test the call of the decorator.
view = views.LoginMixin()
request = MagicMock()
view.dispatch(request)
mock_super().dispatch.assert_called_once_with(request)
class PermissionMixinTest(TestCase):
def test_check_permission_non_required_permission(self):
view = views.PermissionMixin()
view.required_permission = None
request = MagicMock()
self.assertTrue(view.check_permission(request))
def test_check_permission_with_required_permission(self):
view = views.PermissionMixin()
view.required_permission = 'required_permission'
request = MagicMock()
view.check_permission(request)
request.user.has_perm.assert_called_once_with('required_permission')
@patch('builtins.super')
def test_dispatch_with_perm(self, mock_super):
view = views.PermissionMixin()
view.check_permission = MagicMock(return_value=True)
request = MagicMock()
view.dispatch(request)
mock_super().dispatch.called_once_with(request)
@patch('openslides.utils.views.settings')
@patch('openslides.utils.views.HttpResponseRedirect')
@patch('builtins.super')
def test_dispatch_without_perm_logged_out(self, mock_super, mock_response, mock_settings):
view = views.PermissionMixin()
view.check_permission = MagicMock(return_value=False)
request = MagicMock()
request.user.is_authenticated.return_value = False
request.get_full_path.return_value = '/requested/path/'
mock_settings.LOGIN_URL = 'my_login_url'
value = view.dispatch(request)
mock_response.assert_called_once_with('my_login_url?next=/requested/path/')
self.assertEqual(value, mock_response())
@patch('openslides.utils.views.settings')
@patch('openslides.utils.views.HttpResponseRedirect')
@patch('builtins.super')
def test_dispatch_without_perm_logged_in(self, mock_super, mock_response, mock_settings):
view = views.PermissionMixin()
view.check_permission = MagicMock(return_value=False)
request = MagicMock()
request.user.is_authenticated.return_value = True
with self.assertRaises(PermissionDenied):
view.dispatch(request)
class AjaxMixinTest(TestCase):
@patch('openslides.utils.views.json')
@patch('openslides.utils.views.HttpResponse')
def test_ajax_get(self, mock_response, mock_json):
view = views.AjaxMixin()
view.get_ajax_context = MagicMock(return_value='context')
mock_json.dumps.return_value = 'json'
view.ajax_get(MagicMock())
mock_response.assert_called_once_with('json')
mock_json.dumps.assert_called_once_with('context')
def test_get_ajax_context(self):
view = views.AjaxMixin()
context = view.get_ajax_context(t1=1, t2=2, t3=3)
self.assertEqual(context, {'t1': 1, 't2': 2, 't3': 3})
class ExtraContextMixin(TestCase):
@patch('openslides.utils.views.template_manipulation')
@patch('builtins.super')
def test_get_context_data(self, mock_super, mock_signal):
"""
Tests that super is called with the kwargs, that the signal is called
with the returnd context and that the context is returned.
"""
view = views.ExtraContextMixin()
view.request = 'test_request'
mock_super().get_context_data.return_value = 'new_context'
returned_context = view.get_context_data(a1=1, a2=2)
mock_super().get_context_data.assert_called_once_with(a1=1, a2=2)
mock_signal.send.assert_called_once_with(
sender=views.ExtraContextMixin,
request='test_request',
context='new_context')
self.assertEqual(returned_context, 'new_context')
@patch('openslides.utils.views.reverse')
class UrlMixinGetUrl(TestCase):
"""
Tests the method 'get_url' from the UrlMixin.
"""
def test_url_name(self, reverse):
"""
Tests that the return value of reverse(url_pattern) is returned.
"""
view = views.UrlMixin()
reverse.return_value = 'reverse_url'
returned_url = view.get_url('test_url_name')
reverse.assert_called_once_with('test_url_name', args=[])
self.assertEqual(returned_url, 'reverse_url')
def test_url_name_with_args(self, reverse):
"""
Tests that the return value of reverse(url_pattern) with args is returned.
"""
view = views.UrlMixin()
reverse.return_value = 'reverse_url'
returned_url = view.get_url('test_url_name', args=[1, 2, 3])
reverse.assert_called_once_with('test_url_name', args=[1, 2, 3])
self.assertEqual(returned_url, 'reverse_url')
def test_url(self, reverse):
view = views.UrlMixin()
returned_url = view.get_url(url='my_url')
self.assertFalse(
reverse.called,
"reverse should not be called")
self.assertEqual(returned_url, 'my_url')
def test_priority_of_url_name(self, reverse):
view = views.UrlMixin()
reverse.return_value = 'reverse_url'
returned_url = view.get_url(url_name='test_url_name', url='my_url')
reverse.assert_called_once_with('test_url_name', args=[])
self.assertEqual(returned_url, 'reverse_url')
def test_get_absolute_url(self, reverse):
view = views.UrlMixin()
view.object = MagicMock()
view.object.get_absolute_url.return_value = 'object_url'
returned_url = view.get_url()
view.object.get_absolute_url.assert_called_once_with()
self.assertEqual(returned_url, 'object_url')
self.assertFalse(
reverse.called,
"reverse should not be called")
def test_get_absolute_url_with_link(self, reverse):
view = views.UrlMixin()
view.object = MagicMock()
view.object.get_absolute_url.return_value = 'object_url'
returned_url = view.get_url(use_absolute_url_link='test_link')
view.object.get_absolute_url.assert_called_once_with('test_link')
self.assertEqual(returned_url, 'object_url')
self.assertFalse(
reverse.called,
"reverse should not be called")
def test_get_absolute_url_with_invalid_object(self, reverse):
view = views.UrlMixin()
view.object = MagicMock()
del view.object.get_absolute_url
with self.assertRaisesRegex(
ImproperlyConfigured,
'No url to redirect to\. See openslides\.utils\.views\.UrlMixin '
'for more details\.'):
view.get_url()
class UrlMixinGetUrlNameArgs(TestCase):
"""
Tests the method 'get_url_name_args' from the UrlMixin.
"""
def test_has_attribute(self):
view = views.UrlMixin()
view.url_name_args = 'name_args'
returned_args = view.get_url_name_args()
self.assertEqual(
returned_args,
'name_args',
"The object attribute 'url_name_args' should be returned")
def test_without_attribute_with_object_with_pk(self):
view = views.UrlMixin()
view.object = MagicMock()
view.object.pk = 5
returned_args = view.get_url_name_args()
self.assertEqual(
returned_args,
[5],
"object.pk should be returned as a one element list")
def test_without_attribute_with_object_with_pk_is_none(self):
view = views.UrlMixin()
view.object = MagicMock()
view.object.pk = None
returned_args = view.get_url_name_args()
self.assertEqual(
returned_args,
[],
"An empty list should be returned")
def test_without_attribute_with_object_without_pk(self):
view = views.UrlMixin()
view.object = MagicMock()
del view.object.pk
returned_args = view.get_url_name_args()
self.assertEqual(
returned_args,
[],
"An empty list should be returned")
def test_without_attribute_without_object(self):
view = views.UrlMixin()
returned_args = view.get_url_name_args()
self.assertEqual(
returned_args,
[],
"An empty list should be returned")
@patch('builtins.super')
class SingleObjectMixinTest(TestCase):
def test_get_object_cache(self, mock_super):
"""
Test that the method get_object caches his result.
Tests that get_object from the django view is only called once, even if
get_object on our class is called twice.
"""
view = views.SingleObjectMixin()
view.get_object()
view.get_object()
mock_super().get_object.assert_called_once_with()
def test_dispatch_with_existin_object(self, mock_super):
view = views.SingleObjectMixin()
view.object = 'old_object'
view.get_object = MagicMock()
view.dispatch()
mock_super().dispatch.assert_called_with()
self.assertEqual(
view.object,
'old_object',
"view.object should not be changed")
self.assertFalse(
view.get_object.called,
"view.get_object() should not be called")
def test_dispatch_without_existin_object(self, mock_super):
view = views.SingleObjectMixin()
view.get_object = MagicMock(return_value='new_object')
view.dispatch()
mock_super().dispatch.assert_called_with()
self.assertEqual(
view.object,
'new_object',
"view.object should be changed")
self.assertTrue(
view.get_object.called,
"view.get_object() should be called")

View File

@ -1,65 +0,0 @@
from openslides.users.api import gen_password, gen_username
from openslides.users.models import Group, User
from openslides.utils.test import TestCase
class UserTest(TestCase):
def setUp(self):
self.user1 = User()
self.user1.first_name = 'Max'
self.user1.last_name = 'Mustermann'
self.user1.username = gen_username(
self.user1.first_name, self.user1.last_name)
self.user1.default_password = gen_password()
self.user1.save()
def test_str(self):
self.assertEqual(str(self.user1), 'Max Mustermann')
def test_name_suffix(self):
self.user1.structure_level = 'München'
self.user1.save()
self.assertEqual(str(self.user1), 'Max Mustermann (München)')
def test_reset_password(self):
self.assertIsInstance(self.user1.default_password, str)
self.assertEqual(len(self.user1.default_password), 8)
self.user1.set_unusable_password()
self.assertFalse(self.user1.check_password(self.user1.default_password))
self.user1.reset_password()
self.assertTrue(self.user1.check_password(self.user1.default_password))
def test_get_absolute_url(self):
urls = (('detail', '/user/2/'),
('update', '/user/2/edit/'),
('delete', '/user/2/del/'))
for link, url in urls:
self.assertEqual(self.user1.get_absolute_url(link), url)
class DefaultGroups(TestCase):
def test_pks_of_default_groups(self):
default_groups = ((1, 'Anonymous'),
(2, 'Registered'),
(3, 'Delegates'),
(4, 'Staff'))
for pk, name in default_groups:
self.assertEqual(Group.objects.get(pk=pk).name, name)
def test_default_perms_anonymous(self):
anonymous = Group.objects.get(pk=1)
default_perms = ('core.can_see_projector',
'core.can_see_dashboard',
'agenda.can_see_agenda',
'agenda.can_see_orga_items',
'motion.can_see_motion',
'assignment.can_see_assignment',
'users.can_see_name',
'users.can_see_extra_data',
'mediafile.can_see')
for perm_string in default_perms:
perm_string_list = []
for perm in anonymous.permissions.all():
perm_string_list.append('%s.%s' % (perm.content_type.app_label, perm.codename))
self.assertTrue(perm_string in perm_string_list)

View File

@ -1,26 +0,0 @@
from openslides.users.api import gen_username
from openslides.users.models import User
from openslides.utils.test import TestCase
class UserGenUsername(TestCase):
"""
Tests for the function gen_username.
"""
def test_base(self):
self.assertEqual(gen_username('foo', 'bar'), 'foo bar')
self.assertEqual(gen_username('foo ', ' bar\n'), 'foo bar')
self.assertEqual(gen_username('foobar', ''), 'foobar')
self.assertEqual(gen_username('', 'foobar'), 'foobar')
self.assertRaises(ValueError, gen_username, '', '')
def test_used_username(self):
User.objects.create(username='user name')
self.assertEqual(gen_username('user', 'name'), 'user name 1')
User.objects.create(username='user name 1')
self.assertEqual(gen_username('user', 'name'), 'user name 2')
def test_umlauts(self):
self.assertEqual(gen_username('äöü', 'ßüäö'), 'äöü ßüäö')

View File

@ -1,5 +0,0 @@
<html>
<body>
{{ object.title }}
</body>
</html>

View File

@ -1,26 +0,0 @@
from openslides.utils.models import AbsoluteUrlMixin
from openslides.utils.test import TestCase
class MyModel(AbsoluteUrlMixin):
""""
Model for testing
"""
def get_absolute_url(self, link='default'):
if link == 'default' or link == 'known':
url = 'my url'
else:
url = super(MyModel, self).get_absolute_url(link)
return url
class TestAbsoluteUrlMixin(TestCase):
def test_get_absolute_url(self):
my_object = MyModel()
self.assertEqual(my_object.get_absolute_url(), 'my url')
self.assertEqual(my_object.get_absolute_url('known'), 'my url')
self.assertRaisesMessage(
ValueError,
'Unknown Link "unknown" for model "<class \'tests.utils.test_models.MyModel\'>"',
my_object.get_absolute_url, 'unknown')

View File

@ -1,217 +0,0 @@
from unittest.mock import patch
from django.contrib.auth.models import AnonymousUser
from django.core.exceptions import ImproperlyConfigured
from django.core.urlresolvers import clear_url_caches
from django.test import RequestFactory
from django.test.client import Client
from django.test.utils import override_settings
from openslides.utils import views
from openslides.utils.signals import template_manipulation
from openslides.utils.test import TestCase
from . import views as test_views
@override_settings(ROOT_URLCONF='tests.utils.urls')
class ViewTestCase(TestCase):
rf = RequestFactory()
def setUp(self):
# Clear the cache for the urlresolver, so the overriden settings works.
clear_url_caches()
class LoginMixinTest(ViewTestCase):
def test_dispatch(self):
client = Client()
response = client.get('/login_mixin/')
self.assertEqual(response['Location'], 'http://testserver/login/?next=/login_mixin/')
client.login(username='admin', password='admin')
response = client.get('/login_mixin/')
self.assertEqual(response.status_code, 200)
self.assertEqual(response.content, b'Well done.')
class PermissionMixinTest(ViewTestCase):
def test_dispatch(self):
client = Client()
# View without required_permission
response = client.get('/permission_mixin1/')
self.assertEqual(response.status_code, 200)
self.assertEqual(response.content, b'Well done.')
# View with required_permission without login
response = client.get('/permission_mixin2/')
self.assertEqual(response.status_code, 302)
self.assertEqual(response['Location'], 'http://testserver/login/?next=/permission_mixin2/')
# View with required_permission, with login, without permission
client.login(username='admin', password='admin')
response = client.get('/permission_mixin2/')
self.assertEqual(response.status_code, 403)
# View with required_permission, with login, with permission
response = client.get('/permission_mixin3/')
self.assertEqual(response.status_code, 200)
class AjaxMixinTest(ViewTestCase):
def test_ajax_get(self):
view = test_views.AjaxMixinView()
ajax_get = view.ajax_get
response = ajax_get(self.rf.get('/', {}))
self.assertEqual(response.content, b'{"new_context": "newer_context"}')
def test_get_ajax_context(self):
get_ajax_context = test_views.AjaxMixinView().get_ajax_context
self.assertEqual(get_ajax_context()['new_context'], 'newer_context')
self.assertEqual(
get_ajax_context(test_content='some_content')['test_content'],
'some_content')
class ExtraContextMixinTest(ViewTestCase):
"""
Tests the ExtraContextMixin by testing the TemplateView.
"""
def test_get_context_data(self):
view = views.TemplateView()
get_context_data = view.get_context_data
view.request = self.rf.get('/', {})
view.request.user = AnonymousUser()
context = get_context_data()
self.assertIn('extra_stylefiles', context)
self.assertIn('extra_javascript', context)
context = get_context_data(some_context='context')
self.assertIn('some_context', context)
template_manipulation.connect(set_context, dispatch_uid='set_context_test')
context = get_context_data()
self.assertIn('new_context', context)
template_manipulation.disconnect(set_context, dispatch_uid='set_context_test')
class UrlMixinTest(ViewTestCase):
def test_get_url(self):
get_url = test_views.UrlMixinView().get_url
# url_name has the higher priority
self.assertEqual(get_url('test_url_mixin', 'view_url'),
'/url_mixin/')
# If the url_name is none, return the second argument
self.assertEqual(get_url(None, 'view_url'),
'view_url')
# Test argument in url
self.assertEqual(get_url('test_url_mixin_args', None,
args=[1]),
'/url_mixin_args/1/')
# No Url given.
self.assertRaisesMessage(
ImproperlyConfigured,
'No url to redirect to. See openslides.utils.views.UrlMixin for more details.',
get_url, None, None)
def test_get_url_with_object(self):
get_url = test_views.UrlMixinViewWithObject().get_url
self.assertEqual(get_url(None, None),
'default_url')
self.assertEqual(get_url(None, None, use_absolute_url_link='detail'),
'detail_url')
def test_get_url_name_args(self):
view = test_views.UrlMixinViewWithObject()
get_url_name_args = view.get_url_name_args
view.url_name_args = [1]
self.assertEqual(get_url_name_args(), [1])
view.url_name_args = None
self.assertEqual(get_url_name_args(), [])
view.object.pk = 5
self.assertEqual(get_url_name_args(), [5])
class QuestionViewTest(ViewTestCase):
def test_get_redirect_url(self):
view = views.QuestionView()
get_redirect_url = view.get_redirect_url
view.request = self.rf.get('/')
view.question_url = 'redirect_to_get_url'
self.assertEqual(get_redirect_url(), 'redirect_to_get_url')
view.request = self.rf.post('/')
view.url = 'redirect_to_post_url'
self.assertEqual(get_redirect_url(), 'redirect_to_post_url')
def test_get_question_message(self):
view = views.QuestionView()
get_question_message = view.get_question_message
self.assertEqual(get_question_message(), 'Are you sure?')
view.question_message = 'new_question'
self.assertEqual(get_question_message(), 'new_question')
self.assertIsInstance(get_question_message(), str)
def test_get_answer_options(self):
view = views.QuestionView()
get_answer_options = view.get_answer_options
self.assertIn('yes', dict(get_answer_options()))
self.assertIn('no', dict(get_answer_options()))
view.answer_options = [('new_answer', 'Answer')]
self.assertNotIn('yes', dict(get_answer_options()))
self.assertIn('new_answer', dict(get_answer_options()))
@patch('openslides.utils.views.messages')
def test_confirm_form(self, mock_messages):
view = views.QuestionView()
view.question_message = 'the question'
confirm_form = view.confirm_form
view.request = self.rf.get('/')
confirm_form()
self.assertTrue(mock_messages.warning.called)
question = mock_messages.warning.call_args[0][1]
self.assertIn('the question', question)
class SingleObjectMixinTest(TestCase):
@patch('openslides.utils.views.django_views.detail.SingleObjectMixin.get_object')
def test_get_object_cache(self, mock_super_class_get_object):
"""
Test that the method get_object caches his result.
Tests that get_object from the django view is only called once, even if
get_object on our class is called twice.
"""
view = views.SingleObjectMixin()
view.get_object()
view.get_object()
mock_super_class_get_object.assert_called_once_with()
def set_context(sender, request, context, **kwargs):
"""
receiver for testing the ExtraContextMixin
"""
context.update({'new_context': 'some new context'})

View File

@ -1,29 +0,0 @@
from django.conf.urls import patterns, url
from openslides.urls import urlpatterns
from . import views
urlpatterns += patterns(
'',
url(r'^url_mixin/$',
views.UrlMixinView.as_view(),
name='test_url_mixin'),
url(r'^url_mixin_args/(?P<arg>\d+)/$',
views.UrlMixinView.as_view(),
name='test_url_mixin_args'),
url(r'^login_mixin/$',
views.LoginMixinView.as_view()),
url(r'^permission_mixin1/$',
views.PermissionMixinView.as_view()),
url(r'^permission_mixin2/$',
views.PermissionMixinView.as_view(required_permission='permission_string')),
url(r'^permission_mixin3/$',
views.PermissionMixinView.as_view(required_permission='agenda.can_see_agenda')),
)

View File

@ -1,47 +0,0 @@
from django.http import HttpResponse
from openslides.utils import views
class GetAbsoluteUrl(object):
"""
Generates objects with a get_absolute_url method.
Helper Class for the tests.
"""
def get_absolute_url(self, link='default'):
if link == 'detail':
url = 'detail_url'
elif link == 'update':
url = 'update_url'
elif link == 'default':
url = 'default_url'
return url
class LoginMixinView(views.LoginMixin, views.View):
def get(self, *args, **kwargs):
response = HttpResponse('Well done.')
response.status_code = 200
return response
class PermissionMixinView(views.PermissionMixin, views.View):
def get(self, *args, **kwargs):
response = HttpResponse('Well done.')
response.status_code = 200
return response
class AjaxMixinView(views.AjaxMixin, views.View):
def get_ajax_context(self, **kwargs):
return super(AjaxMixinView, self).get_ajax_context(
new_context='newer_context', **kwargs)
class UrlMixinView(views.UrlMixin, views.View):
pass
class UrlMixinViewWithObject(views.UrlMixin, views.View):
object = GetAbsoluteUrl()