From ad6750a055239536bfbdc3726594727c7d1ae43c Mon Sep 17 00:00:00 2001 From: rr- Date: Mon, 4 Apr 2016 16:06:08 +0200 Subject: [PATCH] server/users: improve api coverage in tests --- .../tests/api/test_updating_user.py | 138 --------- server/szurubooru/tests/api/test_user_api.py | 284 ++++++++++++++++++ .../tests/search/test_user_search_config.py | 17 ++ 3 files changed, 301 insertions(+), 138 deletions(-) delete mode 100644 server/szurubooru/tests/api/test_updating_user.py create mode 100644 server/szurubooru/tests/api/test_user_api.py diff --git a/server/szurubooru/tests/api/test_updating_user.py b/server/szurubooru/tests/api/test_updating_user.py deleted file mode 100644 index c1155f25..00000000 --- a/server/szurubooru/tests/api/test_updating_user.py +++ /dev/null @@ -1,138 +0,0 @@ -from datetime import datetime -from szurubooru import api, db, errors, config -from szurubooru.util import auth, misc -from szurubooru.tests.database_test_case import DatabaseTestCase - -class TestUserDetailApi(DatabaseTestCase): - def setUp(self): - super().setUp() - config_mock = { - 'basic': { - 'secret': '', - }, - 'service': { - 'user_name_regex': '.{3,}', - 'password_regex': '.{3,}', - 'user_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:any:name': 'mod', - 'users:edit:any:pass': 'mod', - 'users:edit:any:email': 'mod', - 'users:edit:any:rank': 'admin', - } - } - self.old_config = config.config - config.config = config_mock - self.api = api.UserDetailApi() - self.context = misc.dotdict() - self.context.session = self.session - self.context.request = {} - - def tearDown(self): - config.config = self.old_config - - def _create_user(self, name, rank='admin'): - user = db.User() - user.name = name - user.password = 'dummy' - user.password_salt = 'dummy' - user.password_hash = 'dummy' - user.email = 'dummy' - user.access_rank = rank - user.creation_time = datetime.now() - user.avatar_style = db.User.AVATAR_GRAVATAR - return user - - def test_updating_nothing(self): - admin_user = self._create_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.access_rank, 'admin') - - def test_admin_updating_everything_for_themselves(self): - admin_user = self._create_user('u1', 'admin') - self.session.add(admin_user) - self.context.user = admin_user - self.context.request = { - 'name': 'chewie', - 'email': 'asd@asd.asd', - 'password': 'oks', - 'accessRank': 'mod', - } - 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.access_rank, 'mod') - 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 = self._create_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 = self._create_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 = {'accessRank': '.'} - self.assertRaises( - errors.ValidationError, self.api.put, self.context, 'u1') - self.context.request = {'email': '.'} - self.assertRaises( - errors.ValidationError, self.api.put, self.context, 'u1') - - def test_user_trying_to_update_someone_else(self): - user1 = self._create_user('u1', 'regular_user') - user2 = self._create_user('u2', 'regular_user') - self.session.add_all([user1, user2]) - self.context.user = user1 - for request in [ - {'name': 'whatever'}, - {'email': 'whatever'}, - {'accessRank': '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 = self._create_user('u1', 'regular_user') - user2 = self._create_user('u2', 'regular_user') - self.session.add_all([user1, user2]) - self.context.user = user1 - self.context.request = {'name': 'u2'} - self.assertRaises( - errors.ValidationError, self.api.put, self.context, 'u1') - - def test_mods_trying_to_become_admin(self): - user1 = self._create_user('u1', 'mod') - user2 = self._create_user('u2', 'mod') - self.session.add_all([user1, user2]) - self.context.user = user1 - self.context.request = {'accessRank': 'admin'} - self.assertRaises( - errors.AuthError, self.api.put, self.context, user1.name) - self.assertRaises( - errors.AuthError, self.api.put, self.context, user2.name) diff --git a/server/szurubooru/tests/api/test_user_api.py b/server/szurubooru/tests/api/test_user_api.py new file mode 100644 index 00000000..bfa59320 --- /dev/null +++ b/server/szurubooru/tests/api/test_user_api.py @@ -0,0 +1,284 @@ +from datetime import datetime +from szurubooru import api, db, errors, config +from szurubooru.util import auth, misc +from szurubooru.tests.database_test_case import DatabaseTestCase + +def _create_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.access_rank = rank + user.creation_time = datetime(1997, 1, 1) + user.avatar_style = db.User.AVATAR_GRAVATAR + return user + +def _mock_params(context, params): + def get_param_as_string(key, default=None): + if key not in params: + return default + return params[key] + def get_param_as_int(key, default=None): + if key not in params: + return default + return int(params[key]) + context.get_param_as_string = get_param_as_string + context.get_param_as_int = get_param_as_int + +class TestRetrievingUsers(DatabaseTestCase): + def setUp(self): + super().setUp() + config_mock = { + 'privileges': { + 'users:list': 'regular_user', + 'users:view': 'regular_user', + 'users:create': 'regular_user', + }, + 'service': { + 'user_ranks': ['anonymous', 'regular_user', 'mod', 'admin'], + }, + } + self.old_config = config.config + config.config = config_mock + self.context = misc.dotdict() + self.context.session = self.session + self.context.request = {} + self.context.user = db.User() + + def test_retrieving_multiple(self): + user1 = _create_user('u1', 'mod') + user2 = _create_user('u2', 'mod') + self.session.add_all([user1, user2]) + _mock_params(self.context, {'query': '', 'page': 1}) + self.context.user.access_rank = 'regular_user' + api_ = api.UserListApi() + result = api_.get(self.context) + self.assertEqual(result['query'], '') + self.assertEqual(result['page'], 1) + self.assertEqual(result['page_size'], 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.access_rank = 'anonymous' + _mock_params(self.context, {'query': '', 'page': 1}) + api_ = api.UserListApi() + self.assertRaises(errors.AuthError, api_.get, self.context) + + def test_retrieving_single(self): + user = _create_user('u1', 'regular_user') + self.session.add(user) + self.context.user.access_rank = 'regular_user' + _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']['accessRank'], 'regular_user') + self.assertEqual(result['user']['creationTime'], datetime(1997, 1, 1)) + self.assertEqual(result['user']['lastLoginTime'], None) + self.assertEqual(result['user']['avatarStyle'], 1) # i.e. integer + + def test_retrieving_non_existing(self): + self.context.user.access_rank = 'regular_user' + _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.access_rank = 'anonymous' + _mock_params(self.context, {'query': '', 'page': 1}) + api_ = api.UserDetailApi() + self.assertRaises(errors.AuthError, api_.get, self.context, '-') + +class TestCreatingUser(DatabaseTestCase): + def setUp(self): + super().setUp() + config_mock = { + 'basic': { + 'secret': '', + }, + 'service': { + 'user_name_regex': '.{3,}', + 'password_regex': '.{3,}', + 'user_ranks': ['anonymous', 'regular_user', 'mod', 'admin'], + 'default_user_rank': 'regular_user', + }, + 'privileges': { + 'users:create': 'anonymous', + }, + } + self.old_config = config.config + config.config = config_mock + self.api = api.UserListApi() + self.context = misc.dotdict() + self.context.session = self.session + self.context.request = {} + self.context.user = db.User() + self.context.user.access_rank = 'anonymous' + + def tearDown(self): + config.config = self.old_config + + def test_creating_valid_user(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.access_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_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() + config_mock = { + 'basic': { + 'secret': '', + }, + 'service': { + 'user_name_regex': '.{3,}', + 'password_regex': '.{3,}', + 'user_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:any:name': 'mod', + 'users:edit:any:pass': 'mod', + 'users:edit:any:email': 'mod', + 'users:edit:any:rank': 'admin', + }, + } + self.old_config = config.config + config.config = config_mock + self.api = api.UserDetailApi() + self.context = misc.dotdict() + self.context.session = self.session + self.context.request = {} + + def tearDown(self): + config.config = self.old_config + + def test_update_changing_nothing(self): + admin_user = _create_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.access_rank, 'admin') + + def test_updating_non_existing_user(self): + admin_user = _create_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 = _create_user('u1', 'admin') + self.session.add(admin_user) + self.context.user = admin_user + self.context.request = { + 'name': 'chewie', + 'email': 'asd@asd.asd', + 'password': 'oks', + 'accessRank': 'mod', + } + 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.access_rank, 'mod') + 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 = _create_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 = _create_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 = {'accessRank': '.'} + self.assertRaises( + errors.ValidationError, self.api.put, self.context, 'u1') + self.context.request = {'email': '.'} + self.assertRaises( + errors.ValidationError, self.api.put, self.context, 'u1') + + def test_user_trying_to_update_someone_else(self): + user1 = _create_user('u1', 'regular_user') + user2 = _create_user('u2', 'regular_user') + self.session.add_all([user1, user2]) + self.context.user = user1 + for request in [ + {'name': 'whatever'}, + {'email': 'whatever'}, + {'accessRank': '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 = _create_user('me', 'regular_user') + user2 = _create_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') + + def test_mods_trying_to_become_admin(self): + user1 = _create_user('u1', 'mod') + user2 = _create_user('u2', 'mod') + self.session.add_all([user1, user2]) + self.context.user = user1 + self.context.request = {'accessRank': 'admin'} + self.assertRaises( + errors.AuthError, self.api.put, self.context, user1.name) + self.assertRaises( + errors.AuthError, self.api.put, self.context, user2.name) diff --git a/server/szurubooru/tests/search/test_user_search_config.py b/server/szurubooru/tests/search/test_user_search_config.py index f02c6935..d1059ac2 100644 --- a/server/szurubooru/tests/search/test_user_search_config.py +++ b/server/szurubooru/tests/search/test_user_search_config.py @@ -111,6 +111,12 @@ class TestUserSearchExecutor(DatabaseTestCase): self.session.add(self._create_user('u3')) self._test('name:u1,u2', 1, 2, ['u1', 'u2']) + def test_filter_by_negated_composite_name(self): + self.session.add(self._create_user('u1')) + self.session.add(self._create_user('u2')) + self.session.add(self._create_user('u3')) + self._test('-name:u1,u3', 1, 1, ['u2']) + def test_filter_by_ranged_name(self): self.assertRaises( errors.SearchError, self.executor.execute, self.session, 'name:u1..u2', 1) @@ -132,6 +138,17 @@ class TestUserSearchExecutor(DatabaseTestCase): self._test('-order:name,asc', 1, 2, ['u2', 'u1']) self._test('-order:name,desc', 1, 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.assertRaises( + errors.SearchError, self.executor.execute, self.session, query, 1) + def test_anonymous(self): self.session.add(self._create_user('u1')) self.session.add(self._create_user('u2'))