diff --git a/tests/conftest.py b/tests/conftest.py index 62e5f25..1707b1d 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -23,7 +23,7 @@ from utils import populate_data, Response @pytest.fixture() -def app(): +def app(request): app = Flask(__name__) app.response_class = Response app.debug = True @@ -32,6 +32,14 @@ def app(): app.config['LOGIN_DISABLED'] = False app.config['WTF_CSRF_ENABLED'] = False + for opt in ['changeable', 'recoverable', 'registerable', + 'trackable', 'passwordless', 'confirmable']: + app.config['SECURITY_' + opt.upper()] = opt in request.keywords + + if 'settings' in request.keywords: + for key, value in request.keywords['settings'].kwargs.items(): + app.config['SECURITY_' + key.upper()] = value + mail = Mail(app) app.mail = mail diff --git a/tests/test_changeable.py b/tests/test_changeable.py index 66e9cba..e63d2b2 100644 --- a/tests/test_changeable.py +++ b/tests/test_changeable.py @@ -6,23 +6,16 @@ Changeable tests """ +import pytest + from flask_security.signals import password_changed -from utils import authenticate, init_app_with_options +from utils import authenticate + +pytestmark = pytest.mark.changeable() -def _get_client(app, datastore, **options): - config = { - 'SECURITY_CHANGEABLE': True - } - config.update(options) - init_app_with_options(app, datastore, **config) - return app.test_client() - - -def test_recoverable_flag(app, sqlalchemy_datastore, get_message): - client = _get_client(app, sqlalchemy_datastore) - +def test_recoverable_flag(app, client, get_message): recorded = [] @password_changed.connect_via(app) @@ -97,32 +90,22 @@ def test_recoverable_flag(app, sqlalchemy_datastore, get_message): assert response.headers['Content-Type'] == 'application/json' -def test_custom_change_url(app, sqlalchemy_datastore, get_message): - client = _get_client(app, sqlalchemy_datastore, **{ - 'SECURITY_CHANGE_URL': '/custom_change' - }) - +@pytest.mark.settings(change_url='/custom_change') +def test_custom_change_url(client): authenticate(client) response = client.get('/custom_change') assert response.status_code == 200 -def test_custom_change_template(app, sqlalchemy_datastore, get_message): - client = _get_client(app, sqlalchemy_datastore, **{ - 'SECURITY_CHANGE_PASSWORD_TEMPLATE': 'custom_security/change_password.html' - }) - +@pytest.mark.settings(change_password_template='custom_security/change_password.html') +def test_custom_change_template(client): authenticate(client) response = client.get('/change') assert b'CUSTOM CHANGE PASSWORD' in response.data -def test_disable_change_emails(app, sqlalchemy_datastore): - client = _get_client(app, sqlalchemy_datastore, **{ - 'SECURITY_SEND_PASSWORD_CHANGE_EMAIL': False - }) - authenticate(client) - +@pytest.mark.settings(send_password_change_email=False) +def test_disable_change_emails(app, client): with app.mail.record_messages() as outbox: client.post('/change', data={ 'password': 'password', @@ -132,12 +115,9 @@ def test_disable_change_emails(app, sqlalchemy_datastore): assert len(outbox) == 0 -def test_custom_post_change_view(app, sqlalchemy_datastore): - client = _get_client(app, sqlalchemy_datastore, **{ - 'SECURITY_POST_CHANGE_VIEW': '/profile', - }) +@pytest.mark.settings(post_change_view='/profile') +def test_custom_post_change_view(client): authenticate(client) - response = client.post('/change', data={ 'password': 'password', 'new_password': 'newpassword', diff --git a/tests/test_common.py b/tests/test_common.py index 2aebee3..7eeb298 100644 --- a/tests/test_common.py +++ b/tests/test_common.py @@ -40,8 +40,8 @@ def test_authenticate_with_invalid_next(client, get_message): assert get_message('INVALID_REDIRECT') in response.data -def test_authenticate_case_insensitive_email(client): - response = authenticate(client, email='MATT@lp.com', follow_redirects=True) +def test_authenticate_case_insensitive_email(app, client): + response = authenticate(client, 'MATT@lp.com', follow_redirects=True) assert b'Hello matt@lp.com' in response.data diff --git a/tests/test_configuration.py b/tests/test_configuration.py index 69e6fd8..9a75ae0 100644 --- a/tests/test_configuration.py +++ b/tests/test_configuration.py @@ -8,20 +8,18 @@ import base64 -from utils import authenticate, logout, init_app_with_options +import pytest + +from utils import authenticate, logout -def test_view_configuration(app, sqlalchemy_datastore): - init_app_with_options(app, sqlalchemy_datastore, **{ - 'SECURITY_LOGOUT_URL': '/custom_logout', - 'SECURITY_LOGIN_URL': '/custom_login', - 'SECURITY_POST_LOGIN_VIEW': '/post_login', - 'SECURITY_POST_LOGOUT_VIEW': '/post_logout', - 'SECURITY_DEFAULT_HTTP_AUTH_REALM': 'Custom Realm', - }) - - client = app.test_client() - +@pytest.mark.settings( + logout_url='/custom_logout', + login_url='/custom_login', + post_login_view='/post_login', + post_logout_view='/post_logout', + default_http_auth_realm='Custom Realm') +def test_view_configuration(client): response = client.get('/custom_login') assert b"

Login

" in response.data @@ -39,10 +37,7 @@ def test_view_configuration(app, sqlalchemy_datastore): assert 'Basic realm="Custom Realm"' == response.headers['WWW-Authenticate'] -def test_template_configuration(app, sqlalchemy_datastore): - init_app_with_options(app, sqlalchemy_datastore, **{ - 'SECURITY_LOGIN_USER_TEMPLATE': 'custom_security/login_user.html', - }) - client = app.test_client() +@pytest.mark.settings(login_user_template='custom_security/login_user.html') +def test_template_configuration(client): response = client.get('/login') assert b'CUSTOM LOGIN USER' in response.data diff --git a/tests/test_confirmable.py b/tests/test_confirmable.py index 32fd3e1..f1c0b9e 100644 --- a/tests/test_confirmable.py +++ b/tests/test_confirmable.py @@ -8,20 +8,18 @@ import time +import pytest + from flask_security.signals import user_confirmed, confirm_instructions_sent from flask_security.utils import capture_registrations -from utils import authenticate, logout, init_app_with_options +from utils import authenticate, logout + +pytestmark = pytest.mark.confirmable() -def test_confirmable_flag(app, sqlalchemy_datastore, get_message): - init_app_with_options(app, sqlalchemy_datastore, **{ - 'SECURITY_CONFIRMABLE': True, - 'SECURITY_REGISTERABLE': True, - }) - - client = app.test_client() - +@pytest.mark.registerable() +def test_confirmable_flag(app, client, sqlalchemy_datastore, get_message): recorded_confirms = [] recorded_instructions_sent = [] @@ -100,16 +98,9 @@ def test_confirmable_flag(app, sqlalchemy_datastore, get_message): assert get_message('INVALID_CONFIRMATION_TOKEN') in response.data -def test_expired_confirmation_token(app, sqlalchemy_datastore, get_message): - within = '1 milliseconds' - init_app_with_options(app, sqlalchemy_datastore, **{ - 'SECURITY_CONFIRMABLE': True, - 'SECURITY_REGISTERABLE': True, - 'SECURITY_CONFIRM_EMAIL_WITHIN': within - }) - - client = app.test_client() - +@pytest.mark.registerable() +@pytest.mark.settings(confirm_email_within='1 milliseconds') +def test_expired_confirmation_token(client, get_message): with capture_registrations() as registrations: data = dict(email='mary@lp.com', password='password') client.post('/register', data=data, follow_redirects=True) @@ -120,32 +111,21 @@ def test_expired_confirmation_token(app, sqlalchemy_datastore, get_message): time.sleep(1) response = client.get('/confirm/' + token, follow_redirects=True) - assert get_message('CONFIRMATION_EXPIRED', within=within, email=user.email) in response.data + msg = get_message('CONFIRMATION_EXPIRED', within='1 milliseconds', email=user.email) + assert msg in response.data -def test_login_when_unconfirmed(app, sqlalchemy_datastore, get_message): - init_app_with_options(app, sqlalchemy_datastore, **{ - 'SECURITY_CONFIRMABLE': True, - 'SECURITY_REGISTERABLE': True, - 'SECURITY_LOGIN_WITHOUT_CONFIRMATION': True - }) - - client = app.test_client() - +@pytest.mark.registerable() +@pytest.mark.settings(login_without_confirmation=True) +def test_login_when_unconfirmed(client, get_message): data = dict(email='mary@lp.com', password='password') response = client.post('/register', data=data, follow_redirects=True) assert b'mary@lp.com' in response.data -def test_confirmation_different_user_when_logged_in(app, sqlalchemy_datastore, get_message): - init_app_with_options(app, sqlalchemy_datastore, **{ - 'SECURITY_CONFIRMABLE': True, - 'SECURITY_REGISTERABLE': True, - 'SECURITY_LOGIN_WITHOUT_CONFIRMATION': True - }) - - client = app.test_client() - +@pytest.mark.registerable() +@pytest.mark.settings(login_without_confirmation=True) +def test_confirmation_different_user_when_logged_in(client, get_message): e1 = 'dude@lp.com' e2 = 'lady@lp.com' diff --git a/tests/test_context_processors.py b/tests/test_context_processors.py index cf4cd91..dd8de0f 100644 --- a/tests/test_context_processors.py +++ b/tests/test_context_processors.py @@ -6,26 +6,24 @@ Context processor tests """ -from utils import authenticate, init_app_with_options +import pytest + +from utils import authenticate -def test_context_processors(app, sqlalchemy_datastore): - init_app_with_options(app, sqlalchemy_datastore, **{ - 'SECURITY_RECOVERABLE': True, - 'SECURITY_REGISTERABLE': True, - 'SECURITY_CONFIRMABLE': True, - 'SECURITY_CHANGEABLE': True, - 'SECURITY_LOGIN_WITHOUT_CONFIRMATION': True, - 'SECURITY_CHANGE_PASSWORD_TEMPLATE': 'custom_security/change_password.html', - 'SECURITY_LOGIN_USER_TEMPLATE': 'custom_security/login_user.html', - 'SECURITY_RESET_PASSWORD_TEMPLATE': 'custom_security/reset_password.html', - 'SECURITY_FORGOT_PASSWORD_TEMPLATE': 'custom_security/forgot_password.html', - 'SECURITY_SEND_CONFIRMATION_TEMPLATE': 'custom_security/send_confirmation.html', - 'SECURITY_REGISTER_USER_TEMPLATE': 'custom_security/register_user.html' - }) - - client = app.test_client() - +@pytest.mark.recoverable() +@pytest.mark.registerable() +@pytest.mark.confirmable() +@pytest.mark.changeable() +@pytest.mark.settings( + login_without_confirmation=True, + change_password_template='custom_security/change_password.html', + login_user_template='custom_security/login_user.html', + reset_password_template='custom_security/reset_password.html', + forgot_password_template='custom_security/forgot_password.html', + send_confirmation_template='custom_security/send_confirmation.html', + register_user_template='custom_security/register_user.html') +def test_context_processors(client, app): @app.security.forgot_password_context_processor def forgot_password(): return {'foo': 'bar'} @@ -77,17 +75,12 @@ def test_context_processors(app, sqlalchemy_datastore): client.post('/reset', data=dict(email='matt@lp.com')) email = outbox[0] - assert b'bar' in email.html + assert 'bar' in email.html -def test_passwordless_login_context_processor(app, sqlalchemy_datastore): - init_app_with_options(app, sqlalchemy_datastore, **{ - 'SECURITY_PASSWORDLESS': True, - 'SECURITY_SEND_LOGIN_TEMPLATE': 'custom_security/send_login.html', - }) - - client = app.test_client() - +@pytest.mark.passwordless() +@pytest.mark.settings(send_login_template='custom_security/send_login.html') +def test_passwordless_login_context_processor(app, client): @app.security.send_login_context_processor def send_login(): return {'foo': 'bar'} diff --git a/tests/test_datastore.py b/tests/test_datastore.py index d75ab49..85e2ae9 100644 --- a/tests/test_datastore.py +++ b/tests/test_datastore.py @@ -133,8 +133,11 @@ def test_add_role_to_user(app, datastore): def test_create_user_with_roles(app, datastore): init_app_with_options(app, datastore) + role = datastore.find_role('admin') + datastore.commit() + user = datastore.create_user(email='dude@lp.com', username='dude', - password='password', roles=['admin']) + password='password', roles=[role]) datastore.commit() user = datastore.find_user(email='dude@lp.com') assert user.has_role('admin') is True diff --git a/tests/test_misc.py b/tests/test_misc.py index 8649c36..8be2a7d 100644 --- a/tests/test_misc.py +++ b/tests/test_misc.py @@ -6,7 +6,7 @@ Email functionality tests """ -from pytest import raises +import pytest from flask_security import Security from flask_security.forms import LoginForm, RegisterForm, ConfirmRegisterForm, \ @@ -17,18 +17,14 @@ from flask_security.utils import capture_reset_password_requests from utils import authenticate, init_app_with_options, populate_data -def test_async_email_task(app, sqlalchemy_datastore): - init_app_with_options(app, sqlalchemy_datastore, **{ - 'SECURITY_RECOVERABLE': True - }) - +@pytest.mark.recoverable() +def test_async_email_task(app, client): app.mail_sent = False @app.security.send_mail_task def send_email(msg): app.mail_sent = True - client = app.test_client() client.post('/reset', data=dict(email='matt@lp.com')) assert app.mail_sent is True @@ -40,11 +36,10 @@ def test_register_blueprint_flag(app, sqlalchemy_datastore): assert response.status_code == 404 +@pytest.mark.registerable() +@pytest.mark.recoverable() +@pytest.mark.changeable() def test_basic_custom_forms(app, sqlalchemy_datastore): - app.config['SECURITY_REGISTERABLE'] = True - app.config['SECURITY_RECOVERABLE'] = True - app.config['SECURITY_CHANGEABLE'] = True - class MyLoginForm(LoginForm): email = TextField('My Login Email Address Field') @@ -70,7 +65,6 @@ def test_basic_custom_forms(app, sqlalchemy_datastore): change_password_form=MyChangePasswordForm) populate_data(app) - client = app.test_client() response = client.get('/login') @@ -95,6 +89,8 @@ def test_basic_custom_forms(app, sqlalchemy_datastore): assert b'My Change Password Field' in response.data +@pytest.mark.registerable() +@pytest.mark.confirmable() def test_confirmable_custom_form(app, sqlalchemy_datastore): app.config['SECURITY_REGISTERABLE'] = True app.config['SECURITY_CONFIRMABLE'] = True @@ -154,7 +150,7 @@ def test_flash_messages_off(app, sqlalchemy_datastore, get_message): def test_invalid_hash_scheme(app, sqlalchemy_datastore, get_message): - with raises(ValueError): + with pytest.raises(ValueError): init_app_with_options(app, sqlalchemy_datastore, **{ 'SECURITY_PASSWORD_HASH': 'bogus' }) diff --git a/tests/test_passwordless.py b/tests/test_passwordless.py index 7cf964a..eddf479 100644 --- a/tests/test_passwordless.py +++ b/tests/test_passwordless.py @@ -8,19 +8,17 @@ import time +import pytest + from flask_security.signals import login_instructions_sent from flask_security.utils import capture_passwordless_login_requests -from utils import logout, init_app_with_options +from utils import logout + +pytestmark = pytest.mark.passwordless() -def test_trackable_flag(app, sqlalchemy_datastore, get_message): - init_app_with_options(app, sqlalchemy_datastore, **{ - 'SECURITY_PASSWORDLESS': True - }) - - client = app.test_client() - +def test_trackable_flag(app, client, get_message): recorded = [] @login_instructions_sent.connect_via(app) @@ -75,14 +73,8 @@ def test_trackable_flag(app, sqlalchemy_datastore, get_message): assert get_message('USER_DOES_NOT_EXIST') in response.data -def test_expired_login_token(app, sqlalchemy_datastore, get_message): - init_app_with_options(app, sqlalchemy_datastore, **{ - 'SECURITY_PASSWORDLESS': True, - 'SECURITY_LOGIN_WITHIN': '1 milliseconds', - }) - - client = app.test_client() - +@pytest.mark.settings(login_within='1 milliseconds') +def test_expired_login_token(client, app, get_message): e = 'matt@lp.com' with capture_passwordless_login_requests() as requests: diff --git a/tests/test_recoverable.py b/tests/test_recoverable.py index 94f0950..ade31a0 100644 --- a/tests/test_recoverable.py +++ b/tests/test_recoverable.py @@ -8,24 +8,17 @@ import time +import pytest + from flask_security.signals import reset_password_instructions_sent, password_reset from flask_security.utils import capture_reset_password_requests -from utils import authenticate, logout, init_app_with_options +from utils import authenticate, logout + +pytestmark = pytest.mark.recoverable() -def _get_client(app, datastore, **options): - config = { - 'SECURITY_RECOVERABLE': True - } - config.update(options) - init_app_with_options(app, datastore, **config) - return app.test_client() - - -def test_recoverable_flag(app, sqlalchemy_datastore, get_message): - client = _get_client(app, sqlalchemy_datastore) - +def test_recoverable_flag(app, client, get_message): recorded_resets = [] recorded_instructions_sent = [] @@ -105,12 +98,8 @@ def test_recoverable_flag(app, sqlalchemy_datastore, get_message): assert get_message('INVALID_RESET_PASSWORD_TOKEN') in response.data -def test_expired_reset_token(app, sqlalchemy_datastore, get_message): - within = '1 milliseconds' - client = _get_client(app, sqlalchemy_datastore, **{ - 'SECURITY_RESET_PASSWORD_WITHIN': within - }) - +@pytest.mark.settings(reset_password_within='1 milliseconds') +def test_expired_reset_token(client, get_message): with capture_reset_password_requests() as requests: client.post('/reset', data=dict(email='joe@lp.com'), follow_redirects=True) @@ -124,24 +113,19 @@ def test_expired_reset_token(app, sqlalchemy_datastore, get_message): 'password_confirm': 'newpassword' }, follow_redirects=True) - assert get_message('PASSWORD_RESET_EXPIRED', within=within, email=user.email) in response.data + msg = get_message('PASSWORD_RESET_EXPIRED', within='1 milliseconds', email=user.email) + assert msg in response.data -def test_custom_reset_url(app, sqlalchemy_datastore, get_message): - client = _get_client(app, sqlalchemy_datastore, **{ - 'SECURITY_RESET_URL': '/custom_reset' - }) - +@pytest.mark.settings(reset_url='/custom_reset') +def test_custom_reset_url(client): response = client.get('/custom_reset') assert response.status_code == 200 -def test_custom_reset_templates(app, sqlalchemy_datastore): - client = _get_client(app, sqlalchemy_datastore, **{ - 'SECURITY_RESET_PASSWORD_TEMPLATE': 'custom_security/reset_password.html', - 'SECURITY_FORGOT_PASSWORD_TEMPLATE': 'custom_security/forgot_password.html' - }) - +@pytest.mark.settings(reset_password_template='custom_security/reset_password.html', + forgot_password_template='custom_security/forgot_password.html') +def test_custom_reset_templates(client): response = client.get('/reset') assert b'CUSTOM FORGOT PASSWORD' in response.data diff --git a/tests/test_registerable.py b/tests/test_registerable.py index 09acaf4..542e1e4 100644 --- a/tests/test_registerable.py +++ b/tests/test_registerable.py @@ -6,23 +6,17 @@ Registerable tests """ +import pytest + from flask_security.signals import user_registered -from utils import authenticate, logout, init_app_with_options +from utils import authenticate, logout + +pytestmark = pytest.mark.registerable() -def _get_client(app, datastore, **options): - config = { - 'SECURITY_REGISTERABLE': True, - 'SECURITY_POST_REGISTER_VIEW': '/post_register', - } - config.update(options) - init_app_with_options(app, datastore, **config) - return app.test_client() - - -def test_registerable_flag(app, sqlalchemy_datastore, get_message): - client = _get_client(app, sqlalchemy_datastore) +@pytest.mark.settings(post_register_view='/post_register') +def test_registerable_flag(client, app, get_message): recorded = [] # Test the register view @@ -66,7 +60,6 @@ def test_registerable_flag(app, sqlalchemy_datastore, get_message): # Test registering with invalid JSON data = '{ "email": "bogus", "password": "password"}' response = client.post('/register', data=data, headers={'Content-Type': 'application/json'}) - print response.data assert response.headers['content-type'] == 'application/json' assert response.jdata['meta']['code'] == 400 @@ -81,11 +74,8 @@ def test_registerable_flag(app, sqlalchemy_datastore, get_message): assert b'Page 1' in response.data -def test_custom_register_url(app, sqlalchemy_datastore): - client = _get_client(app, sqlalchemy_datastore, **{ - 'SECURITY_REGISTER_URL': '/custom_register' - }) - +@pytest.mark.settings(register_url='/custom_register', post_register_view='/post_register') +def test_custom_register_url(client): response = client.get('/custom_register') assert b"

