server/tests: switch to pytest
This commit is contained in:
		
							parent
							
								
									7f8c2cfa00
								
							
						
					
					
						commit
						07ea920def
					
				
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -1,2 +1,4 @@ | |||||||
| config.yaml | config.yaml | ||||||
| */*_modules/ | */*_modules/ | ||||||
|  | .coverage | ||||||
|  | .cache | ||||||
|  | |||||||
| @ -3,4 +3,5 @@ pyyaml>=3.11 | |||||||
| falcon>=0.3.0 | falcon>=0.3.0 | ||||||
| psycopg2>=2.6.1 | psycopg2>=2.6.1 | ||||||
| SQLAlchemy>=1.0.12 | SQLAlchemy>=1.0.12 | ||||||
| green>=2.4.0 | pytest>=2.9.1 | ||||||
|  | pytest-cov>=2.2.1 | ||||||
|  | |||||||
							
								
								
									
										78
									
								
								server/szurubooru/tests/api/test_password_reset.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								server/szurubooru/tests/api/test_password_reset.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,78 @@ | |||||||
|  | from datetime import datetime | ||||||
|  | from unittest import mock | ||||||
|  | import pytest | ||||||
|  | from szurubooru import api, db, errors | ||||||
|  | from szurubooru.util import auth, mailer | ||||||
|  | 
 | ||||||
|  | def mock_user(name, rank, email): | ||||||
|  |     user = db.User() | ||||||
|  |     user.name = name | ||||||
|  |     user.password = 'dummy' | ||||||
|  |     user.password_salt = 'dummy' | ||||||
|  |     user.password_hash = 'dummy' | ||||||
|  |     user.email = email | ||||||
|  |     user.rank = rank | ||||||
|  |     user.creation_time = datetime(1997, 1, 1) | ||||||
|  |     user.avatar_style = db.User.AVATAR_GRAVATAR | ||||||
|  |     return user | ||||||
|  | 
 | ||||||
|  | @pytest.fixture | ||||||
|  | def password_reset_api(config_injector): | ||||||
|  |     config_injector({ | ||||||
|  |         'secret': 'x', | ||||||
|  |         'base_url': 'http://example.com/', | ||||||
|  |         'name': 'Test instance', | ||||||
|  |     }) | ||||||
|  |     return api.PasswordResetApi() | ||||||
|  | 
 | ||||||
|  | def test_reset_non_existing(password_reset_api, context_factory): | ||||||
|  |     with pytest.raises(errors.NotFoundError): | ||||||
|  |         password_reset_api.get(context_factory(), 'u1') | ||||||
|  | 
 | ||||||
|  | def test_reset_without_email(password_reset_api, session, context_factory): | ||||||
|  |     user = mock_user('u1', 'regular_user', None) | ||||||
|  |     session.add(user) | ||||||
|  |     with pytest.raises(errors.ValidationError): | ||||||
|  |         password_reset_api.get(context_factory(), 'u1') | ||||||
|  | 
 | ||||||
|  | def test_reset_sending_email(password_reset_api, session, context_factory): | ||||||
|  |     user = mock_user('u1', 'regular_user', 'user@example.com') | ||||||
|  |     session.add(user) | ||||||
|  |     for getter in ['u1', 'user@example.com']: | ||||||
|  |         mailer.send_mail = mock.MagicMock() | ||||||
|  |         assert password_reset_api.get(context_factory(), getter) == {} | ||||||
|  |         mailer.send_mail.assert_called_once_with( | ||||||
|  |             'noreply@Test instance', | ||||||
|  |             'user@example.com', | ||||||
|  |             'Password reset for Test instance', | ||||||
|  |             'You (or someone else) requested to reset your password ' + | ||||||
|  |             'on Test instance.\nIf you wish to proceed, click this l' + | ||||||
|  |             'ink: http://example.com/password-reset/u1:4ac0be176fb36' + | ||||||
|  |             '4f13ee6b634c43220e2\nOtherwise, please ignore this email.') | ||||||
|  | 
 | ||||||
|  | def test_confirmation_non_existing(password_reset_api, context_factory): | ||||||
|  |     with pytest.raises(errors.NotFoundError): | ||||||
|  |         password_reset_api.post(context_factory(), 'u1') | ||||||
|  | 
 | ||||||
|  | def test_confirmation_no_token(password_reset_api, context_factory, session): | ||||||
|  |     user = mock_user('u1', 'regular_user', 'user@example.com') | ||||||
|  |     session.add(user) | ||||||
|  |     with pytest.raises(errors.ValidationError): | ||||||
|  |         password_reset_api.post(context_factory(request={}), 'u1') | ||||||
|  | 
 | ||||||
|  | def test_confirmation_bad_token(password_reset_api, context_factory, session): | ||||||
|  |     user = mock_user('u1', 'regular_user', 'user@example.com') | ||||||
|  |     session.add(user) | ||||||
|  |     with pytest.raises(errors.ValidationError): | ||||||
|  |         password_reset_api.post( | ||||||
|  |             context_factory(request={'token': 'bad'}), 'u1') | ||||||
|  | 
 | ||||||
|  | def test_confirmation_good_token(password_reset_api, context_factory, session): | ||||||
|  |     user = mock_user('u1', 'regular_user', 'user@example.com') | ||||||
|  |     old_hash = user.password_hash | ||||||
|  |     session.add(user) | ||||||
|  |     context = context_factory( | ||||||
|  |         request={'token': '4ac0be176fb364f13ee6b634c43220e2'}) | ||||||
|  |     result = password_reset_api.post(context, 'u1') | ||||||
|  |     assert user.password_hash != old_hash | ||||||
|  |     assert auth.is_valid_password(user, result['password']) is True | ||||||
| @ -1,68 +0,0 @@ | |||||||
| from unittest import mock |  | ||||||
| from szurubooru import api, errors |  | ||||||
| from szurubooru.util import auth, mailer |  | ||||||
| from szurubooru.tests.database_test_case import DatabaseTestCase |  | ||||||
| from szurubooru.tests.api import util |  | ||||||
| 
 |  | ||||||
| class TestPasswordReset(DatabaseTestCase): |  | ||||||
|     def setUp(self): |  | ||||||
|         super().setUp() |  | ||||||
|         util.mock_config({ |  | ||||||
|             'secret': 'x', |  | ||||||
|             'base_url': 'http://example.com/', |  | ||||||
|             'name': 'Test instance', |  | ||||||
|         }) |  | ||||||
|         util.mock_context(self) |  | ||||||
|         self.api = api.PasswordResetApi() |  | ||||||
| 
 |  | ||||||
|     def test_reset_non_existing(self): |  | ||||||
|         self.assertRaises(errors.NotFoundError, self.api.get, self.context, 'u1') |  | ||||||
| 
 |  | ||||||
|     def test_reset_without_email(self): |  | ||||||
|         user = util.mock_user('u1', 'regular_user') |  | ||||||
|         user.email = None |  | ||||||
|         self.session.add(user) |  | ||||||
|         self.assertRaises(errors.ValidationError, self.api.get, self.context, 'u1') |  | ||||||
| 
 |  | ||||||
|     def test_reset_sending_email(self): |  | ||||||
|         user = util.mock_user('u1', 'regular_user') |  | ||||||
|         user.email = 'user@example.com' |  | ||||||
|         self.session.add(user) |  | ||||||
|         for getter in ['u1', 'user@example.com']: |  | ||||||
|             mailer.send_mail = mock.MagicMock() |  | ||||||
|             self.assertEqual({}, self.api.get(self.context, getter)) |  | ||||||
|             mailer.send_mail.assert_called_once_with( |  | ||||||
|                 'noreply@Test instance', |  | ||||||
|                 'user@example.com', |  | ||||||
|                 'Password reset for Test instance', |  | ||||||
|                 'You (or someone else) requested to reset your password ' + |  | ||||||
|                 'on Test instance.\nIf you wish to proceed, click this l' + |  | ||||||
|                 'ink: http://example.com/password-reset/u1:4ac0be176fb36' + |  | ||||||
|                 '4f13ee6b634c43220e2\nOtherwise, please ignore this email.') |  | ||||||
| 
 |  | ||||||
|     def test_confirmation_non_existing(self): |  | ||||||
|         self.assertRaises(errors.NotFoundError, self.api.post, self.context, 'u1') |  | ||||||
| 
 |  | ||||||
|     def test_confirmation_no_token(self): |  | ||||||
|         user = util.mock_user('u1', 'regular_user') |  | ||||||
|         user.email = 'user@example.com' |  | ||||||
|         self.session.add(user) |  | ||||||
|         self.context.request = {} |  | ||||||
|         self.assertRaises(errors.ValidationError, self.api.post, self.context, 'u1') |  | ||||||
| 
 |  | ||||||
|     def test_confirmation_bad_token(self): |  | ||||||
|         user = util.mock_user('u1', 'regular_user') |  | ||||||
|         user.email = 'user@example.com' |  | ||||||
|         self.session.add(user) |  | ||||||
|         self.context.request = {'token': 'bad'} |  | ||||||
|         self.assertRaises(errors.ValidationError, self.api.post, self.context, 'u1') |  | ||||||
| 
 |  | ||||||
|     def test_confirmation_good_token(self): |  | ||||||
|         user = util.mock_user('u1', 'regular_user') |  | ||||||
|         user.email = 'user@example.com' |  | ||||||
|         old_hash = user.password_hash |  | ||||||
|         self.session.add(user) |  | ||||||
|         self.context.request = {'token': '4ac0be176fb364f13ee6b634c43220e2'} |  | ||||||
|         result = self.api.post(self.context, 'u1') |  | ||||||
|         self.assertNotEqual(user.password_hash, old_hash) |  | ||||||
|         self.assertTrue(auth.is_valid_password(user, result['password'])) |  | ||||||
| @ -1,366 +0,0 @@ | |||||||
| import tempfile |  | ||||||
| from datetime import datetime |  | ||||||
| from szurubooru import api, db, errors |  | ||||||
| from szurubooru.util import auth |  | ||||||
| from szurubooru.tests.database_test_case import DatabaseTestCase |  | ||||||
| from szurubooru.tests.api import util |  | ||||||
| 
 |  | ||||||
| class TestRetrievingUsers(DatabaseTestCase): |  | ||||||
|     def setUp(self): |  | ||||||
|         super().setUp() |  | ||||||
|         util.mock_config({ |  | ||||||
|             'privileges': { |  | ||||||
|                 'users:list': 'regular_user', |  | ||||||
|             }, |  | ||||||
|             'thumbnails': {'avatar_width': 200}, |  | ||||||
|             'ranks': ['anonymous', 'regular_user', 'mod', 'admin'], |  | ||||||
|             'rank_names': {}, |  | ||||||
|         }) |  | ||||||
|         util.mock_context(self) |  | ||||||
| 
 |  | ||||||
|     def test_retrieving_multiple(self): |  | ||||||
|         user1 = util.mock_user('u1', 'mod') |  | ||||||
|         user2 = util.mock_user('u2', 'mod') |  | ||||||
|         self.session.add_all([user1, user2]) |  | ||||||
|         util.mock_params(self.context, {'query': '', 'page': 1}) |  | ||||||
|         self.context.user.rank = 'regular_user' |  | ||||||
|         api_ = api.UserListApi() |  | ||||||
|         result = api_.get(self.context) |  | ||||||
|         self.assertEqual(result['query'], '') |  | ||||||
|         self.assertEqual(result['page'], 1) |  | ||||||
|         self.assertEqual(result['pageSize'], 100) |  | ||||||
|         self.assertEqual(result['total'], 2) |  | ||||||
|         self.assertEqual([u['name'] for u in result['users']], ['u1', 'u2']) |  | ||||||
| 
 |  | ||||||
