# -*- coding: utf-8 -*- ########################################################################## # OpenLP - Open Source Lyrics Projection # # ---------------------------------------------------------------------- # # Copyright (c) 2008-2020 OpenLP Developers # # ---------------------------------------------------------------------- # # This program is free software: you can redistribute it and/or modify # # it under the terms of the GNU General Public License as published by # # the Free Software Foundation, either version 3 of the License, or # # (at your option) any later version. # # # # This program is distributed in the hope that it will be useful, # # but WITHOUT ANY WARRANTY; without even the implied warranty of # # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # # GNU General Public License for more details. # # # # You should have received a copy of the GNU General Public License # # along with this program. If not, see . # ########################################################################## """ Package to test the openlp.core.projectors.db module. record functions. PREREQUISITE: add_record() and get_all() functions validated. """ import os import shutil from tempfile import mkdtemp from unittest import TestCase from unittest.mock import MagicMock, patch from openlp.core.common.registry import Registry from openlp.core.common.settings import Settings from openlp.core.lib.db import upgrade_db from openlp.core.projectors import upgrade from openlp.core.projectors.constants import PJLINK_PORT from openlp.core.projectors.db import Manufacturer, Model, Projector, ProjectorDB, ProjectorSource, Source from openlp.core.ui.mainwindow import MainWindow from tests.helpers.testmixin import TestMixin from tests.resources.projector.data import TEST1_DATA, TEST2_DATA, TEST3_DATA, TEST_DB, TEST_DB_PJLINK1 from tests.utils.constants import TEST_RESOURCES_PATH def compare_data(one, two): """ Verify two Projector() instances contain the same data """ return one is not None and \ two is not None and \ one.ip == two.ip and \ one.port == two.port and \ one.name == two.name and \ one.location == two.location and \ one.notes == two.notes and \ one.sw_version == two.sw_version and \ one.serial_no == two.serial_no and \ one.model_filter == two.model_filter and \ one.model_lamp == two.model_lamp def compare_source(one, two): """ Verify two ProjectorSource instances contain the same data """ return one is not None and \ two is not None and \ one.projector_id == two.projector_id and \ one.code == two.code and \ one.text == two.text def add_records(projector_db, test): """ Add record if not in database """ record_list = projector_db.get_projector_all() if len(record_list) < 1: added = False for record in test: added = projector_db.add_projector(record) or added return added for new_record in test: added = None for record in record_list: if compare_data(record, new_record): break added = projector_db.add_projector(new_record) return added class TestProjectorDBUpdate(TestCase): """ Test case for upgrading Projector DB. NOTE: Separate class so I don't have to look for upgrade tests. """ def setUp(self): """ Setup for tests """ self.tmp_folder = mkdtemp(prefix='openlp_') def tearDown(self): """ Clean up after tests """ # Ignore errors since windows can have problems with locked files shutil.rmtree(self.tmp_folder, ignore_errors=True) def test_upgrade_old_projector_db(self): """ Test that we can upgrade a version 1 db to the current schema """ # GIVEN: An old prjector db old_db = os.path.join(TEST_RESOURCES_PATH, "projector", TEST_DB_PJLINK1) tmp_db = os.path.join(self.tmp_folder, TEST_DB) shutil.copyfile(old_db, tmp_db) db_url = 'sqlite:///{db}'.format(db=tmp_db) # WHEN: upgrading the db updated_to_version, latest_version = upgrade_db(db_url, upgrade) # THEN: the song db should have been upgraded to the latest version assert updated_to_version == latest_version, 'The projector DB should have been upgrade to the latest version' class TestProjectorDB(TestCase, TestMixin): """ Test case for ProjectorDB """ @patch('openlp.core.projectors.db.init_url') def setUp(self, mocked_init_url): """ Set up anything necessary for all tests """ self.tmp_folder = mkdtemp(prefix='openlp_') # Create a test app to keep from segfaulting Registry.create() self.registry = Registry() self.setup_application() # Mock cursor busy/normal methods. self.app.set_busy_cursor = MagicMock() self.app.set_normal_cursor = MagicMock() self.app.args = [] Registry().register('application', self.app) Registry().register('settings', Settings()) Registry().set_flag('no_web_server', True) # Mock classes and methods used by mainwindow. with patch('openlp.core.ui.mainwindow.SettingsForm'), \ patch('openlp.core.ui.mainwindow.OpenLPDockWidget'), \ patch('openlp.core.ui.mainwindow.QtWidgets.QToolBox'), \ patch('openlp.core.ui.mainwindow.QtWidgets.QMainWindow.addDockWidget'), \ patch('openlp.core.ui.mainwindow.ServiceManager'), \ patch('openlp.core.ui.mainwindow.ThemeManager'), \ patch('openlp.core.ui.mainwindow.ProjectorManager'), \ patch('openlp.core.ui.mainwindow.WebSocketServer'), \ patch('openlp.core.ui.mainwindow.HttpServer'), \ patch('openlp.core.ui.mainwindow.start_zeroconf'), \ patch('openlp.core.state.State.list_plugins') as mock_plugins: mock_plugins.return_value = [] self.main_window = MainWindow() tmpdb_url = 'sqlite:///{db}'.format(db=os.path.join(self.tmp_folder, TEST_DB)) mocked_init_url.return_value = tmpdb_url self.projector = ProjectorDB() def tearDown(self): """ Clean up Delete all the C++ objects at the end so that we don't have a segfault """ self.projector.session.close() self.projector = None del self.main_window # Ignore errors since windows can have problems with locked files shutil.rmtree(self.tmp_folder, ignore_errors=True) def test_find_record_by_ip(self): """ Test find record by IP """ # GIVEN: Record entries in database add_records(self.projector, [Projector(**TEST1_DATA), Projector(**TEST2_DATA)]) # WHEN: Search for record using IP record = self.projector.get_projector_by_ip(TEST2_DATA['ip']) # THEN: Verify proper record returned assert compare_data(Projector(**TEST2_DATA), record) is True, 'Record found should have been test_2 data' def test_find_record_by_name(self): """ Test find record by name """ # GIVEN: Record entries in database add_records(self.projector, [Projector(**TEST1_DATA), Projector(**TEST2_DATA)]) # WHEN: Search for record using name record = self.projector.get_projector_by_name(TEST2_DATA['name']) # THEN: Verify proper record returned assert compare_data(Projector(**TEST2_DATA), record) is True, 'Record found should have been test_2 data' def test_record_delete(self): """ Test record can be deleted """ # GIVEN: Record in database add_records(self.projector, [Projector(**TEST3_DATA), ]) record = self.projector.get_projector_by_ip(TEST3_DATA['ip']) # WHEN: Record deleted self.projector.delete_projector(record) # THEN: Verify record not retrievable found = self.projector.get_projector_by_ip(TEST3_DATA['ip']) assert found is None, 'test_3 record should have been deleted' def test_record_edit(self): """ Test edited record returns the same record ID with different data """ # GIVEN: Record entries in database add_records(self.projector, [Projector(**TEST1_DATA), Projector(**TEST2_DATA)]) # WHEN: We retrieve a specific record record = self.projector.get_projector_by_ip(TEST1_DATA['ip']) record_id = record.id # WHEN: Data is changed record.ip = TEST3_DATA['ip'] record.port = TEST3_DATA['port'] record.pin = TEST3_DATA['pin'] record.name = TEST3_DATA['name'] record.location = TEST3_DATA['location'] record.notes = TEST3_DATA['notes'] record.sw_version = TEST3_DATA['sw_version'] record.serial_no = TEST3_DATA['serial_no'] record.model_filter = TEST3_DATA['model_filter'] record.model_lamp = TEST3_DATA['model_lamp'] updated = self.projector.update_projector(record) assert updated is True, 'Save updated record should have returned True' record = self.projector.get_projector_by_ip(TEST3_DATA['ip']) # THEN: Record ID should remain the same, but data should be changed assert record_id == record.id, 'Edited record should have the same ID' assert compare_data(Projector(**TEST3_DATA), record) is True, 'Edited record should have new data' def test_source_add(self): """ Test source entry for projector item """ # GIVEN: Record entries in database projector1 = Projector(**TEST1_DATA) self.projector.add_projector(projector1) item = self.projector.get_projector_by_id(projector1.id) item_id = item.id # WHEN: A source entry is saved for item source = ProjectorSource(projector_id=item_id, code='11', text='First RGB source') self.projector.add_source(source) # THEN: Projector should have the same source entry item = self.projector.get_projector_by_id(item_id) assert compare_source(item.source_list[0], source) is True, 'Source entry should be the same' def test_manufacturer_repr(self): """ Test Manufacturer.__repr__() text """ # GIVEN: Test object manufacturer = Manufacturer() # WHEN: Name is set manufacturer.name = 'OpenLP Test' # THEN: __repr__ should return a proper string assert str(manufacturer) == '', \ 'Manufacturer.__repr__() should have returned a proper representation string' def test_model_repr(self): """ Test Model.__repr__() text """ # GIVEN: Test object model = Model() # WHEN: Name is set model.name = 'OpenLP Test' # THEN: __repr__ should return a proper string assert str(model) == '', \ 'Model.__repr__() should have returned a proper representation string' def test_source_repr(self): """ Test Source.__repr__() text """ # GIVEN: Test object source = Source() # WHEN: Source() information is set source.pjlink_name = 'Test object' source.pjlink_code = '11' source.text = 'Input text' # THEN: __repr__ should return a proper string assert str(source) == '', \ 'Source.__repr__() should have returned a proper representation string' def test_projector_repr(self): """ Test Projector.__repr__() text """ # GIVEN: Test object test_string = '< Projector(id="0", ip="127.0.0.1", port="4352", mac_adx="None", pin="None", ' \ 'name="Test One", location="Somewhere over the rainbow", notes="Not again", ' \ 'pjlink_name="TEST", pjlink_class="None", manufacturer="IN YOUR DREAMS", model="OpenLP", ' \ 'serial_no="None", other="None", sources="None", source_list="[]", model_filter="None", ' \ 'model_lamp="None", sw_version="None") >' projector = Projector() # WHEN: projector() is populated # NOTE: projector.[pin, other, sources, sw_version, serial_no, sw_version, model_lamp, model_filter] # should all return None. # projector.source_list should return an empty list projector.id = 0 projector.ip = '127.0.0.1' projector.port = PJLINK_PORT projector.name = 'Test One' projector.location = 'Somewhere over the rainbow' projector.notes = 'Not again' projector.pjlink_name = 'TEST' projector.manufacturer = 'IN YOUR DREAMS' projector.model = 'OpenLP' # THEN: __repr__ should return a proper string assert str(projector) == test_string, 'Projector.__repr__() should have returned a proper string' def test_projectorsource_repr(self): """ Test ProjectorSource.__repr__() text """ # GIVEN: test setup projector1 = Projector(**TEST1_DATA) self.projector.add_projector(projector1) item = self.projector.get_projector_by_id(projector1.id) item_id = item.id # WHEN: A source entry is saved for item source = ProjectorSource(projector_id=item_id, code='11', text='First RGB source') self.projector.add_source(source) # THEN: __repr__ should return a proper string assert str(source) == '', \ 'ProjectorSource.__repr__)_ should have returned a proper representation string' def test_get_projector_by_id_none(self): """ Test get_projector_by_id() returns None if no db entry """ # GIVEN: Test object and data projector = self.projector # WHEN: DB search for entry not saved results = projector.get_projector_by_id(dbid=123134556409824506) # THEN: Verify return was None assert results is None, 'Returned results should have equaled None' def test_get_projector_all_none(self): """ Test get_projector_all() with no projectors in db """ # GIVEN: Test object with no data projector = self.projector # WHEN: We retrieve the database entries results = projector.get_projector_all() # THEN: Verify results is None assert [] == results, 'Returned results should have returned an empty list' def test_get_projector_all_one(self): """ Test get_projector_all() with one entry in db """ # GIVEN: One entry in database projector = Projector(**TEST1_DATA) self.projector.add_projector(projector) # WHEN: We retrieve the database entries results = self.projector.get_projector_all() # THEN: We should have a list with one entry assert 1 == len(results), 'Returned results should have returned a list with one entry' assert (projector in results) is True, 'Result should have been equal to TEST1_DATA' def test_get_projector_all_many(self): """ Test get_projector_all() with multiple entries in db """ # GIVEN: multiple entries in database projector_list = [] projector_list.append(Projector(**TEST1_DATA)) projector_list.append(Projector(**TEST2_DATA)) projector_list.append(Projector(**TEST3_DATA)) for projector in projector_list: self.projector.add_projector(projector) # WHEN: We retrieve the database entries results = self.projector.get_projector_all() # THEN: We should have a list with three entries assert len(results) == len(projector_list), 'Returned results should have returned a list with three entries' for projector in results: assert (projector in projector_list) is True, 'Projector DB entry should have been in expected list' def test_get_projector_by_name_fail(self): """ Test get_projector_by_name() fail """ # GIVEN: Test entry in database self.projector.add_projector(Projector(**TEST1_DATA)) # WHEN: We attempt to get a projector that's not in database results = self.projector.get_projector_by_name(name=TEST2_DATA['name']) # THEN: We should have None assert results is None, 'projector.get_projector_by_name() should have returned None' def test_add_projector_fail(self): """ Test add_projector() fail """ # GIVEN: Test entry in the database self.projector.add_projector(Projector(**TEST1_DATA)) # WHEN: Attempt to add same projector entry results = self.projector.add_projector(Projector(**TEST1_DATA)) # THEN: We should have failed to add new entry assert results is False, 'add_projector() should have failed' def test_update_projector_default_fail(self): """ Test update_projector() with no options fails """ # GIVEN: projector instance projector = self.projector # WHEN: attempt to update a projector entry with no options results = projector.update_projector() # THEN: We should have failed assert results is False, 'update_projector(projector=None) should have returned False' def test_update_projector_not_in_db_fail(self): """ Test update_projector() when entry not in database """ # GIVEN: Projector entry in database self.projector.add_projector(Projector(**TEST1_DATA)) projector = Projector(**TEST2_DATA) # WHEN: Attempt to update data with a different ID results = self.projector.update_projector(projector) # THEN: Results should be False assert results is False, 'update_projector(projector=projector) should have returned False' def test_delete_projector_fail(self): """ Test delete_projector(projector) fails to delete record """ # GIVEN: Test entry in db self.projector.add_projector(Projector(**TEST1_DATA)) # wHEN: Attempting to delete an entry not in the databae results = self.projector.delete_projector(Projector(**TEST2_DATA)) # THEN: Results should be False assert results is False, 'delete_projector() should have returned False'