You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

281 lines
12 KiB

# -*- coding: utf-8 -*-
# Copyright 2016 LasLabs Inc.
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
import mock
from contextlib import contextmanager
from odoo.tests.common import TransactionCase
from odoo.http import Response
from ..controllers import main
IMPORT = 'odoo.addons.password_security.controllers.main'
class EndTestException(Exception):
""" It allows for isolation of resources by raise """
class MockResponse(object):
def __new__(cls):
return mock.Mock(spec=Response)
class MockPassError(main.PassError):
def __init__(self):
super(MockPassError, self).__init__('Message')
class TestPasswordSecurityHome(TransactionCase):
def setUp(self):
super(TestPasswordSecurityHome, self).setUp()
self.PasswordSecurityHome = main.PasswordSecurityHome
self.password_security_home = self.PasswordSecurityHome()
self.passwd = 'I am a password!'
self.qcontext = {
'password': self.passwd,
}
@contextmanager
def mock_assets(self):
""" It mocks and returns assets used by this controller """
methods = ['do_signup', 'web_login', 'web_auth_signup',
'web_auth_reset_password',
]
with mock.patch.multiple(
main.AuthSignupHome, **{m: mock.DEFAULT for m in methods}
) as _super:
mocks = {}
for method in methods:
mocks[method] = _super[method]
mocks[method].return_value = MockResponse()
with mock.patch('%s.request' % IMPORT) as request:
with mock.patch('%s.ensure_db' % IMPORT) as ensure:
with mock.patch('%s.http' % IMPORT) as http:
http.redirect_with_hash.return_value = \
MockResponse()
mocks.update({
'request': request,
'ensure_db': ensure,
'http': http,
})
yield mocks
def test_do_signup_check(self):
""" It should check password on user """
with self.mock_assets() as assets:
check_password = assets['request'].env.user._check_password
check_password.side_effect = EndTestException
with self.assertRaises(EndTestException):
self.password_security_home.do_signup(self.qcontext)
check_password.assert_called_once_with(
self.passwd,
)
def test_do_signup_return(self):
""" It should return result of super """
with self.mock_assets() as assets:
res = self.password_security_home.do_signup(self.qcontext)
self.assertEqual(assets['do_signup'](), res)
def test_web_login_ensure_db(self):
""" It should verify available db """
with self.mock_assets() as assets:
assets['ensure_db'].side_effect = EndTestException
with self.assertRaises(EndTestException):
self.password_security_home.web_login()
def test_web_login_super(self):
""" It should call superclass w/ proper args """
expect_list = [1, 2, 3]
expect_dict = {'test1': 'good1', 'test2': 'good2'}
with self.mock_assets() as assets:
assets['web_login'].side_effect = EndTestException
with self.assertRaises(EndTestException):
self.password_security_home.web_login(
*expect_list, **expect_dict
)
assets['web_login'].assert_called_once_with(
*expect_list, **expect_dict
)
def test_web_login_no_post(self):
""" It should return immediate result of super when not POST """
with self.mock_assets() as assets:
assets['request'].httprequest.method = 'GET'
assets['request'].session.authenticate.side_effect = \
EndTestException
res = self.password_security_home.web_login()
self.assertEqual(
assets['web_login'](), res,
)
def test_web_login_authenticate(self):
""" It should attempt authentication to obtain uid """
with self.mock_assets() as assets:
assets['request'].httprequest.method = 'POST'
authenticate = assets['request'].session.authenticate
request = assets['request']
authenticate.side_effect = EndTestException
with self.assertRaises(EndTestException):
self.password_security_home.web_login()
authenticate.assert_called_once_with(
request.session.db,
request.params['login'],
request.params['password'],
)
def test_web_login_authenticate_fail(self):
""" It should return super result if failed auth """
with self.mock_assets() as assets:
authenticate = assets['request'].session.authenticate
request = assets['request']
request.httprequest.method = 'POST'
request.env['res.users'].sudo.side_effect = EndTestException
authenticate.return_value = False
res = self.password_security_home.web_login()
self.assertEqual(
assets['web_login'](), res,
)
def test_web_login_get_user(self):
""" It should get the proper user as sudo """
with self.mock_assets() as assets:
request = assets['request']
request.httprequest.method = 'POST'
sudo = request.env['res.users'].sudo()
sudo.browse.side_effect = EndTestException
with self.assertRaises(EndTestException):
self.password_security_home.web_login()
sudo.browse.assert_called_once_with(
request.uid
)
def test_web_login_valid_pass(self):
""" It should return parent result if pass isn't expired """
with self.mock_assets() as assets:
request = assets['request']
request.httprequest.method = 'POST'
user = request.env['res.users'].sudo().browse()
user.action_expire_password.side_effect = EndTestException
user._password_has_expired.return_value = False
res = self.password_security_home.web_login()
self.assertEqual(
assets['web_login'](), res,
)
def test_web_login_expire_pass(self):
""" It should expire password if necessary """
with self.mock_assets() as assets:
request = assets['request']
request.httprequest.method = 'POST'
user = request.env['res.users'].sudo().browse()
user.action_expire_password.side_effect = EndTestException
user._password_has_expired.return_value = True
with self.assertRaises(EndTestException):
self.password_security_home.web_login()
def test_web_login_log_out_if_expired(self):
"""It should log out user if password expired"""
with self.mock_assets() as assets:
request = assets['request']
request.httprequest.method = 'POST'
user = request.env['res.users'].sudo().browse()
user._password_has_expired.return_value = True
self.password_security_home.web_login()
logout_mock = request.session.logout
logout_mock.assert_called_once_with(keep_db=True)
def test_web_login_redirect(self):
""" It should redirect w/ hash to reset after expiration """
with self.mock_assets() as assets:
request = assets['request']
request.httprequest.method = 'POST'
user = request.env['res.users'].sudo().browse()
user._password_has_expired.return_value = True
res = self.password_security_home.web_login()
self.assertEqual(
assets['http'].redirect_with_hash(), res,
)
def test_web_auth_signup_valid(self):
""" It should return super if no errors """
with self.mock_assets() as assets:
res = self.password_security_home.web_auth_signup()
self.assertEqual(
assets['web_auth_signup'](), res,
)
def test_web_auth_signup_invalid_qcontext(self):
""" It should catch PassError and get signup qcontext """
with self.mock_assets() as assets:
with mock.patch.object(
main.AuthSignupHome, 'get_auth_signup_qcontext',
) as qcontext:
assets['web_auth_signup'].side_effect = MockPassError
qcontext.side_effect = EndTestException
with self.assertRaises(EndTestException):
self.password_security_home.web_auth_signup()
def test_web_auth_signup_invalid_render(self):
""" It should render & return signup form on invalid """
with self.mock_assets() as assets:
with mock.patch.object(
main.AuthSignupHome, 'get_auth_signup_qcontext', spec=dict
) as qcontext:
assets['web_auth_signup'].side_effect = MockPassError
res = self.password_security_home.web_auth_signup()
assets['request'].render.assert_called_once_with(
'auth_signup.signup', qcontext(),
)
self.assertEqual(
assets['request'].render(), res,
)
def test_web_auth_reset_password_fail_login(self):
""" It should raise from failed _validate_pass_reset by login """
with self.mock_assets() as assets:
with mock.patch.object(
main.AuthSignupHome, 'get_auth_signup_qcontext', spec=dict
) as qcontext:
qcontext['login'] = 'login'
search = assets['request'].env.sudo().search
assets['request'].httprequest.method = 'POST'
user = mock.MagicMock()
user._validate_pass_reset.side_effect = MockPassError
search.return_value = user
with self.assertRaises(MockPassError):
self.password_security_home.web_auth_reset_password()
def test_web_auth_reset_password_fail_email(self):
""" It should raise from failed _validate_pass_reset by email """
with self.mock_assets() as assets:
with mock.patch.object(
main.AuthSignupHome, 'get_auth_signup_qcontext', spec=dict
) as qcontext:
qcontext['login'] = 'login'
search = assets['request'].env.sudo().search
assets['request'].httprequest.method = 'POST'
user = mock.MagicMock()
user._validate_pass_reset.side_effect = MockPassError
search.side_effect = [[], user]
with self.assertRaises(MockPassError):
self.password_security_home.web_auth_reset_password()
def test_web_auth_reset_password_success(self):
""" It should return parent response on no validate errors """
with self.mock_assets() as assets:
with mock.patch.object(
main.AuthSignupHome, 'get_auth_signup_qcontext', spec=dict
) as qcontext:
qcontext['login'] = 'login'
assets['request'].httprequest.method = 'POST'
res = self.password_security_home.web_auth_reset_password()
self.assertEqual(
assets['web_auth_reset_password'](), res,
)