|     def test_retrieving_multiple_without_privileges(self): |  | ||||||
|         self.context.user.rank = 'anonymous' |  | ||||||
|         util.mock_params(self.context, {'query': '', 'page': 1}) |  | ||||||
|         api_ = api.UserListApi() |  | ||||||
|         self.assertRaises(errors.AuthError, api_.get, self.context) |  | ||||||
| 
 |  | ||||||
|     def test_retrieving_non_existing(self): |  | ||||||
|         self.context.user.rank = 'regular_user' |  | ||||||
|         util.mock_params(self.context, {'query': 'asd', 'page': 1}) |  | ||||||
|         api_ = api.UserListApi() |  | ||||||
|         result = api_.get(self.context) |  | ||||||
|         self.assertEqual(result['query'], 'asd') |  | ||||||
|         self.assertEqual(result['page'], 1) |  | ||||||
|         self.assertEqual(result['pageSize'], 100) |  | ||||||
|         self.assertEqual(result['total'], 0) |  | ||||||
|         self.assertEqual([u['name'] for u in result['users']], []) |  | ||||||
| 
 |  | ||||||
| class TestRetrievingUser(DatabaseTestCase): |  | ||||||
|     def setUp(self): |  | ||||||
|         super().setUp() |  | ||||||
|         util.mock_config({ |  | ||||||
|             'privileges': { |  | ||||||
|                 'users:view': 'regular_user', |  | ||||||
|             }, |  | ||||||
|             'thumbnails': {'avatar_width': 200}, |  | ||||||
|             'ranks': ['anonymous', 'regular_user', 'mod', 'admin'], |  | ||||||
|             'rank_names': {}, |  | ||||||
|         }) |  | ||||||
|         util.mock_context(self) |  | ||||||
| 
 |  | ||||||
|     def test_retrieving_single(self): |  | ||||||
|         user = util.mock_user('u1', 'regular_user') |  | ||||||
|         self.session.add(user) |  | ||||||
|         self.context.user.rank = 'regular_user' |  | ||||||
|         util.mock_params(self.context, {'query': '', 'page': 1}) |  | ||||||
|         api_ = api.UserDetailApi() |  | ||||||
|         result = api_.get(self.context, 'u1') |  | ||||||
|         self.assertEqual(result['user']['id'], user.user_id) |  | ||||||
|         self.assertEqual(result['user']['name'], 'u1') |  | ||||||
|         self.assertEqual(result['user']['rank'], 'regular_user') |  | ||||||
|         self.assertEqual(result['user']['creationTime'], datetime(1997, 1, 1)) |  | ||||||
|         self.assertEqual(result['user']['lastLoginTime'], None) |  | ||||||
|         self.assertEqual(result['user']['avatarStyle'], 'gravatar') |  | ||||||
| 
 |  | ||||||
|     def test_retrieving_non_existing(self): |  | ||||||
|         self.context.user.rank = 'regular_user' |  | ||||||
|         util.mock_params(self.context, {'query': '', 'page': 1}) |  | ||||||
|         api_ = api.UserDetailApi() |  | ||||||
|         self.assertRaises(errors.NotFoundError, api_.get, self.context, '-') |  | ||||||
| 
 |  | ||||||
|     def test_retrieving_single_without_privileges(self): |  | ||||||
|         self.context.user.rank = 'anonymous' |  | ||||||
|         util.mock_params(self.context, {'query': '', 'page': 1}) |  | ||||||
|         api_ = api.UserDetailApi() |  | ||||||
|         self.assertRaises(errors.AuthError, api_.get, self.context, '-') |  | ||||||
| 
 |  | ||||||
| class TestDeletingUser(DatabaseTestCase): |  | ||||||
|     def setUp(self): |  | ||||||
|         super().setUp() |  | ||||||
|         util.mock_config({ |  | ||||||
|             'privileges': { |  | ||||||
|                 'users:delete:self': 'regular_user', |  | ||||||
|                 'users:delete:any': 'mod', |  | ||||||
|             }, |  | ||||||
|             'ranks': ['anonymous', 'regular_user', 'mod', 'admin'], |  | ||||||
|             'rank_names': {}, |  | ||||||
|         }) |  | ||||||
|         util.mock_context(self) |  | ||||||
| 
 |  | ||||||
|     def test_removing_oneself(self): |  | ||||||
|         user1 = util.mock_user('u1', 'regular_user') |  | ||||||
|         user2 = util.mock_user('u2', 'regular_user') |  | ||||||
|         self.session.add_all([user1, user2]) |  | ||||||
|         self.session.commit() |  | ||||||
|         self.context.user.user_id = user1.user_id |  | ||||||
|         self.context.user.rank = 'regular_user' |  | ||||||
|         api_ = api.UserDetailApi() |  | ||||||
|         self.assertRaises(errors.AuthError, api_.delete, self.context, 'u2') |  | ||||||
|         api_.delete(self.context, 'u1') |  | ||||||
|         self.assertEqual(self.session.query(db.User).filter_by(name='u1').all(), []) |  | ||||||
| 
 |  | ||||||
|     def test_removing_someone_else(self): |  | ||||||
|         user1 = util.mock_user('u1', 'regular_user') |  | ||||||
|         user2 = util.mock_user('u2', 'regular_user') |  | ||||||
|         self.session.add_all([user1, user2]) |  | ||||||
|         self.session.commit() |  | ||||||
|         self.context.user.rank = 'mod' |  | ||||||
|         api_ = api.UserDetailApi() |  | ||||||
|         api_.delete(self.context, 'u1') |  | ||||||
|         api_.delete(self.context, 'u2') |  | ||||||
|         self.assertEqual(self.session.query(db.User).filter_by(name='u1').all(), []) |  | ||||||
|         self.assertEqual(self.session.query(db.User).filter_by(name='u2').all(), []) |  | ||||||
| 
 |  | ||||||
|     def test_removing_non_existing(self): |  | ||||||
|         self.context.user.rank = 'regular_user' |  | ||||||
|         api_ = api.UserDetailApi() |  | ||||||
|         self.assertRaises(errors.NotFoundError, api_.delete, self.context, 'bad') |  | ||||||
| 
 |  | ||||||
| class TestCreatingUser(DatabaseTestCase): |  | ||||||
|     def setUp(self): |  | ||||||
|         super().setUp() |  | ||||||
|         util.mock_config({ |  | ||||||
|             'secret': '', |  | ||||||
|             'user_name_regex': '.{3,}', |  | ||||||
|             'password_regex': '.{3,}', |  | ||||||
|             'default_rank': 'regular_user', |  | ||||||
|             'thumbnails': {'avatar_width': 200}, |  | ||||||
|             'ranks': ['anonymous', 'regular_user', 'mod', 'admin'], |  | ||||||
|             'rank_names': {}, |  | ||||||
|             'privileges': { |  | ||||||
|                 'users:create': 'anonymous', |  | ||||||
|             }, |  | ||||||
|         }) |  | ||||||
|         self.api = api.UserListApi() |  | ||||||
|         util.mock_context(self) |  | ||||||
|         self.context.user.rank = 'anonymous' |  | ||||||
| 
 |  | ||||||
|     def test_first_user_becomes_admin(self): |  | ||||||
|         self.context.request = { |  | ||||||
|             'name': 'chewie', |  | ||||||
|             'email': 'asd@asd.asd', |  | ||||||
|             'password': 'oks', |  | ||||||
|         } |  | ||||||
|         self.api.post(self.context) |  | ||||||
|         created_user = self.session.query(db.User).filter_by(name='chewie').one() |  | ||||||
|         self.assertEqual(created_user.name, 'chewie') |  | ||||||
|         self.assertEqual(created_user.email, 'asd@asd.asd') |  | ||||||
|         self.assertEqual(created_user.rank, 'admin') |  | ||||||
|         self.assertTrue(auth.is_valid_password(created_user, 'oks')) |  | ||||||
|         self.assertFalse(auth.is_valid_password(created_user, 'invalid')) |  | ||||||
| 
 |  | ||||||
|     def test_subsequent_users_are_created_normally(self): |  | ||||||
|         self.context.request = { |  | ||||||
|             'name': 'chewie', |  | ||||||
|             'email': 'asd@asd.asd', |  | ||||||
|             'password': 'oks', |  | ||||||
|         } |  | ||||||
|         self.api.post(self.context) |  | ||||||
|         self.context.request['name'] = 'chewie2' |  | ||||||
|         self.api.post(self.context) |  | ||||||
|         created_user = self.session.query(db.User).filter_by(name='chewie2').one() |  | ||||||
|         self.assertEqual(created_user.name, 'chewie2') |  | ||||||
|         self.assertEqual(created_user.email, 'asd@asd.asd') |  | ||||||
|         self.assertEqual(created_user.rank, 'regular_user') |  | ||||||
|         self.assertTrue(auth.is_valid_password(created_user, 'oks')) |  | ||||||
|         self.assertFalse(auth.is_valid_password(created_user, 'invalid')) |  | ||||||
| 
 |  | ||||||
|     def test_creating_user_that_already_exists(self): |  | ||||||
|         self.context.request = { |  | ||||||
|             'name': 'chewie', |  | ||||||
|             'email': 'asd@asd.asd', |  | ||||||
|             'password': 'oks', |  | ||||||
|         } |  | ||||||
|         self.api.post(self.context) |  | ||||||
|         self.assertRaises(errors.IntegrityError, self.api.post, self.context) |  | ||||||
| 
 |  | ||||||
|     def test_creating_user_that_already_exists_insensitive(self): |  | ||||||
|         self.context.request = { |  | ||||||
|             'name': 'chewie', |  | ||||||
|             'email': 'asd@asd.asd', |  | ||||||
|             'password': 'oks', |  | ||||||
|         } |  | ||||||
|         self.api.post(self.context) |  | ||||||
|         self.context.name = 'chewie' |  | ||||||
|         self.assertRaises(errors.IntegrityError, self.api.post, self.context) |  | ||||||
| 
 |  | ||||||
|     def test_missing_field(self): |  | ||||||
|         for key in ['name', 'email', 'password']: |  | ||||||
|             self.context.request = { |  | ||||||
|                 'name': 'chewie', |  | ||||||
|                 'email': 'asd@asd.asd', |  | ||||||
|                 'password': 'oks', |  | ||||||
|             } |  | ||||||
|             del self.context.request[key] |  | ||||||
|             self.assertRaises(errors.ValidationError, self.api.post, self.context) |  | ||||||
| 
 |  | ||||||
| class TestUpdatingUser(DatabaseTestCase): |  | ||||||
|     def setUp(self): |  | ||||||
|         super().setUp() |  | ||||||
|         util.mock_config({ |  | ||||||
|             'secret': '', |  | ||||||
|             'user_name_regex': '.{3,}', |  | ||||||
|             'password_regex': '.{3,}', |  | ||||||
|             'data_dir': tempfile.gettempdir(), |  | ||||||
|             'data_url': 'http://example.com/data/', |  | ||||||
|             'thumbnails': {'avatar_width': 200, 'avatar_height': 200}, |  | ||||||
|             'ranks': ['anonymous', 'regular_user', 'mod', 'admin'], |  | ||||||
|             'rank_names': {}, |  | ||||||
|             'privileges': { |  | ||||||
|                 'users:edit:self:name': 'regular_user', |  | ||||||
|                 'users:edit:self:pass': 'regular_user', |  | ||||||
|                 'users:edit:self:email': 'regular_user', |  | ||||||
|                 'users:edit:self:rank': 'mod', |  | ||||||
|                 'users:edit:self:avatar': 'mod', |  | ||||||
|                 'users:edit:any:name': 'mod', |  | ||||||
|                 'users:edit:any:pass': 'mod', |  | ||||||
|                 'users:edit:any:email': 'mod', |  | ||||||
|                 'users:edit:any:rank': 'admin', |  | ||||||
|                 'users:edit:any:avatar': 'admin', |  | ||||||
|             }, |  | ||||||
|         }) |  | ||||||
|         util.mock_context(self) |  | ||||||
|         self.api = api.UserDetailApi() |  | ||||||
| 
 |  | ||||||
