diff --git a/openlp/core/projectors/manager.py b/openlp/core/projectors/manager.py
index cce66e32b..2db1d2966 100644
--- a/openlp/core/projectors/manager.py
+++ b/openlp/core/projectors/manager.py
@@ -332,9 +332,9 @@ class ProjectorManager(QtWidgets.QWidget, RegistryBase, UiProjectorManager, LogM
NOTE: Check if PJLinkUDP port needs to be started when adding
"""
if port in self.pjlink_udp:
- log.warning('UDP Listener for port {port} already added - skipping'.format(port=port))
+ log.warning(f'UDP Listener for port {port} already added - skipping')
else:
- log.debug('Adding UDP listener on port {port}'.format(port=port))
+ log.debug(f'Adding UDP listener on port {port}')
self.pjlink_udp[port] = PJLinkUDP(port=port)
Registry().execute('udp_broadcast_add', port=port, callback=self.pjlink_udp[port].check_settings)
@@ -344,20 +344,20 @@ class ProjectorManager(QtWidgets.QWidget, RegistryBase, UiProjectorManager, LogM
NOTE: Check if PJLinkUDP port needs to be closed/stopped when deleting
"""
- log.debug('Checking for UDP port {port} listener deletion'.format(port=port))
+ log.debug(f'Checking for UDP port {port} listener deletion')
if port not in self.pjlink_udp:
- log.warning('UDP listener for port {port} not there - skipping delete'.format(port=port))
+ log.warning(f'UDP listener for port {port} not there - skipping delete')
return
keep_port = False
for item in self.projector_list:
if port == item.link.port:
keep_port = True
if keep_port:
- log.warning('UDP listener for port {port} needed for other projectors - skipping delete'.format(port=port))
+ log.warning(f'UDP listener for port {port} needed for other projectors - skipping delete')
return
Registry().execute('udp_broadcast_remove', port=port)
del self.pjlink_udp[port]
- log.debug('UDP listener for port {port} deleted'.format(port=port))
+ log.debug(f'UDP listener for port {port} deleted')
def get_settings(self):
"""
@@ -382,7 +382,7 @@ class ProjectorManager(QtWidgets.QWidget, RegistryBase, UiProjectorManager, LogM
real_projector = item.data(QtCore.Qt.UserRole)
projector_name = str(item.text())
visible = real_projector.link.status_connect >= S_CONNECTED
- log.debug('({name}) Building menu - visible = {visible}'.format(name=projector_name, visible=visible))
+ log.debug(f'({projector_name}) Building menu - visible = {visible}')
self.delete_action.setVisible(True)
self.edit_action.setVisible(True)
self.connect_action.setVisible(not visible)
@@ -424,7 +424,7 @@ class ProjectorManager(QtWidgets.QWidget, RegistryBase, UiProjectorManager, LogM
projectordb=self.projectordb,
edit=edit)
source = source_select_form.exec(projector.link)
- log.debug('({ip}) source_select_form() returned {data}'.format(ip=projector.link.ip, data=source))
+ log.debug(f'({projector.link.ip}) source_select_form() returned {source}')
if source is not None and source > 0:
projector.link.set_input_source(str(source))
return
@@ -465,10 +465,10 @@ class ProjectorManager(QtWidgets.QWidget, RegistryBase, UiProjectorManager, LogM
projector = item.data(QtCore.Qt.UserRole)
if QSOCKET_STATE[projector.link.state()] != S_CONNECTED:
try:
- log.debug('ProjectorManager: Calling connect_to_host() on "{ip}"'.format(ip=projector.link.ip))
+ log.debug(f'ProjectorManager: Calling connect_to_host() on "{projector.link.ip}"')
projector.link.connect_to_host()
except Exception:
- log.debug('ProjectorManager: "{ip}" already connected - skipping'.format(ip=projector.link.ip))
+ log.debug(f'ProjectorManager: "{projector.link.ip}" already connected - skipping')
return
def on_connect_projector(self, opt=None):
@@ -501,9 +501,9 @@ class ProjectorManager(QtWidgets.QWidget, RegistryBase, UiProjectorManager, LogM
projector = list_item.data(QtCore.Qt.UserRole)
msg = QtWidgets.QMessageBox()
msg.setText(translate('OpenLP.ProjectorManager',
- 'Delete projector ({ip}) {name}?'.format(ip=projector.link.ip,
- name=projector.link.name)))
- msg.setInformativeText(translate('OpenLP.ProjectorManager', 'Are you sure you want to delete this projector?'))
+ f'Delete projector ({projector.link.ip}) {projector.link.name}?'))
+ msg.setInformativeText(translate('OpenLP.ProjectorManager',
+ 'Are you sure you want to delete this projector?'))
msg.setStandardButtons(msg.Cancel | msg.Ok)
msg.setDefaultButton(msg.Cancel)
ans = msg.exec()
@@ -541,16 +541,16 @@ class ProjectorManager(QtWidgets.QWidget, RegistryBase, UiProjectorManager, LogM
new_list = []
for item in self.projector_list:
if item.link.db_item.id == projector.link.db_item.id:
- log.debug('Removing projector "{item}"'.format(item=item.link.name))
+ log.debug(f'Removing projector "{item.link.name}"')
continue
new_list.append(item)
self.projector_list = new_list
list_item = self.projector_list_widget.takeItem(self.projector_list_widget.currentRow())
list_item = None
if not self.projectordb.delete_projector(projector.db_item):
- log.warning('Delete projector {item} failed'.format(item=projector.db_item))
+ log.warning(f'Delete projector {projector.db_item} failed')
for item in self.projector_list:
- log.debug('New projector list - item: {ip} {name}'.format(ip=item.link.ip, name=item.link.name))
+ log.debug(f'New projector list - item: {item.link.ip} {item.link.name}')
self.udp_listen_delete(old_port)
def on_disconnect_projector(self, opt=None):
@@ -760,7 +760,7 @@ class ProjectorManager(QtWidgets.QWidget, RegistryBase, UiProjectorManager, LogM
if start:
item.link.connect_to_host()
for item in self.projector_list:
- log.debug('New projector list - item: ({ip}) {name}'.format(ip=item.link.ip, name=item.link.name))
+ log.debug(f'New projector list - item: ({item.link.ip}) {item.link.name}')
@QtCore.pyqtSlot(str)
def add_projector_from_wizard(self, ip, opts=None):
@@ -770,7 +770,7 @@ class ProjectorManager(QtWidgets.QWidget, RegistryBase, UiProjectorManager, LogM
:param ip: IP address of new record item to find
:param opts: Needed by PyQt5
"""
- log.debug('add_projector_from_wizard(ip={ip})'.format(ip=ip))
+ log.debug(f'add_projector_from_wizard(ip={ip})')
item = self.projectordb.get_projector_by_ip(ip)
self.add_projector(item)
@@ -781,7 +781,7 @@ class ProjectorManager(QtWidgets.QWidget, RegistryBase, UiProjectorManager, LogM
:param projector: Projector() instance of projector with updated information
"""
- log.debug('edit_projector_from_wizard(ip={ip})'.format(ip=projector.ip))
+ log.debug(f'edit_projector_from_wizard(ip={projector.ip})')
old_port = self.old_projector.link.port
old_ip = self.old_projector.link.ip
self.old_projector.link.name = projector.name
@@ -836,22 +836,22 @@ class ProjectorManager(QtWidgets.QWidget, RegistryBase, UiProjectorManager, LogM
item = list_item
break
if item is None:
- log.error('ProjectorManager: Unknown item "{ip}" - not updating status'.format(ip=ip))
+ log.error(f'ProjectorManager: Unknown item "{ip}" - not updating status')
return
elif item.status == status:
- log.debug('ProjectorManager: No status change for "{ip}" - not updating status'.format(ip=ip))
+ log.debug(f'ProjectorManager: No status change for "{ip}" - not updating status')
return
item.status = status
item.icon = self.status_icons[status]
- log.debug('({name}) Updating icon with {code}'.format(name=item.link.name, code=STATUS_CODE[status]))
+ log.debug(f'({item.link.name}) Updating icon with {STATUS_CODE[status]}')
item.widget.setIcon(item.icon)
return self.update_icons()
def get_toolbar_item(self, name, enabled=False, hidden=False):
item = self.one_toolbar.findChild(QtWidgets.QAction, name)
if item == 0:
- log.debug('No item found with name "{name}"'.format(name=name))
+ log.debug(f'No item found with name "{name}"')
return
item.setVisible(False if hidden else True)
item.setEnabled(True if enabled else False)
diff --git a/tests/openlp_core/projectors/__init__.py b/tests/openlp_core/projectors/__init__.py
deleted file mode 100644
index 9c7075eb1..000000000
--- a/tests/openlp_core/projectors/__init__.py
+++ /dev/null
@@ -1,23 +0,0 @@
-# -*- coding: utf-8 -*-
-
-##########################################################################
-# OpenLP - Open Source Lyrics Projection #
-# ---------------------------------------------------------------------- #
-# Copyright (c) 2008-2022 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 . #
-##########################################################################
-"""
-:mod tests/openlp_core/projectors: Tests for projector code
-"""
diff --git a/tests/openlp_core/projectors/commands/__init__.py b/tests/openlp_core/projectors/commands/__init__.py
deleted file mode 100644
index 61818bcc0..000000000
--- a/tests/openlp_core/projectors/commands/__init__.py
+++ /dev/null
@@ -1,23 +0,0 @@
-# -*- coding: utf-8 -*-
-
-##########################################################################
-# OpenLP - Open Source Lyrics Projection #
-# ---------------------------------------------------------------------- #
-# Copyright (c) 2008-2022 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 . #
-##########################################################################
-"""
-:mod tests/openlp_core/projectors/commands: Tests for PJLink commands
-"""
diff --git a/tests/openlp_core/projectors/commands/test_misc.py b/tests/openlp_core/projectors/commands/test_misc_commands.py
similarity index 100%
rename from tests/openlp_core/projectors/commands/test_misc.py
rename to tests/openlp_core/projectors/commands/test_misc_commands.py
diff --git a/tests/openlp_core/projectors/conftest.py b/tests/openlp_core/projectors/conftest.py
index 08b55ca32..f06c706e8 100644
--- a/tests/openlp_core/projectors/conftest.py
+++ b/tests/openlp_core/projectors/conftest.py
@@ -19,12 +19,63 @@
# along with this program. If not, see . #
##########################################################################
"""
-Package to test the openlp.core.projectors.pjlink command routing.
+Fixtures for projector tests
"""
import pytest
-from openlp.core.projectors.db import Projector
+
+from unittest.mock import patch
+
+from openlp.core.projectors.db import Projector, ProjectorDB
+from openlp.core.projectors.manager import ProjectorManager
from openlp.core.projectors.pjlink import PJLink
-from tests.resources.projector.data import TEST1_DATA
+from tests.resources.projector.data import TEST_DB, TEST1_DATA
+
+'''
+NOTE: Since Registry is a singleton, sleight of hand allows us to verify
+ calls to Registry.methods()
+
+@patch(path.to.imported.Registry)
+def test_function(mock_registry):
+ mocked_registry = MagicMock()
+ mock_registry.return_value = mocked_registry
+ ...
+ assert mocked_registry.method.has_call(...)
+'''
+
+
+@pytest.fixture()
+def projector_manager(settings):
+ with patch('openlp.core.projectors.db.init_url') as mocked_init_url:
+ mocked_init_url.return_value = 'sqlite:///%s' % TEST_DB
+ projectordb = ProjectorDB()
+ proj_manager = ProjectorManager(projectordb=projectordb)
+ yield proj_manager
+ projectordb.session.close()
+ del proj_manager
+
+
+@pytest.fixture()
+def projector_manager_nodb(settings):
+ proj_manager = ProjectorManager(projectordb=None)
+ yield proj_manager
+ del proj_manager
+
+
+@pytest.fixture()
+def projector_manager_mtdb(settings):
+ with patch('openlp.core.projectors.db.init_url') as mock_url:
+ mock_url.return_value = 'sqlite:///%s' % TEST_DB
+ t_db = ProjectorDB()
+ # Ensure we have an empty DB at the beginning of the test
+ for itm in t_db.get_projector_all():
+ t_db.delete_projector(itm)
+ t_db.session.commit()
+
+ t_manager = ProjectorManager(projectordb=t_db)
+ yield t_manager
+ t_db.session.close()
+ del t_db
+ del t_manager
@pytest.fixture()
diff --git a/tests/openlp_core/projectors/manager/test_boostrap.py b/tests/openlp_core/projectors/manager/test_boostrap.py
new file mode 100644
index 000000000..284e686d8
--- /dev/null
+++ b/tests/openlp_core/projectors/manager/test_boostrap.py
@@ -0,0 +1,153 @@
+# -*- coding: utf-8 -*-
+
+##########################################################################
+# OpenLP - Open Source Lyrics Projection #
+# ---------------------------------------------------------------------- #
+# Copyright (c) 2008-2022 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 . #
+##########################################################################
+"""
+Test ProjectorManager.bootstrap_* methods
+"""
+import logging
+import openlp.core.projectors.manager
+
+from unittest.mock import DEFAULT, MagicMock, patch
+
+test_module = openlp.core.projectors.manager.__name__
+
+
+@patch('openlp.core.projectors.manager.ProjectorDB')
+def test_bootstrap_initialise(mock_db, projector_manager, caplog):
+ """
+ Test ProjectorManager initializes with existing ProjectorDB instance
+ """
+ # GIVEN: Test setup
+ caplog.set_level(logging.DEBUG)
+ logs = [(test_module, logging.DEBUG, 'Using existing ProjectorDB() instance')]
+
+ with patch.multiple(projector_manager,
+ setup_ui=DEFAULT,
+ get_settings=DEFAULT) as mock_manager:
+
+ # WHEN: we call bootstrap_initialise
+ caplog.clear()
+ projector_manager.bootstrap_initialise()
+
+ # THEN: Appropriate entries and actions
+ assert caplog.record_tuples == logs, 'Invalid log entries'
+ mock_manager['setup_ui'].assert_called_once()
+ mock_manager['get_settings'].assert_called_once()
+ mock_db.assert_not_called()
+
+
+@patch('openlp.core.projectors.manager.ProjectorDB')
+def test_bootstrap_initialise_nodb(mock_db, projector_manager_nodb, caplog):
+ """
+ Test ProjectorManager initializes with a new ProjectorDB instance
+ """
+ # GIVEN: Test setup
+ caplog.set_level(logging.DEBUG)
+ logs = [(test_module, logging.DEBUG, 'Creating new ProjectorDB() instance')]
+
+ with patch.multiple(projector_manager_nodb,
+ setup_ui=DEFAULT,
+ get_settings=DEFAULT) as mock_manager:
+
+ # WHEN: we call bootstrap_initialise
+ caplog.clear()
+ projector_manager_nodb.bootstrap_initialise()
+
+ # THEN: Appropriate entries and actions
+ assert caplog.record_tuples == logs, 'Invalid log entries'
+ mock_manager['setup_ui'].assert_called_once()
+ mock_manager['get_settings'].assert_called_once()
+ mock_db.assert_called_once()
+
+
+@patch('openlp.core.projectors.manager.ProjectorEditForm')
+@patch('openlp.core.projectors.manager.QtCore.QTimer')
+def test_bootstrap_post_set_up_autostart_false(mock_timer, mocked_edit, projector_manager, settings, caplog):
+ """
+ Test post-initialize calls proper setups
+ """
+ # GIVEN: Test setup
+ caplog.set_level(logging.DEBUG)
+ logs = [(test_module, logging.DEBUG, 'Loading all projectors')]
+
+ mock_newProjector = MagicMock()
+ mock_editProjector = MagicMock()
+ mock_edit = MagicMock()
+ mock_edit.newProjector = mock_newProjector
+ mock_edit.editProjector = mock_editProjector
+ mocked_edit.return_value = mock_edit
+
+ settings.setValue('projector/connect on start', False)
+ projector_manager.bootstrap_initialise()
+
+ with patch.multiple(projector_manager,
+ _load_projectors=DEFAULT,
+ projector_list_widget=DEFAULT) as mock_manager:
+
+ # WHEN: Call to initialize is run
+ caplog.clear()
+ projector_manager.bootstrap_post_set_up()
+
+ # THEN: verify calls and logs
+ mock_timer.assert_not_called()
+ mock_newProjector.connect.assert_called_once()
+ mock_editProjector.connect.assert_called_once()
+ mock_manager['_load_projectors'].assert_called_once(),
+ mock_manager['projector_list_widget'].itemSelectionChanged.connect.assert_called_once()
+ assert caplog.record_tuples == logs, 'Invalid log entries'
+
+
+@patch('openlp.core.projectors.manager.ProjectorEditForm')
+@patch('openlp.core.projectors.manager.QtCore.QTimer')
+def test_bootstrap_post_set_up_autostart_true(mock_timer, mocked_edit, projector_manager, settings, caplog):
+ """
+ Test post-initialize calls proper setups
+ """
+ # GIVEN: Test setup
+ caplog.set_level(logging.DEBUG)
+ logs = [(test_module, logging.DEBUG, 'Delaying 1.5 seconds before loading all projectors')]
+
+ mock_newProjector = MagicMock()
+ mock_editProjector = MagicMock()
+ mock_edit = MagicMock()
+ mock_edit.newProjector = mock_newProjector
+ mock_edit.editProjector = mock_editProjector
+
+ settings.setValue('projector/connect on start', True)
+ projector_manager.bootstrap_initialise()
+
+ with patch.multiple(projector_manager,
+ _load_projectors=DEFAULT,
+ projector_list_widget=DEFAULT) as mock_manager:
+ mocked_edit.return_value = mock_edit
+
+ # WHEN: Call to initialize is run
+ caplog.clear()
+ projector_manager.bootstrap_post_set_up()
+
+ # THEN: verify calls and logs
+ mock_timer.assert_called_once()
+ mock_timer.return_value.singleShot.assert_called_once_with(1500, projector_manager._load_projectors)
+
+ mock_newProjector.connect.assert_called_once()
+ mock_editProjector.connect.assert_called_once()
+ mock_manager['_load_projectors'].assert_not_called(),
+ mock_manager['projector_list_widget'].itemSelectionChanged.connect.assert_called_once()
+ assert caplog.record_tuples == logs, 'Invalid log entries'
diff --git a/tests/openlp_core/projectors/manager/test_misc_manager.py b/tests/openlp_core/projectors/manager/test_misc_manager.py
new file mode 100644
index 000000000..cec3200d8
--- /dev/null
+++ b/tests/openlp_core/projectors/manager/test_misc_manager.py
@@ -0,0 +1,157 @@
+# -*- coding: utf-8 -*-
+
+##########################################################################
+# OpenLP - Open Source Lyrics Projection #
+# ---------------------------------------------------------------------- #
+# Copyright (c) 2008-2022 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 . #
+##########################################################################
+"""
+Test misc. functions with few test paths
+"""
+from unittest.mock import DEFAULT, patch
+
+from openlp.core.projectors.db import Projector
+
+from tests.resources.projector.data import TEST1_DATA, TEST2_DATA, TEST3_DATA
+
+
+def test_private_load_projectors(projector_manager_mtdb):
+ """
+ Test that _load_projectors() retrieves all entries from projector database
+ """
+ # GIVEN: Test environment
+ t_db = projector_manager_mtdb.projectordb # Shortcut helper
+ for itm in (TEST1_DATA, TEST2_DATA, TEST3_DATA):
+ t_db.add_projector(Projector(**itm))
+ t_db.session.commit()
+
+ t_list = t_db.get_projector_all()
+
+ # Mock to keep from getting event not registered error in Registry()
+ # during bootstrap_post_set_up()
+ # Although we're testing _load_projectors, need to mock
+ # it first to get past bootstrap_post_set_up() before test
+ with patch.multiple(projector_manager_mtdb,
+ udp_listen_add=DEFAULT,
+ udp_listen_delete=DEFAULT,
+ _load_projectors=DEFAULT) as mock_manager:
+ # Satisfy Flake8 linting
+ mock_manager['udp_listen_add'].return_value = None
+ projector_manager_mtdb.bootstrap_initialise()
+ projector_manager_mtdb.bootstrap_post_set_up()
+
+ # WHEN: Called
+ projector_manager_mtdb._load_projectors()
+
+ assert len(projector_manager_mtdb.projector_list) == len(t_list), \
+ 'Invalid number of entries between check and list'
+
+ # Isolate the DB entries used to create projector_manager.projector_list
+ t_chk = []
+ for dbitem in projector_manager_mtdb.projector_list:
+ t_chk.append(dbitem.db_item)
+
+ assert t_chk == t_list, 'projector_list DB items do not match test items'
+
+
+def test_on_edit_input(projector_manager):
+ """
+ Test calling edit projector input GUI from input selection icon makes appropriate calls
+ """
+ # GIVEN: Test environment
+ with patch.object(projector_manager, 'on_select_input') as mock_edit:
+
+ # WHEN: Called
+ projector_manager.on_edit_input()
+
+ # THEN: select input called with edit option
+ mock_edit.assert_called_with(opt=None, edit=True)
+
+
+def test_on_add_projector(projector_manager):
+ """
+ Test add new projector edit GUI is called properly
+ """
+ # GIVEN: Test environment
+ # Mock to keep from getting event not registered error in Registry()
+ # during bootstrap_post_set_up()
+ with patch.multiple(projector_manager,
+ udp_listen_add=DEFAULT,
+ udp_listen_delete=DEFAULT) as mock_manager:
+ # Satisfy Flake8 linting
+ mock_manager['udp_listen_add'].return_value = None
+ projector_manager.bootstrap_initialise()
+ projector_manager.bootstrap_post_set_up()
+
+ with patch.object(projector_manager, 'projector_form') as mock_form:
+
+ # WHEN called
+ projector_manager.on_add_projector()
+
+ # THEN: projector form called
+ mock_form.exec.assert_called_once()
+
+
+def test_add_projector_from_wizard(projector_manager):
+ """
+ Test when add projector from GUI, appropriate method is called correctly
+ """
+ # GIVEN: Test environment
+ with patch.multiple(projector_manager,
+ projectordb=DEFAULT,
+ add_projector=DEFAULT) as mock_manager:
+ t_item = Projector(**TEST1_DATA)
+
+ mock_manager['projectordb'].get_projector_by_ip.return_value = t_item
+
+ # WHEN: Called
+ projector_manager.add_projector_from_wizard(ip=t_item.ip)
+
+ # THEN: appropriate calls made
+ mock_manager['add_projector'].assert_called_with(t_item)
+
+
+def test_get_projector_list(projector_manager_mtdb):
+ """
+ Test get_projector_list() returns valid entries
+ """
+ # GIVEN: Test environment
+ t_db = projector_manager_mtdb.projectordb # Shortcut helper
+ for itm in (TEST1_DATA, TEST2_DATA, TEST3_DATA):
+ t_db.add_projector(Projector(**itm))
+ t_list = t_db.get_projector_all()
+
+ # Mock to keep from getting event not registered error in Registry()
+ # during bootstrap_post_set_up()
+ with patch.multiple(projector_manager_mtdb,
+ udp_listen_add=DEFAULT,
+ udp_listen_delete=DEFAULT) as mock_manager:
+ # Satisfy Flake8 linting
+ mock_manager['udp_listen_add'].return_value = None
+ projector_manager_mtdb.bootstrap_initialise()
+ projector_manager_mtdb.bootstrap_post_set_up()
+
+ # WHEN: Called
+ t_chk = projector_manager_mtdb.get_projector_list()
+
+ # THEN: DB items for both t_list and projector_list are the same
+ assert len(t_chk) == len(t_list), 'projector_list length mismatch with test items length'
+
+ # Isolate the DB entries used to create projector_manager.projector_list
+ t_chk_list = []
+ for dbitem in t_chk:
+ t_chk_list.append(dbitem.db_item)
+ assert t_list == t_chk_list, 'projector_list DB items do not match test items'
diff --git a/tests/openlp_core/projectors/manager/test_udp.py b/tests/openlp_core/projectors/manager/test_udp.py
new file mode 100644
index 000000000..37a20d5ab
--- /dev/null
+++ b/tests/openlp_core/projectors/manager/test_udp.py
@@ -0,0 +1,133 @@
+# -*- coding: utf-8 -*-
+
+##########################################################################
+# OpenLP - Open Source Lyrics Projection #
+# ---------------------------------------------------------------------- #
+# Copyright (c) 2008-2022 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 . #
+##########################################################################
+"""
+Test ProjectorManager udp methods
+"""
+import logging
+
+from unittest.mock import MagicMock, patch
+
+
+from tests.resources.projector.data import FakePJLinkUDP, FakeProjector
+
+
+def test_udp_listen_add_duplicate(projector_manager, caplog):
+ """
+ Test adding UDP port listener to port already registered
+ """
+ # GIVEN: Initial setup
+ caplog.set_level(logging.DEBUG)
+ log_entries = ['UDP Listener for port 10 already added - skipping']
+ port_list = {10: 'port1', 20: 'port2'}
+ projector_manager.pjlink_udp = port_list
+
+ # WHEN: udp_listen_add is called with duplicate port number
+ caplog.clear()
+ projector_manager.udp_listen_add(port=10)
+
+ # THEN: Verify log entry and registry entry not called
+ assert projector_manager.pjlink_udp == port_list, "Invalid ports in list"
+ assert caplog.messages == log_entries, "Invalid log entries"
+
+
+@patch('openlp.core.projectors.manager.PJLinkUDP')
+@patch('openlp.core.projectors.manager.Registry')
+def test_udp_listen_add_new(mock_registry, mock_udp, projector_manager, caplog):
+ """
+ Test adding new UDP port listener
+ """
+ # GIVEN: Initial setup
+ caplog.set_level(logging.DEBUG)
+ mocked_registry = MagicMock()
+ mock_registry.return_value = mocked_registry
+ mock_udp.return_value = FakePJLinkUDP()
+ log_entries = ['Adding UDP listener on port 20']
+ projector_manager.pjlink_udp = {10: 'port1'}
+ # WHEN: Adding new listener
+ caplog.clear()
+ projector_manager.udp_listen_add(port=20)
+ # THEN: Appropriate listener and log entries
+ assert 20 in projector_manager.pjlink_udp, "Port not added"
+ assert 2 == len(projector_manager.pjlink_udp), "Invalid ports in list"
+ assert type(projector_manager.pjlink_udp[20]) == FakePJLinkUDP, \
+ 'PJLinkUDP instance should have been added'
+ assert mocked_registry.execute.has_call('udp_broadcast_add', port=20)
+ assert caplog.messages == log_entries, 'Invalid log entries'
+
+
+def test_udp_listen_delete_missing(projector_manager, caplog):
+ """
+ Test deleting UDP port listener not in list
+ """
+ # GIVEN: Initial setup
+ caplog.set_level(logging.DEBUG)
+ projector_manager.pjlink_udp = {10: 'port1'}
+ log_entries = ['Checking for UDP port 20 listener deletion',
+ 'UDP listener for port 20 not there - skipping delete']
+ # WHEN: Deleting port listener from dictinary
+ projector_manager.udp_listen_delete(port=20)
+ # THEN: Log missing port and exit method
+ assert projector_manager.pjlink_udp == {10: 'port1'}, "Invalid ports in list"
+ assert caplog.messages == log_entries, "Invalid log entries"
+
+
+@patch('openlp.core.projectors.manager.Registry')
+def test_udp_listen_delete_single(mock_registry, projector_manager, caplog):
+ """
+ Test deleting UDP listener
+ """
+ # GIVEN: Initial setup
+ mocked_registry = MagicMock()
+ mock_registry.return_value = mocked_registry
+ caplog.set_level(logging.DEBUG)
+ log_entries = ['Checking for UDP port 10 listener deletion',
+ 'UDP listener for port 10 deleted']
+ port_list = {20: 'port2'}
+ projector_manager.pjlink_udp = {10: 'port1', **port_list}
+ projector_manager.projector_list = [FakeProjector(port=20)]
+ # WHEN: deleting a listener
+ caplog.clear()
+ projector_manager.udp_listen_delete(port=10)
+ # THEN: pjlink_udp and logs should have appropriate entries
+ assert caplog.messages == log_entries, 'Invalid log entries'
+ assert projector_manager.pjlink_udp == port_list, 'Invalid ports in list'
+ assert mocked_registry.execute.has_call('udp_broadcast_delete', port=10)
+
+
+def test_udp_listen_delete_skip(projector_manager, caplog):
+ """
+ Test not deleting UDP listener
+ """
+ # GIVEN: Initial setup
+ caplog.set_level(logging.DEBUG)
+ log_entries = ['Checking for UDP port 10 listener deletion',
+ 'UDP listener for port 10 needed for other projectors - skipping delete']
+ port_list = {10: 'port1', 20: 'port2'}
+ projector_manager.pjlink_udp = port_list
+ projector_manager.projector_list = [FakeProjector(port=10),
+ FakeProjector(port=20)]
+ # WHEN: deleting a listener
+ caplog.clear()
+ projector_manager.udp_listen_delete(port=10)
+
+ # THEN: pjlink_udp and logs should have appropriate entries
+ assert caplog.messages == log_entries, 'Invalid log entries'
+ assert projector_manager.pjlink_udp == port_list, 'Invalid ports in list'
diff --git a/tests/openlp_core/projectors/test_projectormanager.py b/tests/openlp_core/projectors/test_projectormanager.py
deleted file mode 100644
index e303d1968..000000000
--- a/tests/openlp_core/projectors/test_projectormanager.py
+++ /dev/null
@@ -1,251 +0,0 @@
-# -*- coding: utf-8 -*-
-
-##########################################################################
-# OpenLP - Open Source Lyrics Projection #
-# ---------------------------------------------------------------------- #
-# Copyright (c) 2008-2022 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 . #
-##########################################################################
-"""
-Interface tests to test the themeManager class and related methods.
-"""
-
-import pytest
-import logging
-
-from unittest.mock import MagicMock, patch
-
-from openlp.core.projectors.db import ProjectorDB
-from openlp.core.projectors.editform import ProjectorEditForm
-from openlp.core.projectors.manager import ProjectorManager
-from tests.resources.projector.data import TEST_DB
-
-'''
-NOTE: Since Registry is a singleton, sleight of hand allows us to verify
- calls to Registry.methods()
-
-@patch(path.to.imported.Registry)
-def test_function(mock_registry):
- mocked_registry = MagicMock()
- mock_registry.return_value = mocked_registry
- ...
- assert mocked_registry.method.has_call(...)
-'''
-
-
-class FakeProjector(object):
- """
- Helper test class
- """
- def __init__(self, port=4352, name="Faker"):
- self.link = self
- self.port = port
- self.name = name
-
-
-class FakePJLinkUDP(object):
- """
- Helper test class
- """
- def __init__(self, *args, **kwargs):
- pass
-
- def check_settings(self, *args, **kwargs):
- pass
-
-
-@pytest.fixture()
-def projector_manager(settings):
- with patch('openlp.core.projectors.db.init_url') as mocked_init_url:
- mocked_init_url.return_value = 'sqlite:///%s' % TEST_DB
- projectordb = ProjectorDB()
- proj_manager = ProjectorManager(projectordb=projectordb)
- yield proj_manager
- projectordb.session.close()
- del proj_manager
-
-
-@pytest.fixture()
-def projector_manager_nodb(settings):
- proj_manager = ProjectorManager(projectordb=None)
- yield proj_manager
- del proj_manager
-
-
-def test_bootstrap_initialise(projector_manager):
- """
- Test initialize calls correct startup functions
- """
- # WHEN: we call bootstrap_initialise
- projector_manager.bootstrap_initialise()
- # THEN: ProjectorDB is setup
- assert type(projector_manager.projectordb) == ProjectorDB, \
- 'Initialization should have created a ProjectorDB() instance'
-
-
-def test_bootstrap_initialise_nodb(projector_manager_nodb, caplog):
- """
- Test log entry creating new projector DB
- """
- caplog.set_level(logging.DEBUG)
- log_entries = 'Creating new ProjectorDB() instance'
- # WHEN: ProjectorManager created with no DB set
- caplog.clear()
- projector_manager_nodb.bootstrap_initialise()
- # THEN: Log should indicate new DB being created
- assert caplog.messages[3] == log_entries, "ProjectorManager should have indicated a new DB being created"
-
-
-def test_bootstrap_post_set_up(projector_manager):
- """
- Test post-initialize calls proper setups
- """
- # GIVEN: setup mocks
- projector_manager._load_projectors = MagicMock()
-
- # WHEN: Call to initialize is run
- projector_manager.bootstrap_initialise()
- projector_manager.bootstrap_post_set_up()
-
- # THEN: verify calls to retrieve saved projectors and edit page initialized
- assert 1 == projector_manager._load_projectors.call_count, \
- 'Initialization should have called load_projectors()'
- assert type(projector_manager.projector_form) == ProjectorEditForm, \
- 'Initialization should have created a Projector Edit Form'
- assert projector_manager.projectordb is projector_manager.projector_form.projectordb, \
- 'ProjectorEditForm should be using same ProjectorDB() instance as ProjectorManager'
-
-
-def test_bootstrap_post_set_up_autostart_projector(projector_manager_nodb, caplog):
- """
- Test post-initialize calling log and QTimer on autostart
- """
- # GIVEN: Setup mocks
- with patch('openlp.core.projectors.manager.QtCore.QTimer.singleShot') as mock_timer:
- caplog.set_level(logging.DEBUG)
- log_entries = 'Delaying 1.5 seconds before loading all projectors'
- # WHEN: Initializations called
- projector_manager_nodb.bootstrap_initialise()
- projector_manager_nodb.autostart = True
- projector_manager_nodb.bootstrap_post_set_up()
-
- # THEN: verify log entries and timer calls
- mock_timer.assert_called_once_with(1500, projector_manager_nodb._load_projectors)
- assert caplog.messages[-1] == log_entries, "Invalid log entries"
-
-
-def test_udp_listen_add_duplicate(projector_manager_nodb, caplog):
- """
- Test adding UDP port listener to port already registered
- """
- # GIVEN: Initial setup
- caplog.set_level(logging.DEBUG)
- log_entries = ['UDP Listener for port 10 already added - skipping']
- port_list = {10: 'port1', 20: 'port2'}
- projector_manager_nodb.pjlink_udp = port_list
-
- # WHEN: udp_listen_add is called with duplicate port number
- caplog.clear()
- projector_manager_nodb.udp_listen_add(port=10)
-
- # THEN: Verify log entry and registry entry not called
- assert projector_manager_nodb.pjlink_udp == port_list, "Invalid ports in list"
- assert caplog.messages == log_entries, "Invalid log entries"
-
-
-@patch('openlp.core.projectors.manager.PJLinkUDP')
-@patch('openlp.core.projectors.manager.Registry')
-def test_udp_listen_add_new(mock_registry, mock_udp, projector_manager_nodb, caplog):
- """
- Test adding new UDP port listener
- """
- # GIVEN: Initial setup
- caplog.set_level(logging.DEBUG)
- mocked_registry = MagicMock()
- mock_registry.return_value = mocked_registry
- mock_udp.return_value = FakePJLinkUDP()
- log_entries = ['Adding UDP listener on port 20']
- projector_manager_nodb.pjlink_udp = {10: 'port1'}
- # WHEN: Adding new listener
- caplog.clear()
- projector_manager_nodb.udp_listen_add(port=20)
- # THEN: Appropriate listener and log entries
- assert 20 in projector_manager_nodb.pjlink_udp, "Port not added"
- assert 2 == len(projector_manager_nodb.pjlink_udp), "Invalid ports in list"
- assert type(projector_manager_nodb.pjlink_udp[20]) == FakePJLinkUDP, \
- 'PJLinkUDP instance should have been added'
- assert mocked_registry.execute.has_call('udp_broadcast_add', port=20)
- assert caplog.messages == log_entries, 'Invalid log entries'
-
-
-def test_udp_listen_delete_missing(projector_manager_nodb, caplog):
- """
- Test deleting UDP port listener not in list
- """
- # GIVEN: Initial setup
- caplog.set_level(logging.DEBUG)
- projector_manager_nodb.pjlink_udp = {10: 'port1'}
- log_entries = ['Checking for UDP port 20 listener deletion',
- 'UDP listener for port 20 not there - skipping delete']
- # WHEN: Deleting port listener from dictinary
- projector_manager_nodb.udp_listen_delete(port=20)
- # THEN: Log missing port and exit method
- assert projector_manager_nodb.pjlink_udp == {10: 'port1'}, "Invalid ports in list"
- assert caplog.messages == log_entries, "Invalid log entries"
-
-
-@patch('openlp.core.projectors.manager.Registry')
-def test_udp_listen_delete_single(mock_registry, projector_manager_nodb, caplog):
- """
- Test deleting UDP listener
- """
- # GIVEN: Initial setup
- mocked_registry = MagicMock()
- mock_registry.return_value = mocked_registry
- caplog.set_level(logging.DEBUG)
- log_entries = ['Checking for UDP port 10 listener deletion',
- 'UDP listener for port 10 deleted']
- port_list = {20: 'port2'}
- projector_manager_nodb.pjlink_udp = {10: 'port1', **port_list}
- projector_manager_nodb.projector_list = [FakeProjector(port=20)]
- # WHEN: deleting a listener
- caplog.clear()
- projector_manager_nodb.udp_listen_delete(port=10)
- # THEN: pjlink_udp and logs should have appropriate entries
- assert caplog.messages == log_entries, 'Invalid log entries'
- assert projector_manager_nodb.pjlink_udp == port_list, 'Invalid ports in list'
- assert mocked_registry.execute.has_call('udp_broadcast_delete', port=10)
-
-
-def test_udp_listen_delete_skip(projector_manager_nodb, caplog):
- """
- Test not deleting UDP listener
- """
- # GIVEN: Initial setup
- caplog.set_level(logging.DEBUG)
- log_entries = ['Checking for UDP port 10 listener deletion',
- 'UDP listener for port 10 needed for other projectors - skipping delete']
- port_list = {10: 'port1', 20: 'port2'}
- projector_manager_nodb.pjlink_udp = port_list
- projector_manager_nodb.projector_list = [FakeProjector(port=10),
- FakeProjector(port=20)]
- # WHEN: deleting a listener
- caplog.clear()
- projector_manager_nodb.udp_listen_delete(port=10)
- print(projector_manager_nodb.pjlink_udp)
- print(caplog.record_tuples)
- # THEN: pjlink_udp and logs should have appropriate entries
- assert caplog.messages == log_entries, 'Invalid log entries'
- assert projector_manager_nodb.pjlink_udp == port_list, 'Invalid ports in list'
diff --git a/tests/resources/projector/data.py b/tests/resources/projector/data.py
index bd76437ca..33e208eaa 100644
--- a/tests/resources/projector/data.py
+++ b/tests/resources/projector/data.py
@@ -283,3 +283,24 @@ TEST_VIDEO_CODES = {
'6Y': 'Internal Y',
'6Z': 'Internal Z'
}
+
+
+class FakeProjector(object):
+ """
+ Helper test class
+ """
+ def __init__(self, port=4352, name="Faker"):
+ self.link = self
+ self.port = port
+ self.name = name
+
+
+class FakePJLinkUDP(object):
+ """
+ Helper test class
+ """
+ def __init__(self, *args, **kwargs):
+ pass
+
+ def check_settings(self, *args, **kwargs):
+ pass