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 | ||||
| */*_modules/ | ||||
| .coverage | ||||
| .cache | ||||
|  | ||||
| @ -3,4 +3,5 @@ pyyaml>=3.11 | ||||
| falcon>=0.3.0 | ||||
| psycopg2>=2.6.1 | ||||
| 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 szurubooru import errors, search | ||||
| from szurubooru.tests.database_test_case import DatabaseTestCase | ||||
| from szurubooru.tests.api import util | ||||
| import pytest | ||||
| from szurubooru import db, errors, search | ||||
| 
 | ||||
| class TestUserSearchExecutor(DatabaseTestCase): | ||||
|     def setUp(self): | ||||
|         super().setUp() | ||||
|         self.search_config = search.UserSearchConfig() | ||||
|         self.executor = search.SearchExecutor(self.search_config) | ||||
| def mock_user(name): | ||||
|     user = db.User() | ||||
|     user.name = name | ||||
|     user.password = 'dummy' | ||||
|     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): | ||||
|         count, users = self.executor.execute(self.session, query, page, page_size) | ||||
|         self.assertEqual(count, expected_count) | ||||
|         self.assertEqual([u.name for u in users], expected_user_names) | ||||
| @pytest.fixture | ||||
| def executor(session): | ||||
|     search_config = search.UserSearchConfig() | ||||
|     return search.SearchExecutor(search_config) | ||||
| 
 | ||||
|     def _test_raises(self, query, page, page_size): | ||||
|         self.assertRaises( | ||||
|             errors.SearchError, | ||||
|             self.executor.execute, | ||||
|             self.session, | ||||
|             query, | ||||
|             page, | ||||
|             page_size) | ||||
| @pytest.fixture | ||||
| def verify_unpaged(session, executor): | ||||
|     def verify(input, expected_user_names): | ||||
|         actual_count, actual_users = executor.execute( | ||||
|             session, input, page=1, page_size=100) | ||||
|         actual_user_names = [u.name for u in actual_users] | ||||
|         assert actual_count == len(expected_user_names) | ||||
|         assert actual_user_names == expected_user_names | ||||
|     return verify | ||||
| 
 | ||||
|     def test_filter_by_creation_time(self): | ||||
|         user1 = util.mock_user('u1') | ||||
|         user2 = util.mock_user('u2') | ||||
|         user1.creation_time = datetime(2014, 1, 1) | ||||
|         user2.creation_time = datetime(2015, 1, 1) | ||||
|         self.session.add_all([user1, user2]) | ||||
|         for alias in ['creation-time', 'creation-date']: | ||||
|             self._test('%s:2014' % alias, 1, 100, 1, ['u1']) | ||||
| 
 | ||||
|     def test_filter_by_negated_creation_time(self): | ||||
|         user1 = util.mock_user('u1') | ||||
|         user2 = util.mock_user('u2') | ||||
|         user1.creation_time = datetime(2014, 1, 1) | ||||
|         user2.creation_time = datetime(2015, 1, 1) | ||||
|         self.session.add_all([user1, user2]) | ||||
|         for alias in ['creation-time', 'creation-date']: | ||||
|             self._test('-%s:2014' % alias, 1, 100, 1, ['u2']) | ||||
| 
 | ||||
|     def test_filter_by_ranged_creation_time(self): | ||||
|         user1 = util.mock_user('u1') | ||||
|         user2 = util.mock_user('u2') | ||||
|         user3 = util.mock_user('u3') | ||||
| # ----------------------------------------------------------------------------- | ||||
| @pytest.mark.parametrize('input,expected_user_names', [ | ||||
|     ('creation-time:2014', ['u1', 'u2']), | ||||
|     ('creation-date:2014', ['u1', 'u2']), | ||||
|     ('-creation-time:2014', ['u3']), | ||||
|     ('-creation-date:2014', ['u3']), | ||||
|     ('creation-time:2014..2014-06', ['u1', 'u2']), | ||||
|     ('creation-time:2014-06..2015-01-01', ['u2', 'u3']), | ||||
|     ('creation-time:2014-06..', ['u2', 'u3']), | ||||
|     ('creation-time:..2014-06', ['u1', 'u2']), | ||||
|     ('-creation-time:2014..2014-06', ['u3']), | ||||
|     ('-creation-time:2014-06..2015-01-01', ['u1']), | ||||
|     ('creation-date:2014..2014-06', ['u1', 'u2']), | ||||
|     ('creation-date:2014-06..2015-01-01', ['u2', 'u3']), | ||||
|     ('creation-date:2014-06..', ['u2', 'u3']), | ||||
|     ('creation-date:..2014-06', ['u1', 'u2']), | ||||
|     ('-creation-date:2014..2014-06', ['u3']), | ||||
|     ('-creation-date:2014-06..2015-01-01', ['u1']), | ||||
|     ('creation-time:2014-01,2015', ['u1', 'u3']), | ||||
|     ('creation-date:2014-01,2015', ['u1', 'u3']), | ||||
|     ('-creation-time:2014-01,2015', ['u2']), | ||||
|     ('-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) | ||||
|     user2.creation_time = datetime(2014, 6, 1) | ||||
|     user3.creation_time = datetime(2015, 1, 1) | ||||
|         self.session.add_all([user1, user2, user3]) | ||||
|         for alias in ['creation-time', 'creation-date']: | ||||
|             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) | ||||
|     session.add_all([user1, user2, user3]) | ||||
|     verify_unpaged(input, expected_user_names) | ||||
| 
 | ||||
|     def test_filter_by_negated_ranged_creation_time(self): | ||||
|         user1 = util.mock_user('u1') | ||||
|         user2 = util.mock_user('u2') | ||||
|         user3 = util.mock_user('u3') | ||||
| # ----------------------------------------------------------------------------- | ||||
| @pytest.mark.parametrize('input,expected_user_names', [ | ||||
|     ('name:user1', ['user1']), | ||||
|     ('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) | ||||
|     user2.creation_time = datetime(2014, 6, 1) | ||||
|     user3.creation_time = datetime(2015, 1, 1) | ||||
|         self.session.add_all([user1, user2, user3]) | ||||
|         for alias in ['creation-time', 'creation-date']: | ||||
|             self._test('-%s:2014..2014-06' % alias, 1, 100, 1, ['u3']) | ||||
|             self._test('-%s:2014-06..2015-01-01' % alias, 1, 100, 1, ['u1']) | ||||
|     session.add_all([user1, user2, user3]) | ||||
|     verify_unpaged(input, expected_user_names) | ||||
| 
 | ||||
|     def test_filter_by_composite_creation_time(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]) | ||||
|         for alias in ['creation-time', 'creation-date']: | ||||
|             self._test('%s:2014-01,2015' % alias, 1, 100, 2, ['u1', 'u3']) | ||||
| # ----------------------------------------------------------------------------- | ||||
| @pytest.mark.parametrize( | ||||
|     'page,page_size,expected_total_count,expected_user_names', [ | ||||
|         (1, 1, 2, ['u1']), | ||||
|         (2, 1, 2, ['u2']), | ||||
|         (3, 1, 2, []), | ||||
|         (0, 1, 2, ['u1']), | ||||
|         (0, 0, 2, ['u1']), | ||||
|     ]) | ||||
| 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') | ||||
|         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]) | ||||
|         for alias in ['creation-time', 'creation-date']: | ||||
|             self._test('-%s:2014-01,2015' % alias, 1, 100, 1, ['u2']) | ||||
| # ----------------------------------------------------------------------------- | ||||
| @pytest.mark.parametrize('input,expected_user_names', [ | ||||
|     ('', ['u1', 'u2']), | ||||
|     ('order:name', ['u1', 'u2']), | ||||
|     ('-order:name', ['u2', 'u1']), | ||||
|     ('order:name,asc', ['u1', 'u2']), | ||||
|     ('order:name,desc', ['u2', 'u1']), | ||||
|     ('-order:name,asc', ['u2', 'u1']), | ||||
|     ('-order:name,desc', ['u1', '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')) | ||||
|         self.session.add(util.mock_user('u2')) | ||||
|         self._test('name:u1', 1, 100, 1, ['u1']) | ||||
|         self._test('name:u2', 1, 100, 1, ['u2']) | ||||
| 
 | ||||
|     def test_filter_by_name_wildcards(self): | ||||
|         self.session.add(util.mock_user('user1')) | ||||
|         self.session.add(util.mock_user('user2')) | ||||
|         self._test('name:*1', 1, 100, 1, ['user1']) | ||||
|         self._test('name:*2', 1, 100, 1, ['user2']) | ||||
|         self._test('name:*', 1, 100, 2, ['user1', 'user2']) | ||||
|         self._test('name:u*', 1, 100, 2, ['user1', 'user2']) | ||||
|         self._test('name:*ser*', 1, 100, 2, ['user1', 'user2']) | ||||
|         self._test('name:*zer*', 1, 100, 0, []) | ||||
|         self._test('name:zer*', 1, 100, 0, []) | ||||
|         self._test('name:*zer', 1, 100, 0, []) | ||||
| 
 | ||||
|     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) | ||||
| # ----------------------------------------------------------------------------- | ||||
| @pytest.mark.parametrize('input,expected_error', [ | ||||
|     ('creation-date:..', errors.SearchError), | ||||
|     ('creation-date:bad..', errors.ValidationError), | ||||
|     ('creation-date:..bad', errors.ValidationError), | ||||
|     ('creation-date:bad..bad', errors.ValidationError), | ||||
|     ('name:a..b', errors.SearchError), | ||||
|     ('order:', errors.SearchError), | ||||
|     ('order:nam', errors.SearchError), | ||||
|     ('order:name,as', errors.SearchError), | ||||
|     ('order:name,asc,desc', errors.SearchError), | ||||
|     ('bad:x', errors.SearchError), | ||||
|     ('special:unsupported', errors.SearchError), | ||||
| ]) | ||||
| def test_bad_tokens(executor, session, input, expected_error): | ||||
|     with pytest.raises(expected_error): | ||||
|         executor.execute(session, input, page=1, page_size=100) | ||||
|  | ||||
| @ -1,42 +1,30 @@ | ||||
| import unittest | ||||
| import pytest | ||||
| from datetime import datetime | ||||
| from szurubooru import errors | ||||
| from szurubooru.util import misc | ||||
| 
 | ||||
| dt = datetime | ||||
| 
 | ||||
| class FakeDatetime(datetime): | ||||
|     @staticmethod | ||||
|     def now(tz=None): | ||||
|         return datetime(1997, 1, 2, 3, 4, 5, tzinfo=tz) | ||||
| 
 | ||||
| class TestParseTime(unittest.TestCase): | ||||
|     def test_empty(self): | ||||
|         self.assertRaises(errors.ValidationError, misc.parse_time_range, '') | ||||
| def test_parsing_empty_date_time(): | ||||
|     with pytest.raises(errors.ValidationError): | ||||
|         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 | ||||
|         date_min, date_max = misc.parse_time_range('today') | ||||
|         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)) | ||||
|     assert misc.parse_time_range(input) == output | ||||
|  | ||||
							
								
								
									
										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-