''' Tests for ordr2.views.account ''' import deform import pytest from pyramid.httpexceptions import HTTPFound from pyramid.testing import DummyRequest, DummyResource from pyramid_mailer import get_mailer from webob.multidict import MultiDict from .. import app_config, dbsession, get_user, create_users, set_deform_data REGISTRATION_FORM_DATA = MultiDict([ ('username', 'AmyMcDonald'), ('first_name', 'Amy'), ('last_name', 'McDonald'), ('email', 'mcdonald@example.com'), ('__start__', 'password:mapping'), ('password', 'Amy'), ('password-confirm', 'Amy'), ('__end__', 'password:mapping'), ]) PASSWORD_RESET_FORM_DATA = MultiDict([ ('__start__', 'password:mapping'), ('password', 'Nudge'), ('password-confirm', 'Nudge'), ('__end__', 'password:mapping'), ]) SETTINGS_FORM_DATA = MultiDict([ ('__start__', 'general:mapping'), ('username', 'TerryGilliam'), ('first_name', 'Terry'), ('last_name', 'Gilliam'), ('email', 'gilliam@example.com'), ('role', 'USER'), ('__end__', 'general:mapping'), ('__start__', 'change_password:mapping'), ('__start__', 'new_password:mapping'), ('new_password', 'Amy'), ('new_password-confirm', 'Amy'), ('__end__', 'new_password:mapping'), ('__end__', 'change_password:mapping'), ('__start__', 'confirm_changes:mapping'), ('password', 'Terry'), ('__end__', 'confirm_changes:mapping') ]) @pytest.mark.parametrize('rolename', ['user', 'purchaser', 'admin']) def test_account_login_active_users(dbsession, rolename): ''' login ok for active users ''' from ordr2.views.account import login create_users(dbsession) user = get_user(rolename) request = DummyRequest( dbsession=dbsession, post={ 'username': user.username, 'password': user.first_name } ) result = login(None, request) assert isinstance(result, HTTPFound) assert result.location == 'http://example.com//orders' @pytest.mark.parametrize('rolename', ['unvalidated', 'new', 'inactive']) def test_account_login_fails_inactive_users(dbsession, rolename): ''' login fails for inactive users ''' from ordr2.views.account import login create_users(dbsession) user = get_user(rolename) request = DummyRequest( dbsession=dbsession, post={ 'username': user.username, 'password': user.first_name } ) result = login(None, request) assert result == {} @pytest.mark.parametrize( 'username, password', [ ('EricIdle', 'wrong password'), ('unknown user', 'Eric'), ('unknown user', 'wrong password'), ('', '') ] ) def test_account_login_fails_wrong_credentials(dbsession, username, password): ''' login fails for unknown or wrong credentials ''' from ordr2.views.account import login create_users(dbsession) request = DummyRequest( dbsession=dbsession, post={ 'username': username, 'password': password } ) result = login(None, request) assert result == {} assert request.session.pop_flash('error') == [ 'You entered the wrong username or password' ] def test_logout(app_config): ''' logout works ''' from ordr2.views.account import logout user = get_user('admin') request = DummyRequest(user=user) result = logout(None, request) assert isinstance(result, HTTPFound) assert result.location == 'http://example.com//' # tests for the registration form def test_registration_form(app_config): ''' registration form ''' from ordr2.views.account import registration_form request = DummyRequest() context = DummyResource() result = registration_form(context, request) assert isinstance(result['form'], deform.Form) def test_registration_form_processing_ok(dbsession): ''' registration form processing with valid data''' from ordr2.models.account import User, Role, TokenSubject from ordr2.views.account import registration_form_processing user = get_user('user') # intentionally not added to database context = DummyResource(model=user) request = DummyRequest(dbsession=dbsession, context=context) set_deform_data(request, REGISTRATION_FORM_DATA) result = registration_form_processing(context, request) # return value of function call assert isinstance(result, HTTPFound) assert result.location == 'http://example.com/registered' # user should be added to database user = dbsession.query(User).first() assert user.username == REGISTRATION_FORM_DATA['username'] assert user.first_name == REGISTRATION_FORM_DATA['first_name'] assert user.last_name == REGISTRATION_FORM_DATA['last_name'] assert user.email == REGISTRATION_FORM_DATA['email'] assert user.check_password(REGISTRATION_FORM_DATA['password']) assert user.role == Role.UNVALIDATED # a token should be created token = user.tokens[0] assert token.subject == TokenSubject.USER_REGISTRATION # warning about a short password assert request.session.pop_flash('warning') == [ 'You should really consider a longer password' ] # and a verification email should be sent # this is tested in the functional test since request.registry.notify # doesn't know about event subscribers in the unittest def test_registration_form_processing_cancel(dbsession): ''' canceling registration form processing ''' from ordr2.models.account import User, Role, TokenSubject from ordr2.views.account import registration_form_processing user = get_user('user') # intentionally not added to database context = DummyResource(model=user) request = DummyRequest(dbsession=dbsession, context=context) set_deform_data(request, REGISTRATION_FORM_DATA, {'Cancel': 'Cancel'}) result = registration_form_processing(context, request) assert isinstance(result, HTTPFound) assert result.location == 'http://example.com//' @pytest.mark.parametrize( 'key,value', [ ('username', ''), ('username', 'TerryGilliam'), ('first_name', ''), ('last_name', ''), ('email', ''), ('email', 'no email'), ('email', 'gilliam@example.com'), ('password', ''), ('password-confirm', ''), ('password-confirm', 'no match') ] ) def test_registration_form_processing_validation_error(dbsession, key, value): ''' registration form processing with valid data''' from ordr2.models.account import User, Role, TokenSubject from ordr2.views.account import registration_form_processing admin = get_user('user') dbsession.add(admin) context = DummyResource(model=get_user('admin')) request = DummyRequest(dbsession=dbsession, context=context) set_deform_data(request, REGISTRATION_FORM_DATA, {key: value}) result = registration_form_processing(context, request) assert isinstance(result['form'], deform.Form) def test_registration_confirmation(): ''' registration, awaiting confirmation of email address ''' from ordr2.views.account import registration_confirmation result = registration_confirmation(None, None) assert result == {} def test_registration_completed(dbsession): ''' registration, confirmation of email address successful ''' from ordr2.models.account import User, Role, Token, TokenSubject from ordr2.views.account import registration_completed request = DummyRequest(dbsession=dbsession) user = get_user('unvalidated') user.issue_token(request, TokenSubject.USER_REGISTRATION) dbsession.add(user) dbsession.flush() token = user.tokens[0] context = DummyResource(model=token) result = registration_completed(context, request) assert result == {} assert user.role == Role.NEW assert dbsession.query(Token).count() == 0 assert dbsession.query(User).count() == 1 # tests for password reset def test_forgot_password_form(): ''' display the forgot password form ''' from ordr2.views.account import forgot_password_form result = forgot_password_form(None, None) assert result == {} @pytest.mark.parametrize('who', ['TerryGilliam', 'gilliam@example.com']) def test_forgot_password_form_processing_ok(dbsession, who): ''' process the forgot password form ''' from ordr2.views.account import forgot_password_form_processing dbsession.add(get_user('user')) request = DummyRequest( dbsession=dbsession, POST={'username_or_email': who} ) result = forgot_password_form_processing(None, request) assert isinstance(result, HTTPFound) assert result.location == 'http://example.com//forgot-password-email' def test_forgot_password_form_processing_cancel(dbsession): ''' forgot password form was canceled ''' from ordr2.views.account import forgot_password_form_processing dbsession.add(get_user('user')) request = DummyRequest( dbsession=dbsession, POST={'username_or_email': 'gilliam@example.com', 'cancel': 'Cancel'} ) result = forgot_password_form_processing(None, request) assert isinstance(result, HTTPFound) assert result.location == 'http://example.com//' @pytest.mark.parametrize( 'who', ['unknown user', 'unknown@example.com', ''] ) def test_forgot_password_form_processing_error(dbsession, who): ''' process the forgot password form ''' from ordr2.views.account import forgot_password_form_processing dbsession.add(get_user('user')) request = DummyRequest( dbsession=dbsession, POST = {'username_or_email': who} ) result = forgot_password_form_processing(None, request) assert result == {} assert request.session.pop_flash('error') == [ 'Username or email address unknown' ] def test_forgot_password_email_sent(): ''' message that a password reset link was sent ''' from ordr2.views.account import forgot_password_email_sent result = forgot_password_email_sent(None, None) assert result == {} def test_reset_password_form(): ''' reset password form display ''' from ordr2.views.account import reset_password_form request = DummyRequest() result = reset_password_form(None, request) assert isinstance(result['form'], deform.Form) def test_reset_password_form_processing_ok(dbsession): ''' reset password form processing is ok ''' from ordr2.models.account import Token, TokenSubject, User from ordr2.views.account import reset_password_form_processing request = DummyRequest(dbsession=dbsession) set_deform_data(request, REGISTRATION_FORM_DATA) account = get_user('user') token = account.issue_token(request, TokenSubject.RESET_PASSWORD) dbsession.add(account) dbsession.flush() context = DummyResource(model=token) result = reset_password_form_processing(context, request) assert isinstance(result, HTTPFound) assert result.location == 'http://example.com//login' assert account.check_password(REGISTRATION_FORM_DATA['password']) assert dbsession.query(Token).count() == 0 assert dbsession.query(User).count() == 1 assert request.session.pop_flash('warning') == [ 'You should really consider a longer password' ] assert request.session.pop_flash('success') == [ 'Your password was changed' ] def test_reset_password_form_processing_cancel(dbsession): ''' reset password form processing is canceled ''' from ordr2.views.account import reset_password_form_processing request = DummyRequest(dbsession=dbsession, POST={'Cancel': 'cancel'}) result = reset_password_form_processing(None, request) assert isinstance(result, HTTPFound) assert result.location == 'http://example.com//' @pytest.mark.parametrize( 'pw, confirm', [ ('', ''), ('no', 'match'), ('one is empty', ''), ('', 'one is empty'), ] ) def test_reset_password_form_processing_invalid(pw, confirm): ''' validation error in reset password form ''' from ordr2.views.account import reset_password_form_processing request = DummyRequest(dbsession=dbsession) modifier = {'password': pw, 'password-confim': confirm} set_deform_data(request, REGISTRATION_FORM_DATA, modifier) result = reset_password_form_processing(None, request) assert isinstance(result['form'], deform.Form) # settings def test_settings_form(dbsession): ''' settings form display ''' from ordr2.views.account import settings_form user = get_user('user') context = DummyResource(model=user) request = DummyRequest() result = settings_form(context, request) assert isinstance(result['form'], deform.Form) def test_settings_form_processing_cancel(dbsession): ''' settings form processing is canceled ''' from ordr2.views.account import settings_form_processing user = get_user('user') context = DummyResource(model=user) request = DummyRequest(dbsession=dbsession, POST={'Cancel': 'cancel'}) result = settings_form_processing(None, request) assert isinstance(result, HTTPFound) assert result.location == 'http://example.com//' def test_settings_form_processing_change_name(dbsession): ''' settings form processing change name only ''' from ordr2.views.account import settings_form_processing user = get_user('user') dbsession.add(user) context = DummyResource(model=user) request = DummyRequest(dbsession=dbsession, user=user, context=context) changes = { 'username': 'AmyMcDonald', 'first_name': 'Amy', 'last_name': 'McDonald', 'role': 'ADMIN', 'new_password': '', 'new_password-confirm': '', } set_deform_data(request, SETTINGS_FORM_DATA, changes) result = settings_form_processing(context, request) assert isinstance(result, HTTPFound) assert result.location == 'http://example.com//' assert user.username == 'TerryGilliam' assert user.first_name == 'Amy' assert user.last_name == 'McDonald' assert user.email == 'gilliam@example.com' assert user.check_password('Terry') def test_settings_form_processing_change_password(dbsession): ''' settings form processing change name only ''' from ordr2.views.account import settings_form_processing user = get_user('user') context = DummyResource(model=user) request = DummyRequest(dbsession=dbsession, user=user, context=context) changes = { 'new_password': 'Amy', 'new_password-confirm': 'Amy', } set_deform_data(request, SETTINGS_FORM_DATA, changes) result = settings_form_processing(context, request) assert isinstance(result, HTTPFound) assert result.location == 'http://example.com//' assert user.check_password('Amy') assert request.session.pop_flash('warning') == [ 'You should really consider a longer password' ] assert request.session.pop_flash('success') == [ 'Password updated sucessfully' ] def test_settings_change_email(dbsession): ''' settings form processing change name only ''' from ordr2.views.account import settings_form_processing from ordr2.models.account import TokenSubject user = get_user('user') dbsession.add(user) context = DummyResource(model=user) request = DummyRequest(dbsession=dbsession, user=user, context=context) changes = { 'email': 'amy@example.com', } set_deform_data(request, SETTINGS_FORM_DATA, changes) result = settings_form_processing(context, request) assert isinstance(result, HTTPFound) assert result.location == 'http://example.com/verify-new-email' token = user.tokens[0] assert token.subject == TokenSubject.CHANGE_EMAIL assert token.payload == {'new_email': 'amy@example.com'} assert user.email == 'gilliam@example.com' @pytest.mark.parametrize( 'key, value', [ ('first_name', ''), ('last_name', ''), ('email', ''), ('email', 'not an email address'), ('email', 'jones@example.com'), ('password', ''), ('password', 'wrong password'), ] ) def test_settings_form_processing_validation_error(dbsession, key, value): ''' settings form processing with validation error ''' from ordr2.views.account import settings_form_processing admin = get_user('admin') user = get_user('user') dbsession.add(admin) dbsession.add(user) context = DummyResource(model=user) request = DummyRequest(dbsession=dbsession, user=user, context=context) set_deform_data(request, SETTINGS_FORM_DATA, {key: value}) result = settings_form_processing(context, request) assert isinstance(result['form'], deform.Form) def test_email_confirmation(): ''' awaiting confirmation of new email address ''' from ordr2.views.account import email_confirmation result = email_confirmation(None, None) assert result == {} def test_email_change_confirmed(dbsession): ''' new email address is verified ''' from ordr2.views.account import email_change_confirmed from ordr2.models.account import User, Token, TokenSubject user = get_user('user') token = user.issue_token( DummyRequest(dbsession=dbsession), TokenSubject.CHANGE_EMAIL, {'new_email': 'amy@example.com'} ) dbsession.add(user) dbsession.flush() context = DummyResource(model=token) request = DummyRequest(dbsession=dbsession, context=context) result = email_change_confirmed(context, request) assert isinstance(result, HTTPFound) assert result.location == 'http://example.com//' assert user.email == 'amy@example.com' assert dbsession.query(Token).count() == 0 assert request.session.pop_flash('success') == ['Email change sucessful']