rename package finish testing

This commit is contained in:
Olivier Larchevêque 2013-08-12 15:13:07 -04:00
parent 6ef2d78904
commit 37a05844fb
31 changed files with 289 additions and 150 deletions

View File

@ -1 +1 @@
recursive-include secretquestions/templates * recursive-include auf/django/secretquestions/templates *

2
auf/__init__.py Normal file
View File

@ -0,0 +1,2 @@
import pkg_resources
pkg_resources.declare_namespace(__name__)

2
auf/django/__init__.py Normal file
View File

@ -0,0 +1,2 @@
import pkg_resources
pkg_resources.declare_namespace(__name__)

View File

@ -0,0 +1,48 @@
# -*- coding: utf-8 -*-
from datetime import timedelta, datetime
import re
from django.shortcuts import redirect
from django.utils.translation import ugettext as _
from django.contrib import messages
from .views import SecretQuestionWizard
from .conf import SQ_SESSION_KEY, SQ_TOKEN_TTL
def secret_questions_required(ttl=SQ_TOKEN_TTL):
def _inner(view):
def _wrapped(request, *args, **kwargs):
session_token, url, date = request.session.get(SQ_SESSION_KEY,
(None,
None,
datetime.now(),))
get_token = request.GET.get(SQ_SESSION_KEY, None)
date_max = date + timedelta(seconds=ttl)
if session_token is None or get_token is None:
wiz = SecretQuestionWizard(request)
return wiz(request, *args, **kwargs)
if date_max < datetime.now() or \
not request.get_full_path().startswith(url):
if request.method == "POST":
messages.error(request,
_("Your modifications were canceled."))
url = request.get_full_path()
regex_no_session_key = "(.*)%s=[a..z0..9]*(.*)" % \
SQ_SESSION_KEY
clean_url = re.sub(regex_no_session_key, "\\1", url)
return redirect(clean_url)
if session_token == get_token:
return view(request, *args, **kwargs)
# should not be raised
raise Exception('SQ') # pragma: no cover
return _wrapped
return _inner

View File

@ -0,0 +1,3 @@
from .configuration import ConfigurationTest
from .use import UseTest
from .token import TokenTest

View File

@ -0,0 +1,92 @@
# -*- coding: utf-8 -*-
import re
from django.test import TestCase
from django.test.client import Client
from django.contrib.auth.models import User
from auf.django.secretquestions.models import Question, Answer, crypt_answer
class SecretQuestionTest(TestCase):
client = Client()
username = 'paul'
password = 'lemay'
def setUp(self):
self.create_user()
self.create_questions()
def create_user(self):
self.user = User.objects.create(username=self.username)
self.user.set_password(self.password)
self.user.save()
def create_questions(self):
self.question1 = Question.objects.create(text="question1")
self.question1.save()
self.question2 = Question.objects.create(text="question2")
self.question2.save()
def create_answers(self):
self.answer1 = Answer.objects.create(question=self.question1,
secret=crypt_answer('one'),
user=self.user)
self.answer1.save()
self.answer2 = Answer.objects.create(question=self.question2,
secret=crypt_answer('two'),
user=self.user)
self.answer2.save()
def _get_hashs(self, response):
"""
Parse response to prepare POST according previous hash
"""
regex_hash = 'name="(hash_[0-9])+" value="([a-z0-9]+)"'
found = re.findall(regex_hash, response.content)
hashs = {}
for k, v in found:
hashs.update({k: v})
return hashs
def get_response_from_final_step(self, url):
self.create_answers()
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
data = {'wizard_step': 0,
'0-username': self.username, }
response = self.client.post(url, data)
self.assertEqual(response.status_code, 200)
self.assertTrue(self.question1.text in response.content)
# wrong response
data = {'wizard_step': 1,
'0-username': self.username,
'1-raw_answer': 'wrong answer', }
data.update(self._get_hashs(response))
response = self.client.post(url, data)
self.assertEqual(response.status_code, 200)
self.assertFalse('2-raw_answer' in response.content)
# good response
data = {'wizard_step': 1,
'0-username': self.username,
'1-raw_answer': 'one', }
data.update(self._get_hashs(response))
response = self.client.post(url, data)
self.assertEqual(response.status_code, 200)
self.assertTrue('2-raw_answer' in response.content)
# good response
data = {'wizard_step': 2,
'0-username': self.username,
'1-raw_answer': 'one',
'2-raw_answer': 'two', }
data.update(self._get_hashs(response))
response = self.client.post(url, data)
return response