|     def test_update_changing_nothing(self): |  | ||||||
|         admin_user = util.mock_user('u1', 'admin') |  | ||||||
|         self.session.add(admin_user) |  | ||||||
|         self.context.user = admin_user |  | ||||||
|         self.api.put(self.context, 'u1') |  | ||||||
|         admin_user = self.session.query(db.User).filter_by(name='u1').one() |  | ||||||
|         self.assertEqual(admin_user.name, 'u1') |  | ||||||
|         self.assertEqual(admin_user.email, 'dummy') |  | ||||||
|         self.assertEqual(admin_user.rank, 'admin') |  | ||||||
| 
 |  | ||||||
|     def test_updating_non_existing_user(self): |  | ||||||
|         admin_user = util.mock_user('u1', 'admin') |  | ||||||
|         self.session.add(admin_user) |  | ||||||
|         self.context.user = admin_user |  | ||||||
|         self.assertRaises(errors.NotFoundError, self.api.put, self.context, 'u2') |  | ||||||
| 
 |  | ||||||
|     def test_admin_updating_everything_for_themselves(self): |  | ||||||
|         admin_user = util.mock_user('u1', 'admin') |  | ||||||
|         self.session.add(admin_user) |  | ||||||
|         self.context.user = admin_user |  | ||||||
|         self.context.request = { |  | ||||||
|             'name': 'chewie', |  | ||||||
|             'email': 'asd@asd.asd', |  | ||||||
|             'password': 'oks', |  | ||||||
|             'rank': 'mod', |  | ||||||
|             'avatarStyle': 'gravatar', |  | ||||||
|         } |  | ||||||
|         self.api.put(self.context, 'u1') |  | ||||||
|         admin_user = self.session.query(db.User).filter_by(name='chewie').one() |  | ||||||
|         self.assertEqual(admin_user.name, 'chewie') |  | ||||||
|         self.assertEqual(admin_user.email, 'asd@asd.asd') |  | ||||||
|         self.assertEqual(admin_user.rank, 'mod') |  | ||||||
|         self.assertEqual(admin_user.avatar_style, admin_user.AVATAR_GRAVATAR) |  | ||||||
|         self.assertTrue(auth.is_valid_password(admin_user, 'oks')) |  | ||||||
|         self.assertFalse(auth.is_valid_password(admin_user, 'invalid')) |  | ||||||
| 
 |  | ||||||
|     def test_removing_email(self): |  | ||||||
|         admin_user = util.mock_user('u1', 'admin') |  | ||||||
|         self.session.add(admin_user) |  | ||||||
|         self.context.user = admin_user |  | ||||||
|         self.context.request = {'email': ''} |  | ||||||
|         self.api.put(self.context, 'u1') |  | ||||||
|         admin_user = self.session.query(db.User).filter_by(name='u1').one() |  | ||||||
|         self.assertEqual(admin_user.email, None) |  | ||||||
| 
 |  | ||||||
|     def test_invalid_inputs(self): |  | ||||||
|         admin_user = util.mock_user('u1', 'admin') |  | ||||||
|         self.session.add(admin_user) |  | ||||||
|         self.context.user = admin_user |  | ||||||
|         self.context.request = {'name': '.'} |  | ||||||
|         self.assertRaises( |  | ||||||
|             errors.ValidationError, self.api.put, self.context, 'u1') |  | ||||||
|         self.context.request = {'password': '.'} |  | ||||||
|         self.assertRaises( |  | ||||||
|             errors.ValidationError, self.api.put, self.context, 'u1') |  | ||||||
|         self.context.request = {'rank': '.'} |  | ||||||
|         self.assertRaises( |  | ||||||
|             errors.ValidationError, self.api.put, self.context, 'u1') |  | ||||||
|         self.context.request = {'email': '.'} |  | ||||||
|         self.assertRaises( |  | ||||||
|             errors.ValidationError, self.api.put, self.context, 'u1') |  | ||||||
|         self.context.request = {'avatarStyle': 'manual'} |  | ||||||
|         self.assertRaises( |  | ||||||
|             errors.ValidationError, self.api.put, self.context, 'u1') |  | ||||||
| 
 |  | ||||||
|     def test_user_trying_to_update_someone_else(self): |  | ||||||
|         user1 = util.mock_user('u1', 'regular_user') |  | ||||||
|         user2 = util.mock_user('u2', 'regular_user') |  | ||||||
|         self.session.add_all([user1, user2]) |  | ||||||
|         self.context.user = user1 |  | ||||||
|         for request in [ |  | ||||||
|                 {'name': 'whatever'}, |  | ||||||
|                 {'email': 'whatever'}, |  | ||||||
|                 {'rank': 'whatever'}, |  | ||||||
|                 {'password': 'whatever'}]: |  | ||||||
|             self.context.request = request |  | ||||||
|             self.assertRaises( |  | ||||||
|                 errors.AuthError, self.api.put, self.context, user2.name) |  | ||||||
| 
 |  | ||||||
|     def test_user_trying_to_become_someone_else(self): |  | ||||||
|         user1 = util.mock_user('me', 'regular_user') |  | ||||||
|         user2 = util.mock_user('her', 'regular_user') |  | ||||||
|         self.session.add_all([user1, user2]) |  | ||||||
|         self.context.user = user1 |  | ||||||
|         self.context.request = {'name': 'her'} |  | ||||||
|         self.assertRaises( |  | ||||||
|             errors.IntegrityError, self.api.put, self.context, 'me') |  | ||||||
|         self.session.rollback() |  | ||||||
| 
 |  | ||||||
|     def test_user_trying_to_become_someone_else_insensitive(self): |  | ||||||
|         user1 = util.mock_user('me', 'regular_user') |  | ||||||
|         user2 = util.mock_user('her', 'regular_user') |  | ||||||
|         self.session.add_all([user1, user2]) |  | ||||||
|         self.context.user = user1 |  | ||||||
|         self.context.request = {'name': 'HER'} |  | ||||||
|         self.assertRaises( |  | ||||||
|             errors.IntegrityError, self.api.put, self.context, 'me') |  | ||||||
|         self.session.rollback() |  | ||||||
| 
 |  | ||||||
|     def test_mods_trying_to_become_admin(self): |  | ||||||
|         user1 = util.mock_user('u1', 'mod') |  | ||||||
|         user2 = util.mock_user('u2', 'mod') |  | ||||||
|         self.session.add_all([user1, user2]) |  | ||||||
|         self.context.user = user1 |  | ||||||
|         self.context.request = {'rank': 'admin'} |  | ||||||
|         self.assertRaises( |  | ||||||
|             errors.AuthError, self.api.put, self.context, user1.name) |  | ||||||
|         self.assertRaises( |  | ||||||
|             errors.AuthError, self.api.put, self.context, user2.name) |  | ||||||
| 
 |  | ||||||
|     def test_uploading_avatar(self): |  | ||||||
|         user = util.mock_user('u1', 'mod') |  | ||||||
|         self.session.add(user) |  | ||||||
|         self.context.user = user |  | ||||||
|         self.context.request = { |  | ||||||
|             'avatarStyle': 'manual', |  | ||||||
|         } |  | ||||||
|         empty_pixel = \ |  | ||||||
|             b'\x47\x49\x46\x38\x39\x61\x01\x00\x01\x00\x80\x01\x00\x00\x00\x00' \ |  | ||||||
|             b'\xff\xff\xff\x21\xf9\x04\x01\x00\x00\x01\x00\x2c\x00\x00\x00\x00' \ |  | ||||||
|             b'\x01\x00\x01\x00\x00\x02\x02\x4c\x01\x00\x3b' |  | ||||||
|         self.context.files['avatar'] = empty_pixel |  | ||||||
|         response = self.api.put(self.context, 'u1') |  | ||||||
|         user = self.session.query(db.User).filter_by(name='u1').one() |  | ||||||
|         self.assertEqual(user.avatar_style, user.AVATAR_MANUAL) |  | ||||||
|         self.assertEqual( |  | ||||||
|             response['user']['avatarUrl'], |  | ||||||
|             'http://example.com/data/avatars/u1.jpg') |  | ||||||
							
								
								
									
										112
									
								
								server/szurubooru/tests/api/test_user_creating.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								server/szurubooru/tests/api/test_user_creating.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,112 @@ | |||||||
|  | import pytest | ||||||
|  | from datetime import datetime | ||||||
|  | from szurubooru import api, db, errors | ||||||
|  | from szurubooru.util import auth | ||||||
|  | 
 | ||||||
|  | @pytest.fixture | ||||||
|  | def user_list_api(): | ||||||
|  |     return api.UserListApi() | ||||||
|  | 
 | ||||||
|  | def test_creating_users( | ||||||
|  |         session, | ||||||
|  |         config_injector, | ||||||
|  |         context_factory, | ||||||
|  |         user_factory, | ||||||
|  |         user_list_api): | ||||||
|  |     config_injector({ | ||||||
|  |         'secret': '', | ||||||
|  |         'user_name_regex': '.{3,}', | ||||||
|  |         'password_regex': '.{3,}', | ||||||
|  |         'default_rank': 'regular_user', | ||||||
|  |         'thumbnails': {'avatar_width': 200}, | ||||||
|  |         'ranks': ['anonymous', 'regular_user', 'mod', 'admin'], | ||||||
|  |         'rank_names': {}, | ||||||
|  |         'privileges': {'users:create': 'anonymous'}, | ||||||
|  |     }) | ||||||
|  | 
 | ||||||
|  |     user_list_api.post( | ||||||
|  |         context_factory( | ||||||
|  |             request={ | ||||||
|  |                 'name': 'chewie1', | ||||||
|  |                 'email': 'asd@asd.asd', | ||||||
|  |                 'password': 'oks', | ||||||
|  |             }, | ||||||
|  |             user=user_factory(rank='regular_user'))) | ||||||
|  |     user_list_api.post( | ||||||
|  |         context_factory( | ||||||
|  |             request={ | ||||||
|  |                 'name': 'chewie2', | ||||||
|  |                 'email': 'asd@asd.asd', | ||||||
|  |                 'password': 'sok', | ||||||
|  |             }, | ||||||
|  |             user=user_factory(rank='regular_user'))) | ||||||
|  | 
 | ||||||
|  |     first_user = session.query(db.User).filter_by(name='chewie1').one() | ||||||
|  |     other_user = session.query(db.User).filter_by(name='chewie2').one() | ||||||
|  |     assert first_user.name == 'chewie1' | ||||||
|  |     assert first_user.email == 'asd@asd.asd' | ||||||
|  |     assert first_user.rank == 'admin' | ||||||
|  |     assert auth.is_valid_password(first_user, 'oks') is True | ||||||
|  |     assert auth.is_valid_password(first_user, 'invalid') is False | ||||||
|  |     assert other_user.name == 'chewie2' | ||||||
|  |     assert other_user.email == 'asd@asd.asd' | ||||||
|  |     assert other_user.rank == 'regular_user' | ||||||
|  |     assert auth.is_valid_password(other_user, 'sok') is True | ||||||
|  |     assert auth.is_valid_password(other_user, 'invalid') is False | ||||||
|  | 
 | ||||||
