server/tests: use real database
I'm experimenting with snapshots and found following limitation of SQLite: https://www.sqlite.org/isolation.html
This commit is contained in:
		
							parent
							
								
									0320a0b55b
								
							
						
					
					
						commit
						87b1ee4564
					
				@ -25,6 +25,15 @@ database:
 | 
			
		||||
    pass: # example: dog
 | 
			
		||||
    name: # example: szuru
 | 
			
		||||
 | 
			
		||||
# required for runing the test suite
 | 
			
		||||
test_database:
 | 
			
		||||
    schema: postgres
 | 
			
		||||
    host: # example: localhost
 | 
			
		||||
    port: # example: 5432
 | 
			
		||||
    user: # example: szuru
 | 
			
		||||
    pass: # example: dog
 | 
			
		||||
    name: # example: szuru_test
 | 
			
		||||
 | 
			
		||||
# used to send password reminders
 | 
			
		||||
smtp:
 | 
			
		||||
    host: # example: localhost
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,9 @@
 | 
			
		||||
# pylint: disable=redefined-outer-name
 | 
			
		||||
import contextlib
 | 
			
		||||
import os
 | 
			
		||||
import datetime
 | 
			
		||||
import uuid
 | 
			
		||||
import random
 | 
			
		||||
import string
 | 
			
		||||
from datetime import datetime
 | 
			
		||||
import pytest
 | 
			
		||||
import freezegun
 | 
			
		||||
import sqlalchemy
 | 
			
		||||
@ -30,8 +31,19 @@ class QueryCounter(object):
 | 
			
		||||
        return self._statements
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if not config.config['test_database']['host']:
 | 
			
		||||
    raise RuntimeError('Test database not configured.')
 | 
			
		||||
 | 
			
		||||
_query_counter = QueryCounter()
 | 
			
		||||
_engine = sqlalchemy.create_engine('sqlite:///:memory:')
 | 
			
		||||
_engine = sqlalchemy.create_engine(
 | 
			
		||||
    '{schema}://{user}:{password}@{host}:{port}/{name}'.format(
 | 
			
		||||
        schema=config.config['test_database']['schema'],
 | 
			
		||||
        user=config.config['test_database']['user'],
 | 
			
		||||
        password=config.config['test_database']['pass'],
 | 
			
		||||
        host=config.config['test_database']['host'],
 | 
			
		||||
        port=config.config['test_database']['port'],
 | 
			
		||||
        name=config.config['test_database']['name']))
 | 
			
		||||
db.Base.metadata.drop_all(bind=_engine)
 | 
			
		||||
db.Base.metadata.create_all(bind=_engine)
 | 
			
		||||
