From c39f09709b8cbc92717bc2ef8be56846fab143f3 Mon Sep 17 00:00:00 2001 From: Jens Kleineheismann Date: Tue, 12 Mar 2019 18:13:45 +0100 Subject: [PATCH] UPD: dav_auth: tests! --- dav_auth/tests/__init__.py | 0 dav_auth/tests/test_apps.py | 15 +++ dav_auth/tests/test_emails.py | 30 +++++ dav_auth/tests/test_forms.py | 182 ++++++++++++++++++++++++++ dav_auth/tests/test_screenshots.py | 19 +++ dav_auth/tests/test_templates.py | 14 ++ dav_auth/tests/test_urls.py | 13 ++ dav_auth/tests/test_views.py | 199 +++++++++++++++++++++++++++++ 8 files changed, 472 insertions(+) create mode 100644 dav_auth/tests/__init__.py create mode 100644 dav_auth/tests/test_apps.py create mode 100644 dav_auth/tests/test_emails.py create mode 100644 dav_auth/tests/test_forms.py create mode 100644 dav_auth/tests/test_screenshots.py create mode 100644 dav_auth/tests/test_templates.py create mode 100644 dav_auth/tests/test_urls.py create mode 100644 dav_auth/tests/test_views.py diff --git a/dav_auth/tests/__init__.py b/dav_auth/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/dav_auth/tests/test_apps.py b/dav_auth/tests/test_apps.py new file mode 100644 index 0000000..3fcdda2 --- /dev/null +++ b/dav_auth/tests/test_apps.py @@ -0,0 +1,15 @@ +from django.apps import apps +from django.test import SimpleTestCase + + +class AppsTestCase(SimpleTestCase): + def setUp(self): + app_config = apps.get_containing_app_config(__package__) + self.settings = app_config.settings + + def test_settings(self): + setting_names = ('login_redirect_url', + 'logout_redirect_url') + + for s in setting_names: + self.assertTrue(hasattr(self.settings, s), 'Settings do not contain {}'.format(s)) diff --git a/dav_auth/tests/test_emails.py b/dav_auth/tests/test_emails.py new file mode 100644 index 0000000..1dda6c4 --- /dev/null +++ b/dav_auth/tests/test_emails.py @@ -0,0 +1,30 @@ +from django.contrib.auth import get_user_model +from django.core import mail as django_mail +from django.test import TestCase + +from ..emails import PasswordSetEmail + + +TEST_USERNAME = 'user' +TEST_PASSWORD = 'mellon12' +TEST_EMAIL = 'root@localhost' + + +class EmailsTestCase(TestCase): + def setUp(self): + model = get_user_model() + self.user = model.objects.create_user(username=TEST_USERNAME, password=TEST_PASSWORD, email=TEST_EMAIL) + + def test_send(self): + password = TEST_PASSWORD[::-1] + + email = PasswordSetEmail(self.user, password) + email.send() + + self.assertEqual(len(django_mail.outbox), 1) + mail = django_mail.outbox[0] + recipient = '%s <%s>' % (self.user.get_full_name(), self.user.email) + recipients = mail.recipients() + self.assertIn(recipient, recipients) + self.assertEqual(len(recipients), 1) + self.assertIn(password, mail.body) diff --git a/dav_auth/tests/test_forms.py b/dav_auth/tests/test_forms.py new file mode 100644 index 0000000..f3924b7 --- /dev/null +++ b/dav_auth/tests/test_forms.py @@ -0,0 +1,182 @@ +# -*- coding: utf-8 -*- +from unittest import skip +from django.contrib.auth import get_user_model +from django.core import mail as django_mail + +from dav_base.tests.generic import FormDataSet, FormsTestCase + +from ..forms import LoginForm, SetPasswordForm, ResetPasswordForm + +TEST_USERNAME = 'root@localhost' +TEST_PASSWORD = 'mellon12' +TEST_EMAIL = TEST_USERNAME + + +class LoginFormTestCase(FormsTestCase): + form_class = LoginForm + + def setUp(self): + # Need a test user + self.test_username = TEST_USERNAME + self.test_password = TEST_PASSWORD + model = get_user_model() + self.user = model.objects.create_user(username=TEST_USERNAME, password=TEST_PASSWORD, email=TEST_EMAIL) + + def test_login_username_empty(self): + data_sets = [ + FormDataSet({'username': '', 'password': self.test_password}, + expected_errors=[('username', 'required')]), + ] + super(LoginFormTestCase, self).test_invalid_data(data_sets=data_sets) + + def test_login_password_empty(self): + data_sets = [ + FormDataSet({'username': self.test_username, 'password': ''}, + expected_errors=[('password', 'required')]), + ] + super(LoginFormTestCase, self).test_invalid_data(data_sets=data_sets) + + def test_login_username_too_long(self): + data_sets = [ + FormDataSet({'username': 'u' * 255, 'password': self.test_password}, + expected_errors=[('username', 'max_length')]), + ] + super(LoginFormTestCase, self).test_invalid_data(data_sets=data_sets) + + def test_login_invalid_username(self): + data_sets = [ + FormDataSet({'username': self.test_username[::-1], 'password': self.test_password}, + expected_errors=[('__all__', 'invalid_login')]), + ] + super(LoginFormTestCase, self).test_invalid_data(data_sets=data_sets) + + def test_login_invalid_password(self): + data_sets = [ + FormDataSet({'username': self.test_username, 'password': self.test_password[::-1]}, + expected_errors=[('__all__', 'invalid_login')]), + ] + super(LoginFormTestCase, self).test_invalid_data(data_sets=data_sets) + + def test_login_inactive_user(self): + self.user.is_active = False + self.user.save() + data_sets = [ + FormDataSet({'username': self.test_username, 'password': self.test_password}, + expected_errors=[('__all__', 'invalid_login')]), + ] + super(LoginFormTestCase, self).test_invalid_data(data_sets=data_sets) + + def test_login_valid_credentials(self): + data_sets = [ + FormDataSet({'username': self.test_username, 'password': self.test_password}), + ] + super(LoginFormTestCase, self).test_valid_data(data_sets=data_sets) + + +class SetPasswordFormTestCase(FormsTestCase): + form_class = SetPasswordForm + + def setUp(self): + # Need a test user + self.test_username = TEST_USERNAME + self.test_password = TEST_PASSWORD + model = get_user_model() + self.user = model.objects.create_user(username=TEST_USERNAME, password=TEST_PASSWORD, email=TEST_EMAIL) + + def test_set_password_mismatch(self): + data_sets = [ + FormDataSet({'new_password': 'mellon12', 'new_password_repeat': 'mellon13'}, + [('new_password_repeat', 'password_mismatch')]), + ] + super(SetPasswordFormTestCase, self).test_invalid_data(data_sets=data_sets, form_kwargs={'user': self.user}) + + def test_set_password_empty(self): + data_sets = [ + FormDataSet({'new_password': '', 'new_password_repeat': ''}, + [('new_password', 'required')]), + ] + super(SetPasswordFormTestCase, self).test_invalid_data(data_sets=data_sets, form_kwargs={'user': self.user}) + + def test_set_password_too_short(self): + data_sets = [ + FormDataSet({'new_password': 'mellon', 'new_password_repeat': 'mellon'}, + [('new_password', 'password_too_short')]), + ] + super(SetPasswordFormTestCase, self).test_invalid_data(data_sets=data_sets, form_kwargs={'user': self.user}) + + def test_set_password_entirely_numeric(self): + data_sets = [ + FormDataSet({'new_password': '1357924680', 'new_password_repeat': '1357924680'}, + [('new_password', 'password_entirely_numeric')]), + ] + super(SetPasswordFormTestCase, self).test_invalid_data(data_sets=data_sets, form_kwargs={'user': self.user}) + + def test_set_password_too_similar(self): + data_sets = [ + FormDataSet({'new_password': self.test_username, 'new_password_repeat': self.test_username}, + [('new_password', 'password_too_similar')]), + ] + super(SetPasswordFormTestCase, self).test_invalid_data(data_sets=data_sets, form_kwargs={'user': self.user}) + + def test_set_password_too_common(self): + data_sets = [ + FormDataSet({'new_password': 'password', 'new_password_repeat': 'password'}, + [('new_password', 'password_too_common')]), + ] + super(SetPasswordFormTestCase, self).test_invalid_data(data_sets=data_sets, form_kwargs={'user': self.user}) + + def test_set_password_valid(self): + data_sets = [ + FormDataSet({'new_password': 'mellon12', 'new_password_repeat': 'mellon12'}), + FormDataSet({'new_password': 'mellon12', 'new_password_repeat': 'mellon12', 'send_password_mail': True}), + FormDataSet({'new_password': u'"ä§ Mellon12', 'new_password_repeat': u'"ä§ Mellon12'}), + FormDataSet({'new_password': 'mellon12' * 128, 'new_password_repeat': 'mellon12' * 128}), + ] + super(SetPasswordFormTestCase, self).test_valid_data(data_sets=data_sets, form_kwargs={'user': self.user}) + + def test_set_password_save(self): + new_passwords = [ + u'"ä§ Mellon12' + 'mellon12' * 128, + ] + + for new_password in new_passwords: + data = {'new_password': new_password, 'new_password_repeat': new_password} + form = SetPasswordForm(data=data, user=self.user) + self.assertTrue(form.is_valid()) + form.save() + self.assertEqual(len(django_mail.outbox), 0) + self.assertTrue(self.client.login(username=self.test_username, password=new_password)) + + @skip('Function is implemented in SetPasswordView instead of SetPasswordForm') + def test_set_password_save_with_mail(self): + new_passwords = [ + u'"ä§ Mellon12' + 'mellon12' * 128, + ] + + for new_password in new_passwords: + data = {'new_password': new_password, 'new_password_repeat': new_password, 'send_password_mail': True} + form = SetPasswordForm(data=data, user=self.user) + self.assertTrue(form.is_valid()) + form.save() + self.assertEqual(len(django_mail.outbox), 1) + mail = django_mail.outbox[0] + recipient = '%s <%s>' % (self.user.get_full_name(), self.user.email) + recipients = mail.recipients() + self.assertIn(recipient, recipients) + self.assertEqual(len(recipients), 1) + self.assertIn(new_password, mail.body) + self.assertTrue(self.client.login(username=self.test_username, password=new_password)) + + +class ResetPasswordFormTestCase(FormsTestCase): + form_class = ResetPasswordForm + + valid_data_sets = ( + FormDataSet({'username': 'unittest@example.com'}), + ) + invalid_data_sets = ( + FormDataSet({'username': ''}, expected_errors=[('username', 'required')]), + FormDataSet({'username': 'u' * 255}, expected_errors=[('username', 'max_length')]), + ) diff --git a/dav_auth/tests/test_screenshots.py b/dav_auth/tests/test_screenshots.py new file mode 100644 index 0000000..77d306b --- /dev/null +++ b/dav_auth/tests/test_screenshots.py @@ -0,0 +1,19 @@ +from django.test import tag +from django.urls import reverse +from selenium.webdriver.common.keys import Keys + +from dav_base.tests.generic import skip_unless_tag_option, ScreenshotTestCase + + +#@skip_unless_tag_option() +#@tag('screenshots') +class TestCase(ScreenshotTestCase): + def test_some(self): + c = self.selenium + c.get(self.complete_url('/')) + link = c.find_element_by_css_selector('#login-widget a') + link.click() + self.save_screenshot('login-form') + link = c.find_element_by_link_text('Passwort vergessen?') + link.click() + self.save_screenshot('reset-password-form') diff --git a/dav_auth/tests/test_templates.py b/dav_auth/tests/test_templates.py new file mode 100644 index 0000000..15cf643 --- /dev/null +++ b/dav_auth/tests/test_templates.py @@ -0,0 +1,14 @@ +# -*- coding: utf-8 -*- +from django.test import SimpleTestCase +from django.utils.translation import ugettext +from django.urls import reverse + + +class TemplatesTestCase(SimpleTestCase): + def test_reset_link_in_login_form(self): + login_url = reverse('dav_auth:login') + reset_url = reverse('dav_auth:reset_password') + text = ugettext(u'Passwort vergessen?') + html = u'{text}'.format(url=reset_url, text=text) + response = self.client.get(login_url) + self.assertInHTML(html, response.content) diff --git a/dav_auth/tests/test_urls.py b/dav_auth/tests/test_urls.py new file mode 100644 index 0000000..dcd2259 --- /dev/null +++ b/dav_auth/tests/test_urls.py @@ -0,0 +1,13 @@ +from dav_base.tests.generic import Url, UrlsTestCase + +from .. import views + + +class TestCase(UrlsTestCase): + urls = ( + Url('/auth/login', 'dav_auth:login', views.LoginView.as_view()), + Url('/auth/logout', 'dav_auth:logout', views.LogoutView.as_view(), status_code=302), + Url('/auth/password', 'dav_auth:set_password', views.SetPasswordView.as_view(), + redirect='/auth/login?next=/auth/password'), + Url('/auth/password/reset', 'dav_auth:reset_password', views.ResetPasswordView.as_view()), + ) diff --git a/dav_auth/tests/test_views.py b/dav_auth/tests/test_views.py new file mode 100644 index 0000000..5fb115a --- /dev/null +++ b/dav_auth/tests/test_views.py @@ -0,0 +1,199 @@ +from django.apps import apps +from django.contrib.auth import get_user_model +from django.core import mail as django_mail +from django.shortcuts import resolve_url +from django.test import TestCase +from django.utils.translation import ugettext +from django.urls import reverse + +from ..forms import LoginForm, SetPasswordForm, ResetPasswordForm + +TEST_USERNAME = 'root@localhost' +TEST_PASSWORD = 'mellon12' +TEST_EMAIL = TEST_USERNAME + + +class ViewsTestCase(TestCase): + @classmethod + def setUpClass(cls): + super(ViewsTestCase, cls).setUpClass() + + cls.app_settings = apps.get_containing_app_config(__package__).settings + + # Some locations + cls.login_url = reverse('dav_auth:login') + cls.login_redirect_url = resolve_url(cls.app_settings.login_redirect_url) + cls.logout_url = reverse('dav_auth:logout') + cls.logout_redirect_url = resolve_url(cls.app_settings.logout_redirect_url) + cls.set_password_url = reverse('dav_auth:set_password') + cls.reset_password_url = reverse('dav_auth:reset_password') + + # Some messages + cls.wrong_credentials_message = ugettext(u'Benutzername oder Passwort falsch.') + cls.logout_message = ugettext(u'Benutzer abgemeldet.') + cls.set_password_message = ugettext(u'Passwort gespeichert.') + + def setUp(self): + # Need a test user + self.test_username = TEST_USERNAME + self.test_password = TEST_PASSWORD + model = get_user_model() + self.user = model.objects.create_user(username=TEST_USERNAME, password=TEST_PASSWORD, email=TEST_EMAIL) + + def test_integrated_login_get(self): + response = self.client.get(self.login_url) + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'dav_auth/forms/login.html') + self.assertIn('form', response.context) + self.assertIsInstance(response.context['form'], LoginForm) + + def test_integrated_login_inactive_user(self): + user = self.user + user.is_active = False + user.save() + + response = self.client.post(self.login_url, {'username': self.test_username, 'password': self.test_password}) + self.assertEqual(response.status_code, 200) + self.assertFormError(response, 'form', None, self.wrong_credentials_message) + self.assertFalse(response.context['user'].is_authenticated, 'User is logged in') + + def test_integrated_login_fail_with_wrong_credentials(self): + wrong_password = self.test_password[::-1] + + response = self.client.post(self.login_url, {'username': self.test_username, 'password': wrong_password}) + self.assertEqual(response.status_code, 200) + self.assertFormError(response, 'form', None, self.wrong_credentials_message) + self.assertFalse(response.context['user'].is_authenticated, 'User is logged in') + + def test_integrated_login_succeed(self): + username = self.user.username + message = ugettext(u'Benutzer angemeldet: %(username)s') % {'username': username} + + response = self.client.post(self.login_url, {'username': username, 'password': self.test_password}) + self.assertEqual(response.status_code, 302) + self.assertEqual(response.url, self.login_redirect_url) + + response = self.client.get(response.url) + self.assertContains(response, message) + + self.assertTrue(response.context['user'].is_authenticated, 'Login failed') + + def test_integrated_logout(self): + self.client.login(username=self.test_username, password=self.test_password) + + response = self.client.get(self.logout_url) + self.assertEqual(response.status_code, 302) + self.assertEqual(response.url, self.logout_redirect_url) + + response = self.client.get(response.url) + self.assertContains(response, self.logout_message) + + self.assertFalse(response.context['user'].is_authenticated, 'Logout failed') + + def test_integrated_set_password_unauth_get_redirect_to_login(self): + location = self.set_password_url + redirect_to = '%s?next=%s' % (self.login_url, location) + + response = self.client.get(location) + self.assertRedirects(response, redirect_to) + + def test_integrated_set_password_unauth_post_redirect_to_login(self): + location = self.set_password_url + redirect_to = '%s?next=%s' % (self.login_url, location) + changed_password = self.test_password[::-1] + + response = self.client.post(location, {'new_password': changed_password, + 'new_password_repeat': changed_password}) + self.assertRedirects(response, redirect_to) + + def test_integrated_set_password_get(self): + location = self.set_password_url + username = self.test_username + password = self.test_password + + self.client.login(username=username, password=password) + + response = self.client.get(location) + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'dav_auth/forms/set_password.html') + self.assertIn('form', response.context) + self.assertIsInstance(response.context['form'], SetPasswordForm) + + def test_integrated_set_password_post(self): + location = self.set_password_url + username = self.test_username + password = self.test_password + new_password = password * 8 + + self.client.login(username=username, password=password) + + response = self.client.post(location, {'new_password': new_password, + 'new_password_repeat': new_password}) + self.assertEqual(response.status_code, 302) + self.assertEqual(response.url, self.login_redirect_url) + + self.assertEqual(len(django_mail.outbox), 0) + + response = self.client.get(response.url) + self.assertContains(response, self.set_password_message) + + self.client.logout() + self.assertFalse(self.client.login(username=username, password=password), 'Old password still valid') + self.assertTrue(self.client.login(username=username, password=new_password), 'New password not valid') + + # TODO + # maybe we should test also: + # - new password does no match new password repeat + # - new password is not suitable + + def test_integrated_set_password_with_mail(self): + location = self.set_password_url + username = self.test_username + password = self.test_password + new_password = password * 8 + + self.client.login(username=username, password=password) + + response = self.client.post(location, {'new_password': new_password, + 'new_password_repeat': new_password, + 'send_password_mail': True}) + self.assertEqual(len(django_mail.outbox), 1) + mail = django_mail.outbox[0] + recipient = '%s <%s>' % (self.user.get_full_name(), self.user.email) + recipients = mail.recipients() + self.assertIn(recipient, recipients) + self.assertEqual(len(recipients), 1) + self.assertIn(new_password, mail.body) + + response = self.client.get(response.url) + self.assertContains(response, self.set_password_message) + + self.client.logout() + self.assertFalse(self.client.login(username=username, password=password), 'Old password still valid') + self.assertTrue(self.client.login(username=username, password=new_password), 'New password not valid') + + def test_reset_password_integrated_get(self): + response = self.client.get(self.reset_password_url) + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'dav_auth/forms/reset_password.html') + self.assertIn('form', response.context) + self.assertIsInstance(response.context['form'], ResetPasswordForm) + + def test_reset_password_integrated_post(self): + location = self.reset_password_url + + response = self.client.post(location, {'username': self.user.username}) + self.assertRedirects(response, self.login_url) + + self.assertEqual(len(django_mail.outbox), 1) + mail = django_mail.outbox[0] + recipient = '%s <%s>' % (self.user.get_full_name(), self.user.email) + recipients = mail.recipients() + self.assertIn(recipient, recipients) + self.assertEqual(len(recipients), 1) + + response = self.client.get(location) + self.assertFalse(response.context['user'].is_authenticated, 'User is logged in') + + self.assertFalse(self.client.login(username=self.test_username, password=self.test_password), + 'Old password still valid')