|  | def test_creating_user_that_already_exists( | ||||||
|  |         config_injector, context_factory, user_factory, user_list_api): | ||||||
|  |     config_injector({ | ||||||
|  |         'secret': '', | ||||||
|  |         'user_name_regex': '.{3,}', | ||||||
|  |         'password_regex': '.{3,}', | ||||||
|  |         'default_rank': 'regular_user', | ||||||
|  |         'thumbnails': {'avatar_width': 200}, | ||||||
|  |         'ranks': ['anonymous', 'regular_user', 'mod', 'admin'], | ||||||
|  |         'rank_names': {}, | ||||||
|  |         'privileges': {'users:create': 'anonymous'}, | ||||||
|  |     }) | ||||||
|  |     user_list_api.post( | ||||||
|  |         context_factory( | ||||||
|  |             request={ | ||||||
|  |                 'name': 'chewie', | ||||||
|  |                 'email': 'asd@asd.asd', | ||||||
|  |                 'password': 'oks', | ||||||
|  |             }, | ||||||
|  |             user=user_factory(rank='regular_user'))) | ||||||
|  |     with pytest.raises(errors.IntegrityError): | ||||||
|  |         user_list_api.post( | ||||||
|  |             context_factory( | ||||||
|  |                 request={ | ||||||
|  |                     'name': 'chewie', | ||||||
|  |                     'email': 'asd@asd.asd', | ||||||
|  |                     'password': 'oks', | ||||||
|  |                 }, | ||||||
|  |                 user=user_factory(rank='regular_user'))) | ||||||
|  |     with pytest.raises(errors.IntegrityError): | ||||||
|  |         user_list_api.post( | ||||||
|  |             context_factory( | ||||||
|  |                 request={ | ||||||
|  |                     'name': 'CHEWIE', | ||||||
|  |                     'email': 'asd@asd.asd', | ||||||
|  |                     'password': 'oks', | ||||||
|  |                 }, | ||||||
|  |                 user=user_factory(rank='regular_user'))) | ||||||
|  | 
 | ||||||
|  | @pytest.mark.parametrize('field', ['name', 'email', 'password']) | ||||||
|  | def test_missing_field( | ||||||
|  |         config_injector, context_factory, user_factory, user_list_api, field): | ||||||
|  |     config_injector({ | ||||||
|  |         'ranks': ['anonymous', 'regular_user', 'mod', 'admin'], | ||||||
|  |         'privileges': {'users:create': 'anonymous'}, | ||||||
|  |     }) | ||||||
|  |     request = { | ||||||
|  |         'name': 'chewie', | ||||||
|  |         'email': 'asd@asd.asd', | ||||||
|  |         'password': 'oks', | ||||||
|  |     } | ||||||
|  |     del request[field] | ||||||
|  |     with pytest.raises(errors.ValidationError): | ||||||
|  |         user_list_api.post( | ||||||
|  |             context_factory( | ||||||
|  |                 request=request, user=user_factory(rank='regular_user'))) | ||||||
							
								
								
									
										65
									
								
								server/szurubooru/tests/api/test_user_deletion.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								server/szurubooru/tests/api/test_user_deletion.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,65 @@ | |||||||
|  | import pytest | ||||||
|  | from datetime import datetime | ||||||
|  | from szurubooru import api, db, errors | ||||||
|  | 
 | ||||||
|  | @pytest.fixture | ||||||
|  | def user_detail_api(): | ||||||
|  |     return api.UserDetailApi() | ||||||
|  | 
 | ||||||
|  | def test_removing_oneself( | ||||||
|  |         session, | ||||||
|  |         config_injector, | ||||||
|  |         context_factory, | ||||||
|  |         user_factory, | ||||||
|  |         user_detail_api): | ||||||
|  |     config_injector({ | ||||||
|  |         'privileges': { | ||||||
|  |             'users:delete:self': 'regular_user', | ||||||
|  |             'users:delete:any': 'mod', | ||||||
|  |         }, | ||||||
|  |         'ranks': ['anonymous', 'regular_user', 'mod', 'admin'], | ||||||
|  |     }) | ||||||
|  |     user1 = user_factory(name='u1', rank='regular_user') | ||||||
|  |     user2 = user_factory(name='u2', rank='regular_user') | ||||||
|  |     session.add_all([user1, user2]) | ||||||
|  |     session.commit() | ||||||
|  |     with pytest.raises(errors.AuthError): | ||||||
|  |         user_detail_api.delete(context_factory(user=user1), 'u2') | ||||||
|  |     user_detail_api.delete(context_factory(user=user1), 'u1') | ||||||
|  |     assert [u.name for u in session.query(db.User).all()] == ['u2'] | ||||||
|  | 
 | ||||||
|  | def test_removing_someone_else( | ||||||
|  |         session, | ||||||
|  |         config_injector, | ||||||
|  |         context_factory, | ||||||
|  |         user_factory, | ||||||
|  |         user_detail_api): | ||||||
|  |     config_injector({ | ||||||
|  |         'privileges': { | ||||||
|  |             'users:delete:self': 'regular_user', | ||||||
|  |             'users:delete:any': 'mod', | ||||||
|  |         }, | ||||||
|  |         'ranks': ['anonymous', 'regular_user', 'mod', 'admin'], | ||||||
|  |     }) | ||||||
|  |     user1 = user_factory(name='u1', rank='regular_user') | ||||||
|  |     user2 = user_factory(name='u2', rank='regular_user') | ||||||
|  |     mod_user = user_factory(rank='mod') | ||||||
|  |     session.add_all([user1, user2]) | ||||||
|  |     session.commit() | ||||||
|  |     user_detail_api.delete(context_factory(user=mod_user), 'u1') | ||||||
|  |     user_detail_api.delete(context_factory(user=mod_user), 'u2') | ||||||
|  |     assert session.query(db.User).all() == [] | ||||||
|  | 
 | ||||||
|  | def test_removing_non_existing( | ||||||
|  |         context_factory, config_injector, user_factory, user_detail_api): | ||||||
|  |     config_injector({ | ||||||
|  |         'privileges': { | ||||||
|  |             'users:delete:self': 'regular_user', | ||||||
|  |             'users:delete:any': 'mod', | ||||||
|  |         }, | ||||||
|  |         'ranks': ['anonymous', 'regular_user', 'mod', 'admin'], | ||||||
|  |     }) | ||||||
|  |     with pytest.raises(errors.NotFoundError): | ||||||
|  |         user_detail_api.delete( | ||||||
|  |             context_factory(user=user_factory(rank='regular_user')), 'bad') | ||||||
|  | 
 | ||||||
							
								
								
									
										116
									
								
								server/szurubooru/tests/api/test_user_retrieval.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										116
									
								
								server/szurubooru/tests/api/test_user_retrieval.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,116 @@ | |||||||
|  | import pytest | ||||||
|  | from datetime import datetime | ||||||
|  | from szurubooru import api, db, errors | ||||||
|  | 
 | ||||||
|  | @pytest.fixture | ||||||
|  | def user_list_api(): | ||||||
|  |     return api.UserListApi() | ||||||
|  | 
 | ||||||
|  | @pytest.fixture | ||||||
|  | def user_detail_api(): | ||||||
|  |     return api.UserDetailApi() | ||||||
|  | 
 | ||||||
|  | def test_retrieving_multiple( | ||||||
|  |         session, | ||||||
|  |         config_injector, | ||||||
|  |         context_factory, | ||||||
|  |         user_factory, | ||||||
|  |         user_list_api): | ||||||
|  |     config_injector({ | ||||||
|  |         'privileges': {'users:list': 'regular_user'}, | ||||||
|  |         'thumbnails': {'avatar_width': 200}, | ||||||
|  |         'ranks': ['anonymous', 'regular_user', 'mod', 'admin'], | ||||||
|  |         'rank_names': {}, | ||||||
|  |     }) | ||||||
|  |     user1 = user_factory(name='u1', rank='mod') | ||||||
|  |     user2 = user_factory(name='u2', rank='mod') | ||||||
|  |     session.add_all([user1, user2]) | ||||||
|  |     result = user_list_api.get( | ||||||
|  |         context_factory( | ||||||
|  |             params={'query': '', 'page': 1}, | ||||||
|  |             user=user_factory(rank='regular_user'))) | ||||||
|  |     assert result['query'] == '' | ||||||
|  |     assert result['page'] == 1 | ||||||
|  |     assert result['pageSize'] == 100 | ||||||
|  |     assert result['total'] == 2 | ||||||
|  |     assert [u['name'] for u in result['users']] == ['u1', 'u2'] | ||||||
|  | 
 | ||||||
|  | def test_retrieving_multiple_without_privileges( | ||||||
|  |         context_factory, config_injector, user_factory, user_list_api): | ||||||
|  |     config_injector({ | ||||||
|  |         'privileges': {'users:list': 'regular_user'}, | ||||||
|  |         'ranks': ['anonymous', 'regular_user', 'mod', 'admin'], | ||||||
|  |     }) | ||||||
|  |     with pytest.raises(errors.AuthError): | ||||||
|  |         user_list_api.get( | ||||||
|  |             context_factory( | ||||||
|  |                 params={'query': '', 'page': 1}, | ||||||
|  |                 user=user_factory(rank='anonymous'))) | ||||||
|  | 
 | ||||||
|  | def test_retrieving_multiple_with_privileges( | ||||||
|  |         context_factory, config_injector, user_factory, user_list_api): | ||||||
|  |     config_injector({ | ||||||
|  |         'privileges': {'users:list': 'regular_user'}, | ||||||
|  |         'ranks': ['anonymous', 'regular_user', 'mod', 'admin'], | ||||||
|  |     }) | ||||||
|  |     result = user_list_api.get( | ||||||
|  |         context_factory( | ||||||
|  |             params={'query': 'asd', 'page': 1}, | ||||||
|  |             user=user_factory(rank='regular_user'))) | ||||||
|  |     assert result['query'] == 'asd' | ||||||
|  |     assert result['page'] == 1 | ||||||
|  |     assert result['pageSize'] == 100 | ||||||
|  |     assert result['total'] == 0 | ||||||
|  |     assert [u['name'] for u in result['users']] == [] | ||||||
|  | 
 | ||||||
|  | def test_retrieving_single( | ||||||
|  |         session, | ||||||
|  |         config_injector, | ||||||
|  |         context_factory, | ||||||
|  |         user_factory, | ||||||
|  |         user_detail_api): | ||||||
|  |     config_injector({ | ||||||
|  |         'privileges': {'users:view': 'regular_user'}, | ||||||
|  |         'thumbnails': {'avatar_width': 200}, | ||||||
|  |         'ranks': ['anonymous', 'regular_user', 'mod', 'admin'], | ||||||
|  |         'rank_names': {}, | ||||||
|  |     }) | ||||||
|  |     user = user_factory(name='u1', rank='regular_user') | ||||||
|  |     session.add(user) | ||||||
|  |     result = user_detail_api.get( | ||||||
|  |         context_factory( | ||||||
|  |             params={'query': '', 'page': 1}, | ||||||
|  |             user=user_factory(rank='regular_user')), | ||||||
|  |         'u1') | ||||||
|  |     assert result['user']['id'] == user.user_id | ||||||
|  |     assert result['user']['name'] == 'u1' | ||||||
|  |     assert result['user']['rank'] == 'regular_user' | ||||||
|  |     assert result['user']['creationTime'] == datetime(1997, 1, 1) | ||||||
|  |     assert result['user']['lastLoginTime'] == None | ||||||
|  |     assert result['user']['avatarStyle'] == 'gravatar' | ||||||
|  | 
 | ||||||