View File

@ -3,8 +3,9 @@
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.conf import settings from django.conf import settings
from secretquestions.tests.common import SecretQuestionTest from auf.django.secretquestions.models import Answer
from secretquestions.models import Answer
from .common import SecretQuestionTest
class ConfigurationTest(SecretQuestionTest): class ConfigurationTest(SecretQuestionTest):
@ -55,6 +56,30 @@ class ConfigurationTest(SecretQuestionTest):
self.assertNotEqual(answer.secret, raw_password) self.assertNotEqual(answer.secret, raw_password)
self.assertNotEqual(answer.secret, '') self.assertNotEqual(answer.secret, '')
def test_setting_2_same_questions(self):
"""
Check if error is raised if you choose 2 same questions
"""
raw_password = 'xxx'
self.assertEqual(self.client.login(username=self.username,
password=self.password), True)
url = reverse('sq_setup')
data = {'form-TOTAL_FORMS': u'2',
'form-INITIAL_FORMS': u'0',
'form-MAX_NUM_FORMS': u'',
'form-0-question': self.question1.id,
'form-0-secret': raw_password,
'form-1-question': self.question1.id,
'form-1-secret': raw_password, }
response = self.client.post(url, data)
self.assertEqual(response.status_code, 200)
answers = Answer.objects.filter(user=self.user)
self.assertEqual(len(answers), 0)
self.assertTrue(
"Each question has to be different." in response.content)
def test_setting_empty_answer_for_one_question(self): def test_setting_empty_answer_for_one_question(self):
""" """
Check if the answer is not empty Check if the answer is not empty

View File

@ -1,8 +1,10 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
USE_I18N = False
SECRET_KEY = 'secret' SECRET_KEY = 'secret'
ROOT_URLCONF = 'secretquestions.tests.urls' ROOT_URLCONF = 'auf.django.secretquestions.tests.urls'
DATABASES = {'default': DATABASES = {'default':
{'ENGINE': 'django.db.backends.sqlite3', 'NAME': ':memory:', }} {'ENGINE': 'django.db.backends.sqlite3', 'NAME': ':memory:', }}
@ -12,4 +14,4 @@ INSTALLED_APPS = ('django.contrib.auth',
'django.contrib.sessions', 'django.contrib.sessions',
'django.contrib.admin', 'django.contrib.admin',
'registration', 'registration',
'secretquestions',) 'auf.django.secretquestions',)

View File

@ -0,0 +1,52 @@
# -*- coding: utf-8 -*-
import time
from django.core.urlresolvers import reverse
from .common import SecretQuestionTest
from .views import TTL
class TokenTest(SecretQuestionTest):
"""
TestCase for token testing
"""
def test_expiracy(self):
"""
Check if you try to access page after X times.
"""
url = reverse('sq_test_private_ttl')
response = self.get_response_from_final_step(url)
location = response['location']
response = self.client.get(location)
self.assertEqual(response.status_code, 200)
self.assertTrue('OK' in response.content)
time.sleep(TTL+1)
response = self.client.get(location)
self.assertEqual(response.status_code, 302)
redirect = response['location'].replace('http://testserver', '')
self.assertEqual(redirect, url)
def test_warning(self):
"""
Check if you try to access page after X times.
"""
url = reverse('sq_test_private_ttl')
response = self.get_response_from_final_step(url)
location = response['location']
response = self.client.get(location)
self.assertEqual(response.status_code, 200)
self.assertTrue('OK' in response.content)
time.sleep(TTL+1)
response = self.client.post(location, {})
self.assertEqual(response.status_code, 302)
redirect = response['location'].replace('http://testserver', '')
self.assertEqual(redirect, url)
response = self.client.get(url)
messages = [m.message for m in response.context['messages']]
self.assertTrue("Your modifications were canceled." in messages)

View File

@ -0,0 +1,21 @@
from django.conf.urls.defaults import patterns, include, url
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns(
'',
(r'^admin/(.*)', include(admin.site.urls)),
(r'^accounts/', include('registration.urls')),
(r'^secret/',
include('auf.django.secretquestions.urls')),
url(r'^test_public/',
'auf.django.secretquestions.tests.views.public',
name='sq_test_public'),
url(r'^test_private/',
'auf.django.secretquestions.tests.views.private',
name='sq_test_private'),
url(r'^test_private_ttl/',
'auf.django.secretquestions.tests.views.private_ttl',
name='sq_test_private_ttl'),)

