server/tests: switch to pytest
This commit is contained in:
parent
7f8c2cfa00
commit
07ea920def
18 changed files with 859 additions and 701 deletions
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…
Reference in a new issue