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:
parent
ea45469338
commit
e7230b7391
10
.travis.yml
10
.travis.yml
@ -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"
|
||||
|
@ -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')
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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'
|
||||
|
@ -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')
|
||||
|
@ -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):
|
||||
"""
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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(),
|
||||
|
@ -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()
|
||||
|
@ -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.
|
||||
|
@ -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):
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
14
tests/integration/users/test_views.py
Normal file
14
tests/integration/users/test_views.py
Normal 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)
|
@ -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(
|
@ -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')
|
0
tests/old/projector/__init__.py
Normal file
0
tests/old/projector/__init__.py
Normal file
56
tests/old/settings.py
Normal file
56
tests/old/settings.py
Normal 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',
|
||||
)
|
0
tests/old/users/__init__.py
Normal file
0
tests/old/users/__init__.py
Normal 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'])
|
0
tests/old/utils/__init__.py
Normal file
0
tests/old/utils/__init__.py
Normal 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
|
@ -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
0
tests/unit/__init__.py
Normal file
0
tests/unit/users/__init__.py
Normal file
0
tests/unit/users/__init__.py
Normal file
184
tests/unit/users/test_api.py
Normal file
184
tests/unit/users/test_api.py
Normal 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")
|
140
tests/unit/users/test_auth.py
Normal file
140
tests/unit/users/test_auth.py
Normal 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})
|
312
tests/unit/users/test_models.py
Normal file
312
tests/unit/users/test_models.py
Normal 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")
|
0
tests/unit/utils/__init__.py
Normal file
0
tests/unit/utils/__init__.py
Normal file
16
tests/unit/utils/test_models.py
Normal file
16
tests/unit/utils/test_models.py
Normal 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')
|
@ -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):
|
318
tests/unit/utils/test_views.py
Normal file
318
tests/unit/utils/test_views.py
Normal 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")
|
@ -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)
|
@ -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('äöü', 'ßüäö'), 'äöü ßüäö')
|
@ -1,5 +0,0 @@
|
||||
<html>
|
||||
<body>
|
||||
{{ object.title }}
|
||||
</body>
|
||||
</html>
|
@ -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')
|
@ -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'})
|
@ -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')),
|
||||
)
|
@ -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()
|
Loading…
Reference in New Issue
Block a user