View File

@ -1,11 +1,10 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import re
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from secretquestions.tests.common import SecretQuestionTest from auf.django.secretquestions import conf
from secretquestions.conf import SQ_SESSION_KEY
from .common import SecretQuestionTest
class UseTest(SecretQuestionTest): class UseTest(SecretQuestionTest):
@ -72,7 +71,7 @@ class UseTest(SecretQuestionTest):
self.assertFalse('OK' in response.content) self.assertFalse('OK' in response.content)
self.assertFalse('username' in response.content) self.assertFalse('username' in response.content)
self.assertTrue(url in response['location']) self.assertTrue(url in response['location'])
self.assertTrue(SQ_SESSION_KEY in response['location']) self.assertTrue(conf.SQ_SESSION_KEY in response['location'])
def test_username_form(self): def test_username_form(self):
""" """
@ -91,18 +90,7 @@ class UseTest(SecretQuestionTest):
response = self.client.post(url, data) response = self.client.post(url, data)
self.assertEqual(response.status_code, 302) self.assertEqual(response.status_code, 302)
self.assertTrue(url in response['location']) self.assertTrue(url in response['location'])
self.assertTrue(SQ_SESSION_KEY in response['location']) self.assertTrue(conf.SQ_SESSION_KEY in response['location'])
def _get_hashs(self, response):
"""
Parse response to prepare POST according previous hash
"""
regex_hash = 'name="(hash_[0-9])+" value="([a-z0-9]+)"'
found = re.findall(regex_hash, response.content)
hashs = {}
for k, v in found:
hashs.update({k: v})
return hashs
def test_question_form(self): def test_question_form(self):
""" """
@ -146,7 +134,7 @@ class UseTest(SecretQuestionTest):
response = self.client.post(url, data) response = self.client.post(url, data)
self.assertEqual(response.status_code, 302) self.assertEqual(response.status_code, 302)
self.assertTrue(url in response['location']) self.assertTrue(url in response['location'])
self.assertTrue(SQ_SESSION_KEY in response['location']) self.assertTrue(conf.SQ_SESSION_KEY in response['location'])
response = self.client.get(response['location']) response = self.client.get(response['location'])
self.assertTrue('OK' in response.content) self.assertTrue('OK' in response.content)

View File

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
from django.http import HttpResponse
from auf.django.secretquestions.decorators import secret_questions_required
TTL = 1
def public(request):
return HttpResponse("OK")
@secret_questions_required()
def private(request):
return HttpResponse("OK")
@secret_questions_required(ttl=TTL)
def private_ttl(request):
return HttpResponse("OK")

View File

@ -4,5 +4,5 @@ from django.conf.urls.defaults import patterns, url
urlpatterns = patterns('', urlpatterns = patterns('',
url(r'questions/setup$', url(r'questions/setup$',
'secretquestions.views.setup_form', 'auf.django.secretquestions.views.setup_form',
name="sq_setup"), ) name="sq_setup"), )

View File

@ -1,43 +0,0 @@
# -*- coding: utf-8 -*-
from datetime import timedelta, datetime
import re
from django.shortcuts import redirect
from django.utils.translation import ugettext as _
from django.contrib import messages
from .views import SecretQuestionWizard
from .conf import SQ_SESSION_KEY, SQ_TOKEN_TTL
def secret_questions_required(view, ttl=SQ_TOKEN_TTL):
def _wrapped(request, *args, **kwargs):
session_token, url, date = request.session.get(SQ_SESSION_KEY,
(None,
None,
datetime.now()
))
get_token = request.GET.get(SQ_SESSION_KEY, None)
date_max = date + timedelta(seconds=ttl)
if session_token is None or get_token is None:
wiz = SecretQuestionWizard(request)
return wiz(request, *args, **kwargs)
if date_max < datetime.now() or \
not request.get_full_path().startswith(url):
if request.method == "POST":
messages.error(request, _("Your modifications were canceled."))
url = request.get_full_path()
regex_no_session_key = "(.*)%s=[a..z0..9]*(.*)" % SQ_SESSION_KEY
clean_url = re.sub(regex_no_session_key, "\\1", url)
return redirect(clean_url)
if session_token == get_token:
return view(request, *args, **kwargs)
raise Exception('SQ')
return _wrapped