|  | def test_retrieving_non_existing( | ||||||
|  |         context_factory, config_injector, user_factory, user_detail_api): | ||||||
|  |     config_injector({ | ||||||
|  |         'privileges': {'users:view': 'regular_user'}, | ||||||
|  |         'ranks': ['anonymous', 'regular_user', 'mod', 'admin'], | ||||||
|  |     }) | ||||||
|  |     with pytest.raises(errors.NotFoundError): | ||||||
|  |         user_detail_api.get( | ||||||
|  |             context_factory( | ||||||
|  |                 params={'query': '', 'page': 1}, | ||||||
|  |                 user=user_factory(rank='regular_user')), | ||||||
|  |             '-') | ||||||
|  | 
 | ||||||
|  | def test_retrieving_single_without_privileges( | ||||||
|  |         context_factory, config_injector, user_factory, user_detail_api): | ||||||
|  |     config_injector({ | ||||||
|  |         'privileges': {'users:view': 'regular_user'}, | ||||||
|  |         'ranks': ['anonymous', 'regular_user', 'mod', 'admin'], | ||||||
|  |     }) | ||||||
|  |     with pytest.raises(errors.AuthError): | ||||||
|  |         user_detail_api.get( | ||||||
|  |             context_factory( | ||||||
|  |                 params={'query': '', 'page': 1}, | ||||||
|  |                 user=user_factory(rank='anonymous')), | ||||||
|  |             '-') | ||||||
							
								
								
									
										237
									
								
								server/szurubooru/tests/api/test_user_updating.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										237
									
								
								server/szurubooru/tests/api/test_user_updating.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,237 @@ | |||||||
|  | import pytest | ||||||
|  | from szurubooru import api, db, errors | ||||||
|  | from szurubooru.util import auth | ||||||
|  | 
 | ||||||
|  | @pytest.fixture | ||||||
|  | def user_detail_api(): | ||||||
|  |     return api.UserDetailApi() | ||||||
|  | 
 | ||||||
|  | def test_updating_user( | ||||||
|  |         session, | ||||||
|  |         config_injector, | ||||||
|  |         context_factory, | ||||||
|  |         user_factory, | ||||||
|  |         user_detail_api): | ||||||
|  |     config_injector({ | ||||||
|  |         'secret': '', | ||||||
|  |         'user_name_regex': '.{3,}', | ||||||
|  |         'password_regex': '.{3,}', | ||||||
|  |         'thumbnails': {'avatar_width': 200}, | ||||||
|  |         'ranks': ['anonymous', 'regular_user', 'mod', 'admin'], | ||||||
|  |         'rank_names': {}, | ||||||
|  |         'privileges': { | ||||||
|  |             'users:edit:self:name': 'regular_user', | ||||||
|  |             'users:edit:self:pass': 'regular_user', | ||||||
|  |             'users:edit:self:email': 'regular_user', | ||||||
|  |             'users:edit:self:rank': 'mod', | ||||||
|  |             'users:edit:self:avatar': 'mod', | ||||||
|  |         }, | ||||||
|  |     }) | ||||||
|  |     user = user_factory(name='u1', rank='admin') | ||||||
|  |     session.add(user) | ||||||
|  |     user_detail_api.put( | ||||||
|  |         context_factory( | ||||||
|  |             request={ | ||||||
|  |                 'name': 'chewie', | ||||||
|  |                 'email': 'asd@asd.asd', | ||||||
|  |                 'password': 'oks', | ||||||
|  |                 'rank': 'mod', | ||||||
|  |                 'avatarStyle': 'gravatar', | ||||||
|  |             }, | ||||||
|  |             user=user), | ||||||
|  |         'u1') | ||||||
|  |     user = session.query(db.User).filter_by(name='chewie').one() | ||||||
|  |     assert user.name == 'chewie' | ||||||
|  |     assert user.email == 'asd@asd.asd' | ||||||
|  |     assert user.rank == 'mod' | ||||||
|  |     assert user.avatar_style == user.AVATAR_GRAVATAR | ||||||
|  |     assert auth.is_valid_password(user, 'oks') is True | ||||||
|  |     assert auth.is_valid_password(user, 'invalid') is False | ||||||
|  | 
 | ||||||
|  | def test_update_changing_nothing( | ||||||
|  |         session, | ||||||
|  |         config_injector, | ||||||
|  |         context_factory, | ||||||
|  |         user_factory, | ||||||
|  |         user_detail_api): | ||||||
|  |     config_injector({ | ||||||
|  |         'thumbnails': {'avatar_width': 200}, | ||||||
|  |         'ranks': ['anonymous', 'regular_user', 'mod', 'admin'], | ||||||
|  |         'rank_names': {}, | ||||||
|  |     }) | ||||||
|  |     user = user_factory(name='u1', rank='admin') | ||||||
|  |     session.add(user) | ||||||
|  |     user_detail_api.put(context_factory(user=user), 'u1') | ||||||
|  |     user = session.query(db.User).filter_by(name='u1').one() | ||||||
|  |     assert user.name == 'u1' | ||||||
|  |     assert user.email == 'dummy' | ||||||
|  |     assert user.rank == 'admin' | ||||||
|  | 
 | ||||||
|  | def test_updating_non_existing_user( | ||||||
|  |         session, | ||||||
|  |         config_injector, | ||||||
|  |         context_factory, | ||||||
|  |         user_factory, | ||||||
|  |         user_detail_api): | ||||||
|  |     config_injector({ | ||||||
|  |         'ranks': ['anonymous', 'regular_user', 'mod', 'admin'], | ||||||
|  |     }) | ||||||
|  |     user = user_factory(name='u1', rank='admin') | ||||||
|  |     session.add(user) | ||||||
|  |     with pytest.raises(errors.NotFoundError): | ||||||
|  |         user_detail_api.put(context_factory(user=user), 'u2') | ||||||
|  | 
 | ||||||
|  | def test_removing_email( | ||||||
|  |         session, | ||||||
|  |         config_injector, | ||||||
|  |         context_factory, | ||||||
|  |         user_factory, | ||||||
|  |         user_detail_api): | ||||||
|  |     config_injector({ | ||||||
|  |         'thumbnails': {'avatar_width': 200}, | ||||||
|  |         'ranks': ['anonymous', 'regular_user', 'mod', 'admin'], | ||||||
|  |         'rank_names': {}, | ||||||
|  |         'privileges': {'users:edit:self:email': 'regular_user'}, | ||||||
|  |     }) | ||||||
|  |     user = user_factory(name='u1', rank='admin') | ||||||
|  |     session.add(user) | ||||||
|  |     user_detail_api.put( | ||||||
|  |         context_factory(request={'email': ''}, user=user), 'u1') | ||||||
|  |     assert session.query(db.User).filter_by(name='u1').one().email is None | ||||||
|  | 
 | ||||||
|  | @pytest.mark.parametrize('request', [ | ||||||
|  |     {'name': '.'}, | ||||||
|  |     {'password': '.'}, | ||||||
|  |     {'rank': '.'}, | ||||||
|  |     {'email': '.'}, | ||||||
|  |     {'avatarStyle': 'manual'}, | ||||||
|  | ]) | ||||||
|  | def test_invalid_inputs( | ||||||
|  |         session, | ||||||
|  |         config_injector, | ||||||
|  |         context_factory, | ||||||
|  |         user_factory, | ||||||
|  |         user_detail_api, | ||||||
|  |         request): | ||||||
|  |     config_injector({ | ||||||
|  |         'user_name_regex': '.{3,}', | ||||||
|  |         'password_regex': '.{3,}', | ||||||
|  |         'ranks': ['anonymous', 'regular_user', 'mod', 'admin'], | ||||||
|  |         'privileges': { | ||||||
|  |             'users:edit:self:name': 'regular_user', | ||||||
|  |             'users:edit:self:pass': 'regular_user', | ||||||
|  |             'users:edit:self:email': 'regular_user', | ||||||
|  |             'users:edit:self:rank': 'mod', | ||||||
|  |             'users:edit:self:avatar': 'mod', | ||||||
|  |         }, | ||||||
|  |     }) | ||||||
|  |     user = user_factory(name='u1', rank='admin') | ||||||
|  |     session.add(user) | ||||||
|  |     with pytest.raises(errors.ValidationError): | ||||||
|  |         user_detail_api.put(context_factory(request=request, user=user), 'u1') | ||||||
|  | 
 | ||||||
|  | @pytest.mark.parametrize('request', [ | ||||||
|  |     {'name': 'whatever'}, | ||||||
|  |     {'email': 'whatever'}, | ||||||
|  |     {'rank': 'whatever'}, | ||||||
|  |     {'password': 'whatever'}, | ||||||
|  |     {'avatarStyle': 'whatever'}, | ||||||
|  | ]) | ||||||
|  | def test_user_trying_to_update_someone_else( | ||||||
|  |         session, | ||||||
|  |         config_injector, | ||||||
|  |         context_factory, | ||||||
|  |         user_factory, | ||||||
|  |         user_detail_api, | ||||||
|  |         request): | ||||||
|  |     config_injector({ | ||||||
|  |         'ranks': ['anonymous', 'regular_user', 'mod', 'admin'], | ||||||
|  |         'privileges': { | ||||||
|  |             'users:edit:any:name': 'mod', | ||||||
|  |             'users:edit:any:pass': 'mod', | ||||||
|  |             'users:edit:any:email': 'mod', | ||||||
|  |             'users:edit:any:rank': 'admin', | ||||||
|  |             'users:edit:any:avatar': 'admin', | ||||||
|  |         }, | ||||||
|  |     }) | ||||||
|  |     user1 = user_factory(name='u1', rank='regular_user') | ||||||
|  |     user2 = user_factory(name='u2', rank='regular_user') | ||||||
|  |     session.add_all([user1, user2]) | ||||||
|  |     with pytest.raises(errors.AuthError): | ||||||
|  |         user_detail_api.put( | ||||||
|  |             context_factory(request=request, user=user1), user2.name) | ||||||
|  | 
 | ||||||
|  | def test_user_trying_to_become_someone_else( | ||||||
|  |         session, | ||||||
|  |         config_injector, | ||||||
|  |         context_factory, | ||||||
|  |         user_factory, | ||||||
|  |         user_detail_api): | ||||||
|  |     config_injector({ | ||||||
|  |         'ranks': ['anonymous', 'regular_user', 'mod', 'admin'], | ||||||
|  |         'privileges': {'users:edit:self:name': 'regular_user'}, | ||||||
|  |     }) | ||||||
|  |     user1 = user_factory(name='me', rank='regular_user') | ||||||
|  |     user2 = user_factory(name='her', rank='regular_user') | ||||||
|  |     session.add_all([user1, user2]) | ||||||
|  |     with pytest.raises(errors.IntegrityError): | ||||||
|  |         user_detail_api.put( | ||||||
|  |             context_factory(request={'name': 'her'}, user=user1), | ||||||
|  |             'me') | ||||||
|  |     with pytest.raises(errors.IntegrityError): | ||||||
|  |         user_detail_api.put( | ||||||
|  |             context_factory(request={'name': 'HER'}, user=user1), 'me') | ||||||
|  | 
 | ||||||