sqlalchemy.event.listen(
 | 
			
		||||
    _engine,
 | 
			
		||||
@ -40,7 +52,8 @@ sqlalchemy.event.listen(
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_unique_name():
 | 
			
		||||
    return str(uuid.uuid4())
 | 
			
		||||
    alphabet = string.ascii_letters + string.digits
 | 
			
		||||
    return ''.join(random.choice(alphabet) for _ in range(8))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture
 | 
			
		||||
@ -72,16 +85,15 @@ def query_logger():
 | 
			
		||||
 | 
			
		||||
@pytest.yield_fixture(scope='function', autouse=True)
 | 
			
		||||
def session(query_logger):  # pylint: disable=unused-argument
 | 
			
		||||
    session_maker = sqlalchemy.orm.sessionmaker(bind=_engine)
 | 
			
		||||
    session = sqlalchemy.orm.scoped_session(session_maker)
 | 
			
		||||
    db.session = session
 | 
			
		||||
    db.sessionmaker = sqlalchemy.orm.sessionmaker(bind=_engine)
 | 
			
		||||
    db.session = sqlalchemy.orm.scoped_session(db.sessionmaker)
 | 
			
		||||
    try:
 | 
			
		||||
        yield session
 | 
			
		||||
        yield db.session
 | 
			
		||||
    finally:
 | 
			
		||||
        session.remove()
 | 
			
		||||
        db.session.remove()
 | 
			
		||||
        for table in reversed(db.Base.metadata.sorted_tables):
 | 
			
		||||
            session.execute(table.delete())
 | 
			
		||||
        session.commit()
 | 
			
		||||
            db.session.execute(table.delete())
 | 
			
		||||
        db.session.commit()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture
 | 
			
		||||
@ -115,7 +127,7 @@ def user_factory():
 | 
			
		||||
        user.password_hash = 'dummy'
 | 
			
		||||
        user.email = email
 | 
			
		||||
        user.rank = rank
 | 
			
		||||
        user.creation_time = datetime.datetime(1997, 1, 1)
 | 
			
		||||
        user.creation_time = datetime(1997, 1, 1)
 | 
			
		||||
        user.avatar_style = db.User.AVATAR_GRAVATAR
 | 
			
		||||
        return user
 | 
			
		||||
    return factory
 | 
			
		||||
@ -142,7 +154,7 @@ def tag_factory():
 | 
			
		||||
        tag.names = [
 | 
			
		||||
            db.TagName(name) for name in names or [get_unique_name()]]
 | 
			
		||||
        tag.category = category
 | 
			
		||||
        tag.creation_time = datetime.datetime(1996, 1, 1)
 | 
			
		||||
        tag.creation_time = datetime(1996, 1, 1)
 | 
			
		||||
        return tag
 | 
			
		||||
    return factory
 | 
			
		||||
 | 
			
		||||
@ -162,14 +174,14 @@ def post_factory():
 | 
			
		||||
        post.checksum = checksum
 | 
			
		||||
        post.flags = []
 | 
			
		||||
        post.mime_type = 'application/octet-stream'
 | 
			
		||||
        post.creation_time = datetime.datetime(1996, 1, 1)
 | 
			
		||||
        post.creation_time = datetime(1996, 1, 1)
 | 
			
		||||
        return post
 | 
			
		||||
    return factory
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture
 | 
			
		||||
def comment_factory(user_factory, post_factory):
 | 
			
		||||
    def factory(user=None, post=None, text='dummy'):
 | 
			
		||||
    def factory(user=None, post=None, text='dummy', time=None):
 | 
			
		||||
        if not user:
 | 
			
		||||
            user = user_factory()
 | 
			
		||||
            db.session.add(user)
 | 
			
		||||
@ -180,7 +192,7 @@ def comment_factory(user_factory, post_factory):
 | 
			
		||||
        comment.user = user
 | 
			
		||||
        comment.post = post
 | 
			
		||||
        comment.text = text
 | 
			
		||||
        comment.creation_time = datetime.datetime(1996, 1, 1)
 | 
			
		||||
        comment.creation_time = time or datetime(1996, 1, 1)
 | 
			
		||||
        return comment
 | 
			
		||||
    return factory
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -145,12 +145,12 @@ def test_cascade_deletions(post_factory, user_factory, comment_factory):
 | 
			
		||||
    snapshot.user = user
 | 
			
		||||
    snapshot.creation_time = datetime(1997, 1, 1)
 | 
			
		||||
    snapshot.resource_type = '-'
 | 
			
		||||
    snapshot.resource_id = '-'
 | 
			
		||||
    snapshot.resource_id = 1
 | 
			
		||||
    snapshot.resource_repr = '-'
 | 
			
		||||
    snapshot.operation = '-'
 | 
			
		||||
 | 
			
		||||
    db.session.add_all([user, post, comment, snapshot])
 | 
			
		||||
    db.session.flush()
 | 
			
		||||
    db.session.commit()
 | 
			
		||||
 | 
			
		||||
    assert not db.session.dirty
 | 
			
		||||
    assert post.user is not None and post.user.user_id is not None
 | 
			
		||||
 | 
			
		||||
@ -35,8 +35,9 @@ def test_serialize_user(user_factory, comment_factory):
 | 
			
		||||
def test_try_get_comment(comment_factory):
 | 
			
		||||
    comment = comment_factory()
 | 
			
		||||
    db.session.add(comment)
 | 
			
		||||
    assert comments.try_get_comment_by_id(999) is None
 | 
			
		||||
    assert comments.try_get_comment_by_id(1) is comment
 | 
			
		||||
    db.session.flush()
 | 
			
		||||
    assert comments.try_get_comment_by_id(comment.comment_id + 1) is None
 | 
			
		||||
    assert comments.try_get_comment_by_id(comment.comment_id) is comment
 | 
			
		||||
    with pytest.raises(comments.InvalidCommentIdError):
 | 
			
		||||
        comments.try_get_comment_by_id('-')
 | 
			
		||||
 | 
			
		||||
@ -44,9 +45,10 @@ def test_try_get_comment(comment_factory):
 | 
			
		||||
def test_get_comment(comment_factory):
 | 
			
		||||
    comment = comment_factory()
 | 
			
		||||
    db.session.add(comment)
 | 
			
		||||
    db.session.flush()
 | 
			
		||||
    with pytest.raises(comments.CommentNotFoundError):
 | 
			
		||||
        comments.get_comment_by_id(999)
 | 
			
		||||
    assert comments.get_comment_by_id(1) is comment
 | 
			
		||||
        comments.get_comment_by_id(comment.comment_id + 1)
 | 
			
		||||
    assert comments.get_comment_by_id(comment.comment_id) is comment
 | 
			
		||||
    with pytest.raises(comments.InvalidCommentIdError):
 | 
			
		||||
        comments.get_comment_by_id('-')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -110,8 +110,14 @@ def test_serialize_post(
 | 
			
		||||
 | 
			
		||||
        db.session.flush()
 | 
			
		||||
        db.session.add_all([
 | 
			
		||||
            comment_factory(user=user_factory(name='commenter1'), post=post),
 | 
			
		||||
            comment_factory(user=user_factory(name='commenter2'), post=post),
 | 
			
		||||
            comment_factory(
 | 
			
		||||
                user=user_factory(name='commenter1'),
 | 
			
		||||
                post=post,
 | 
			
		||||
                time=datetime(1999, 1, 1)),
 | 
			
		||||
            comment_factory(
 | 
			
		||||
                user=user_factory(name='commenter2'),
 | 
			
		||||
                post=post,
 | 
			
		||||
                time=datetime(1999, 1, 2)),
 | 
			
		||||
            db.PostFavorite(
 | 
			
		||||
                post=post,
 | 
			
		||||
                user=user_factory(name='fav1'),
 | 
			
		||||
@ -458,8 +464,8 @@ def test_update_post_relations(post_factory):
 | 
			
		||||
    post = post_factory()
 | 
			
		||||
    posts.update_post_relations(post, [relation1.post_id, relation2.post_id])
 | 
			
		||||
    assert len(post.relations) == 2
 | 
			
		||||
    assert post.relations[0].post_id == relation1.post_id
 | 
			
		||||
    assert post.relations[1].post_id == relation2.post_id
 | 
			
		||||
    assert sorted(r.post_id for r in post.relations) == [
 | 
			
		||||
        relation1.post_id, relation2.post_id]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_update_post_relations_bidirectionality(post_factory):
 | 
			
		||||
 | 
			
		||||
@ -110,7 +110,12 @@ def test_export_to_json(
 | 
			
		||||
    export_path = os.path.join(str(tmpdir), 'tags.json')
 | 
			
		||||
    assert os.path.exists(export_path)
 | 
			
		||||
    with open(export_path, 'r') as handle:
 | 
			
		||||
        assert json.loads(handle.read()) == {
 | 
			
		||||
        actual_json = json.loads(handle.read())
 | 
			
		||||
        assert actual_json['tags']
 | 
			
		||||
        assert actual_json['categories']
 | 
			
		||||
        actual_json['tags'].sort(key=lambda tag: tag['names'][0])
 | 
			
		||||
        actual_json['categories'].sort(key=lambda category: category['name'])
 | 
			
		||||
        assert actual_json == {
 | 
			
		||||
            'tags': [
 | 
			
		||||
                {
 | 
			
		||||
                    'names': ['alias1', 'alias2'],
 | 
			
		||||
@ -119,14 +124,14 @@ def test_export_to_json(
 | 
			
		||||
                    'suggestions': ['sug1', 'sug2'],
 | 
			
		||||
                    'implications': ['imp1', 'imp2'],
 | 
			
		||||
                },
 | 
			
		||||
                {'names': ['sug1'], 'usages': 0, 'category': 'cat1'},
 | 
			
		||||
                {'names': ['sug2'], 'usages': 0, 'category': 'cat1'},
 | 
			
		||||
                {'names': ['imp1'], 'usages': 0, 'category': 'cat1'},
 | 
			
		||||
                {'names': ['imp2'], 'usages': 0, 'category': 'cat1'},
 | 
			
		||||
                {'names': ['sug1'], 'usages': 0, 'category': 'cat1'},
 | 
			
		||||
                {'names': ['sug2'], 'usages': 0, 'category': 'cat1'},
 | 
			
		||||
            ],
 | 
			
		||||
            'categories': [
 | 
			
		||||
                {'name': 'cat2', 'color': 'white'},
 | 
			
		||||
                {'name': 'cat1', 'color': 'black'},
 | 
			
		||||
                {'name': 'cat2', 'color': 'white'},
 | 
			
		||||
            ]
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -164,76 +169,81 @@ def test_get_tag_by_name(name_to_search, expected_to_find, tag_factory):
 | 
			
		||||
            tags.get_tag_by_name(name_to_search)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('names,expected_ids', [
 | 
			
		||||
@pytest.mark.parametrize('names,expected_indexes', [
 | 
			
		||||
    ([], []),
 | 
			
		||||
    (['name1'], [1]),
 | 
			
		||||
    (['NAME1'], [1]),
 | 
			
		||||
    (['alias1'], [1]),
 | 
			
		||||
    (['ALIAS1'], [1]),
 | 
			
		||||
    (['name2'], [2]),
 | 
			
		||||
    (['name1', 'name1'], [1]),
 | 
			
		||||
    (['name1', 'NAME1'], [1]),
 | 
			
		||||
    (['name1', 'alias1'], [1]),
 | 
			
		||||
    (['name1', 'alias2'], [1, 2]),
 | 
			
		||||
    (['NAME1', 'alias2'], [1, 2]),
 | 
			
		||||
    (['name1', 'ALIAS2'], [1, 2]),
 | 
			
		||||
    (['name2', 'alias1'], [1, 2]),
 | 
			
		||||
    (['name1'], [0]),
 | 
			
		||||
    (['NAME1'], [0]),
 | 
			
		||||
    (['alias1'], [0]),
 | 
			
		||||
    (['ALIAS1'], [0]),
 | 
			
		||||
    (['name2'], [1]),
 | 
			
		||||
    (['name1', 'name1'], [0]),
 | 
			
		||||
    (['name1', 'NAME1'], [0]),
 | 
			
		||||
    (['name1', 'alias1'], [0]),
 | 
			
		||||
    (['name1', 'alias2'], [0, 1]),
 | 
			
		||||
    (['NAME1', 'alias2'], [0, 1]),
 | 
			
		||||
    (['name1', 'ALIAS2'], [0, 1]),
 | 
			
		||||
    (['name2', 'alias1'], [0, 1]),
 | 
			
		||||
])
 | 
			
		||||
def test_get_tag_by_names(names, expected_ids, tag_factory):
 | 
			
		||||
    tag1 = tag_factory(names=['name1', 'ALIAS1'])
 | 
			
		||||
    tag2 = tag_factory(names=['name2', 'ALIAS2'])
 | 
			
		||||
    tag1.tag_id = 1
 | 
			
		||||
    tag2.tag_id = 2
 | 
			
		||||
    db.session.add_all([tag1, tag2])
 | 
			
		||||
def test_get_tag_by_names(names, expected_indexes, tag_factory):
 | 
			
		||||
    input_tags = [
 | 
			
		||||
        tag_factory(names=['name1', 'ALIAS1']),
 | 
			
		||||
        tag_factory(names=['name2', 'ALIAS2']),
 | 
			
		||||
    ]
 | 
			
		||||
    db.session.add_all(input_tags)
 | 
			
		||||
    db.session.flush()
 | 
			
		||||
    expected_ids = [input_tags[i].tag_id for i in expected_indexes]
 | 
			
		||||
    actual_ids = [tag.tag_id for tag in tags.get_tags_by_names(names)]
 | 
			
		||||
    assert actual_ids == expected_ids
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize(
 | 
			
		||||
    'names,expected_ids,expected_created_names', [
 | 
			
		||||
    'names,expected_indexes,expected_created_names', [
 | 
			
		||||
        ([], [], []),
 | 
			
		||||
        (['name1'], [1], []),
 | 
			
		||||
        (['NAME1'], [1], []),
 | 
			
		||||
        (['alias1'], [1], []),
 | 
			
		||||
        (['ALIAS1'], [1], []),
 | 
			
		||||
        (['name2'], [2], []),
 | 
			
		||||
        (['name1', 'name1'], [1], []),
 | 
			
		||||
        (['name1', 'NAME1'], [1], []),
 | 
			
		||||
        (['name1', 'alias1'], [1], []),
 | 
			
		||||
        (['name1', 'alias2'], [1, 2], []),
 | 
			
		||||
        (['NAME1', 'alias2'], [1, 2], []),
 | 
			
		||||
        (['name1', 'ALIAS2'], [1, 2], []),
 | 
			
		||||
        (['name2', 'alias1'], [1, 2], []),
 | 
			
		||||
        (['name1'], [0], []),
 | 
			
		||||
        (['NAME1'], [0], []),
 | 
			
		||||
        (['alias1'], [0], []),
 | 
			
		||||
        (['ALIAS1'], [0], []),
 | 
			
		||||
        (['name2'], [1], []),
 | 
			
		||||
        (['name1', 'name1'], [0], []),
 | 
			
		||||
        (['name1', 'NAME1'], [0], []),
 | 
			
		||||
        (['name1', 'alias1'], [0], []),
 | 
			
		||||
        (['name1', 'alias2'], [0, 1], []),
 | 
			
		||||
        (['NAME1', 'alias2'], [0, 1], []),
 | 
			
		||||
        (['name1', 'ALIAS2'], [0, 1], []),
 | 
			
		||||
        (['name2', 'alias1'], [0, 1], []),
 | 
			
		||||
        (['new'], [], ['new']),
 | 
			
		||||
        (['new', 'name1'], [1], ['new']),
 | 
			
		||||
        (['new', 'NAME1'], [1], ['new']),
 | 
			
		||||
        (['new', 'alias1'], [1], ['new']),
 | 
			
		||||
        (['new', 'ALIAS1'], [1], ['new']),
 | 
			
		||||
        (['new', 'name2'], [2], ['new']),
 | 
			
		||||
        (['new', 'name1', 'name1'], [1], ['new']),
 | 
			
		||||
        (['new', 'name1', 'NAME1'], [1], ['new']),
 | 
			
		||||
        (['new', 'name1', 'alias1'], [1], ['new']),
 | 
			
		||||
        (['new', 'name1', 'alias2'], [1, 2], ['new']),
 | 
			
		||||
        (['new', 'NAME1', 'alias2'], [1, 2], ['new']),
 | 
			
		||||
        (['new', 'name1', 'ALIAS2'], [1, 2], ['new']),
 | 
			
		||||
        (['new', 'name2', 'alias1'], [1, 2], ['new']),
 | 
			
		||||
        (['new', 'name1'], [0], ['new']),
 | 
			
		||||
        (['new', 'NAME1'], [0], ['new']),
 | 
			
		||||
        (['new', 'alias1'], [0], ['new']),
 | 
			
		||||
        (['new', 'ALIAS1'], [0], ['new']),
 | 
			
		||||
        (['new', 'name2'], [1], ['new']),
 | 
			
		||||
        (['new', 'name1', 'name1'], [0], ['new']),
 | 
			
		||||
        (['new', 'name1', 'NAME1'], [0], ['new']),
 | 
			
		||||
        (['new', 'name1', 'alias1'], [0], ['new']),
 | 
			
		||||
        (['new', 'name1', 'alias2'], [0, 1], ['new']),
 | 
			
		||||
        (['new', 'NAME1', 'alias2'], [0, 1], ['new']),
 | 
			
		||||
        (['new', 'name1', 'ALIAS2'], [0, 1], ['new']),
 | 
			
		||||
        (['new', 'name2', 'alias1'], [0, 1], ['new']),
 | 
			
		||||
        (['new', 'new'], [], ['new']),
 | 
			
		||||
        (['new', 'NEW'], [], ['new']),
 | 
			
		||||
        (['new', 'new2'], [], ['new', 'new2']),
 | 
			
		||||
    ])
 | 
			
		||||
def test_get_or_create_tags_by_names(
 | 
			
		||||
        names,
 | 
			
		||||
        expected_ids,
 | 
			
		||||
        expected_indexes,
 | 
			
		||||
        expected_created_names,
 | 
			
		||||
        tag_factory,
 | 
			
		||||
        tag_category_factory,
 | 
			
		||||
        config_injector):
 | 
			
		||||
    config_injector({'tag_name_regex': '.*'})
 | 
			
		||||
    category = tag_category_factory()
 | 
			
		||||
    tag1 = tag_factory(names=['name1', 'ALIAS1'], category=category)
 | 
			
		||||
    tag2 = tag_factory(names=['name2', 'ALIAS2'], category=category)
 | 
			
		||||
    db.session.add_all([tag1, tag2])
 | 
			
		||||
    input_tags = [
 | 
			
		||||
        tag_factory(names=['name1', 'ALIAS1'], category=category),
 | 
			
		||||
        tag_factory(names=['name2', 'ALIAS2'], category=category),
 | 
			
		||||
    ]
 | 
			
		||||
    db.session.add_all(input_tags)
 | 
			
		||||
    result = tags.get_or_create_tags_by_names(names)
 | 
			
		||||
    expected_ids = [input_tags[i].tag_id for i in expected_indexes]
 | 
			
		||||
    actual_ids = [tag.tag_id for tag in result[0]]
 | 
			
		||||
    actual_created_names = [tag.names[0].name for tag in result[1]]
 | 
			
		||||
    assert actual_ids == expected_ids
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user