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/gulp --production"
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"
- "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
FAIL = '\033[91m'
SUCCESS = '\033[92m'
RESET = '\033[0m'
@argument('module', nargs='?', default='')
@command('test', help='runs the tests')
@ -10,8 +14,8 @@ def test(args=None):
Runs the tests.
"""
module = getattr(args, 'module', '')
return call("DJANGO_SETTINGS_MODULE='tests.settings' coverage run "
"./manage.py test %s" % module)
return call("DJANGO_SETTINGS_MODULE='tests.integration.settings' coverage run "
"./manage.py test tests.%s" % module)
@argument('--plain', action='store_true')
@ -51,11 +55,17 @@ def travis(args=None):
if line == 'script:':
script_lines = True
continue
if not script_lines:
if not script_lines or not line:
continue
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
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])
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 }}
<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 %}
<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 %}
{% if field.errors %}
<span class="help-inline">{{ field.errors }}</span>

View File

@ -149,7 +149,7 @@
<span class="glyphicon glyphicon-ok" aria-hidden="true"></span>
</button>
{% 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' %}">
<span class="glyphicon glyphicon-user" aria-hidden="true"></span>
</a>

View File

@ -173,3 +173,5 @@ CKEDITOR_CONFIGS = {
# Use small alternative with tornado as frontend or big alternative with a
# webserver as wsgi server.
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
function used to protect manager users from locking out themselves.
"""
return Permission.objects.get(
content_type=ContentType.objects.get(app_label='users', model='user'),
codename='can_manage')
return Permission.objects.get_by_natural_key(
app_label='users', model='user', codename='can_manage')

View File

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

View File

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

View File

@ -20,11 +20,11 @@
{% trans "Users" %}
<small class="pull-right">
{% 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>
{% trans "New" %}
</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>
{% trans 'New multiple' %}
</a>
@ -102,9 +102,9 @@
<td class="optional">{{ user.title }}</td>
<td>
{% 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 %}
<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 %}
</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>
</a>
{% 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">
<i class="icon-pencil"></i>
</a>

View File

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

View File

@ -1,9 +1,32 @@
from django.core.management import call_command
from django.test import TestCase as _TestCase
from django.test.runner import DiscoverRunner
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):
"""
Overwrites Django's TestCase class to refreshs the config cache.

View File

@ -2,44 +2,15 @@ import difflib
import roman
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):
"""
Deletes the permissions, django creates by default for the admin.
"""
# TODO: Create an participant app which does not create the permissions.
# Delete this function afterwards
# TODO: Find a way not to create the permissions in the first place.
# Meta.default_permissions does not work, because django will
# nevertheless create permissions for its own models like "group"
for p in Permission.objects.all():
if (p.codename.startswith('add') or
p.codename.startswith('delete') or
@ -51,7 +22,7 @@ def html_strong(string):
"""
Returns the text wrapped in an HTML-Strong element.
"""
return u"<strong>%s</strong>" % string
return "<strong>%s</strong>" % string
def htmldiff(text1, text2):

View File

@ -33,7 +33,7 @@ class LoginMixin(object):
"""
Check if the user is loged in.
"""
return super(LoginMixin, self).dispatch(request, *args, **kwargs)
return super().dispatch(request, *args, **kwargs)
class PermissionMixin(object):
@ -68,7 +68,7 @@ class PermissionMixin(object):
"%s?next=%s" % (settings.LOGIN_URL, path))
else:
raise PermissionDenied
return super(PermissionMixin, self).dispatch(request, *args, **kwargs)
return super().dispatch(request, *args, **kwargs)
class AjaxMixin(object):
@ -103,7 +103,7 @@ class ExtraContextMixin(object):
"""
context = super(ExtraContextMixin, self).get_context_data(**kwargs)
template_manipulation.send(
sender=self.__class__, request=self.request, context=context)
sender=type(self), request=self.request, context=context)
return context
@ -130,11 +130,13 @@ class UrlMixin(object):
elif url:
value = url
else:
try:
if use_absolute_url_link is None:
value = self.object.get_absolute_url()
get_absolute_url_args = []
else:
value = self.object.get_absolute_url(use_absolute_url_link)
get_absolute_url_args = [use_absolute_url_link]
try:
value = self.object.get_absolute_url(*get_absolute_url_args)
except AttributeError:
raise ImproperlyConfigured(
'No url to redirect to. See openslides.utils.views.UrlMixin '
@ -155,10 +157,7 @@ class UrlMixin(object):
except AttributeError:
value = []
else:
if pk:
value = [pk]
else:
value = []
value = [pk] if pk else []
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.users.models import User
from openslides.utils.test import TestCase
from openslides.config.api import config
class CSVImport(TestCase):
@ -20,6 +21,9 @@ class CSVImport(TestCase):
Category.objects.create(name='Bildung', prefix='B2')
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',
password='iegheeChaje7guthie4a',
first_name='Harry',
@ -31,7 +35,7 @@ class CSVImport(TestCase):
first_name='John',
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)
with open(csv_dir + '/motions-demo_de.csv', 'rb') as f:
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
@override_settings(INSTALLED_PLUGINS=('tests.plugin_api.test_plugin_one',))
@override_settings(INSTALLED_PLUGINS=('tests.old.plugin_api.test_plugin_one',))
class TestPluginOne(TestCase):
def setUp(self):
self.admin_client = Client()
@ -27,11 +27,11 @@ class TestPluginOne(TestCase):
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):
def test_version_page(self):
admin_client = Client()
admin_client.login(username='admin', password='admin')
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')

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):
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'))
self.assertEqual(match[0], 'admins_first_name Administrator')
self.assertEqual(match[1], 'aWei4ien6Se0vie0xeiv uquahx3Wohtieph9baer')
self.assertEqual(match[0], 'Administrator, admins_first_name')
self.assertEqual(match[1], 'uquahx3Wohtieph9baer, aWei4ien6Se0vie0xeiv')
config['users_sort_users_by_first_name'] = True
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):
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):
TestBaseOne.get_all(self.request_factory.request)
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):
class TestChildOne(TestBaseOne):
pass

View File

@ -6,20 +6,18 @@ 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.
# Use 'DEBUG = True' to get more details for server errors.
# SECURITY WARNING: Don't run with debug turned on in production!
DEBUG = True
TEMPLATE_DEBUG = DEBUG
INSTALLED_PLUGINS += (
'tests.old.utils',
)
INSTALLED_APPS += INSTALLED_PLUGINS
@ -31,7 +29,6 @@ INSTALLED_APPS += INSTALLED_PLUGINS
DATABASES = {
'default': {
'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
class Test_functions(TestCase):
def test_string(self):
def test_html_strong(self):
self.assertEqual(html_strong('some text'), '<strong>some text</strong>')
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()