[Erp5-report] r38924 fabien - in /experimental/bt5/erp5_credential: TestTemplateItem/ bt/
nobody at svn.erp5.org
nobody at svn.erp5.org
Wed Oct 6 14:47:47 CEST 2010
Author: fabien
Date: Wed Oct 6 14:47:45 2010
New Revision: 38924
URL: http://svn.erp5.org?rev=38924&view=rev
Log:
add a test to check that Credential Recovery permit to change password
Modified:
experimental/bt5/erp5_credential/TestTemplateItem/testERP5Credential.py
experimental/bt5/erp5_credential/bt/revision
Modified: experimental/bt5/erp5_credential/TestTemplateItem/testERP5Credential.py
URL: http://svn.erp5.org/experimental/bt5/erp5_credential/TestTemplateItem/testERP5Credential.py?rev=38924&r1=38923&r2=38924&view=diff
==============================================================================
--- experimental/bt5/erp5_credential/TestTemplateItem/testERP5Credential.py [utf8] (original)
+++ experimental/bt5/erp5_credential/TestTemplateItem/testERP5Credential.py [utf8] Wed Oct 6 14:47:45 2010
@@ -28,9 +28,15 @@
import unittest
from Products.ERP5Type.tests.utils import reindex
from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase
+from Products.ERP5Type.tests.utils import DummyMailHost
from Products.ERP5Type.tests.Sequence import SequenceList
+import email, re
+from email.Header import decode_header, make_header
+from email.Utils import parseaddr
from zLOG import LOG
import transaction
+import cgi
+from urlparse import urlparse
use_verbose_security = 0
if use_verbose_security:
@@ -54,6 +60,10 @@ class TestERP5Credential(ERP5TypeTestCas
def afterSetUp(self):
"""Prepare the test."""
self.createCategories()
+ # add a dummy mailhost not to send real messages
+ if 'MailHost' in self.portal.objectIds():
+ self.portal.manage_delObjects(['MailHost'])
+ self.portal._setObject('MailHost', DummyMailHost('MailHost'))
@reindex
def createCategories(self):
@@ -110,6 +120,65 @@ class TestERP5Credential(ERP5TypeTestCas
self.tic()
self.logout()
+ # Copied from bt5/erp5_egov/TestTemplateItem/testEGovMixin.py
+ def decode_email(self, file):
+ # Prepare result
+ theMail = {
+ 'attachment_list': [],
+ 'body': '',
+ # Place all the email header in the headers dictionary in theMail
+ 'headers': {}
+ }
+ # Get Message
+ msg = email.message_from_string(file)
+ # Back up original file
+ theMail['__original__'] = file
+ # Recode headers to UTF-8 if needed
+ for key, value in msg.items():
+ decoded_value_list = decode_header(value)
+ unicode_value = make_header(decoded_value_list)
+ new_value = unicode_value.__unicode__().encode('utf-8')
+ theMail['headers'][key.lower()] = new_value
+ # Filter mail addresses
+ for header in ('resent-to', 'resent-from', 'resent-cc', 'resent-sender',
+ 'to', 'from', 'cc', 'sender', 'reply-to'):
+ header_field = theMail['headers'].get(header)
+ if header_field:
+ theMail['headers'][header] = parseaddr(header_field)[1]
+ # Get attachments
+ body_found = 0
+ for part in msg.walk():
+ content_type = part.get_content_type()
+ file_name = part.get_filename()
+ # multipart/* are just containers
+ # XXX Check if data is None ?
+ if content_type.startswith('multipart'):
+ continue
+ # message/rfc822 contains attached email message
+ # next 'part' will be the message itself
+ # so we ignore this one to avoid doubling
+ elif content_type == 'message/rfc822':
+ continue
+ elif content_type in ("text/plain", "text/html"):
+ charset = part.get_content_charset()
+ payload = part.get_payload(decode=True)
+ #LOG('CMFMailIn -> ',0,'charset: %s, payload: %s' % (charset,payload))
+ if charset:
+ payload = unicode(payload, charset).encode('utf-8')
+ if body_found:
+ # Keep the content type
+ theMail['attachment_list'].append((file_name,
+ content_type, payload))
+ else:
+ theMail['body'] = payload
+ body_found = 1
+ else:
+ payload = part.get_payload(decode=True)
+ # Keep the content type
+ theMail['attachment_list'].append((file_name, content_type,
+ payload))
+ return theMail
+
def _getPreference(self):
portal_preferences = self.getPreferenceTool()
preference = getattr(portal_preferences, 'test_site_preference', None)
@@ -134,8 +203,8 @@ class TestERP5Credential(ERP5TypeTestCas
self.login()
preference = self._getPreference()
preference.edit(preferred_credential_request_automatic_approval=False,
- preferred_organisation_credential_update_automatic_approval=False,
preferred_credential_recovery_automatic_approval=False,
+ preferred_organisation_credential_update_automatic_approval=False,
preferred_person_credential_update_automatic_approval=False)
self._enablePreference()
transaction.commit()
@@ -408,6 +477,115 @@ class TestERP5Credential(ERP5TypeTestCas
self.assertEquals(related_person.getDefaultCredentialQuestionAnswer(),
'Renault 4L')
+ def stepCreateCredentialRecovery(self, sequence=None, sequence_list=None,
+ **kw):
+ '''
+ Create a simple subscription request
+ '''
+ portal = self.getPortalObject()
+ # create a person with 'secret' as password
+ self.login()
+ person_module = portal.getDefaultModule('Person')
+ barney = person_module.newContent(title='Barney',
+ reference='barney',
+ password='secret',
+ default_email_text='barney at duff.com')
+ # create an assignment
+ assignment = barney.newContent(portal_type='Assignment',
+ function='member')
+ assignment.open()
+ transaction.commit()
+ self.tic()
+ sequence.edit(barney=barney)
+ # check barney can log in the system
+ self._assertUserExists('barney', 'secret')
+ self.login('barney')
+ from AccessControl import getSecurityManager
+ self.assertEquals(str(getSecurityManager().getUser()), 'barney')
+
+ self.login()
+ # create a credential recovery
+ credential_recovery_module = portal.getDefaultModule('Credential Recovery')
+ credential_recovery = credential_recovery_module.newContent(portal_type=\
+ 'Credential Recovery')
+
+ # associate it with barney
+ credential_recovery.setDestinationDecisionValue(barney)
+ sequence.edit(credential_recovery=credential_recovery)
+
+ def stepSubmitCredentialRecovery(self, sequence=None, sequence_list=None,
+ **kw):
+ credential_recovery = sequence.get('credential_recovery')
+ credential_recovery.submit()
+
+ def stepAcceptCredentialRecovery(self, sequence=None, sequence_list=None,
+ **kw):
+ credential_recovery = sequence.get('credential_recovery')
+ credential_recovery.accept()
+
+ def stepCheckEmailIsSent(self, sequence=None, sequence_list=None, **kw):
+ '''
+ Check an email containing the password reset link as been sent
+ '''
+ barney = sequence.get('barney')
+
+ # after accept, an email is send containing the reset link
+ last_message = self.portal.MailHost._last_message
+ rawstr = r"""PasswordTool_viewResetPassword"""
+ decoded_message = self.decode_email(last_message[2])
+ body_message = decoded_message['body']
+ match_obj = re.search(rawstr, body_message)
+
+ # check the reset password link is in the mail
+ self.assertNotEquals(match_obj, None)
+
+ # check the mail is sent to the requester :
+ send_to = decoded_message['headers']['to']
+ self.assertEqual(barney.getDefaultEmailText(), send_to)
+
+ def stepCheckPasswordChange(self, sequence=None, sequence_list=None, **kw):
+ '''
+ check it's possible to change the user password using the link in the
+ email
+ '''
+ # get the url
+ last_message = self.portal.MailHost._last_message
+ rawstr = r"""PasswordTool_viewResetPassword"""
+ decoded_message = self.decode_email(last_message[2])
+ body_message = decoded_message['body']
+ match_obj = re.search(rawstr, body_message)
+ # check the reset password link is in the mail
+ self.assertNotEquals(match_obj, None)
+ url = None
+ for line in body_message.splitlines():
+ match_obj = re.search(rawstr, line)
+ if match_obj is not None:
+ url = line[line.find('http:'):]
+ self.assertNotEquals(url, None)
+ response = self.publish(url)
+ parameters = cgi.parse_qs(urlparse(url)[4])
+ self.assertTrue('reset_key' in parameters)
+ key = parameters['reset_key'][0]
+ self.logout()
+ # before changing, check that the user exists with 'secret' password
+ self._assertUserExists('barney', 'secret')
+
+ self.portal.portal_password.changeUserPassword(user_login="barney",
+ password="new_password",
+ password_confirmation="new_password",
+ password_key=key)
+ transaction.commit()
+ self.tic()
+
+ # reset the cache
+ self.portal.portal_caches.clearAllCache()
+
+ # check we cannot login anymore with the previous password 'secret'
+ self._assertUserDoesNotExists('barney', 'secret')
+
+ # check we can now login with the new password 'new_password'
+ self._assertUserExists('barney', 'new_password')
+
def test_01_simpleSubsciptionRequest(self):
'''
Check that is possible to subscribe to erp5
@@ -505,11 +683,20 @@ class TestERP5Credential(ERP5TypeTestCas
sequence_list.addSequenceString(sequence_string)
sequence_list.play(self)
- def test_xx_passwordRecovery(self):
+ def test_08_passwordRecovery(self):
'''
check that a user that forget his password is able to set a new one and
log in the system with this new password
'''
+ sequence_list = SequenceList()
+ sequence_string = 'CreateCredentialRecovery Tic '\
+ 'SubmitCredentialRecovery Tic '\
+ 'AcceptCredentialRecovery Tic '\
+ 'CheckEmailIsSent Tic '\
+ 'CheckPasswordChange Tic '\
+
+ sequence_list.addSequenceString(sequence_string)
+ sequence_list.play(self)
def test_xx_checkCredentialQuestionIsNotCaseSensitive(self):
'''
Modified: experimental/bt5/erp5_credential/bt/revision
URL: http://svn.erp5.org/experimental/bt5/erp5_credential/bt/revision?rev=38924&r1=38923&r2=38924&view=diff
==============================================================================
--- experimental/bt5/erp5_credential/bt/revision [utf8] (original)
+++ experimental/bt5/erp5_credential/bt/revision [utf8] Wed Oct 6 14:47:45 2010
@@ -1 +1 @@
-263
\ No newline at end of file
+264
More information about the Erp5-report
mailing list