/tests/test_handlers.py
Python | 418 lines | 394 code | 10 blank | 14 comment | 0 complexity | f16b393353be9112cf5784249b03a9c6 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception
- # This Source Code Form is subject to the terms of the Mozilla Public
- # License, v. 2.0. If a copy of the MPL was not distributed with this
- # file, You can obtain one at http://mozilla.org/MPL/2.0/.
- """Unit tests for the handlers"""
- import json
- from datetime import datetime
- from datetime import timedelta as tdelta
- import jwt
- from sqlalchemy import create_engine
- from sqlalchemy.orm import sessionmaker
- from tornado import testing, escape
- from tornado.web import Application
- from tornado_sqlalchemy import make_session_factory
- from grumponado.app import assign_handlers
- from grumponado.models import Users, BASE, Tokens
- PW = b'password'
- PW_HASH = b'$2b$04$eA9hGoyi5xAp0SKE49RW2eMpOA69u0ObcmQoV/M82UtzHlDydjHwy'
- class HandlerTests(testing.AsyncHTTPTestCase):
- """Base class for the setup and tear down of handler tests. It defines the
- basic setup for the database and also provides the tear down method
- """
- db = 'postgres://localhost:5432/py_unit_test'
- engine = create_engine(db)
- def setUp(self):
- """Set up for the database"""
- super(HandlerTests, self).setUp()
- BASE.metadata.create_all(self.engine)
- def tearDown(self):
- """Tear down for the database"""
- super(HandlerTests, self).tearDown()
- BASE.metadata.drop_all(self.engine)
- def get_app(self):
- """Get the tornado app to run the tests. This is a default
- configuration
- """
- routes = assign_handlers('tests')
- session_factory = make_session_factory(self.db)
- return Application(routes,
- session_factory=session_factory,
- cookie_secret='pytest',
- hashing_salt='pysalt')
- class UserHandlerPreps(HandlerTests):
- """Setup different users"""
- def setUp(self):
- """Database set up with a default user. Base class is overwritten"""
- super(UserHandlerPreps, self).setUp()
- session = sessionmaker()
- session.configure(bind=self.engine)
- users_sammy = Users(
- user='sammy',
- email='sammy@gmx.net',
- password=PW_HASH,
- avatar=''
- )
- users_notsammy = Users(
- user='notsammy',
- email='notsammy@gmx.net',
- password=PW_HASH,
- avatar=''
- )
- dbsession = session()
- try:
- dbsession.add(users_notsammy)
- dbsession.commit()
- dbsession.add(users_sammy)
- dbsession.commit()
- token = Tokens(users_notsammy.id, 'yay', 'nope', 'nope')
- delta = datetime.utcnow() - tdelta(days=15)
- token2 = Tokens(users_notsammy.id, 'yay2', 'nope', 'nope', delta)
- token2.last_refresh = delta
- dbsession.add(token)
- dbsession.commit()
- dbsession.add(token2)
- dbsession.commit()
- finally:
- dbsession.close()
- def get_app(self):
- """Create an app for testing"""
- routes = assign_handlers('tests')
- session_factory = make_session_factory(self.db)
- return Application(routes,
- session_factory=session_factory,
- cookie_secret='pytest',
- login_url='/404',
- hashing_salt='pysalt')
- class TestMainHandlers(HandlerTests):
- """Tests for the main entry point"""
- def test_get_main(self):
- """Get the base route, without a trailing slash"""
- response = self.fetch('/tests')
- self.assertEqual(response.code, 200)
- def test_get_main_trailing_slash(self):
- """Get the base route, without a trailing slash"""
- response = self.fetch('/tests/')
- self.assertEqual(response.code, 200)
- class TestUserHandlers(HandlerTests):
- """The user handler tests to test the creation, deletion and update of
- users.
- """
- def setUp(self):
- """Database set up with a default user. Base class is overwritten"""
- super(TestUserHandlers, self).setUp()
- session = sessionmaker()
- session.configure(bind=self.engine)
- user = Users(
- user='notsammy',
- email='notsammy@gmx.net',
- password=PW,
- avatar=''
- )
- dbsession = session()
- try:
- dbsession.add(user)
- dbsession.commit()
- finally:
- dbsession.close()
- def test_user_get_inexistent_user(self):
- """Get the infos of a particular user, that does not exist"""
- response = self.fetch('/tests/users/sammy')
- self.assertEqual(response.code, 404)
- def test_user_get_user(self):
- """Get the infos of a particular user, that does exist"""
- response = self.fetch('/tests/users/notsammy')
- self.assertEqual(response.code, 200)
- def test_user_create_validation(self):
- """Test the validation when creating a user"""
- response = self.fetch('/tests/users/', method='POST', body='{}')
- self.assertEqual(response.code, 400)
- def test_user_create_not_json(self):
- """Test if the validation fails if the supplied data is not json"""
- response = self.fetch('/tests/users/', method='POST', body='_')
- self.assertEqual(response.code, 400)
- def test_user_create_user_exists(self):
- """Test handling if someone tries to create a user, that already
- exists
- """
- test_user = {'name': 'sammy',
- 'email': 'sammy@domain.tld',
- 'password': '12345678abcd'}
- self.fetch('/tests/users/', method='POST', body=json.dumps(test_user))
- response = self.fetch('/tests/users/',
- method='POST',
- body=json.dumps(test_user))
- self.assertEqual(response.code, 400)
- def test_user_create_type_error(self):
- """Test exception handling, when the supplied data are of the wrong
- type
- """
- test_user = {'name': 102,
- 'email': 'samm2y@domain.tld',
- 'password': '12345678abcd'}
- response = self.fetch('/tests/users/', method='POST', body=json.dumps(test_user))
- self.assertEqual(response.code, 400)
- class TestLoginLogoutHandlers(UserHandlerPreps):
- """Login and logout tests"""
- def test_login_login_errors(self):
- """Login with an error, missing user or email"""
- body = json.dumps({'email': 'notsammy@gmx.net'})
- response = self.fetch('/tests/login', method='POST', body=body)
- self.assertEqual(response.code, 400)
- body2 = json.dumps({'password': 'password'})
- response2 = self.fetch('/tests/login', method='POST', body=body2)
- self.assertEqual(response2.code, 400)
- body3 = json.dumps({'password': None})
- response3 = self.fetch('/tests/login', method='POST', body=body3)
- self.assertEqual(response3.code, 400)
- def test_login_format_errors(self):
- """Test login with a format error"""
- body = "{'email': 'notsammy@gmx.net'})2"
- response = self.fetch('/tests/login', method='POST', body=body)
- self.assertEqual(400, response.code)
- def test_login_wrong_password(self):
- """Test login with a wrong password"""
- body = json.dumps({'email': 'notsammy@gmx.net',
- 'password': 'password2'})
- response = self.fetch('/tests/login', method='POST', body=body)
- self.assertEqual(400, response.code)
- body = response.body.decode('utf-8')
- self.assertTrue('2004' in body)
- def test_login_wrong_name(self):
- """Test login with a wrong name"""
- body = json.dumps({'email': 'notsammy@gmx.net2',
- 'password': 'password'})
- response = self.fetch('/tests/login', method='POST', body=body)
- self.assertEqual(400, response.code)
- body = response.body.decode('utf-8')
- self.assertTrue('2004' in body)
- def test_login_success(self):
- """Test the successfull login"""
- body = json.dumps({'email': 'notsammy@gmx.net',
- 'password': 'password'})
- response = self.fetch('/tests/login', method='POST', body=body)
- body = response.body.decode('utf-8')
- self.assertEqual(200, response.code)
- self.assertTrue('5002' in body)
- self.assertTrue('user_name' in body)
- def test_logout(self):
- """Test to logout users"""
- token = jwt.encode({
- 'sub': 0,
- 'name': 'notsammy',
- 'iat': datetime.utcnow().timestamp(),
- 'exp': datetime.utcnow().timestamp() + 86000,
- 'refresh': 'yay'
- }, key='pytest', algorithm='HS256').decode('utf-8')
- response = self.fetch('/tests/logout', method='GET', headers={'Authorization': 'Bearer ' + token})
- self.assertEqual(200, response.code)
- decoded_body = response.body.decode('utf-8')
- found = '5001' in decoded_body
- self.assertTrue(found)
- def test_refresh_valid_jwt(self):
- """Test the refresh with a valid token"""
- token = jwt.encode({
- 'sub': 0,
- 'name': 'notsammy',
- 'iat': datetime.utcnow().timestamp(),
- 'exp': datetime.utcnow().timestamp() + 86000,
- 'refresh': 'yay'
- }, key='pytest', algorithm='HS256').decode('utf-8')
- response = self.fetch('/tests/me', method='GET', headers={'Authorization': 'Bearer ' + token})
- body = escape.json_decode(response.body.decode('utf-8'))
- self.assertIsNotNone(body['auth'])
- self.assertEqual(body['auth'].split('.')[0], 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9')
- def test_refresh_old_jwt(self):
- """Test the refresh with an expired token"""
- token = jwt.encode({
- 'sub': 0,
- 'name': 'notsammy',
- 'iat': datetime.utcnow().timestamp(),
- 'exp': datetime.utcnow().timestamp() - 86000,
- 'refresh': 'yay'
- }, key='pytest', algorithm='HS256').decode('utf-8')
- response = self.fetch('/tests/me', method='GET', headers={'Authorization': 'Bearer ' + token})
- body = escape.json_decode(response.body.decode('utf-8'))
- self.assertIsNotNone(body['auth'])
- self.assertEqual(body['auth'].split('.')[0], 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9')
- def test_refresh_old_refresh(self):
- """Test the refresh with an expired token"""
- token = jwt.encode({
- 'sub': 0,
- 'name': 'notsammy',
- 'iat': datetime.utcnow().timestamp(),
- 'exp': datetime.utcnow().timestamp() - 86000,
- 'refresh': 'yay2'
- }, key='pytest', algorithm='HS256').decode('utf-8')
- response = self.fetch('/tests/me', method='GET', headers={'Authorization': 'Bearer ' + token})
- self.assertEqual(response.code, 404)
- def test_missing_inexisting_user(self):
- """Test the refresh with an expired token"""
- token = jwt.encode({
- 'sub': 0,
- 'name': 'nope',
- 'iat': datetime.utcnow().timestamp(),
- 'exp': datetime.utcnow().timestamp() + 86000,
- 'refresh': 'yay'
- }, key='pytest', algorithm='HS256').decode('utf-8')
- response = self.fetch('/tests/me', method='GET', headers={'Authorization': 'Bearer ' + token})
- self.assertEqual(response.code, 401)
- def test_missing_refresh(self):
- """Test the refresh with an expired token"""
- token = jwt.encode({
- 'sub': 0,
- 'name': 'notsammy',
- 'iat': datetime.utcnow().timestamp(),
- 'exp': datetime.utcnow().timestamp() - 86000,
- }, key='pytest', algorithm='HS256').decode('utf-8')
- response = self.fetch('/tests/me', method='GET', headers={'Authorization': 'Bearer ' + token})
- self.assertEqual(response.code, 404)
- def test_malicious_token(self):
- """Test the refresh with an expired token"""
- response = self.fetch('/tests/me', method='GET', headers={'Authorization': 'Bearer ' + 'aaX'})
- self.assertEqual(response.code, 404)
- class TestRating(UserHandlerPreps):
- """Rating tests"""
- jwt_token = jwt.encode({
- 'sub': 1,
- 'name': 'sammy',
- 'iat': datetime.utcnow().timestamp(),
- 'exp': datetime.utcnow().timestamp() + 86000,
- 'refresh': 'yay'
- }, key='pytest', algorithm='HS256').decode('utf-8')
- def get_app(self):
- """Create an app for testing"""
- routes = assign_handlers('tests')
- session_factory = make_session_factory(self.db)
- return Application(routes,
- session_factory=session_factory,
- cookie_secret='pytest',
- login_url='/404',
- hashing_salt='pysalt')
- def test_increase_ratings(self):
- """Test of increasing ratings"""
- responses_community = []
- responses_self = []
- for _ in range(5):
- responses_community.append(self.fetch('/tests/users/sammy', method='PUT', body='action=increase',
- headers={'Authorization': 'Bearer ' + self.jwt_token,
- 'Content-Type': 'application/x-www-form-urlencoded'}))
- responses_self.append(self.fetch('/tests/users/notsammy', method='PUT', body='action=increase',
- headers={'Authorization': 'Bearer ' + self.jwt_token,
- 'Content-Type': 'application/x-www-form-urlencoded'}))
- response_bodies_community = [escape.json_decode(i.body.decode('utf-8')) for i in responses_community]
- response_bodies_self = [escape.json_decode(i.body.decode('utf-8')) for i in responses_self]
- try:
- ratings_community = [i['result']['community_rating'] for i in response_bodies_community]
- ratings_self = [i['result']['self_rating'] for i in response_bodies_self]
- except KeyError:
- raise KeyError
- self.assertGreater(ratings_community[4], ratings_community[3])
- self.assertGreater(ratings_self[4], ratings_self[3])
- def test_decrease_ratings(self):
- """Test of decreasing ratings"""
- responses_community = []
- responses_self = []
- action = 'action=increase'
- for i in range(5):
- if i > 3:
- action = 'action=decrease'
- responses_community.append(self.fetch('/tests/users/sammy', method='PUT', body=action,
- headers={'Authorization': 'Bearer ' + self.jwt_token,
- 'Content-Type': 'application/x-www-form-urlencoded'}))
- responses_self.append(self.fetch('/tests/users/notsammy', method='PUT', body=action,
- headers={'Authorization': 'Bearer ' + self.jwt_token,
- 'Content-Type': 'application/x-www-form-urlencoded'}))
- response_bodies_community = [escape.json_decode(i.body.decode('utf-8')) for i in responses_community]
- response_bodies_self = [escape.json_decode(i.body.decode('utf-8')) for i in responses_self]
- try:
- ratings_community = [i['result']['community_rating'] for i in response_bodies_community]
- ratings_self = [i['result']['self_rating'] for i in response_bodies_self]
- except KeyError:
- raise KeyError
- self.assertLess(ratings_community[4], ratings_community[3])
- self.assertLess(ratings_self[4], ratings_self[3])
- def test_missing_arguments(self):
- """Test of missing arguments when ratings"""
- responses = self.fetch('/tests/users/notsammy', method='PUT', body=b'',
- headers={'Authorization': 'Bearer ' + self.jwt_token,
- 'Content-Type': 'application/x-www-form-urlencoded'})
- self.assertEqual(responses.code, 403)
- class TestUserProfileHandler(UserHandlerPreps):
- """Profile tests"""
- jwt_token = jwt.encode({
- 'sub': 1,
- 'name': 'sammy',
- 'iat': datetime.utcnow().timestamp(),
- 'exp': datetime.utcnow().timestamp() + 86000,
- 'refresh': 'yay'
- }, key='pytest', algorithm='HS256').decode('utf-8')
- def get_app(self):
- """Create an app for testing"""
- routes = assign_handlers('tests')
- session_factory = make_session_factory(self.db)
- return Application(routes,
- session_factory=session_factory,
- cookie_secret='pytest',
- login_url='/404',
- hashing_salt='pysalt')
- def test_delete_user(self):
- """Test for the deletion of users"""
- response_before_delete = self.fetch('/tests/users/sammy')
- self.assertEqual(response_before_delete.code, 200)
- responses_delete = self.fetch('/tests/me', method='DELETE',
- headers={'Authorization': 'Bearer ' + self.jwt_token,
- 'Content-Type': 'application/x-www-form-urlencoded'})
- body = escape.json_decode(responses_delete.body.decode('utf-8'))
- self.assertEqual(body['code'], 5006)
- response_after_delete = self.fetch('/tests/users/sammy')
- self.assertEqual(response_after_delete.code, 404)