diff options
Diffstat (limited to 'service/test/unit')
-rw-r--r-- | service/test/unit/resources/test_auth.py | 73 | ||||
-rw-r--r-- | service/test/unit/resources/test_inbox_resource.py | 46 | ||||
-rw-r--r-- | service/test/unit/resources/test_login_resource.py | 15 | ||||
-rw-r--r-- | service/test/unit/resources/test_root_resource.py | 258 | ||||
-rw-r--r-- | service/test/unit/resources/test_session.py | 25 | ||||
-rw-r--r-- | service/test/unit/test_welcome_mail.py | 3 |
6 files changed, 389 insertions, 31 deletions
diff --git a/service/test/unit/resources/test_auth.py b/service/test/unit/resources/test_auth.py new file mode 100644 index 00000000..3dc3e29f --- /dev/null +++ b/service/test/unit/resources/test_auth.py @@ -0,0 +1,73 @@ +from mockito import mock, when, any as ANY + +from pixelated.application import get_static_folder +from pixelated.resources.auth import SessionChecker, PixelatedRealm, PixelatedAuthSessionWrapper +from pixelated.resources.login_resource import LoginResource +from pixelated.resources.root_resource import RootResource +from test.unit.resources import DummySite +from twisted.cred import error +from twisted.cred.checkers import ANONYMOUS, AllowAnonymousAccess +from twisted.cred.portal import Portal +from twisted.internet.defer import succeed, fail +from twisted.python import failure +from twisted.trial import unittest +from twisted.web._auth.wrapper import UnauthorizedResource +from twisted.web.resource import IResource, getChildForRequest +from twisted.web.test.requesthelper import DummyRequest + + +class TestPixelatedRealm(unittest.TestCase): + + def setUp(self): + self.authenticated_root_resource = mock() + self.public_root_resource = mock() + self.realm = PixelatedRealm(self.authenticated_root_resource, self.public_root_resource) + + def test_anonymous_user_gets_anonymous_resource(self): + interface, avatar, logout_handler = self.realm.requestAvatar(ANONYMOUS, None, IResource) + self.assertEqual(interface, IResource) + self.assertIs(avatar, self.public_root_resource) + + def test_authenticated_user_gets_root_resource(self): + interface, avatar, logout_handler = self.realm.requestAvatar('username', None, IResource) + self.assertEqual(interface, IResource) + self.assertIs(avatar, self.authenticated_root_resource) + + +class TestPixelatedAuthSessionWrapper(unittest.TestCase): + + def setUp(self): + self.realm_mock = mock() + services_factory = mock() + session_checker = SessionChecker(services_factory) + self.portal = Portal(self.realm_mock, [session_checker, AllowAnonymousAccess()]) + self.user_uuid_mock = mock() + self.root_resource = RootResource(services_factory, get_static_folder()) + self.anonymous_resource = RootResource(services_factory, get_static_folder(), public=True) + + self.session_wrapper = PixelatedAuthSessionWrapper(self.portal) + self.request = DummyRequest([]) + self.request.prepath = [''] + self.request.path = '/' + + def test_root_url_should_delegate_to_public_root_resource_for_unauthenticated_user(self): + when(self.realm_mock).requestAvatar(ANONYMOUS, None, IResource).thenReturn((IResource, self.anonymous_resource, lambda: None)) + request = DummyRequest(['']) + deferred_resource = getChildForRequest(self.session_wrapper, request) + d = deferred_resource.d + + def assert_public_root_resource(resource): + self.assertIs(resource, self.anonymous_resource) + + return d.addCallback(assert_public_root_resource) + + def test_root_url_should_delegate_to_protected_root_resource_for_authenticated_user(self): + when(self.realm_mock).requestAvatar(ANY(), None, IResource).thenReturn((IResource, self.root_resource, lambda: None)) + request = DummyRequest(['']) + deferred_resource = getChildForRequest(self.session_wrapper, request) + d = deferred_resource.d + + def assert_protected_root_resource(resource): + self.assertIsInstance(resource, RootResource) + + return d.addCallback(assert_protected_root_resource) diff --git a/service/test/unit/resources/test_inbox_resource.py b/service/test/unit/resources/test_inbox_resource.py new file mode 100644 index 00000000..9af355ca --- /dev/null +++ b/service/test/unit/resources/test_inbox_resource.py @@ -0,0 +1,46 @@ +import re + +from mock import MagicMock, patch +from mockito import mock, when, any as ANY + +from pixelated.application import UserAgentMode +from pixelated.resources.features_resource import FeaturesResource +from test.unit.resources import DummySite +from twisted.trial import unittest +from twisted.web.test.requesthelper import DummyRequest +from pixelated.resources.inbox_resource import InboxResource, MODE_STARTUP, MODE_RUNNING + + +class TestInboxResource(unittest.TestCase): + MAIL_ADDRESS = 'test_user@pixelated-project.org' + + def setUp(self): + mail_service = mock() + mail_service.account_email = self.MAIL_ADDRESS + + services = mock() + services.mail_service = mail_service + + services_factory = mock() + services_factory.mode = mock() + when(services_factory).services(ANY()).thenReturn(services) + + self.inbox_resource = InboxResource(services_factory) + self.web = DummySite(self.inbox_resource) + + def test_render_GET_should_template_account_email(self): + self.inbox_resource._html_template = "<html><head><title>$account_email</title></head></html>" + self.inbox_resource.initialize() + + request = DummyRequest(['']) + request.addCookie = lambda key, value: 'stubbed' + + d = self.web.get(request) + + def assert_response(_): + expected = "<title>{0}</title>".format(self.MAIL_ADDRESS) + matches = re.findall(expected, request.written[0]) + self.assertEquals(len(matches), 1) + + d.addCallback(assert_response) + return d diff --git a/service/test/unit/resources/test_login_resource.py b/service/test/unit/resources/test_login_resource.py index 45036f8d..1161acc4 100644 --- a/service/test/unit/resources/test_login_resource.py +++ b/service/test/unit/resources/test_login_resource.py @@ -157,6 +157,19 @@ class TestLoginResource(unittest.TestCase): d.addCallback(assert_default_invalid_banner_disclaimer_rendered) return d + def test_form_should_contain_csrftoken_input(self): + request = DummyRequest(['']) + + d = self.web.get(request) + + def assert_form_has_csrftoken_input(_): + input_username = 'name="csrftoken"' + written_response = ''.join(request.written) + self.assertIn(input_username, written_response) + + d.addCallback(assert_form_has_csrftoken_input) + return d + class TestLoginPOST(unittest.TestCase): def setUp(self): @@ -222,7 +235,7 @@ class TestLoginPOST(unittest.TestCase): def assert_interstitial_in_response(_): mock_authenticate.assert_called_once_with(self.username, self.password) - interstitial_js_in_template = '<script src="startup-assets/Interstitial.js"></script>' + interstitial_js_in_template = '<script src="static/Interstitial.js"></script>' self.assertIn(interstitial_js_in_template, self.request.written[0]) d.addCallback(assert_interstitial_in_response) diff --git a/service/test/unit/resources/test_root_resource.py b/service/test/unit/resources/test_root_resource.py index 4ff11ce8..1edba98c 100644 --- a/service/test/unit/resources/test_root_resource.py +++ b/service/test/unit/resources/test_root_resource.py @@ -1,14 +1,95 @@ -import unittest +import os import re from mock import MagicMock, patch from mockito import mock, when, any as ANY -from pixelated.application import UserAgentMode +import pixelated +from pixelated.application import UserAgentMode, get_static_folder +from pixelated.resources import IPixelatedSession, UnAuthorizedResource from pixelated.resources.features_resource import FeaturesResource +from pixelated.resources.login_resource import LoginResource from test.unit.resources import DummySite +from twisted.cred.checkers import ANONYMOUS +from twisted.internet.defer import succeed +from twisted.trial import unittest +from twisted.web.resource import IResource, getChildForRequest +from twisted.web.static import File from twisted.web.test.requesthelper import DummyRequest -from pixelated.resources.root_resource import RootResource, MODE_STARTUP, MODE_RUNNING +from pixelated.resources.root_resource import InboxResource, RootResource, MODE_STARTUP, MODE_RUNNING + + +class TestPublicRootResource(unittest.TestCase): + + def setUp(self): + self.public_root_resource = RootResource(mock(), get_static_folder(), public=True) + self.web = DummySite(self.public_root_resource) + + @patch('pixelated.resources.mails_resource.events.register') + def test_put_child_public_adds_resource(self, *mocks): + self.public_root_resource.initialize(provider=mock(), authenticator=mock()) + url_fragment, resource_mock = 'some-url-fragment', mock() + self.public_root_resource.putChildPublic(url_fragment, resource_mock) + request = DummyRequest([url_fragment]) + request.addCookie = MagicMock(return_value='stubbed') + child_resource = getChildForRequest(self.public_root_resource, request) + self.assertIs(child_resource, resource_mock) + + @patch('pixelated.resources.mails_resource.events.register') + def test_put_child_protected_adds_unauthorized(self, *mocks): + self.public_root_resource.initialize(provider=mock(), authenticator=mock()) + url_fragment, resource_mock = 'some-url-fragment', mock() + self.public_root_resource.putChildProtected(url_fragment, resource_mock) + request = DummyRequest([url_fragment]) + request.addCookie = MagicMock(return_value='stubbed') + child_resource = getChildForRequest(self.public_root_resource, request) + self.assertIsInstance(child_resource, UnAuthorizedResource) + + @patch('pixelated.resources.mails_resource.events.register') + def test_put_child_adds_unauthorized(self, *mocks): + self.public_root_resource.initialize(provider=mock(), authenticator=mock()) + url_fragment, resource_mock = 'some-url-fragment', mock() + self.public_root_resource.putChild(url_fragment, resource_mock) + request = DummyRequest([url_fragment]) + request.addCookie = MagicMock(return_value='stubbed') + child_resource = getChildForRequest(self.public_root_resource, request) + self.assertIsInstance(child_resource, UnAuthorizedResource) + + @patch('pixelated.resources.mails_resource.events.register') + def test_private_resource_returns_401(self, *mocks): + self.public_root_resource.initialize(provider=mock(), authenticator=mock()) + request = DummyRequest(['mails']) + request.addCookie = MagicMock(return_value='stubbed') + d = self.web.get(request) + + def assert_unauthorized(request): + self.assertEqual(401, request.responseCode) + self.assertEqual("Unauthorized!", request.written[0]) + + d.addCallback(assert_unauthorized) + return d + + @patch('pixelated.resources.mails_resource.events.register') + def test_login_url_should_delegate_to_login_resource(self, *mocks): + self.public_root_resource.initialize(provider=mock(), authenticator=mock()) + request = DummyRequest(['login']) + request.addCookie = MagicMock(return_value='stubbed') + child_resource = getChildForRequest(self.public_root_resource, request) + self.assertIsInstance(child_resource, LoginResource) + + @patch('pixelated.resources.mails_resource.events.register') + def test_root_url_should_redirect_to_login_resource(self, *mocks): + self.public_root_resource.initialize(provider=mock(), authenticator=mock()) + request = DummyRequest(['']) + request.addCookie = MagicMock(return_value='stubbed') + d = self.web.get(request) + + def assert_redirect(request): + self.assertEqual(302, request.responseCode) + self.assertEqual(["login"], request.responseHeaders.getRawHeaders('location', [None])) + + d.addCallback(assert_redirect) + return d class TestRootResource(unittest.TestCase): @@ -24,29 +105,46 @@ class TestRootResource(unittest.TestCase): when(self.services_factory).services(ANY()).thenReturn(self.services) self.mail_service.account_email = self.MAIL_ADDRESS - root_resource = RootResource(self.services_factory) - root_resource._html_template = "<html><head><title>$account_email</title></head></html>" - root_resource._mode = root_resource - self.web = DummySite(root_resource) - self.root_resource = root_resource - - def test_render_GET_should_template_account_email(self): + self.root_resource = RootResource(self.services_factory, get_static_folder()) + self.web = DummySite(self.root_resource) + + @patch('pixelated.resources.mails_resource.events.register') + def test_put_child_protected_adds_resource(self, *mocks): + self.root_resource.initialize(provider=mock(), authenticator=mock()) + url_fragment, resource_mock = 'some-url-fragment', mock() + self.root_resource.putChildProtected(url_fragment, resource_mock) + request = DummyRequest([url_fragment]) + request.addCookie = MagicMock(return_value='stubbed') + child_resource = getChildForRequest(self.root_resource, request) + self.assertIs(child_resource, resource_mock) + + @patch('pixelated.resources.mails_resource.events.register') + def test_put_child_adds_resource(self, *mocks): + self.root_resource.initialize(provider=mock(), authenticator=mock()) + url_fragment, resource_mock = 'some-url-fragment', mock() + self.root_resource.putChild(url_fragment, resource_mock) + request = DummyRequest([url_fragment]) + request.addCookie = MagicMock(return_value='stubbed') + child_resource = getChildForRequest(self.root_resource, request) + self.assertIs(child_resource, resource_mock) + + def test_root_url_should_delegate_to_inbox(self): request = DummyRequest(['']) - request.addCookie = lambda key, value: 'stubbed' - - d = self.web.get(request) - - def assert_response(_): - expected = "<title>{0}</title>".format(self.MAIL_ADDRESS) - matches = re.findall(expected, request.written[0]) - self.assertEquals(len(matches), 1) - - d.addCallback(assert_response) - return d + request.addCookie = MagicMock(return_value='stubbed') + child_resource = getChildForRequest(self.root_resource, request) + self.assertIsInstance(child_resource, InboxResource) + + @patch('pixelated.resources.mails_resource.events.register') + def test_login_url_should_delegate_to_login_resource(self, *mocks): + self.root_resource.initialize(provider=mock(), authenticator=mock()) + request = DummyRequest(['login']) + request.addCookie = MagicMock(return_value='stubbed') + child_resource = getChildForRequest(self.root_resource, request) + self.assertIsInstance(child_resource, LoginResource) def _test_should_renew_xsrf_cookie(self): request = DummyRequest(['']) - request.addCookie = MagicMock() + request.addCookie = MagicMock(return_value='stubbed') generated_csrf_token = 'csrf_token' mock_sha = MagicMock() mock_sha.hexdigest = MagicMock(return_value=generated_csrf_token) @@ -72,6 +170,7 @@ class TestRootResource(unittest.TestCase): self.root_resource._mode = MODE_STARTUP request = DummyRequest(['/child']) + request.addCookie = MagicMock(return_value='stubbed') request.getCookie = MagicMock(return_value='irrelevant -- stubbed') d = self.web.get(request) @@ -87,8 +186,12 @@ class TestRootResource(unittest.TestCase): request.requestHeaders.setRawHeaders('x-requested-with', ['XMLHttpRequest']) request.requestHeaders.setRawHeaders('x-xsrf-token', [csrf_token]) - def test_should_unauthorize_child_resource_ajax_requests_when_csrf_mismatch(self): + @patch('pixelated.resources.mails_resource.events.register') + def test_should_unauthorize_child_resource_ajax_requests_when_csrf_mismatch(self, *mocks): + self.root_resource.initialize(provider=mock(), authenticator=mock()) + request = DummyRequest(['/child']) + request.addCookie = MagicMock(return_value='stubbed') request.method = 'POST' self._mock_ajax_csrf(request, 'stubbed csrf token') @@ -103,11 +206,46 @@ class TestRootResource(unittest.TestCase): d.addCallback(assert_unauthorized) return d - def test_should_404_non_existing_resource_with_valid_csrf(self): - request = DummyRequest(['/non-existing-child']) + def test_GET_should_return_503_for_uninitialized_resource(self): + request = DummyRequest(['/sandbox/']) + request.addCookie = MagicMock(return_value='stubbed') + request.method = 'GET' + + request.getCookie = MagicMock(return_value='stubbed csrf token') + + d = self.web.get(request) + + def assert_unavailable(_): + self.assertEqual(503, request.responseCode) + + d.addCallback(assert_unavailable) + return d + + @patch('pixelated.resources.mails_resource.events.register') + def test_GET_should_return_404_for_non_existing_resource(self, *mocks): + self.root_resource.initialize(provider=mock(), authenticator=mock()) + + request = DummyRequest(['non-existing-child']) + request.addCookie = MagicMock(return_value='stubbed') + request.method = 'GET' + request.getCookie = MagicMock(return_value='stubbed csrf token') + + d = self.web.get(request) + + def assert_not_found(_): + self.assertEqual(404, request.responseCode) + + d.addCallback(assert_not_found) + return d + + @patch('pixelated.resources.mails_resource.events.register') + def test_should_404_non_existing_resource_with_valid_csrf(self, *mocks): + self.root_resource.initialize(provider=mock(), authenticator=mock()) + + request = DummyRequest(['non-existing-child']) + request.addCookie = MagicMock(return_value='stubbed') request.method = 'POST' self._mock_ajax_csrf(request, 'stubbed csrf token') - request.getCookie = MagicMock(return_value='stubbed csrf token') d = self.web.get(request) @@ -121,9 +259,10 @@ class TestRootResource(unittest.TestCase): def test_should_authorize_child_resource_non_ajax_GET_requests(self): request = DummyRequest(['features']) + request.addCookie = MagicMock(return_value='stubbed') request.getCookie = MagicMock(return_value='irrelevant -- stubbed') - self.root_resource._child_resources.add('features', FeaturesResource()) + self.root_resource.putChild('features', FeaturesResource()) self.root_resource._mode = MODE_RUNNING d = self.web.get(request) @@ -134,7 +273,10 @@ class TestRootResource(unittest.TestCase): d.addCallback(assert_unauthorized) return d - def test_should_unauthorize_child_resource_non_ajax_POST_requests_when_csrf_input_mismatch(self): + @patch('pixelated.resources.mails_resource.events.register') + def test_should_unauthorize_child_resource_non_ajax_POST_requests_when_csrf_input_mismatch(self, *mocks): + self.root_resource.initialize(provider=mock(), authenticator=mock()) + request = DummyRequest(['mails']) request.method = 'POST' request.addArg('csrftoken', 'some csrf token') @@ -142,6 +284,7 @@ class TestRootResource(unittest.TestCase): mock_content.read = MagicMock(return_value={}) request.content = mock_content + request.addCookie = MagicMock(return_value='stubbed') request.getCookie = MagicMock(return_value='mismatched csrf token') d = self.web.get(request) @@ -152,3 +295,62 @@ class TestRootResource(unittest.TestCase): d.addCallback(assert_unauthorized) return d + + @patch('pixelated.resources.mails_resource.events.register') + def test_assets_should_be_publicly_available(self, *mocks): + self.root_resource.initialize(provider=mock(), authenticator=mock()) + + request = DummyRequest(['static', 'dummy.json']) + request.addCookie = MagicMock(return_value='stubbed') + d = self.web.get(request) + + def assert_response(_): + self.assertEqual(200, request.responseCode) + + d.addCallback(assert_response) + return d + + @patch('pixelated.resources.mails_resource.events.register') + def test_login_should_be_publicly_available(self, *mocks): + self.root_resource.initialize(provider=mock(), authenticator=mock()) + + request = DummyRequest(['login']) + request.addCookie = MagicMock(return_value='stubbed') + d = self.web.get(request) + + def assert_response(_): + self.assertEqual(200, request.responseCode) + + d.addCallback(assert_response) + return d + + def test_root_should_be_handled_by_inbox_resource(self): + request = DummyRequest([]) + request.addCookie = MagicMock(return_value='stubbed') + request.prepath = [''] + request.path = '/' + + resource = self.root_resource.getChildWithDefault(request.prepath[-1], request) + self.assertIsInstance(resource, InboxResource) + + def test_inbox_should_not_be_public(self): + request = DummyRequest([]) + request.addCookie = MagicMock(return_value='stubbed') + request.prepath = [''] + request.path = '/' + + resource = self.root_resource.getChildWithDefault(request.prepath[-1], request) + self.assertIsInstance(resource, InboxResource) + + def test_every_url_should_get_csrftoken_header(self): + # self.root_resource.initialize(provider=mock(), authenticator=mock()) + request = DummyRequest(['any']) + request.addCookie = MagicMock(return_value='stubbed') + d = self.web.get(request) + + def assert_add_cookie_called_for_csrftoken(request): + csrftoken = IPixelatedSession(request.getSession()).get_csrf_token() + self.assertEqual([(('XSRF-TOKEN', csrftoken),)], request.addCookie.call_args_list) + + d.addCallback(assert_add_cookie_called_for_csrftoken) + return d diff --git a/service/test/unit/resources/test_session.py b/service/test/unit/resources/test_session.py new file mode 100644 index 00000000..fe47483d --- /dev/null +++ b/service/test/unit/resources/test_session.py @@ -0,0 +1,25 @@ +from twisted.trial import unittest +from mockito import mock +from pixelated.resources.session import CSRF_TOKEN_LENGTH, PixelatedSession + + +class TestPixelatedSession(unittest.TestCase): + + def setUp(self): + self.pixelated_session = PixelatedSession(mock()) + + def test_csrf_token_should_be_configured_length(self): + self.assertEqual(len(self.pixelated_session.get_csrf_token()), 2 * CSRF_TOKEN_LENGTH) + + def test_csrf_token_should_be_hexdigested(self): + self.assertTrue(all(c in '0123456789abcdef' for c in self.pixelated_session.get_csrf_token())) + + def test_csrf_token_should_always_be_the_same_for_one_session(self): + first_csrf_token = self.pixelated_session.get_csrf_token() + second_csrf_token = self.pixelated_session.get_csrf_token() + self.assertEqual(first_csrf_token, second_csrf_token) + + def test_csrf_token_should_be_different_for_different_session(self): + first_csrf_token = self.pixelated_session.get_csrf_token() + second_csrf_token = PixelatedSession(mock()).get_csrf_token() + self.assertNotEqual(first_csrf_token, second_csrf_token) diff --git a/service/test/unit/test_welcome_mail.py b/service/test/unit/test_welcome_mail.py index 7eb65903..42e21e8d 100644 --- a/service/test/unit/test_welcome_mail.py +++ b/service/test/unit/test_welcome_mail.py @@ -41,8 +41,7 @@ class TestWelcomeMail(unittest.TestCase): with open(os.path.join(current_path, '..', '..', - 'pixelated', - 'assets', + 'templates', 'welcome.mail.pt-BR')) as mail_template_file: mail_template = message_from_file(mail_template_file) |