|  | def test_mods_trying_to_become_admin( | ||||||
|  |         session, | ||||||
|  |         config_injector, | ||||||
|  |         context_factory, | ||||||
|  |         user_factory, | ||||||
|  |         user_detail_api): | ||||||
|  |     config_injector({ | ||||||
|  |         'ranks': ['anonymous', 'regular_user', 'mod', 'admin'], | ||||||
|  |         'privileges': { | ||||||
|  |             'users:edit:self:rank': 'mod', | ||||||
|  |             'users:edit:any:rank': 'admin', | ||||||
|  |         }, | ||||||
|  |     }) | ||||||
|  |     user1 = user_factory(name='u1', rank='mod') | ||||||
|  |     user2 = user_factory(name='u2', rank='mod') | ||||||
|  |     session.add_all([user1, user2]) | ||||||
|  |     context = context_factory(request={'rank': 'admin'}, user=user1) | ||||||
|  |     with pytest.raises(errors.AuthError): | ||||||
|  |         user_detail_api.put(context, user1.name) | ||||||
|  |     with pytest.raises(errors.AuthError): | ||||||
|  |         user_detail_api.put(context, user2.name) | ||||||
|  | 
 | ||||||
|  | def test_uploading_avatar( | ||||||
|  |         tmpdir, | ||||||
|  |         session, | ||||||
|  |         config_injector, | ||||||
|  |         context_factory, | ||||||
|  |         user_factory, | ||||||
|  |         user_detail_api): | ||||||
|  |     config_injector({ | ||||||
|  |         'data_dir': str(tmpdir.mkdir('data')), | ||||||
|  |         'data_url': 'http://example.com/data/', | ||||||
|  |         'thumbnails': {'avatar_width': 200, 'avatar_height': 200}, | ||||||
|  |         'ranks': ['anonymous', 'regular_user', 'mod', 'admin'], | ||||||
|  |         'rank_names': {}, | ||||||
|  |         'privileges': {'users:edit:self:avatar': 'mod'}, | ||||||
|  |     }) | ||||||
|  |     user = user_factory(name='u1', rank='mod') | ||||||
|  |     session.add(user) | ||||||
|  |     empty_pixel = \ | ||||||
|  |         b'\x47\x49\x46\x38\x39\x61\x01\x00\x01\x00\x80\x01\x00\x00\x00\x00' \ | ||||||
|  |         b'\xff\xff\xff\x21\xf9\x04\x01\x00\x00\x01\x00\x2c\x00\x00\x00\x00' \ | ||||||
|  |         b'\x01\x00\x01\x00\x00\x02\x02\x4c\x01\x00\x3b' | ||||||
|  |     response = user_detail_api.put( | ||||||
|  |         context_factory( | ||||||
|  |             request={'avatarStyle': 'manual'}, | ||||||
|  |             files={'avatar': empty_pixel}, | ||||||
|  |             user=user), | ||||||
|  |         'u1') | ||||||
|  |     user = session.query(db.User).filter_by(name='u1').one() | ||||||
|  |     assert user.avatar_style == user.AVATAR_MANUAL | ||||||
|  |     assert response['user']['avatarUrl'] == \ | ||||||
|  |         'http://example.com/data/avatars/u1.jpg' | ||||||
| @ -1,42 +0,0 @@ | |||||||
| from datetime import datetime |  | ||||||
| from szurubooru import config, db |  | ||||||
| from szurubooru.util import misc |  | ||||||
| 
 |  | ||||||
| def mock_config(config_mock): |  | ||||||
|     config.config = config_mock |  | ||||||
| 
 |  | ||||||
| def mock_user(name, rank='admin'): |  | ||||||
|     user = db.User() |  | ||||||
|     user.name = name |  | ||||||
|     user.password = 'dummy' |  | ||||||
|     user.password_salt = 'dummy' |  | ||||||
|     user.password_hash = 'dummy' |  | ||||||
|     user.email = 'dummy' |  | ||||||
|     user.rank = rank |  | ||||||
|     user.creation_time = datetime(1997, 1, 1) |  | ||||||
|     user.avatar_style = db.User.AVATAR_GRAVATAR |  | ||||||
|     return user |  | ||||||
| 
 |  | ||||||
| def mock_context(parent): |  | ||||||
|     context = misc.dotdict() |  | ||||||
|     context.session = parent.session |  | ||||||
|     context.request = {} |  | ||||||
|     context.files = {} |  | ||||||
|     context.user = db.User() |  | ||||||
|     parent.context = context |  | ||||||
| 
 |  | ||||||
| def mock_params(context, params): |  | ||||||
|     def get_param_as_string(key, default=None, required=False): |  | ||||||
|         if key not in params: |  | ||||||
|             if required: |  | ||||||
|                 raise RuntimeError('Param is missing!') |  | ||||||
|             return default |  | ||||||
|         return params[key] |  | ||||||
|     def get_param_as_int(key, default=None, required=False): |  | ||||||
|         if key not in params: |  | ||||||
|             if required: |  | ||||||
|                 raise RuntimeError('Param is missing!') |  | ||||||
|             return default |  | ||||||
|         return int(params[key]) |  | ||||||
|     context.get_param_as_string = get_param_as_string |  | ||||||
|     context.get_param_as_int = get_param_as_int |  | ||||||
							
								
								
									
										61
									
								
								server/szurubooru/tests/conftest.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								server/szurubooru/tests/conftest.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,61 @@ | |||||||
|  | from datetime import datetime | ||||||
|  | import pytest | ||||||
|  | import sqlalchemy | ||||||
|  | from szurubooru import db, config | ||||||
|  | from szurubooru.util import misc | ||||||
|  | 
 | ||||||
|  | @pytest.fixture | ||||||
|  | def session(): | ||||||
|  |     engine = sqlalchemy.create_engine('sqlite:///:memory:') | ||||||
|  |     session_maker = sqlalchemy.orm.sessionmaker(bind=engine) | ||||||
|  |     session_instance = sqlalchemy.orm.scoped_session(session_maker) | ||||||
|  |     db.Base.query = session_instance.query_property() | ||||||
|  |     db.Base.metadata.create_all(bind=engine) | ||||||
|  |     return session_instance | ||||||
|  | 
 | ||||||
|  | @pytest.fixture | ||||||
|  | def context_factory(session): | ||||||
|  |     def factory(request=None, params=None, files=None, user=None): | ||||||
|  |         params = params or {} | ||||||
|  |         def get_param_as_string(key, default=None, required=False): | ||||||
|  |             if key not in params: | ||||||
|  |                 if required: | ||||||
|  |                     raise RuntimeError('Param is missing!') | ||||||
|  |                 return default | ||||||
|  |             return params[key] | ||||||
|  |         def get_param_as_int(key, default=None, required=False): | ||||||
|  |             if key not in params: | ||||||
|  |                 if required: | ||||||
|  |                     raise RuntimeError('Param is missing!') | ||||||
|  |                 return default | ||||||
|  |             return int(params[key]) | ||||||
|  |         context = misc.dotdict() | ||||||
|  |         context.session = session | ||||||
|  |         context.request = request or {} | ||||||
|  |         context.files = files or {} | ||||||
|  |         context.user = user or db.User() | ||||||
|  |         context.get_param_as_string = get_param_as_string | ||||||
|  |         context.get_param_as_int = get_param_as_int | ||||||
|  |         return context | ||||||
|  |     return factory | ||||||
|  | 
 | ||||||
|  | @pytest.fixture | ||||||
|  | def config_injector(): | ||||||
|  |     def injector(new_config_content): | ||||||
|  |         config.config = new_config_content | ||||||
|  |     return injector | ||||||
|  | 
 | ||||||
|  | @pytest.fixture | ||||||
|  | def user_factory(): | ||||||
|  |     def factory(name='dummy', rank='regular_user'): | ||||||
|  |         user = db.User() | ||||||
|  |         user.name = name | ||||||
|  |         user.password = 'dummy' | ||||||
|  |         user.password_salt = 'dummy' | ||||||
|  |         user.password_hash = 'dummy' | ||||||
|  |         user.email = 'dummy' | ||||||
|  |         user.rank = rank | ||||||
|  |         user.creation_time = datetime(1997, 1, 1) | ||||||
|  |         user.avatar_style = db.User.AVATAR_GRAVATAR | ||||||
|  |         return user | ||||||
|  |     return factory | ||||||
| @ -1,11 +0,0 @@ | |||||||
| import unittest |  | ||||||
| import sqlalchemy |  | ||||||
| from szurubooru import db |  | ||||||
| 
 |  | ||||||
| class DatabaseTestCase(unittest.TestCase): |  | ||||||
|     def setUp(self): |  | ||||||
|         engine = sqlalchemy.create_engine('sqlite:///:memory:') |  | ||||||
|         session_maker = sqlalchemy.orm.sessionmaker(bind=engine) |  | ||||||
|         self.session = sqlalchemy.orm.scoped_session(session_maker) |  | ||||||
|         db.Base.query = self.session.query_property() |  | ||||||
|         db.Base.metadata.create_all(bind=engine) |  | ||||||
| @ -1,192 +1,170 @@ | |||||||
| from datetime import datetime | from datetime import datetime | ||||||
| from szurubooru import errors, search | import pytest | ||||||
| from szurubooru.tests.database_test_case import DatabaseTestCase | from szurubooru import db, errors, search | ||||||
| from szurubooru.tests.api import util |  | ||||||
| 
 | 
 | ||||||
| class TestUserSearchExecutor(DatabaseTestCase): | def mock_user(name): | ||||||
|     def setUp(self): |     user = db.User() | ||||||
|         super().setUp() |     user.name = name | ||||||
|         self.search_config = search.UserSearchConfig() |     user.password = 'dummy' | ||||||
|         self.executor = search.SearchExecutor(self.search_config) |     user.password_salt = 'dummy' | ||||||
|  |     user.password_hash = 'dummy' | ||||||
|  |     user.email = 'dummy' | ||||||
|  |     user.rank = 'dummy' | ||||||
|  |     user.creation_time = datetime(1997, 1, 1) | ||||||
|  |     user.avatar_style = db.User.AVATAR_GRAVATAR | ||||||
|  |     return user | ||||||
| 
 | 
 | ||||||
|     def _test(self, query, page, page_size, expected_count, expected_user_names): | @pytest.fixture | ||||||
|         count, users = self.executor.execute(self.session, query, page, page_size) | def executor(session): | ||||||
|         self.assertEqual(count, expected_count) |     search_config = search.UserSearchConfig() | ||||||
|         self.assertEqual([u.name for u in users], expected_user_names) |     return search.SearchExecutor(search_config) | ||||||
| 
 | 
 | ||||||
|     def _test_raises(self, query, page, page_size): | @pytest.fixture | ||||||
|         self.assertRaises( | def verify_unpaged(session, executor): | ||||||
|             errors.SearchError, |     def verify(input, expected_user_names): | ||||||
|             self.executor.execute, |         actual_count, actual_users = executor.execute( | ||||||
|             self.session, |             session, input, page=1, page_size=100) | ||||||
|             query, |         actual_user_names = [u.name for u in actual_users] | ||||||
|             page, |         assert actual_count == len(expected_user_names) | ||||||
|             page_size) |         assert actual_user_names == expected_user_names | ||||||
|  |     return verify | ||||||
| 
 | 
 | ||||||
