From 64b90c50778caf073f9ec2ba1fcb3c5a332c8c4e Mon Sep 17 00:00:00 2001 From: Valentin Samir Date: Sat, 25 Jun 2016 11:09:46 +0200 Subject: [PATCH] Use django integrated unit tests --- requirements-dev.txt | 1 + run_tests | 22 +++++ settings_tests.py | 83 +++++++++++++++++ tests/__init__.py | 0 tests/dummy.py | 136 --------------------------- tests/init.py | 32 ------- tests/test_proxy.py | 52 ----------- tests/test_validate_service.py | 87 ------------------ tests/test_views_auth.py | 46 ---------- tests/test_views_login.py | 163 --------------------------------- tests/test_views_logout.py | 80 ---------------- tests/test_views_validate.py | 58 ------------ tox.ini | 2 +- 13 files changed, 107 insertions(+), 655 deletions(-) create mode 100755 run_tests create mode 100644 settings_tests.py delete mode 100644 tests/__init__.py delete mode 100644 tests/dummy.py delete mode 100644 tests/init.py delete mode 100644 tests/test_proxy.py delete mode 100644 tests/test_validate_service.py delete mode 100644 tests/test_views_auth.py delete mode 100644 tests/test_views_login.py delete mode 100644 tests/test_views_logout.py delete mode 100644 tests/test_views_validate.py diff --git a/requirements-dev.txt b/requirements-dev.txt index 9998ce7..e6ef993 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -7,3 +7,4 @@ django-picklefield>=0.3.1 requests_futures>=0.9.5 django-bootstrap3>=5.4 lxml>=3.4 +six>=1 diff --git a/run_tests b/run_tests new file mode 100755 index 0000000..4ea21ee --- /dev/null +++ b/run_tests @@ -0,0 +1,22 @@ +#!/usr/bin/env python +import os, sys +import django +from django.conf import settings + +import settings_tests + +settings.configure(**settings_tests.__dict__) +django.setup() + +try: + # Django <= 1.8 + from django.test.simple import DjangoTestSuiteRunner + test_runner = DjangoTestSuiteRunner(verbosity=1) +except ImportError: + # Django >= 1.8 + from django.test.runner import DiscoverRunner + test_runner = DiscoverRunner(verbosity=1) + +failures = test_runner.run_tests(['cas_server']) +if failures: + sys.exit(failures) diff --git a/settings_tests.py b/settings_tests.py new file mode 100644 index 0000000..4588c2c --- /dev/null +++ b/settings_tests.py @@ -0,0 +1,83 @@ +""" +Django test settings for cas_server application. + +Generated by 'django-admin startproject' using Django 1.9.7. + +For more information on this file, see +https://docs.djangoproject.com/en/1.9/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/1.9/ref/settings/ +""" + +import os + +# Build paths inside the project like this: os.path.join(BASE_DIR, ...) +BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/1.9/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = 'changeme' + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = [] + + +# Application definition + +INSTALLED_APPS = [ + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'bootstrap3', + 'cas_server', +] + +MIDDLEWARE_CLASSES = [ + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.auth.middleware.SessionAuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', + 'django.middleware.locale.LocaleMiddleware', +] + +ROOT_URLCONF = 'cas_server.urls' + +# Database +# https://docs.djangoproject.com/en/1.9/ref/settings/#databases + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + } +} + +# Internationalization +# https://docs.djangoproject.com/en/1.9/topics/i18n/ + +LANGUAGE_CODE = 'en-us' + +TIME_ZONE = 'UTC' + +USE_I18N = True + +USE_L10N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/1.9/howto/static-files/ + +STATIC_URL = '/static/' diff --git a/tests/__init__.py b/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/tests/dummy.py b/tests/dummy.py deleted file mode 100644 index 8266d7b..0000000 --- a/tests/dummy.py +++ /dev/null @@ -1,136 +0,0 @@ -import functools -from cas_server import models - -class DummyUserManager(object): - def __init__(self, username, session_key): - self.username = username - self.session_key = session_key - def get(self, username=None, session_key=None): - if username == self.username and session_key == self.session_key: - return models.User(username=username, session_key=session_key) - else: - raise models.User.DoesNotExist() - - -def dummy(*args, **kwds): - pass - -def dummy_service_pattern(**kwargs): - def decorator(func): - @functools.wraps(func) - def wrapper(*args, **kwds): - service_validate = models.ServicePattern.validate - models.ServicePattern.validate = classmethod(lambda x,y: models.ServicePattern(**kwargs)) - ret = func(*args, **kwds) - models.ServicePattern.validate = service_validate - return ret - return wrapper - return decorator - -def dummy_user(username, session_key): - def decorator(func): - @functools.wraps(func) - def wrapper(*args, **kwds): - user_manager = models.User.objects - user_save = models.User.save - user_delete = models.User.delete - models.User.objects = DummyUserManager(username, session_key) - models.User.save = dummy - models.User.delete = dummy - ret = func(*args, **kwds) - models.User.objects = user_manager - models.User.save = user_save - models.User.delete = user_delete - return ret - return wrapper - return decorator - -def dummy_ticket(ticket_class, service, ticket): - def decorator(func): - @functools.wraps(func) - def wrapper(*args, **kwds): - ticket_manager = ticket_class.objects - ticket_save = ticket_class.save - ticket_delete = ticket_class.delete - ticket_class.objects = DummyTicketManager(ticket_class, service, ticket) - ticket_class.save = dummy - ticket_class.delete = dummy - ret = func(*args, **kwds) - ticket_class.objects = ticket_manager - ticket_class.save = ticket_save - ticket_class.delete = ticket_delete - return ret - return wrapper - return decorator - - -def dummy_proxy(func): - @functools.wraps(func) - def wrapper(*args, **kwds): - proxy_manager = models.Proxy.objects - models.Proxy.objects = DummyProxyManager() - ret = func(*args, **kwds) - models.Proxy.objects = proxy_manager - return ret - return wrapper - -class DummyProxyManager(object): - def create(self, **kwargs): - for field in models.Proxy._meta.fields: - field.allow_unsaved_instance_assignment = True - return models.Proxy(**kwargs) - -class DummyTicketManager(object): - def __init__(self, ticket_class, service, ticket): - self.ticket_class = ticket_class - self.service = service - self.ticket = ticket - - def create(self, **kwargs): - for field in self.ticket_class._meta.fields: - field.allow_unsaved_instance_assignment = True - return self.ticket_class(**kwargs) - - def filter(self, *args, **kwargs): - return DummyQuerySet() - - def get(self, **kwargs): - for field in self.ticket_class._meta.fields: - field.allow_unsaved_instance_assignment = True - if 'value' in kwargs: - if kwargs['value'] != self.ticket: - raise self.ticket_class.DoesNotExist() - else: - kwargs['value'] = self.ticket - - if 'service' in kwargs: - if kwargs['service'] != self.service: - raise self.ticket_class.DoesNotExist() - else: - kwargs['service'] = self.service - if not 'user' in kwargs: - kwargs['user'] = models.User(username="test") - - for field in models.ServiceTicket._meta.fields: - field.allow_unsaved_instance_assignment = True - for key in list(kwargs): - if '__' in key: - del kwargs[key] - kwargs['attributs'] = {'mail': 'test@example.com'} - kwargs['service_pattern'] = models.ServicePattern() - return self.ticket_class(**kwargs) - - - -class DummySession(dict): - session_key = "test_session" - - def set_expiry(self, int): - pass - - def flush(self): - self.clear() - - -class DummyQuerySet(set): - pass diff --git a/tests/init.py b/tests/init.py deleted file mode 100644 index f6ede9e..0000000 --- a/tests/init.py +++ /dev/null @@ -1,32 +0,0 @@ -import django -from django.conf import settings -from django.contrib import messages - -settings.configure() -settings.STATIC_URL = "/static/" -settings.DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.sqlite3', - 'NAME': '/dev/null', - } -} -settings.INSTALLED_APPS = ( - 'django.contrib.admin', - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.messages', - 'django.contrib.staticfiles', - 'bootstrap3', - 'cas_server', -) - -settings.ROOT_URLCONF = "/" -settings.CAS_AUTH_CLASS = 'cas_server.auth.TestAuthUser' - -try: - django.setup() -except AttributeError: - pass -messages.add_message = lambda x,y,z:None - diff --git a/tests/test_proxy.py b/tests/test_proxy.py deleted file mode 100644 index 963d834..0000000 --- a/tests/test_proxy.py +++ /dev/null @@ -1,52 +0,0 @@ -from __future__ import absolute_import -from tests.init import * - -from django.test import RequestFactory - -import os -import pytest -from lxml import etree -from cas_server.views import ValidateService, Proxy -from cas_server import models - -from tests.dummy import * - -@pytest.mark.django_db -@dummy_ticket(models.ProxyGrantingTicket, '', "PGT-random") -@dummy_service_pattern(proxy=True) -@dummy_user(username="test", session_key="test_session") -@dummy_ticket(models.ProxyTicket, "https://www.example.com", "PT-random") -@dummy_proxy -def test_proxy_ok(): - factory = RequestFactory() - request = factory.get('/proxy?pgt=PGT-random&targetService=https://www.example.com') - - request.session = DummySession() - - proxy = Proxy() - response = proxy.get(request) - - assert response.status_code == 200 - - root = etree.fromstring(response.content) - proxy_tickets = root.xpath("//cas:proxyTicket", namespaces={'cas': "http://www.yale.edu/tp/cas"}) - - assert len(proxy_tickets) == 1 - - factory = RequestFactory() - request = factory.get('/proxyValidate?ticket=PT-random&service=https://www.example.com') - - validate = ValidateService() - validate.allow_proxy_ticket = True - response = validate.get(request) - - assert response.status_code == 200 - - root = etree.fromstring(response.content) - users = root.xpath("//cas:user", namespaces={'cas': "http://www.yale.edu/tp/cas"}) - - assert len(users) == 1 - assert users[0].text == "test" - - - diff --git a/tests/test_validate_service.py b/tests/test_validate_service.py deleted file mode 100644 index 940e23b..0000000 --- a/tests/test_validate_service.py +++ /dev/null @@ -1,87 +0,0 @@ -from __future__ import absolute_import -from .init import * - -from django.test import RequestFactory - -import os -import pytest -from lxml import etree -from cas_server.views import ValidateService -from cas_server import models - -from .dummy import * - -@pytest.mark.django_db -@dummy_ticket(models.ServiceTicket, 'https://www.example.com', "ST-random") -def test_validate_service_view_ok(): - factory = RequestFactory() - request = factory.get('/serviceValidate?ticket=ST-random&service=https://www.example.com') - - request.session = DummySession() - - validate = ValidateService() - validate.allow_proxy_ticket = False - response = validate.get(request) - - assert response.status_code == 200 - - root = etree.fromstring(response.content) - users = root.xpath("//cas:user", namespaces={'cas': "http://www.yale.edu/tp/cas"}) - - assert len(users) == 1 - assert users[0].text == "test" - - attributes = root.xpath("//cas:attributes", namespaces={'cas': "http://www.yale.edu/tp/cas"}) - - assert len(attributes) == 1 - - attrs = {} - for attr in attributes[0]: - attrs[attr.tag[len("http://www.yale.edu/tp/cas")+2:]]=attr.text - - assert 'mail' in attrs - assert attrs['mail'] == 'test@example.com' - - - -@pytest.mark.django_db -@dummy_ticket(models.ServiceTicket, 'https://www.example2.com', "ST-random") -def test_validate_service_view_badservice(): - factory = RequestFactory() - request = factory.get('/serviceValidate?ticket=ST-random&service=https://www.example1.com') - - request.session = DummySession() - - validate = ValidateService() - validate.allow_proxy_ticket = False - response = validate.get(request) - - assert response.status_code == 200 - - root = etree.fromstring(response.content) - - error = root.xpath("//cas:authenticationFailure", namespaces={'cas': "http://www.yale.edu/tp/cas"}) - - assert len(error) == 1 - assert error[0].attrib['code'] == 'INVALID_SERVICE' - -@pytest.mark.django_db -@dummy_ticket(models.ServiceTicket, 'https://www.example.com', "ST-random2") -def test_validate_service_view_badticket(): - factory = RequestFactory() - request = factory.get('/serviceValidate?ticket=ST-random1&service=https://www.example.com') - - request.session = DummySession() - - validate = ValidateService() - validate.allow_proxy_ticket = False - response = validate.get(request) - - assert response.status_code == 200 - - root = etree.fromstring(response.content) - - error = root.xpath("//cas:authenticationFailure", namespaces={'cas': "http://www.yale.edu/tp/cas"}) - - assert len(error) == 1 - assert error[0].attrib['code'] == 'INVALID_TICKET' diff --git a/tests/test_views_auth.py b/tests/test_views_auth.py deleted file mode 100644 index 4b4a9eb..0000000 --- a/tests/test_views_auth.py +++ /dev/null @@ -1,46 +0,0 @@ -from __future__ import absolute_import -from .init import * - -from django.test import RequestFactory - -import os -import pytest - -from cas_server.views import Auth -from cas_server import models - -from .dummy import * - -settings.CAS_AUTH_SHARED_SECRET = "test" - -@pytest.mark.django_db -@dummy_ticket(models.ServiceTicket, 'https://www.example.com', "ST-random") -@dummy_user(username="test", session_key="test_session") -@dummy_service_pattern() -def test_auth_view_goodpass(): - factory = RequestFactory() - request = factory.post('/auth', {'username':'test', 'password':'test', 'service':'https://www.example.com', 'secret':'test'}) - - request.session = DummySession() - - auth = Auth() - response = auth.post(request) - - assert response.status_code == 200 - assert response.content == b"yes\n" - -@dummy_service_pattern() -@dummy_ticket(models.ServiceTicket, 'https://www.example.com', "ST-random") -@dummy_user(username="test", session_key="test_session") -def test_auth_view_badpass(): - factory = RequestFactory() - request = factory.post('/auth', {'username':'test', 'password':'badpass', 'service':'https://www.example.com', 'secret':'test'}) - - request.session = DummySession() - - auth = Auth() - response = auth.post(request) - - assert response.status_code == 200 - assert response.content == b"no\n" - diff --git a/tests/test_views_login.py b/tests/test_views_login.py deleted file mode 100644 index 6aabe80..0000000 --- a/tests/test_views_login.py +++ /dev/null @@ -1,163 +0,0 @@ -from __future__ import absolute_import -from .init import * - -from django.test import RequestFactory - -import os -import pytest - -from cas_server.views import LoginView -from cas_server import models - -from .dummy import * - - - -def test_login_view_post_goodpass_goodlt(): - factory = RequestFactory() - request = factory.post('/login', {'username':'test', 'password':'test', 'lt':'LT-random'}) - request.session = DummySession() - - request.session['lt'] = ['LT-random'] - - request.session["username"] = os.urandom(20) - request.session["warn"] = os.urandom(20) - - login = LoginView() - login.init_post(request) - - ret = login.process_post(pytest=True) - - assert ret == LoginView.USER_LOGIN_OK - assert request.session.get("authenticated") == True - assert request.session.get("username") == "test" - assert request.session.get("warn") == False - -def test_login_view_post_badlt(): - factory = RequestFactory() - request = factory.post('/login', {'username':'test', 'password':'test', 'lt':'LT-random1'}) - request.session = DummySession() - - request.session['lt'] = ['LT-random2'] - - authenticated = os.urandom(20) - username = os.urandom(20) - warn = os.urandom(20) - - request.session["authenticated"] = authenticated - request.session["username"] = username - request.session["warn"] = warn - - login = LoginView() - login.init_post(request) - - ret = login.process_post(pytest=True) - - assert ret == LoginView.INVALID_LOGIN_TICKET - assert request.session.get("authenticated") == authenticated - assert request.session.get("username") == username - assert request.session.get("warn") == warn - -def test_login_view_post_badpass_good_lt(): - factory = RequestFactory() - request = factory.post('/login', {'username':'test', 'password':'badpassword', 'lt':'LT-random'}) - request.session = DummySession() - - request.session['lt'] = ['LT-random'] - - login = LoginView() - login.init_post(request) - ret = login.process_post() - - assert ret == LoginView.USER_LOGIN_FAILURE - assert not request.session.get("authenticated") - assert not request.session.get("username") - assert not request.session.get("warn") - - -def test_view_login_get_unauth(): - factory = RequestFactory() - request = factory.post('/login') - request.session = DummySession() - - login = LoginView() - login.init_get(request) - ret = login.process_get() - - assert ret == LoginView.USER_NOT_AUTHENTICATED - - login = LoginView() - response = login.get(request) - - assert response.status_code == 200 - -@pytest.mark.django_db -@dummy_user(username="test", session_key="test_session") -def test_view_login_get_auth(): - factory = RequestFactory() - request = factory.post('/login') - request.session = DummySession() - - request.session["authenticated"] = True - request.session["username"] = "test" - request.session["warn"] = False - - login = LoginView() - login.init_get(request) - ret = login.process_get() - - assert ret == LoginView.USER_AUTHENTICATED - - login = LoginView() - response = login.get(request) - - assert response.status_code == 200 - -@pytest.mark.django_db -@dummy_service_pattern() -@dummy_user(username="test", session_key="test_session") -@dummy_ticket(models.ServiceTicket, 'https://www.example.com', "ST-random") -def test_view_login_get_auth_service(): - factory = RequestFactory() - request = factory.post('/login?service=https://www.example.com') - request.session = DummySession() - - request.session["authenticated"] = True - request.session["username"] = "test" - request.session["warn"] = False - - login = LoginView() - login.init_get(request) - ret = login.process_get() - - assert ret == LoginView.USER_AUTHENTICATED - - login = LoginView() - response = login.get(request) - - assert response.status_code == 302 - assert response['Location'].startswith('https://www.example.com?ticket=ST-') - -@pytest.mark.django_db -@dummy_service_pattern() -@dummy_user(username="test", session_key="test_session") -@dummy_ticket(models.ServiceTicket, 'https://www.example.com', "ST-random") -def test_view_login_get_auth_service_warn(): - factory = RequestFactory() - request = factory.post('/login?service=https://www.example.com') - request.session = DummySession() - - request.session["authenticated"] = True - request.session["username"] = "test" - request.session["warn"] = True - - login = LoginView() - login.init_get(request) - ret = login.process_get() - - assert ret == LoginView.USER_AUTHENTICATED - - login = LoginView() - response = login.get(request) - - assert response.status_code == 200 diff --git a/tests/test_views_logout.py b/tests/test_views_logout.py deleted file mode 100644 index 03410bd..0000000 --- a/tests/test_views_logout.py +++ /dev/null @@ -1,80 +0,0 @@ -from __future__ import absolute_import -from .init import * - -from django.test import RequestFactory - -import os -import pytest - -from cas_server.views import LogoutView -from cas_server import models - -from .dummy import * - - -@pytest.mark.django_db -@dummy_user(username="test", session_key="test_session") -def test_logout_view(): - factory = RequestFactory() - request = factory.get('/logout') - - request.session = DummySession() - - request.session["authenticated"] = True - request.session["username"] = "test" - request.session["warn"] = False - - logout = LogoutView() - response = logout.get(request) - - assert response.status_code == 200 - assert not request.session.get("authenticated") - assert not request.session.get("username") - assert not request.session.get("warn") - - -@pytest.mark.django_db -@dummy_user(username="test", session_key="test_session") -def test_logout_view_url(): - factory = RequestFactory() - request = factory.get('/logout?url=https://www.example.com') - - request.session = DummySession() - - request.session["authenticated"] = True - request.session["username"] = "test" - request.session["warn"] = False - - logout = LogoutView() - response = logout.get(request) - - assert response.status_code == 302 - assert response['Location'] == 'https://www.example.com' - assert not request.session.get("authenticated") - assert not request.session.get("username") - assert not request.session.get("warn") - - - -@pytest.mark.django_db -@dummy_user(username="test", session_key="test_session") -def test_logout_view_service(): - factory = RequestFactory() - request = factory.get('/logout?service=https://www.example.com') - - request.session = DummySession() - - request.session["authenticated"] = True - request.session["username"] = "test" - request.session["warn"] = False - - logout = LogoutView() - response = logout.get(request) - - assert response.status_code == 302 - assert response['Location'] == 'https://www.example.com' - assert not request.session.get("authenticated") - assert not request.session.get("username") - assert not request.session.get("warn") - - diff --git a/tests/test_views_validate.py b/tests/test_views_validate.py deleted file mode 100644 index 201387f..0000000 --- a/tests/test_views_validate.py +++ /dev/null @@ -1,58 +0,0 @@ -from __future__ import absolute_import -from .init import * - -from django.test import RequestFactory - -import os -import pytest - -from cas_server.views import Validate -from cas_server import models - -from .dummy import * - -@pytest.mark.django_db -@dummy_ticket(models.ServiceTicket, 'https://www.example.com', "ST-random") -def test_validate_view_ok(): - factory = RequestFactory() - request = factory.get('/validate?ticket=ST-random&service=https://www.example.com') - - request.session = DummySession() - - validate = Validate() - response = validate.get(request) - - assert response.status_code == 200 - assert response.content == b"yes\ntest\n" - - - -@pytest.mark.django_db -@dummy_ticket(models.ServiceTicket, 'https://www.example.com', "ST-random") -def test_validate_view_badservice(): - factory = RequestFactory() - request = factory.get('/validate?ticket=ST-random&service=https://www.example2.com') - - request.session = DummySession() - - validate = Validate() - response = validate.get(request) - - assert response.status_code == 200 - assert response.content == b"no\n" - - - -@pytest.mark.django_db -@dummy_ticket(models.ServiceTicket, 'https://www.example.com', "ST-random1") -def test_validate_view_badticket(): - factory = RequestFactory() - request = factory.get('/validate?ticket=ST-random2&service=https://www.example.com') - - request.session = DummySession() - - validate = Validate() - response = validate.get(request) - - assert response.status_code == 200 - assert response.content == b"no\n" diff --git a/tox.ini b/tox.ini index 997620a..0b65c56 100644 --- a/tox.ini +++ b/tox.ini @@ -17,7 +17,7 @@ deps = -r{toxinidir}/requirements-dev.txt [testenv] -commands=py.test --tb native {posargs:tests} +commands=python run_tests {posargs:tests} [testenv:py27-django17] basepython=python2.7