# -*- coding: utf-8; -*- from unittest import TestCase from unittest.mock import MagicMock from pyramid import testing from pyramid.httpexceptions import HTTPFound from wuttjamaican.conf import WuttaConfig from wuttaweb.views import auth as mod from wuttaweb.auth import WuttaSecurityPolicy class TestAuthView(TestCase): def setUp(self): self.config = WuttaConfig(defaults={ 'wutta.db.default.url': 'sqlite://', }) self.request = testing.DummyRequest(wutta_config=self.config, user=None) self.pyramid_config = testing.setUp(request=self.request) self.app = self.config.get_app() auth = self.app.get_auth_handler() model = self.app.model model.Base.metadata.create_all(bind=self.config.appdb_engine) self.session = self.app.make_session() self.user = model.User(username='barney') self.session.add(self.user) auth.set_user_password(self.user, 'testpass') self.session.commit() self.pyramid_config.set_security_policy(WuttaSecurityPolicy(db_session=self.session)) self.pyramid_config.include('wuttaweb.views.auth') self.pyramid_config.include('wuttaweb.views.common') def tearDown(self): testing.tearDown() def test_login(self): view = mod.AuthView(self.request) context = view.login() self.assertIn('form', context) # redirect if user already logged in self.request.user = self.user view = mod.AuthView(self.request) redirect = view.login(session=self.session) self.assertIsInstance(redirect, HTTPFound) # login fails w/ wrong password self.request.user = None self.request.method = 'POST' self.request.POST = {'username': 'barney', 'password': 'WRONG'} view = mod.AuthView(self.request) context = view.login(session=self.session) self.assertIn('form', context) # redirect if login succeeds self.request.method = 'POST' self.request.POST = {'username': 'barney', 'password': 'testpass'} view = mod.AuthView(self.request) redirect = view.login(session=self.session) self.assertIsInstance(redirect, HTTPFound) def test_logout(self): view = mod.AuthView(self.request) self.request.session.delete = MagicMock() redirect = view.logout() self.request.session.delete.assert_called_once_with() self.assertIsInstance(redirect, HTTPFound) def test_change_password(self): view = mod.AuthView(self.request) auth = self.app.get_auth_handler() # unauthenticated user is redirected redirect = view.change_password() self.assertIsInstance(redirect, HTTPFound) # now "login" the user, and set initial password self.request.user = self.user auth.set_user_password(self.user, 'foo') self.session.commit() # view should now return context w/ form context = view.change_password() self.assertIn('form', context) # submit valid form, ensure password is changed # (nb. this also would redirect user to home page) self.request.method = 'POST' self.request.POST = { 'current_password': 'foo', # nb. new_password requires colander mapping structure '__start__': 'new_password:mapping', 'new_password': 'bar', 'new_password-confirm': 'bar', '__end__': 'new_password:mapping', } redirect = view.change_password() self.assertIsInstance(redirect, HTTPFound) self.session.commit() self.session.refresh(self.user) self.assertFalse(auth.check_user_password(self.user, 'foo')) self.assertTrue(auth.check_user_password(self.user, 'bar')) # at this point 'foo' is the password, now let's submit some # invalid forms and make sure we get back a context w/ form # first try empty data self.request.POST = {} context = view.change_password() self.assertIn('form', context) dform = context['form'].get_deform() self.assertEqual(dform['current_password'].errormsg, "Required") self.assertEqual(dform['new_password'].errormsg, "Required") # now try bad current password self.request.POST = { 'current_password': 'blahblah', '__start__': 'new_password:mapping', 'new_password': 'baz', 'new_password-confirm': 'baz', '__end__': 'new_password:mapping', } context = view.change_password() self.assertIn('form', context) dform = context['form'].get_deform() self.assertEqual(dform['current_password'].errormsg, "Current password is incorrect.") # now try bad new password self.request.POST = { 'current_password': 'bar', '__start__': 'new_password:mapping', 'new_password': 'bar', 'new_password-confirm': 'bar', '__end__': 'new_password:mapping', } context = view.change_password() self.assertIn('form', context) dform = context['form'].get_deform() self.assertEqual(dform['new_password'].errormsg, "New password must be different from old password.")