|     def test_filter_by_creation_time(self): | # ----------------------------------------------------------------------------- | ||||||
|         user1 = util.mock_user('u1') | @pytest.mark.parametrize('input,expected_user_names', [ | ||||||
|         user2 = util.mock_user('u2') |     ('creation-time:2014', ['u1', 'u2']), | ||||||
|         user1.creation_time = datetime(2014, 1, 1) |     ('creation-date:2014', ['u1', 'u2']), | ||||||
|         user2.creation_time = datetime(2015, 1, 1) |     ('-creation-time:2014', ['u3']), | ||||||
|         self.session.add_all([user1, user2]) |     ('-creation-date:2014', ['u3']), | ||||||
|         for alias in ['creation-time', 'creation-date']: |     ('creation-time:2014..2014-06', ['u1', 'u2']), | ||||||
|             self._test('%s:2014' % alias, 1, 100, 1, ['u1']) |     ('creation-time:2014-06..2015-01-01', ['u2', 'u3']), | ||||||
| 
 |     ('creation-time:2014-06..', ['u2', 'u3']), | ||||||
|     def test_filter_by_negated_creation_time(self): |     ('creation-time:..2014-06', ['u1', 'u2']), | ||||||
|         user1 = util.mock_user('u1') |     ('-creation-time:2014..2014-06', ['u3']), | ||||||
|         user2 = util.mock_user('u2') |     ('-creation-time:2014-06..2015-01-01', ['u1']), | ||||||
|         user1.creation_time = datetime(2014, 1, 1) |     ('creation-date:2014..2014-06', ['u1', 'u2']), | ||||||
|         user2.creation_time = datetime(2015, 1, 1) |     ('creation-date:2014-06..2015-01-01', ['u2', 'u3']), | ||||||
|         self.session.add_all([user1, user2]) |     ('creation-date:2014-06..', ['u2', 'u3']), | ||||||
|         for alias in ['creation-time', 'creation-date']: |     ('creation-date:..2014-06', ['u1', 'u2']), | ||||||
|             self._test('-%s:2014' % alias, 1, 100, 1, ['u2']) |     ('-creation-date:2014..2014-06', ['u3']), | ||||||
| 
 |     ('-creation-date:2014-06..2015-01-01', ['u1']), | ||||||
|     def test_filter_by_ranged_creation_time(self): |     ('creation-time:2014-01,2015', ['u1', 'u3']), | ||||||
|         user1 = util.mock_user('u1') |     ('creation-date:2014-01,2015', ['u1', 'u3']), | ||||||
|         user2 = util.mock_user('u2') |     ('-creation-time:2014-01,2015', ['u2']), | ||||||
|         user3 = util.mock_user('u3') |     ('-creation-date:2014-01,2015', ['u2']), | ||||||
|  | ]) | ||||||
|  | def test_filter_by_creation_time( | ||||||
|  |         verify_unpaged, session, input, expected_user_names): | ||||||
|  |     user1 = mock_user('u1') | ||||||
|  |     user2 = mock_user('u2') | ||||||
|  |     user3 = mock_user('u3') | ||||||
|     user1.creation_time = datetime(2014, 1, 1) |     user1.creation_time = datetime(2014, 1, 1) | ||||||
|     user2.creation_time = datetime(2014, 6, 1) |     user2.creation_time = datetime(2014, 6, 1) | ||||||
|     user3.creation_time = datetime(2015, 1, 1) |     user3.creation_time = datetime(2015, 1, 1) | ||||||
|         self.session.add_all([user1, user2, user3]) |     session.add_all([user1, user2, user3]) | ||||||
|         for alias in ['creation-time', 'creation-date']: |     verify_unpaged(input, expected_user_names) | ||||||
|             self._test('%s:2014..2014-06' % alias, 1, 100, 2, ['u1', 'u2']) |  | ||||||
|             self._test('%s:2014-06..2015-01-01' % alias, 1, 100, 2, ['u2', 'u3']) |  | ||||||
|             self._test('%s:2014-06..' % alias, 1, 100, 2, ['u2', 'u3']) |  | ||||||
|             self._test('%s:..2014-06' % alias, 1, 100, 2, ['u1', 'u2']) |  | ||||||
|             self._test_raises('%s:..' % alias, 1, 100) |  | ||||||
| 
 | 
 | ||||||
|     def test_filter_by_negated_ranged_creation_time(self): | # ----------------------------------------------------------------------------- | ||||||
|         user1 = util.mock_user('u1') | @pytest.mark.parametrize('input,expected_user_names', [ | ||||||
|         user2 = util.mock_user('u2') |     ('name:user1', ['user1']), | ||||||
|         user3 = util.mock_user('u3') |     ('name:user2', ['user2']), | ||||||
|  |     ('name:none', []), | ||||||
|  |     ('name:', []), | ||||||
|  |     ('name:*1', ['user1']), | ||||||
|  |     ('name:*2', ['user2']), | ||||||
|  |     ('name:*', ['user1', 'user2', 'user3']), | ||||||
|  |     ('name:u*', ['user1', 'user2', 'user3']), | ||||||
|  |     ('name:*ser*', ['user1', 'user2', 'user3']), | ||||||
|  |     ('name:*zer*', []), | ||||||
|  |     ('name:zer*', []), | ||||||
|  |     ('name:*zer', []), | ||||||
|  |     ('-name:user1', ['user2', 'user3']), | ||||||
|  |     ('-name:user2', ['user1', 'user3']), | ||||||
|  |     ('name:user1,user2', ['user1', 'user2']), | ||||||
|  |     ('-name:user1,user3', ['user2']), | ||||||
|  | ]) | ||||||
|  | def test_filter_by_name(session, verify_unpaged, input, expected_user_names): | ||||||
|  |     session.add(mock_user('user1')) | ||||||
|  |     session.add(mock_user('user2')) | ||||||
|  |     session.add(mock_user('user3')) | ||||||
|  |     verify_unpaged(input, expected_user_names) | ||||||
|  | 
 | ||||||
|  | # ----------------------------------------------------------------------------- | ||||||
|  | @pytest.mark.parametrize('input,expected_user_names', [ | ||||||
|  |     ('', ['u1', 'u2']), | ||||||
|  |     ('u1', ['u1']), | ||||||
|  |     ('u2', ['u2']), | ||||||
|  |     ('u1,u2', ['u1', 'u2']), | ||||||
|  | ]) | ||||||
|  | def test_anonymous(session, verify_unpaged, input, expected_user_names): | ||||||
|  |     session.add(mock_user('u1')) | ||||||
|  |     session.add(mock_user('u2')) | ||||||
|  |     verify_unpaged(input, expected_user_names) | ||||||
|  | 
 | ||||||
|  | # ----------------------------------------------------------------------------- | ||||||
|  | @pytest.mark.parametrize('input,expected_user_names', [ | ||||||
|  |     ('creation-time:2014 u1', ['u1']), | ||||||
|  |     ('creation-time:2014 u2', ['u2']), | ||||||
|  |     ('creation-time:2016 u2', []), | ||||||
|  | ]) | ||||||
|  | def test_combining_tokens(session, verify_unpaged, input, expected_user_names): | ||||||
|  |     user1 = mock_user('u1') | ||||||
|  |     user2 = mock_user('u2') | ||||||
|  |     user3 = mock_user('u3') | ||||||
|     user1.creation_time = datetime(2014, 1, 1) |     user1.creation_time = datetime(2014, 1, 1) | ||||||
|     user2.creation_time = datetime(2014, 6, 1) |     user2.creation_time = datetime(2014, 6, 1) | ||||||
|     user3.creation_time = datetime(2015, 1, 1) |     user3.creation_time = datetime(2015, 1, 1) | ||||||
|         self.session.add_all([user1, user2, user3]) |     session.add_all([user1, user2, user3]) | ||||||
|         for alias in ['creation-time', 'creation-date']: |     verify_unpaged(input, expected_user_names) | ||||||
|             self._test('-%s:2014..2014-06' % alias, 1, 100, 1, ['u3']) |  | ||||||
|             self._test('-%s:2014-06..2015-01-01' % alias, 1, 100, 1, ['u1']) |  | ||||||
| 
 | 
 | ||||||
|     def test_filter_by_composite_creation_time(self): | # ----------------------------------------------------------------------------- | ||||||
|         user1 = util.mock_user('u1') | @pytest.mark.parametrize( | ||||||
|         user2 = util.mock_user('u2') |     'page,page_size,expected_total_count,expected_user_names', [ | ||||||
|         user3 = util.mock_user('u3') |         (1, 1, 2, ['u1']), | ||||||
|         user1.creation_time = datetime(2014, 1, 1) |         (2, 1, 2, ['u2']), | ||||||
|         user2.creation_time = datetime(2014, 6, 1) |         (3, 1, 2, []), | ||||||
|         user3.creation_time = datetime(2015, 1, 1) |         (0, 1, 2, ['u1']), | ||||||
|         self.session.add_all([user1, user2, user3]) |         (0, 0, 2, ['u1']), | ||||||
|         for alias in ['creation-time', 'creation-date']: |     ]) | ||||||
|             self._test('%s:2014-01,2015' % alias, 1, 100, 2, ['u1', 'u3']) | def test_paging( | ||||||
|  |         session, executor, page, page_size, | ||||||
|  |         expected_total_count, expected_user_names): | ||||||
|  |     session.add(mock_user('u1')) | ||||||
|  |     session.add(mock_user('u2')) | ||||||
|  |     actual_count, actual_users = executor.execute( | ||||||
|  |         session, '', page=page, page_size=page_size) | ||||||
|  |     actual_user_names = [u.name for u in actual_users] | ||||||
|  |     assert actual_count == expected_total_count | ||||||
|  |     assert actual_user_names == expected_user_names | ||||||
| 
 | 
 | ||||||
|     def test_filter_by_negated_composite_creation_time(self): | # ----------------------------------------------------------------------------- | ||||||
|         user1 = util.mock_user('u1') | @pytest.mark.parametrize('input,expected_user_names', [ | ||||||
|         user2 = util.mock_user('u2') |     ('', ['u1', 'u2']), | ||||||
|         user3 = util.mock_user('u3') |     ('order:name', ['u1', 'u2']), | ||||||
|         user1.creation_time = datetime(2014, 1, 1) |     ('-order:name', ['u2', 'u1']), | ||||||
|         user2.creation_time = datetime(2014, 6, 1) |     ('order:name,asc', ['u1', 'u2']), | ||||||
|         user3.creation_time = datetime(2015, 1, 1) |     ('order:name,desc', ['u2', 'u1']), | ||||||
|         self.session.add_all([user1, user2, user3]) |     ('-order:name,asc', ['u2', 'u1']), | ||||||
|         for alias in ['creation-time', 'creation-date']: |     ('-order:name,desc', ['u1', 'u2']), | ||||||
|             self._test('-%s:2014-01,2015' % alias, 1, 100, 1, ['u2']) | ]) | ||||||
|  | def test_order_by_name(session, verify_unpaged, input, expected_user_names): | ||||||
|  |     session.add(mock_user('u2')) | ||||||
|  |     session.add(mock_user('u1')) | ||||||
|  |     verify_unpaged(input, expected_user_names) | ||||||
| 
 | 
 | ||||||
|     def test_filter_by_name(self): | # ----------------------------------------------------------------------------- | ||||||
|         self.session.add(util.mock_user('u1')) | @pytest.mark.parametrize('input,expected_error', [ | ||||||
|         self.session.add(util.mock_user('u2')) |     ('creation-date:..', errors.SearchError), | ||||||
|         self._test('name:u1', 1, 100, 1, ['u1']) |     ('creation-date:bad..', errors.ValidationError), | ||||||
|         self._test('name:u2', 1, 100, 1, ['u2']) |     ('creation-date:..bad', errors.ValidationError), | ||||||
| 
 |     ('creation-date:bad..bad', errors.ValidationError), | ||||||
|     def test_filter_by_name_wildcards(self): |     ('name:a..b', errors.SearchError), | ||||||
|         self.session.add(util.mock_user('user1')) |     ('order:', errors.SearchError), | ||||||
|         self.session.add(util.mock_user('user2')) |     ('order:nam', errors.SearchError), | ||||||
|         self._test('name:*1', 1, 100, 1, ['user1']) |     ('order:name,as', errors.SearchError), | ||||||
|         self._test('name:*2', 1, 100, 1, ['user2']) |     ('order:name,asc,desc', errors.SearchError), | ||||||
|         self._test('name:*', 1, 100, 2, ['user1', 'user2']) |     ('bad:x', errors.SearchError), | ||||||
|         self._test('name:u*', 1, 100, 2, ['user1', 'user2']) |     ('special:unsupported', errors.SearchError), | ||||||
|         self._test('name:*ser*', 1, 100, 2, ['user1', 'user2']) | ]) | ||||||
|         self._test('name:*zer*', 1, 100, 0, []) | def test_bad_tokens(executor, session, input, expected_error): | ||||||
|         self._test('name:zer*', 1, 100, 0, []) |     with pytest.raises(expected_error): | ||||||
|         self._test('name:*zer', 1, 100, 0, []) |         executor.execute(session, input, page=1, page_size=100) | ||||||
| 
 |  | ||||||
