Migrate lib part 1

This commit is contained in:
Tim 2020-02-13 21:04:15 +00:00
parent a544aa11ff
commit dae7880604
No known key found for this signature in database
GPG Key ID: 3D454289AF831A6D
2 changed files with 124 additions and 137 deletions

View File

@ -21,10 +21,9 @@
""" """
Package to test the openlp.core.lib package. Package to test the openlp.core.lib package.
""" """
import shutil import pytest
from pathlib import Path from pathlib import Path
from tempfile import mkdtemp from tempfile import mkdtemp
from unittest import TestCase
from unittest.mock import MagicMock, patch from unittest.mock import MagicMock, patch
from sqlalchemy import MetaData from sqlalchemy import MetaData
@ -34,142 +33,136 @@ from sqlalchemy.pool import NullPool
from openlp.core.lib.db import delete_database, get_upgrade_op, init_db, upgrade_db from openlp.core.lib.db import delete_database, get_upgrade_op, init_db, upgrade_db
class TestDB(TestCase): @pytest.fixture(scope='module')
def tmp_folder():
tmp_folder = mkdtemp(prefix='openlp_')
return tmp_folder
def test_init_db_calls_correct_functions():
""" """
A test case for all the tests for the :mod:`~openlp.core.lib.db` module. Test that the init_db function makes the correct function calls
""" """
def setUp(self): # GIVEN: Mocked out SQLAlchemy calls and return objects, and an in-memory SQLite database URL
""" with patch('openlp.core.lib.db.create_engine') as mocked_create_engine, \
Set up anything necessary for all tests patch('openlp.core.lib.db.MetaData') as MockedMetaData, \
""" patch('openlp.core.lib.db.sessionmaker') as mocked_sessionmaker, \
self.tmp_folder = mkdtemp(prefix='openlp_') patch('openlp.core.lib.db.scoped_session') as mocked_scoped_session:
mocked_engine = MagicMock()
def tearDown(self): mocked_metadata = MagicMock()
""" mocked_sessionmaker_object = MagicMock()
Clean up mocked_scoped_session_object = MagicMock()
""" mocked_create_engine.return_value = mocked_engine
# Ignore errors since windows can have problems with locked files MockedMetaData.return_value = mocked_metadata
shutil.rmtree(self.tmp_folder, ignore_errors=True) mocked_sessionmaker.return_value = mocked_sessionmaker_object
mocked_scoped_session.return_value = mocked_scoped_session_object
def test_init_db_calls_correct_functions(self):
"""
Test that the init_db function makes the correct function calls
"""
# GIVEN: Mocked out SQLAlchemy calls and return objects, and an in-memory SQLite database URL
with patch('openlp.core.lib.db.create_engine') as mocked_create_engine, \
patch('openlp.core.lib.db.MetaData') as MockedMetaData, \
patch('openlp.core.lib.db.sessionmaker') as mocked_sessionmaker, \
patch('openlp.core.lib.db.scoped_session') as mocked_scoped_session:
mocked_engine = MagicMock()
mocked_metadata = MagicMock()
mocked_sessionmaker_object = MagicMock()
mocked_scoped_session_object = MagicMock()
mocked_create_engine.return_value = mocked_engine
MockedMetaData.return_value = mocked_metadata
mocked_sessionmaker.return_value = mocked_sessionmaker_object
mocked_scoped_session.return_value = mocked_scoped_session_object
db_url = 'sqlite://'
# WHEN: We try to initialise the db
session, metadata = init_db(db_url)
# THEN: We should see the correct function calls
mocked_create_engine.assert_called_with(db_url, poolclass=NullPool)
MockedMetaData.assert_called_with(bind=mocked_engine)
mocked_sessionmaker.assert_called_with(autoflush=True, autocommit=False, bind=mocked_engine)
mocked_scoped_session.assert_called_with(mocked_sessionmaker_object)
assert session is mocked_scoped_session_object, 'The ``session`` object should be the mock'
assert metadata is mocked_metadata, 'The ``metadata`` object should be the mock'
def test_init_db_defaults(self):
"""
Test that initialising an in-memory SQLite database via ``init_db`` uses the defaults
"""
# GIVEN: An in-memory SQLite URL
db_url = 'sqlite://' db_url = 'sqlite://'
# WHEN: The database is initialised through init_db # WHEN: We try to initialise the db
session, metadata = init_db(db_url) session, metadata = init_db(db_url)
# THEN: Valid session and metadata objects should be returned # THEN: We should see the correct function calls
assert isinstance(session, ScopedSession), 'The ``session`` object should be a ``ScopedSession`` instance' mocked_create_engine.assert_called_with(db_url, poolclass=NullPool)
assert isinstance(metadata, MetaData), 'The ``metadata`` object should be a ``MetaData`` instance' MockedMetaData.assert_called_with(bind=mocked_engine)
mocked_sessionmaker.assert_called_with(autoflush=True, autocommit=False, bind=mocked_engine)
mocked_scoped_session.assert_called_with(mocked_sessionmaker_object)
assert session is mocked_scoped_session_object, 'The ``session`` object should be the mock'
assert metadata is mocked_metadata, 'The ``metadata`` object should be the mock'
def test_get_upgrade_op(self):
"""
Test that the ``get_upgrade_op`` function creates a MigrationContext and an Operations object
"""
# GIVEN: Mocked out alembic classes and a mocked out SQLAlchemy session object
with patch('openlp.core.lib.db.MigrationContext') as MockedMigrationContext, \
patch('openlp.core.lib.db.Operations') as MockedOperations:
mocked_context = MagicMock()
mocked_op = MagicMock()
mocked_connection = MagicMock()
MockedMigrationContext.configure.return_value = mocked_context
MockedOperations.return_value = mocked_op
mocked_session = MagicMock()
mocked_session.bind.connect.return_value = mocked_connection
# WHEN: get_upgrade_op is executed with the mocked session object def test_init_db_defaults():
op = get_upgrade_op(mocked_session) """
Test that initialising an in-memory SQLite database via ``init_db`` uses the defaults
"""
# GIVEN: An in-memory SQLite URL
db_url = 'sqlite://'
# THEN: The op object should be mocked_op, and the correction function calls should have been made # WHEN: The database is initialised through init_db
assert op is mocked_op, 'The return value should be the mocked object' session, metadata = init_db(db_url)
mocked_session.bind.connect.assert_called_with()
MockedMigrationContext.configure.assert_called_with(mocked_connection)
MockedOperations.assert_called_with(mocked_context)
def test_delete_database_without_db_file_name(self): # THEN: Valid session and metadata objects should be returned
""" assert isinstance(session, ScopedSession), 'The ``session`` object should be a ``ScopedSession`` instance'
Test that the ``delete_database`` function removes a database file, without the file name parameter assert isinstance(metadata, MetaData), 'The ``metadata`` object should be a ``MetaData`` instance'
"""
# GIVEN: Mocked out AppLocation class and delete_file method, a test plugin name and a db location
with patch('openlp.core.lib.db.AppLocation') as MockedAppLocation, \
patch('openlp.core.lib.db.delete_file') as mocked_delete_file:
MockedAppLocation.get_section_data_path.return_value = Path('test-dir')
mocked_delete_file.return_value = True
test_plugin = 'test'
test_location = Path('test-dir', test_plugin)
# WHEN: delete_database is run without a database file
result = delete_database(test_plugin)
# THEN: The AppLocation.get_section_data_path and delete_file methods should have been called def test_get_upgrade_op():
MockedAppLocation.get_section_data_path.assert_called_with(test_plugin) """
mocked_delete_file.assert_called_with(test_location) Test that the ``get_upgrade_op`` function creates a MigrationContext and an Operations object
assert result is True, 'The result of delete_file should be True (was rigged that way)' """
# GIVEN: Mocked out alembic classes and a mocked out SQLAlchemy session object
with patch('openlp.core.lib.db.MigrationContext') as MockedMigrationContext, \
patch('openlp.core.lib.db.Operations') as MockedOperations:
mocked_context = MagicMock()
mocked_op = MagicMock()
mocked_connection = MagicMock()
MockedMigrationContext.configure.return_value = mocked_context
MockedOperations.return_value = mocked_op
mocked_session = MagicMock()
mocked_session.bind.connect.return_value = mocked_connection
def test_delete_database_with_db_file_name(self): # WHEN: get_upgrade_op is executed with the mocked session object
""" op = get_upgrade_op(mocked_session)
Test that the ``delete_database`` function removes a database file, with the file name supplied
"""
# GIVEN: Mocked out AppLocation class and delete_file method, a test plugin name and a db location
with patch('openlp.core.lib.db.AppLocation') as MockedAppLocation, \
patch('openlp.core.lib.db.delete_file') as mocked_delete_file:
MockedAppLocation.get_section_data_path.return_value = Path('test-dir')
mocked_delete_file.return_value = False
test_plugin = 'test'
test_db_file = 'mydb.sqlite'
test_location = Path('test-dir', test_db_file)
# WHEN: delete_database is run without a database file # THEN: The op object should be mocked_op, and the correction function calls should have been made
result = delete_database(test_plugin, test_db_file) assert op is mocked_op, 'The return value should be the mocked object'
mocked_session.bind.connect.assert_called_with()
MockedMigrationContext.configure.assert_called_with(mocked_connection)
MockedOperations.assert_called_with(mocked_context)
# THEN: The AppLocation.get_section_data_path and delete_file methods should have been called
MockedAppLocation.get_section_data_path.assert_called_with(test_plugin)
mocked_delete_file.assert_called_with(test_location)
assert result is False, 'The result of delete_file should be False (was rigged that way)'
def test_skip_db_upgrade_with_no_database(self): def test_delete_database_without_db_file_name():
""" """
Test the upgrade_db function does not try to update a missing database Test that the ``delete_database`` function removes a database file, without the file name parameter
""" """
# GIVEN: Database URL that does not (yet) exist # GIVEN: Mocked out AppLocation class and delete_file method, a test plugin name and a db location
url = 'sqlite:///{tmp}/test_db.sqlite'.format(tmp=self.tmp_folder) with patch('openlp.core.lib.db.AppLocation') as MockedAppLocation, \
mocked_upgrade = MagicMock() patch('openlp.core.lib.db.delete_file') as mocked_delete_file:
MockedAppLocation.get_section_data_path.return_value = Path('test-dir')
mocked_delete_file.return_value = True
test_plugin = 'test'
test_location = Path('test-dir', test_plugin)
# WHEN: We attempt to upgrade a non-existant database # WHEN: delete_database is run without a database file
upgrade_db(url, mocked_upgrade) result = delete_database(test_plugin)
# THEN: upgrade should NOT have been called # THEN: The AppLocation.get_section_data_path and delete_file methods should have been called
assert mocked_upgrade.called is False, 'Database upgrade function should NOT have been called' MockedAppLocation.get_section_data_path.assert_called_with(test_plugin)
mocked_delete_file.assert_called_with(test_location)
assert result is True, 'The result of delete_file should be True (was rigged that way)'
def test_delete_database_with_db_file_name():
"""
Test that the ``delete_database`` function removes a database file, with the file name supplied
"""
# GIVEN: Mocked out AppLocation class and delete_file method, a test plugin name and a db location
with patch('openlp.core.lib.db.AppLocation') as MockedAppLocation, \
patch('openlp.core.lib.db.delete_file') as mocked_delete_file:
MockedAppLocation.get_section_data_path.return_value = Path('test-dir')
mocked_delete_file.return_value = False
test_plugin = 'test'
test_db_file = 'mydb.sqlite'
test_location = Path('test-dir', test_db_file)
# WHEN: delete_database is run without a database file
result = delete_database(test_plugin, test_db_file)
# THEN: The AppLocation.get_section_data_path and delete_file methods should have been called
MockedAppLocation.get_section_data_path.assert_called_with(test_plugin)
mocked_delete_file.assert_called_with(test_location)
assert result is False, 'The result of delete_file should be False (was rigged that way)'
def test_skip_db_upgrade_with_no_database(tmp_folder):
"""
Test the upgrade_db function does not try to update a missing database
"""
# GIVEN: Database URL that does not (yet) exist
url = 'sqlite:///{tmp}/test_db.sqlite'.format(tmp=tmp_folder)
mocked_upgrade = MagicMock()
# WHEN: We attempt to upgrade a non-existent database
upgrade_db(url, mocked_upgrade)
# THEN: upgrade should NOT have been called
assert mocked_upgrade.called is False, 'Database upgrade function should NOT have been called'

View File

@ -21,24 +21,18 @@
""" """
Package to test the openlp.core.lib.exceptions package. Package to test the openlp.core.lib.exceptions package.
""" """
from unittest import TestCase
from openlp.core.lib.exceptions import ValidationError from openlp.core.lib.exceptions import ValidationError
class TestValidationError(TestCase): def test_validation_error():
""" """
Test the ValidationError Class Test the creation of a ValidationError
""" """
def test_validation_error(self): # GIVEN: The ValidationError class
"""
Test the creation of a ValidationError
"""
# GIVEN: The ValidationError class
# WHEN: Creating an instance of ValidationError # WHEN: Creating an instance of ValidationError
error = ValidationError('Test ValidationError') error = ValidationError('Test ValidationError')
# THEN: Then calling str on the error should return the correct text and it should be an instance of `Exception` # THEN: Then calling str on the error should return the correct text and it should be an instance of `Exception`
assert str(error) == 'Test ValidationError' assert str(error) == 'Test ValidationError'
assert isinstance(error, Exception) assert isinstance(error, Exception)