View File

@ -1,2 +0,0 @@
from configuration import ConfigurationTest
from use import UseTest

View File

@ -1,40 +0,0 @@
# -*- coding: utf-8 -*-
from django.test import TestCase
from django.test.client import Client
from django.contrib.auth.models import User
from secretquestions.models import Question, Answer, crypt_answer
class SecretQuestionTest(TestCase):
client = Client()
username = 'paul'
password = 'lemay'
def setUp(self):
self.create_user()
self.create_questions()
def create_user(self):
self.user = User.objects.create(username=self.username)
self.user.set_password(self.password)
self.user.save()
def create_questions(self):
self.question1 = Question.objects.create(text="question1")
self.question1.save()
self.question2 = Question.objects.create(text="question2")
self.question2.save()
def create_answers(self):
self.answer1 = Answer.objects.create(question=self.question1,
secret=crypt_answer('one'),
user=self.user)
self.answer1.save()
self.answer2 = Answer.objects.create(question=self.question2,
secret=crypt_answer('two'),
user=self.user)
self.answer2.save()

View File

@ -1,16 +0,0 @@
from django.conf.urls.defaults import patterns, include, url
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
(r'^admin/(.*)', include(admin.site.urls)),
(r'^accounts/', include('registration.urls')),
(r'^secret/', include('secretquestions.urls')),
url(r'^test_public/',
'secretquestions.tests.views.public',
name='sq_test_public'),
url(r'^test_private/',
'secretquestions.tests.views.private',
name='sq_test_private'),)

View File

@ -1,14 +0,0 @@
# -*- coding: utf-8 -*-
from django.http import HttpResponse
from secretquestions.decorators import secret_questions_required
def public(request):
return HttpResponse("OK")
@secret_questions_required
def private(request):
return HttpResponse("OK")

View File

@ -2,8 +2,9 @@ from setuptools import setup, find_packages
import sys, os import sys, os
version = '0.0' version = '0.0'
name = 'auf.django.secretquestions'
setup(name='django-secretquestions', setup(name=name,
version=version, version=version,
description="Provides secret questions toolkit", description="Provides secret questions toolkit",
long_description="""\ long_description="""\
@ -12,9 +13,10 @@ setup(name='django-secretquestions',
keywords='django secretquestions authentication security', keywords='django secretquestions authentication security',
author='Olivier Larchev\xc3\xaaque', author='Olivier Larchev\xc3\xaaque',
author_email='olivier.larcheveque@auf.org', author_email='olivier.larcheveque@auf.org',
url='', url='http://pypi.auf.org/%s' % name,
license='', license='GPL',
packages=find_packages(exclude=['ez_setup', 'examples', 'tests']), packages=find_packages(exclude=['ez_setup', 'examples', 'tests']),
namespace_packages = ['auf'],
include_package_data=True, include_package_data=True,
zip_safe=False, zip_safe=False,
install_requires=[ install_requires=[

12
tox.ini
View File

@ -1,5 +1,5 @@
[tox] [tox]
envlist = django1.3, django1.4 envlist = django1.3
[testenv] [testenv]
deps = deps =
@ -9,16 +9,12 @@ deps =
commands = commands =
coverage erase coverage erase
coverage run --source="{envsitepackagesdir}/secretquestions/" {envdir}/bin/django-admin.py test secretquestions --settings=secretquestions.tests.settings coverage run --source="{envsitepackagesdir}/auf/django/secretquestions/" {envdir}/bin/django-admin.py test secretquestions --settings=auf.django.secretquestions.tests.settings
pep8 -r --statistics --count {envsitepackagesdir}/secretquestions/ --exclude={envsitepackagesdir}/secretquestions/migrations/* pep8 -r --statistics --count {envsitepackagesdir}/auf/django/secretquestions/ --exclude={envsitepackagesdir}/auf/django/secretquestions/migrations/*
coverage report coverage report
coverage html
[testenv:django1.3] [testenv:django1.3]
deps = deps =
{[testenv]deps} {[testenv]deps}
django==1.3 django==1.3
[testenv:django1.4]
deps =
{[testenv]deps}
django==1.4