Register

" in response.data @@ -97,18 +87,14 @@ def test_custom_register_url(app, sqlalchemy_datastore): assert b'Post Register' in response.data -def test_custom_register_tempalate(app, sqlalchemy_datastore): - client = _get_client(app, sqlalchemy_datastore, **{ - 'SECURITY_REGISTER_USER_TEMPLATE': 'custom_security/register_user.html' - }) +@pytest.mark.settings(register_user_template='custom_security/register_user.html') +def test_custom_register_tempalate(client): response = client.get('/register') assert b'CUSTOM REGISTER USER' in response.data -def test_disable_register_emails(app, sqlalchemy_datastore): - client = _get_client(app, sqlalchemy_datastore, **{ - 'SECURITY_SEND_REGISTER_EMAIL': False - }) +@pytest.mark.settings(send_register_email=False) +def test_disable_register_emails(client, app): data = dict(email='dude@lp.com', password='password', password_confirm='password') with app.mail.record_messages() as outbox: client.post('/register', data=data, follow_redirects=True) diff --git a/tests/test_trackable.py b/tests/test_trackable.py index 8667fe3..d47f7d3 100644 --- a/tests/test_trackable.py +++ b/tests/test_trackable.py @@ -6,16 +6,14 @@ Trackable tests """ -from utils import authenticate, logout, init_app_with_options +import pytest + +from utils import authenticate, logout + +pytestmark = pytest.mark.trackable() -def test_trackable_flag(app, sqlalchemy_datastore): - init_app_with_options(app, sqlalchemy_datastore, **{ - 'SECURITY_TRACKABLE': True - }) - - client = app.test_client() - +def test_trackable_flag(app, client): e = 'matt@lp.com' authenticate(client, email=e) logout(client)