Merge pull request #35 from alphagov/did-not-receive-code

Implementation for did not receive email or sms code
This commit is contained in:
Rebecca Law
2015-12-31 10:32:34 +00:00
24 changed files with 511 additions and 229 deletions

View File

@@ -4,13 +4,25 @@ from app.main.dao import users_dao
from app.models import User
def create_test_user():
def create_test_user(state):
user = User(name='Test User',
password='somepassword',
email_address='test@user.gov.uk',
mobile_number='+441234123412',
created_at=datetime.now(),
role_id=1,
state='pending')
state=state)
users_dao.insert_user(user)
return user
def create_another_test_user(state):
user = User(name='Another Test User',
password='someOtherpassword',
email_address='another_test@user.gov.uk',
mobile_number='+442233123412',
created_at=datetime.now(),
role_id=1,
state=state)
users_dao.insert_user(user)
return user

View File

@@ -6,7 +6,7 @@ from tests.app.main import create_test_user
def test_can_insert_and_retrieve_new_service(notifications_admin, notifications_admin_db, notify_db_session):
user = create_test_user()
user = create_test_user('active')
id = services_dao.insert_new_service('testing service', user)
saved_service = services_dao.get_service_by_id(id)
assert id == saved_service.id
@@ -15,7 +15,7 @@ def test_can_insert_and_retrieve_new_service(notifications_admin, notifications_
def test_unrestrict_service_updates_the_service(notifications_admin, notifications_admin_db, notify_db_session):
user = create_test_user()
user = create_test_user('active')
id = services_dao.insert_new_service('unrestricted service', user)
saved_service = services_dao.get_service_by_id(id)
assert saved_service.restricted is True
@@ -25,7 +25,7 @@ def test_unrestrict_service_updates_the_service(notifications_admin, notificatio
def test_activate_service_update_service(notifications_admin, notifications_admin_db, notify_db_session):
user = create_test_user()
user = create_test_user('active')
id = services_dao.insert_new_service('activated service', user)
service = services_dao.get_service_by_id(id)
assert service.active is False
@@ -44,7 +44,7 @@ def test_get_service_returns_none_if_service_does_not_exist(notifications_admin,
def test_find_by_service_name_returns_right_service(notifications_admin,
notifications_admin_db,
notify_db_session):
user = create_test_user()
user = create_test_user('active')
id = services_dao.insert_new_service('testing service', user)
another = services_dao.insert_new_service('Testing the Service', user)
found = services_dao.find_service_by_service_name('testing service')
@@ -55,7 +55,7 @@ def test_find_by_service_name_returns_right_service(notifications_admin,
def test_should_not_allow_two_services_of_the_same_name(notifications_admin, notifications_admin_db, notify_db_session):
user = create_test_user()
user = create_test_user('active')
services_dao.insert_new_service('duplicate service', user)
with pytest.raises(sqlalchemy.exc.IntegrityError) as error:
services_dao.insert_new_service('duplicate service', user)

View File

@@ -144,3 +144,20 @@ def test_should_throws_error_when_id_does_not_exist(notifications_admin, notific
with pytest.raises(AttributeError) as error:
users_dao.activate_user(123)
assert '''object has no attribute 'state''''' in str(error.value)
def test_should_update_email_address(notifications_admin, notifications_admin_db, notify_db_session):
user = User(name='Update Email',
password='somepassword',
email_address='test@it.gov.uk',
mobile_number='+441234123412',
created_at=datetime.now(),
role_id=1,
state='inactive')
users_dao.insert_user(user)
saved = users_dao.get_user_by_id(user.id)
assert saved.email_address == 'test@it.gov.uk'
users_dao.update_email_address(user.id, 'new_email@testit.gov.uk')
updated = users_dao.get_user_by_id(user.id)
assert updated.email_address == 'new_email@testit.gov.uk'

View File

@@ -3,14 +3,16 @@ from pytest import fail
from app.main.dao import verify_codes_dao
from app.main.encryption import check_hash
from tests.app.main import create_test_user
from tests.app.main import create_test_user, create_another_test_user
def test_insert_new_code_and_get_it_back(notifications_admin, notifications_admin_db, notify_db_session):
user = create_test_user()
user = create_test_user('pending')
verify_codes_dao.add_code(user_id=user.id, code='12345', code_type='email')
saved_code = verify_codes_dao.get_code(user_id=user.id, code_type='email')
saved_codes = verify_codes_dao.get_codes(user_id=user.id, code_type='email')
assert len(saved_codes) == 1
saved_code = saved_codes[0]
assert saved_code.user_id == user.id
assert check_hash('12345', saved_code.code)
assert saved_code.code_type == 'email'
@@ -20,7 +22,7 @@ def test_insert_new_code_and_get_it_back(notifications_admin, notifications_admi
def test_insert_new_code_should_thrw_exception_when_type_does_not_exist(notifications_admin,
notifications_admin_db,
notify_db_session):
user = create_test_user()
user = create_test_user('pending')
try:
verify_codes_dao.add_code(user_id=user.id, code='23545', code_type='not_real')
fail('Should have thrown an exception')
@@ -42,7 +44,7 @@ def test_should_throw_exception_when_user_does_not_exist(notifications_admin,
def test_should_return_none_if_code_is_used(notifications_admin,
notifications_admin_db,
notify_db_session):
user = create_test_user()
user = create_test_user('pending')
verify_codes_dao.add_code(user_id=user.id, code='12345', code_type='email')
verify_codes_dao.use_code(user_id=user.id, code='12345', code_type='email')
@@ -53,10 +55,32 @@ def test_should_return_none_if_code_is_used(notifications_admin,
def test_should_return_none_if_code_is_used(notifications_admin,
notifications_admin_db,
notify_db_session):
user = create_test_user()
user = create_test_user('pending')
verify_codes_dao.add_code(user_id=user.id, code='12345', code_type='sms')
code = verify_codes_dao.get_code(user_id=user.id, code_type='sms')
verify_codes_dao.use_code(code.id)
code = verify_codes_dao.get_code(user_id=user.id, code_type='sms')
assert code is None
code = verify_codes_dao.get_codes(user_id=user.id, code_type='sms')
verify_codes_dao.use_code(code[0].id)
used_code = verify_codes_dao.get_codes(user_id=user.id, code_type='sms')
assert used_code == []
def test_should_return_all_unused_code_when_there_are_many(notifications_admin,
notifications_admin_db,
notify_db_session):
user = create_test_user('pending')
another_user = create_another_test_user('active')
verify_codes_dao.add_code(user_id=user.id, code='12345', code_type='sms')
id = verify_codes_dao.add_code(user_id=user.id, code='09876', code_type='email')
verify_codes_dao.use_code(id)
verify_codes_dao.add_code(user_id=user.id, code='12345', code_type='email')
verify_codes_dao.add_code(user_id=user.id, code='23456', code_type='email')
verify_codes_dao.add_code(user_id=another_user.id, code='12345', code_type='sms')
verify_codes_dao.add_code(user_id=another_user.id, code='12345', code_type='email')
user_codes = verify_codes_dao.get_codes(user_id=user.id, code_type='email')
assert len(user_codes) == 2
s = sorted(user_codes, key=lambda r: r.expiry_datetime)
assert check_hash('12345', s[0].code)
assert check_hash('23456', s[1].code)
assert [(code.code_used, code.code_type, code.user_id) for code in user_codes] == \
[(False, 'email', user.id), (False, 'email', user.id)]

View File

@@ -8,7 +8,7 @@ def test_form_should_have_errors_when_duplicate_service_is_added(notifications_a
notify_db_session):
with notifications_admin.test_request_context(method='POST',
data={'service_name': 'some service'}) as req:
user = create_test_user()
user = create_test_user('active')
services_dao.insert_new_service('some service', user)
req.session['user_id'] = user.id
form = AddServiceForm(req.request.form)

View File

@@ -51,13 +51,12 @@ def test_returns_errors_when_code_contains_letters(notifications_admin, notifica
def test_should_return_errors_when_code_is_expired(notifications_admin, notifications_admin_db, notify_db_session):
with notifications_admin.test_request_context(method='POST',
data={'sms_code': '23456'}) as req:
user = create_test_user()
user = create_test_user('active')
req.session['user_id'] = user.id
verify_codes_dao.add_code_with_expiry(user_id=user.id,
code='23456',
code_type='sms',
expiry=datetime.now() + timedelta(hours=-2))
req.session['user_id'] = user.id
form = TwoFactorForm(req.request.form)
assert form.validate() is False
errors = form.errors
@@ -66,6 +65,6 @@ def test_should_return_errors_when_code_is_expired(notifications_admin, notifica
def set_up_test_data():
user = create_test_user()
user = create_test_user('active')
verify_codes_dao.add_code(user_id=user.id, code='12345', code_type='sms')
return user

View File

@@ -65,7 +65,7 @@ def test_should_return_errors_when_code_is_expired(notifications_admin, notifica
with notifications_admin.test_request_context(method='POST',
data={'sms_code': '23456',
'email_code': '23456'}) as req:
user = create_test_user()
user = create_test_user('pending')
req.session['user_id'] = user.id
verify_codes_dao.add_code_with_expiry(user_id=user.id,
code='23456',
@@ -86,8 +86,24 @@ def test_should_return_errors_when_code_is_expired(notifications_admin, notifica
assert set(errors) == set(expected)
def test_should_return_valid_form_when_many_codes_exist(notifications_admin,
notifications_admin_db,
notify_db_session):
with notifications_admin.test_request_context(method='POST',
data={'sms_code': '23456',
'email_code': '23456'}) as req:
user = set_up_test_data()
verify_codes_dao.add_code(user_id=user.id, code='23456', code_type='email')
verify_codes_dao.add_code(user_id=user.id, code='23456', code_type='sms')
verify_codes_dao.add_code(user_id=user.id, code='60456', code_type='email')
verify_codes_dao.add_code(user_id=user.id, code='27856', code_type='sms')
req.session['user_id'] = user.id
form = VerifyForm(req.request.form)
assert form.validate() is True
def set_up_test_data():
user = create_test_user()
user = create_test_user('pending')
verify_codes_dao.add_code(user_id=user.id, code='12345', code_type='email')
verify_codes_dao.add_code(user_id=user.id, code='12345', code_type='sms')
return user

View File

@@ -5,7 +5,7 @@ from tests.app.main import create_test_user
def test_get_should_render_add_service_template(notifications_admin, notifications_admin_db, notify_db_session):
with notifications_admin.test_client() as client:
with client.session_transaction() as session:
user = create_test_user()
user = create_test_user('active')
session['user_id'] = user.id
verify_codes_dao.add_code(user_id=user.id, code='12345', code_type='sms')
client.post('/two-factor', data={'sms_code': '12345'})
@@ -17,7 +17,7 @@ def test_get_should_render_add_service_template(notifications_admin, notificatio
def test_should_add_service_and_redirect_to_next_page(notifications_admin, notifications_admin_db, notify_db_session):
with notifications_admin.test_client() as client:
with client.session_transaction() as session:
user = create_test_user()
user = create_test_user('active')
session['user_id'] = user.id
verify_codes_dao.add_code(user_id=user.id, code='12345', code_type='sms')
client.post('/two-factor', data={'sms_code': '12345'})
@@ -33,7 +33,7 @@ def test_should_return_form_errors_when_service_name_is_empty(notifications_admi
notify_db_session):
with notifications_admin.test_client() as client:
with client.session_transaction() as session:
user = create_test_user()
user = create_test_user('active')
session['user_id'] = user.id
verify_codes_dao.add_code(user_id=user.id, code='12345', code_type='sms')
client.post('/two-factor', data={'sms_code': '12345'})

View File

@@ -0,0 +1,106 @@
from app.main.dao import verify_codes_dao, users_dao
from tests.app.main import create_test_user
def test_should_render_email_code_not_received_template_and_populate_email_address(notifications_admin,
notifications_admin_db,
notify_db_session):
with notifications_admin.test_client() as client:
with client.session_transaction() as session:
user = create_test_user('pending')
session['user_id'] = user.id
response = client.get('/email-not-received')
assert response.status_code == 200
assert 'Check your email address is correct and then resend the confirmation code' \
in response.get_data(as_text=True)
assert 'value="test@user.gov.uk"' in response.get_data(as_text=True)
def test_should_check_and_resend_email_code_redirect_to_verify(notifications_admin,
notifications_admin_db,
notify_db_session,
mocker):
with notifications_admin.test_client() as client:
with client.session_transaction() as session:
_set_up_mocker(mocker)
user = create_test_user('pending')
session['user_id'] = user.id
verify_codes_dao.add_code(user.id, code='12345', code_type='email')
response = client.post('/email-not-received',
data={'email_address': 'test@user.gov.uk'})
assert response.status_code == 302
assert response.location == 'http://localhost/verify'
def test_should_render_text_code_not_received_template(notifications_admin,
notifications_admin_db,
notify_db_session,
mocker):
with notifications_admin.test_client() as client:
with client.session_transaction() as session:
_set_up_mocker(mocker)
user = create_test_user('pending')
session['user_id'] = user.id
verify_codes_dao.add_code(user.id, code='12345', code_type='email')
response = client.get('/text-not-received')
assert response.status_code == 200
assert 'Check your mobile phone number is correct and then resend the confirmation code.' \
in response.get_data(as_text=True)
assert 'value="+441234123412"'
def test_should_check_and_redirect_to_verify(notifications_admin,
notifications_admin_db,
notify_db_session,
mocker):
with notifications_admin.test_client() as client:
with client.session_transaction() as session:
_set_up_mocker(mocker)
user = create_test_user('pending')
session['user_id'] = user.id
verify_codes_dao.add_code(user.id, code='12345', code_type='sms')
response = client.post('/text-not-received',
data={'mobile_number': '+441234123412'})
assert response.status_code == 302
assert response.location == 'http://localhost/verify'
def test_should_update_email_address_resend_code(notifications_admin,
notifications_admin_db,
notify_db_session,
mocker):
with notifications_admin.test_client() as client:
with client.session_transaction() as session:
_set_up_mocker(mocker)
user = create_test_user('pending')
session['user_id'] = user.id
verify_codes_dao.add_code(user_id=user.id, code='12345', code_type='email')
response = client.post('/email-not-received',
data={'email_address': 'new@address.gov.uk'})
assert response.status_code == 302
assert response.location == 'http://localhost/verify'
updated_user = users_dao.get_user_by_id(user.id)
assert updated_user.email_address == 'new@address.gov.uk'
def test_should_update_mobile_number_resend_code(notifications_admin,
notifications_admin_db,
notify_db_session,
mocker):
with notifications_admin.test_client() as client:
with client.session_transaction() as session:
_set_up_mocker(mocker)
user = create_test_user('pending')
session['user_id'] = user.id
verify_codes_dao.add_code(user_id=user.id, code='12345', code_type='sms')
response = client.post('/text-not-received',
data={'mobile_number': '+443456789012'})
assert response.status_code == 302
assert response.location == 'http://localhost/verify'
updated_user = users_dao.get_user_by_id(user.id)
assert updated_user.mobile_number == '+443456789012'
def _set_up_mocker(mocker):
mocker.patch("app.admin_api_client.send_sms")
mocker.patch("app.admin_api_client.send_email")

View File

@@ -20,7 +20,8 @@ def test_process_sign_in_return_2fa_template(notifications_admin, notifications_
mobile_number='+441234123123',
name='valid',
created_at=datetime.now(),
role_id=1)
role_id=1,
state='active')
users_dao.insert_user(user)
response = notifications_admin.test_client().post('/sign-in',
data={'email_address': 'valid@example.gov.uk',
@@ -37,7 +38,8 @@ def test_should_return_locked_out_true_when_user_is_locked(notifications_admin,
mobile_number='+441234123123',
name='valid',
created_at=datetime.now(),
role_id=1)
role_id=1,
state='active')
users_dao.insert_user(user)
for _ in range(10):
notifications_admin.test_client().post('/sign-in',
@@ -86,6 +88,22 @@ def test_should_return_401_when_user_does_not_exist(notifications_admin, notific
assert response.status_code == 401
def test_should_return_400_when_user_is_not_active(notifications_admin, notifications_admin_db, notify_db_session):
user = User(email_address='PendingUser@example.gov.uk',
password='val1dPassw0rd!',
mobile_number='+441234123123',
name='pending user',
created_at=datetime.now(),
role_id=1,
state='pending')
users_dao.insert_user(user)
response = notifications_admin.test_client().post('/sign-in',
data={'email_address': 'PendingUser@example.gov.uk',
'password': 'val1dPassw0rd!'})
assert response.status_code == 401
assert '"active_user": false' in response.get_data(as_text=True)
def _set_up_mocker(mocker):
mocker.patch("app.admin_api_client.send_sms")
mocker.patch("app.admin_api_client.send_email")

View File

@@ -13,7 +13,7 @@ def test_should_render_two_factor_page(notifications_admin, notifications_admin_
def test_should_login_user_and_redirect_to_dashboard(notifications_admin, notifications_admin_db, notify_db_session):
with notifications_admin.test_client() as client:
with client.session_transaction() as session:
user = create_test_user()
user = create_test_user('active')
session['user_id'] = user.id
verify_codes_dao.add_code(user_id=user.id, code='12345', code_type='sms')
response = client.post('/two-factor',
@@ -28,7 +28,7 @@ def test_should_return_400_with_sms_code_error_when_sms_code_is_wrong(notificati
notify_db_session):
with notifications_admin.test_client() as client:
with client.session_transaction() as session:
user = create_test_user()
user = create_test_user('active')
session['user_id'] = user.id
verify_codes_dao.add_code(user_id=user.id, code='12345', code_type='sms')
response = client.post('/two-factor',

View File

@@ -14,7 +14,7 @@ def test_should_redirect_to_add_service_when_code_are_correct(notifications_admi
notify_db_session):
with notifications_admin.test_client() as client:
with client.session_transaction() as session:
user = create_test_user()
user = create_test_user('pending')
session['user_id'] = user.id
verify_codes_dao.add_code(user_id=user.id, code='12345', code_type='sms')
verify_codes_dao.add_code(user_id=user.id, code='23456', code_type='email')
@@ -28,7 +28,7 @@ def test_should_redirect_to_add_service_when_code_are_correct(notifications_admi
def test_should_activate_user_after_verify(notifications_admin, notifications_admin_db, notify_db_session):
with notifications_admin.test_client() as client:
with client.session_transaction() as session:
user = create_test_user()
user = create_test_user('pending')
session['user_id'] = user.id
verify_codes_dao.add_code(user_id=user.id, code='12345', code_type='sms')
verify_codes_dao.add_code(user_id=user.id, code='23456', code_type='email')
@@ -43,7 +43,7 @@ def test_should_activate_user_after_verify(notifications_admin, notifications_ad
def test_should_return_400_when_codes_are_wrong(notifications_admin, notifications_admin_db, notify_db_session):
with notifications_admin.test_client() as client:
with client.session_transaction() as session:
user = create_test_user()
user = create_test_user('pending')
session['user_id'] = user.id
verify_codes_dao.add_code(user_id=user.id, code='23345', code_type='sms')
verify_codes_dao.add_code(user_id=user.id, code='98456', code_type='email')
@@ -56,3 +56,24 @@ def test_should_return_400_when_codes_are_wrong(notifications_admin, notificatio
errors = json.loads(response.get_data(as_text=True))
assert len(errors) == 2
assert set(errors) == set(expected)
def test_should_mark_all_codes_as_used_when_many_codes_exist(notifications_admin,
notifications_admin_db,
notify_db_session):
with notifications_admin.test_client() as client:
with client.session_transaction() as session:
user = create_test_user('pending')
session['user_id'] = user.id
code1 = verify_codes_dao.add_code(user_id=user.id, code='23345', code_type='sms')
code2 = verify_codes_dao.add_code(user_id=user.id, code='98456', code_type='email')
code3 = verify_codes_dao.add_code(user_id=user.id, code='12345', code_type='sms')
code4 = verify_codes_dao.add_code(user_id=user.id, code='23412', code_type='email')
response = client.post('/verify',
data={'sms_code': '23345',
'email_code': '23412'})
assert response.status_code == 302
assert verify_codes_dao.get_code_by_id(code1).code_used is True
assert verify_codes_dao.get_code_by_id(code2).code_used is True
assert verify_codes_dao.get_code_by_id(code3).code_used is True
assert verify_codes_dao.get_code_by_id(code4).code_used is True