|     def test_filter_by_negated_name(self): |  | ||||||
|         self.session.add(util.mock_user('u1')) |  | ||||||
|         self.session.add(util.mock_user('u2')) |  | ||||||
|         self._test('-name:u1', 1, 100, 1, ['u2']) |  | ||||||
|         self._test('-name:u2', 1, 100, 1, ['u1']) |  | ||||||
| 
 |  | ||||||
|     def test_filter_by_composite_name(self): |  | ||||||
|         self.session.add(util.mock_user('u1')) |  | ||||||
|         self.session.add(util.mock_user('u2')) |  | ||||||
|         self.session.add(util.mock_user('u3')) |  | ||||||
|         self._test('name:u1,u2', 1, 100, 2, ['u1', 'u2']) |  | ||||||
| 
 |  | ||||||
|     def test_filter_by_negated_composite_name(self): |  | ||||||
|         self.session.add(util.mock_user('u1')) |  | ||||||
|         self.session.add(util.mock_user('u2')) |  | ||||||
|         self.session.add(util.mock_user('u3')) |  | ||||||
|         self._test('-name:u1,u3', 1, 100, 1, ['u2']) |  | ||||||
| 
 |  | ||||||
|     def test_filter_by_ranged_name(self): |  | ||||||
|         self._test_raises('name:u1..u2', 1, 100) |  | ||||||
| 
 |  | ||||||
|     def test_paging(self): |  | ||||||
|         self.session.add(util.mock_user('u1')) |  | ||||||
|         self.session.add(util.mock_user('u2')) |  | ||||||
|         self._test('', 1, 1, 2, ['u1']) |  | ||||||
|         self._test('', 2, 1, 2, ['u2']) |  | ||||||
|         self._test('', 3, 1, 2, []) |  | ||||||
|         self._test('', 0, 1, 2, ['u1']) |  | ||||||
|         self._test('', 0, 0, 2, ['u1']) |  | ||||||
| 
 |  | ||||||
|     def test_order_by_name(self): |  | ||||||
|         self.session.add(util.mock_user('u2')) |  | ||||||
|         self.session.add(util.mock_user('u1')) |  | ||||||
|         self._test('', 1, 100, 2, ['u1', 'u2']) |  | ||||||
|         self._test('order:name', 1, 100, 2, ['u1', 'u2']) |  | ||||||
|         self._test('-order:name', 1, 100, 2, ['u2', 'u1']) |  | ||||||
|         self._test('order:name,asc', 1, 100, 2, ['u1', 'u2']) |  | ||||||
|         self._test('order:name,desc', 1, 100, 2, ['u2', 'u1']) |  | ||||||
|         self._test('-order:name,asc', 1, 100, 2, ['u2', 'u1']) |  | ||||||
|         self._test('-order:name,desc', 1, 100, 2, ['u1', 'u2']) |  | ||||||
| 
 |  | ||||||
|     def test_invalid_tokens(self): |  | ||||||
|         for query in [ |  | ||||||
|                 'order:', |  | ||||||
|                 'order:nam', |  | ||||||
|                 'order:name,as', |  | ||||||
|                 'order:name,asc,desc', |  | ||||||
|                 'bad:x', |  | ||||||
|                 'special:unsupported']: |  | ||||||
|             self._test_raises(query, 1, 100) |  | ||||||
| 
 |  | ||||||
|     def test_anonymous(self): |  | ||||||
|         self.session.add(util.mock_user('u1')) |  | ||||||
|         self.session.add(util.mock_user('u2')) |  | ||||||
|         self._test('u1', 1, 100, 1, ['u1']) |  | ||||||
|         self._test('u2', 1, 100, 1, ['u2']) |  | ||||||
| 
 |  | ||||||
|     def test_empty_search(self): |  | ||||||
|         self.session.add(util.mock_user('u1')) |  | ||||||
|         self.session.add(util.mock_user('u2')) |  | ||||||
|         self._test('', 1, 100, 2, ['u1', 'u2']) |  | ||||||
| 
 |  | ||||||
|     def test_negated_anonymous(self): |  | ||||||
|         self.session.add(util.mock_user('u1')) |  | ||||||
|         self.session.add(util.mock_user('u2')) |  | ||||||
|         self._test('-u1', 1, 100, 1, ['u2']) |  | ||||||
|         self._test('-u2', 1, 100, 1, ['u1']) |  | ||||||
| 
 |  | ||||||
|     def test_combining(self): |  | ||||||
|         user1 = util.mock_user('u1') |  | ||||||
|         user2 = util.mock_user('u2') |  | ||||||
|         user3 = util.mock_user('u3') |  | ||||||
|         user1.creation_time = datetime(2014, 1, 1) |  | ||||||
|         user2.creation_time = datetime(2014, 6, 1) |  | ||||||
|         user3.creation_time = datetime(2015, 1, 1) |  | ||||||
|         self.session.add_all([user1, user2, user3]) |  | ||||||
|         self._test('creation-time:2014 u1', 1, 100, 1, ['u1']) |  | ||||||
|         self._test('creation-time:2014 u2', 1, 100, 1, ['u2']) |  | ||||||
|         self._test('creation-time:2016 u2', 1, 100, 0, []) |  | ||||||
| 
 |  | ||||||
|     def test_special(self): |  | ||||||
|         self._test_raises('special:-', 1, 100) |  | ||||||
|  | |||||||
| @ -1,42 +1,30 @@ | |||||||
| import unittest | import pytest | ||||||
| from datetime import datetime | from datetime import datetime | ||||||
| from szurubooru import errors | from szurubooru import errors | ||||||
| from szurubooru.util import misc | from szurubooru.util import misc | ||||||
| 
 | 
 | ||||||
|  | dt = datetime | ||||||
|  | 
 | ||||||
| class FakeDatetime(datetime): | class FakeDatetime(datetime): | ||||||
|     @staticmethod |     @staticmethod | ||||||
|     def now(tz=None): |     def now(tz=None): | ||||||
|         return datetime(1997, 1, 2, 3, 4, 5, tzinfo=tz) |         return datetime(1997, 1, 2, 3, 4, 5, tzinfo=tz) | ||||||
| 
 | 
 | ||||||
| class TestParseTime(unittest.TestCase): | def test_parsing_empty_date_time(): | ||||||
|     def test_empty(self): |     with pytest.raises(errors.ValidationError): | ||||||
|         self.assertRaises(errors.ValidationError, misc.parse_time_range, '') |         misc.parse_time_range('') | ||||||
| 
 | 
 | ||||||
|     def test_today(self): | @pytest.mark.parametrize('input,output', [ | ||||||
|  |     ('today',       (dt(1997, 1, 2, 0, 0, 0), dt(1997, 1, 2, 23, 59, 59))), | ||||||
|  |     ('yesterday',   (dt(1997, 1, 1, 0, 0, 0), dt(1997, 1, 1, 23, 59, 59))), | ||||||
|  |     ('1999',        (dt(1999, 1, 1, 0, 0, 0), dt(1999, 12, 31, 23, 59, 59))), | ||||||
|  |     ('1999-2',      (dt(1999, 2, 1, 0, 0, 0), dt(1999, 2, 28, 23, 59, 59))), | ||||||
|  |     ('1999-02',     (dt(1999, 2, 1, 0, 0, 0), dt(1999, 2, 28, 23, 59, 59))), | ||||||
|  |     ('1999-2-6',    (dt(1999, 2, 6, 0, 0, 0), dt(1999, 2, 6, 23, 59, 59))), | ||||||
|  |     ('1999-02-6',   (dt(1999, 2, 6, 0, 0, 0), dt(1999, 2, 6, 23, 59, 59))), | ||||||
|  |     ('1999-2-06',   (dt(1999, 2, 6, 0, 0, 0), dt(1999, 2, 6, 23, 59, 59))), | ||||||
|  |     ('1999-02-06',  (dt(1999, 2, 6, 0, 0, 0), dt(1999, 2, 6, 23, 59, 59))), | ||||||
|  | ]) | ||||||
|  | def test_parsing_date_time(input, output): | ||||||
|     misc.datetime.datetime = FakeDatetime |     misc.datetime.datetime = FakeDatetime | ||||||
|         date_min, date_max = misc.parse_time_range('today') |     assert misc.parse_time_range(input) == output | ||||||
|         self.assertEqual(date_min, datetime(1997, 1, 2, 0, 0, 0)) |  | ||||||
|         self.assertEqual(date_max, datetime(1997, 1, 2, 23, 59, 59)) |  | ||||||
| 
 |  | ||||||
|     def test_yesterday(self): |  | ||||||
|         misc.datetime.datetime = FakeDatetime |  | ||||||
|         date_min, date_max = misc.parse_time_range('yesterday') |  | ||||||
|         self.assertEqual(date_min, datetime(1997, 1, 1, 0, 0, 0)) |  | ||||||
|         self.assertEqual(date_max, datetime(1997, 1, 1, 23, 59, 59)) |  | ||||||
| 
 |  | ||||||
|     def test_year(self): |  | ||||||
|         date_min, date_max = misc.parse_time_range('1999') |  | ||||||
|         self.assertEqual(date_min, datetime(1999, 1, 1, 0, 0, 0)) |  | ||||||
|         self.assertEqual(date_max, datetime(1999, 12, 31, 23, 59, 59)) |  | ||||||
| 
 |  | ||||||
|     def test_month(self): |  | ||||||
|         for text in ['1999-2', '1999-02']: |  | ||||||
|             date_min, date_max = misc.parse_time_range(text) |  | ||||||
|             self.assertEqual(date_min, datetime(1999, 2, 1, 0, 0, 0)) |  | ||||||
|             self.assertEqual(date_max, datetime(1999, 2, 28, 23, 59, 59)) |  | ||||||
| 
 |  | ||||||
|     def test_day(self): |  | ||||||
|         for text in ['1999-2-6', '1999-02-6', '1999-2-06', '1999-02-06']: |  | ||||||
|             date_min, date_max = misc.parse_time_range(text) |  | ||||||
|             self.assertEqual(date_min, datetime(1999, 2, 6, 0, 0, 0)) |  | ||||||
|             self.assertEqual(date_max, datetime(1999, 2, 6, 23, 59, 59)) |  | ||||||
|  | |||||||
							
								
								
									
										7
									
								
								server/test
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										7
									
								
								server/test
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,7 @@ | |||||||
|  | #!/usr/bin/env python3 | ||||||
|  | import pytest | ||||||
|  | import sys | ||||||
|  | pytest.main(' '.join([ | ||||||
|  |     '--cov-report=term-missing', | ||||||
|  |     '--cov=szurubooru', | ||||||
|  |     'szurubooru'] + sys.argv[1:])) | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 rr-
						rr-