openlp-core team mailing list archive
-
openlp-core team
-
Mailing list archive
-
Message #32801
[Merge] lp:~trb143/openlp/localserver into lp:openlp
Tim Bentley has proposed merging lp:~trb143/openlp/localserver into lp:openlp.
Commit message:
Replace the Memory check with a local server which stops and starts correctly.
One the 2nd instance pass the service file if one is included
Stop the 2nd instance starting as it will fail due to port clashes and a monster thread issue(may be connected).
Removed redundant code
Add a number of new tests.
Jenkins is broken so cannot run them
Requested reviews:
OpenLP Core (openlp-core)
Related bugs:
Bug #1181425 in OpenLP: "Change double-click-osz-file behaviour"
https://bugs.launchpad.net/openlp/+bug/1181425
Bug #1751626 in OpenLP: "-d flag is used in a very confusing way"
https://bugs.launchpad.net/openlp/+bug/1751626
Bug #1751628 in OpenLP: "portabe flag is marked as not implemented"
https://bugs.launchpad.net/openlp/+bug/1751628
For more details, see:
https://code.launchpad.net/~trb143/openlp/localserver/+merge/342477
--
Your team OpenLP Core is requested to review the proposed merge of lp:~trb143/openlp/localserver into lp:openlp.
=== modified file 'openlp/.version'
--- openlp/.version 2016-12-12 22:16:23 +0000
+++ openlp/.version 2018-03-31 08:02:59 +0000
@@ -1,1 +1,1 @@
-2.5.0
+2.9.0
=== modified file 'openlp/core/app.py'
--- openlp/core/app.py 2018-02-03 12:03:37 +0000
+++ openlp/core/app.py 2018-03-31 08:02:59 +0000
@@ -38,7 +38,6 @@
from openlp.core.common import is_macosx, is_win
from openlp.core.common.applocation import AppLocation
from openlp.core.common.i18n import LanguageManager, UiStrings, translate
-from openlp.core.common.mixins import LogMixin
from openlp.core.common.path import create_paths, copytree
from openlp.core.common.registry import Registry
from openlp.core.common.settings import Settings
@@ -50,6 +49,7 @@
from openlp.core.ui.firsttimelanguageform import FirstTimeLanguageForm
from openlp.core.ui.mainwindow import MainWindow
from openlp.core.ui.style import get_application_stylesheet
+from openlp.core.server import Server
from openlp.core.version import check_for_update, get_version
__all__ = ['OpenLP', 'main']
@@ -58,7 +58,7 @@
log = logging.getLogger()
-class OpenLP(QtWidgets.QApplication, LogMixin):
+class OpenLP(QtWidgets.QApplication):
"""
The core application class. This class inherits from Qt's QApplication
class in order to provide the core of the application.
@@ -72,7 +72,7 @@
"""
self.is_event_loop_active = True
result = QtWidgets.QApplication.exec()
- self.shared_memory.detach()
+ self.server.close_server()
return result
def run(self, args):
@@ -135,23 +135,16 @@
self.main_window.app_startup()
return self.exec()
- def is_already_running(self):
- """
- Look to see if OpenLP is already running and ask if a 2nd instance is to be started.
- """
- self.shared_memory = QtCore.QSharedMemory('OpenLP')
- if self.shared_memory.attach():
- status = QtWidgets.QMessageBox.critical(None, UiStrings().Error, UiStrings().OpenLPStart,
- QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Yes |
- QtWidgets.QMessageBox.No))
- if status == QtWidgets.QMessageBox.No:
- return True
- return False
- else:
- self.shared_memory.create(1)
- return False
+ @staticmethod
+ def is_already_running():
+ """
+ Tell the user there is a 2nd instance running.
+ """
+ QtWidgets.QMessageBox.critical(None, UiStrings().Error, UiStrings().OpenLPStart,
+ QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Ok))
- def is_data_path_missing(self):
+ @staticmethod
+ def is_data_path_missing():
"""
Check if the data folder path exists.
"""
@@ -301,10 +294,7 @@
parser.add_argument('-l', '--log-level', dest='loglevel', default='warning', metavar='LEVEL',
help='Set logging to LEVEL level. Valid values are "debug", "info", "warning".')
parser.add_argument('-p', '--portable', dest='portable', action='store_true',
- help='Specify if this should be run as a portable app, '
- 'off a USB flash drive (not implemented).')
- parser.add_argument('-d', '--dev-version', dest='dev_version', action='store_true',
- help='Ignore the version file and pull the version directly from Bazaar')
+ help='Specify if this should be run as a portable app, ')
parser.add_argument('-w', '--no-web-server', dest='no_web_server', action='store_true',
help='Turn off the Web and Socket Server ')
parser.add_argument('rargs', nargs='?', default=[])
@@ -383,11 +373,17 @@
Registry().set_flag('no_web_server', args.no_web_server)
application.setApplicationVersion(get_version()['version'])
# Check if an instance of OpenLP is already running. Quit if there is a running instance and the user only wants one
- if application.is_already_running():
+ server = Server()
+ if server.is_another_instance_running():
+ application.is_already_running()
+ server.post_to_server(qt_args)
sys.exit()
+ else:
+ server.start_server()
+ application.server = server
# If the custom data path is missing and the user wants to restore the data path, quit OpenLP.
if application.is_data_path_missing():
- application.shared_memory.detach()
+ server.close_server()
sys.exit()
# Upgrade settings.
settings = Settings()
=== modified file 'openlp/core/common/i18n.py'
--- openlp/core/common/i18n.py 2017-12-29 09:15:48 +0000
+++ openlp/core/common/i18n.py 2018-03-31 08:02:59 +0000
@@ -415,7 +415,7 @@
self.NoResults = translate('OpenLP.Ui', 'No Search Results')
self.OpenLP = translate('OpenLP.Ui', 'OpenLP')
self.OpenLPv2AndUp = translate('OpenLP.Ui', 'OpenLP 2.0 and up')
- self.OpenLPStart = translate('OpenLP.Ui', 'OpenLP is already running. Do you wish to continue?')
+ self.OpenLPStart = translate('OpenLP.Ui', 'OpenLP is already running on this machine. \nClosing this instance')
self.OpenService = translate('OpenLP.Ui', 'Open service.')
self.OptionalShowInFooter = translate('OpenLP.Ui', 'Optional, this will be displayed in footer.')
self.OptionalHideInFooter = translate('OpenLP.Ui', 'Optional, this won\'t be displayed in footer.')
=== added file 'openlp/core/server.py'
--- openlp/core/server.py 1970-01-01 00:00:00 +0000
+++ openlp/core/server.py 2018-03-31 08:02:59 +0000
@@ -0,0 +1,109 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2018 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; version 2 of the License. #
+# #
+# 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, write to the Free Software Foundation, Inc., 59 #
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
+###############################################################################
+from PyQt5 import QtCore, QtNetwork
+
+from openlp.core.common.registry import Registry
+from openlp.core.common.mixins import LogMixin
+
+
+class Server(QtCore.QObject, LogMixin):
+ """
+ The local server to handle OpenLP running in more than one instance and allows file
+ handles to be transferred from the new to the existing one.
+ """
+ def __init__(self):
+ super(Server, self).__init__()
+ self.out_socket = QtNetwork.QLocalSocket()
+ self.server = None
+ self.id = 'OpenLPDual'
+
+ def is_another_instance_running(self):
+ """
+ Check the see if an other instance is running
+ :return: True of False
+ """
+ # Is there another instance running?
+ self.out_socket.connectToServer(self.id)
+ return self.out_socket.waitForConnected()
+
+ def post_to_server(self, args):
+ """
+ Post the file name to the over instance
+ :param args: The passed arguments including maybe a file name
+ """
+ if 'OpenLP' in args:
+ args.remove('OpenLP')
+ # Yes, there is.
+ self.out_stream = QtCore.QTextStream(self.out_socket)
+ self.out_stream.setCodec('UTF-8')
+ self.out_socket.write(str.encode("".join(args)))
+ if not self.out_socket.waitForBytesWritten(10):
+ raise Exception(str(self.out_socket.errorString()))
+ self.out_socket.disconnectFromServer()
+
+ def start_server(self):
+ """
+ Start the socket server to allow inter app communication
+ :return:
+ """
+ self.out_socket = None
+ self.out_stream = None
+ self.in_socket = None
+ self.in_stream = None
+ self.server = QtNetwork.QLocalServer()
+ self.server.listen(self.id)
+ self.server.newConnection.connect(self._on_new_connection)
+ return True
+
+ def _on_new_connection(self):
+ """
+ Handle a new connection to the server
+ :return:
+ """
+ if self.in_socket:
+ self.in_socket.readyRead.disconnect(self._on_ready_read)
+ self.in_socket = self.server.nextPendingConnection()
+ if not self.in_socket:
+ return
+ self.in_stream = QtCore.QTextStream(self.in_socket)
+ self.in_stream.setCodec('UTF-8')
+ self.in_socket.readyRead.connect(self._on_ready_read)
+
+ def _on_ready_read(self):
+ """
+ Read a record passed to the server and pass to the service manager to handle
+ :return:
+ """
+ msg = self.in_stream.readLine()
+ if msg:
+ self.log_debug("socket msg = " + msg)
+ Registry().get('service_manager').on_load_service_clicked(msg)
+
+ def close_server(self):
+ """
+ Shutdown to local socket server and make sure the server is removed.
+ :return:
+ """
+ if self.server:
+ self.server.close()
+ # Make sure the server file is removed.
+ QtNetwork.QLocalServer.removeServer(self.id)
=== modified file 'openlp/core/version.py'
--- openlp/core/version.py 2018-01-04 06:10:20 +0000
+++ openlp/core/version.py 2018-03-31 08:02:59 +0000
@@ -136,48 +136,12 @@
global APPLICATION_VERSION
if APPLICATION_VERSION:
return APPLICATION_VERSION
- if '--dev-version' in sys.argv or '-d' in sys.argv:
- # NOTE: The following code is a duplicate of the code in setup.py. Any fix applied here should also be applied
- # there.
-
- # Get the revision of this tree.
- bzr = Popen(('bzr', 'revno'), stdout=PIPE)
- tree_revision, error = bzr.communicate()
- tree_revision = tree_revision.decode()
- code = bzr.wait()
- if code != 0:
- raise Exception('Error running bzr log')
-
- # Get all tags.
- bzr = Popen(('bzr', 'tags'), stdout=PIPE)
- output, error = bzr.communicate()
- code = bzr.wait()
- if code != 0:
- raise Exception('Error running bzr tags')
- tags = list(map(bytes.decode, output.splitlines()))
- if not tags:
- tag_version = '0.0.0'
- tag_revision = '0'
- else:
- # Remove any tag that has "?" as revision number. A "?" as revision number indicates, that this tag is from
- # another series.
- tags = [tag for tag in tags if tag.split()[-1].strip() != '?']
- # Get the last tag and split it in a revision and tag name.
- tag_version, tag_revision = tags[-1].split()
- # If they are equal, then this tree is tarball with the source for the release. We do not want the revision
- # number in the full version.
- if tree_revision == tag_revision:
- full_version = tag_version.strip()
- else:
- full_version = '{tag}-bzr{tree}'.format(tag=tag_version.strip(), tree=tree_revision.strip())
- else:
- # We're not running the development version, let's use the file.
- file_path = AppLocation.get_directory(AppLocation.VersionDir) / '.version'
- try:
- full_version = file_path.read_text().rstrip()
- except OSError:
- log.exception('Error in version file.')
- full_version = '0.0.0-bzr000'
+ file_path = AppLocation.get_directory(AppLocation.VersionDir) / '.version'
+ try:
+ full_version = file_path.read_text().rstrip()
+ except OSError:
+ log.exception('Error in version file.')
+ full_version = '0.0.0-bzr000'
bits = full_version.split('-')
APPLICATION_VERSION = {
'full': full_version,
=== added file 'tests/functional/openlp_core/api/http/test_init.py'
--- tests/functional/openlp_core/api/http/test_init.py 1970-01-01 00:00:00 +0000
+++ tests/functional/openlp_core/api/http/test_init.py 2018-03-31 08:02:59 +0000
@@ -0,0 +1,151 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2018 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; version 2 of the License. #
+# #
+# 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, write to the Free Software Foundation, Inc., 59 #
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
+###############################################################################
+"""
+Functional tests to test the Http init.
+"""
+from unittest import TestCase
+from unittest.mock import MagicMock
+
+from openlp.core.api.http import check_auth, requires_auth, authenticate
+from openlp.core.common.registry import Registry
+from openlp.core.common.settings import Settings
+
+from tests.helpers.testmixin import TestMixin
+
+
+class TestInit(TestCase, TestMixin):
+ """
+ A test suite to test the functions on the init
+ """
+
+ def setUp(self):
+ """
+ Create the UI
+ """
+ Registry().create()
+ Registry().register('service_list', MagicMock())
+ self.build_settings()
+ self.password = 'c3VwZXJmbHk6bGFtYXM='
+
+ def tearDown(self):
+ self.destroy_settings()
+
+ def test_auth(self):
+ """
+ Test the check_auth method with a match
+ :return:
+ """
+ # GIVEN: a known user
+ Settings().setValue('api/user id', "superfly")
+ Settings().setValue('api/password', "lamas")
+
+ # WHEN : I check the authorisation
+ is_valid = check_auth(['aaaaa', self.password])
+
+ # THEN:
+ assert is_valid is True
+
+ def test_auth_falure(self):
+ """
+ Test the check_auth method with a match
+ :return:
+ """
+ # GIVEN: a known user
+ Settings().setValue('api/user id', 'superfly')
+ Settings().setValue('api/password', 'lamas')
+
+ # WHEN : I check the authorisation
+ is_valid = check_auth(['aaaaa', 'monkey123'])
+
+ # THEN:
+ assert is_valid is False
+
+ def test_requires_auth_disabled(self):
+ """
+ Test the requires_auth wrapper with disabled security
+ :return:
+ """
+ # GIVEN: A disabled security
+ Settings().setValue('api/authentication enabled', False)
+
+ # WHEN: I call the function
+ wrapped_function = requires_auth(func)
+ value = wrapped_function()
+
+ # THEN: the result will be as expected
+ assert value == 'called'
+
+ def test_requires_auth_enabled(self):
+ """
+ Test the requires_auth wrapper with enabled security
+ :return:
+ """
+ # GIVEN: A disabled security
+ Settings().setValue('api/authentication enabled', True)
+
+ # WHEN: I call the function
+ wrapped_function = requires_auth(func)
+ req = MagicMock()
+ value = wrapped_function(req)
+
+ # THEN: the result will be as expected
+ assert str(value) == str(authenticate())
+
+ def test_requires_auth_enabled_auth_error(self):
+ """
+ Test the requires_auth wrapper with enabled security and authorization taken place and and error
+ :return:
+ """
+ # GIVEN: A enabled security
+ Settings().setValue('api/authentication enabled', True)
+
+ # WHEN: I call the function with the wrong password
+ wrapped_function = requires_auth(func)
+ req = MagicMock()
+ req.authorization = ['Basic', 'cccccccc']
+ value = wrapped_function(req)
+
+ # THEN: the result will be as expected - try again
+ assert str(value) == str(authenticate())
+
+ def test_requires_auth_enabled_auth(self):
+ """
+ Test the requires_auth wrapper with enabled security and authorization taken place and and error
+ :return:
+ """
+ # GIVEN: An enabled security and a known user
+ Settings().setValue('api/authentication enabled', True)
+ Settings().setValue('api/user id', 'superfly')
+ Settings().setValue('api/password', 'lamas')
+
+ # WHEN: I call the function with the wrong password
+ wrapped_function = requires_auth(func)
+ req = MagicMock()
+ req.authorization = ['Basic', self.password]
+ value = wrapped_function(req)
+
+ # THEN: the result will be as expected - try again
+ assert str(value) == 'called'
+
+
+def func(field=None):
+ return 'called'
=== modified file 'tests/functional/openlp_core/test_app.py'
--- tests/functional/openlp_core/test_app.py 2018-01-07 05:24:55 +0000
+++ tests/functional/openlp_core/test_app.py 2018-03-31 08:02:59 +0000
@@ -28,6 +28,7 @@
from openlp.core.app import OpenLP, parse_options
from openlp.core.common.settings import Settings
from tests.utils.constants import RESOURCE_PATH
+from tests.helpers.testmixin import TestMixin
def test_parse_options_basic():
@@ -41,7 +42,6 @@
args = parse_options()
# THEN: the following fields will have been extracted.
- assert args.dev_version is False, 'The dev_version flag should be False'
assert args.loglevel == 'warning', 'The log level should be set to warning'
assert args.no_error_form is False, 'The no_error_form should be set to False'
assert args.portable is False, 'The portable flag should be set to false'
@@ -59,7 +59,6 @@
args = parse_options()
# THEN: the following fields will have been extracted.
- assert args.dev_version is False, 'The dev_version flag should be False'
assert args.loglevel == ' debug', 'The log level should be set to debug'
assert args.no_error_form is False, 'The no_error_form should be set to False'
assert args.portable is False, 'The portable flag should be set to false'
@@ -77,7 +76,6 @@
args = parse_options()
# THEN: the following fields will have been extracted.
- assert args.dev_version is False, 'The dev_version flag should be False'
assert args.loglevel == 'warning', 'The log level should be set to warning'
assert args.no_error_form is False, 'The no_error_form should be set to False'
assert args.portable is True, 'The portable flag should be set to true'
@@ -89,16 +87,15 @@
Test the parse options process works with two options
"""
# GIVEN: a a set of system arguments.
- sys.argv[1:] = ['-l debug', '-d']
+ sys.argv[1:] = ['-l debug', '-p']
# WHEN: We we parse them to expand to options
args = parse_options()
# THEN: the following fields will have been extracted.
- assert args.dev_version is True, 'The dev_version flag should be True'
assert args.loglevel == ' debug', 'The log level should be set to debug'
assert args.no_error_form is False, 'The no_error_form should be set to False'
- assert args.portable is False, 'The portable flag should be set to false'
+ assert args.portable is True, 'The portable flag should be set to True'
assert args.rargs == [], 'The service file should be blank'
@@ -113,7 +110,6 @@
args = parse_options()
# THEN: the following fields will have been extracted.
- assert args.dev_version is False, 'The dev_version flag should be False'
assert args.loglevel == 'warning', 'The log level should be set to warning'
assert args.no_error_form is False, 'The no_error_form should be set to False'
assert args.portable is False, 'The portable flag should be set to false'
@@ -131,36 +127,32 @@
args = parse_options()
# THEN: the following fields will have been extracted.
- assert args.dev_version is False, 'The dev_version flag should be False'
assert args.loglevel == ' debug', 'The log level should be set to debug'
assert args.no_error_form is False, 'The no_error_form should be set to False'
assert args.portable is False, 'The portable flag should be set to false'
assert args.rargs == 'dummy_temp', 'The service file should not be blank'
-@skip('Figure out why this is causing a segfault')
-class TestOpenLP(TestCase):
+class TestOpenLP(TestCase, TestMixin):
"""
Test the OpenLP app class
"""
def setUp(self):
+ self.setup_application()
self.build_settings()
- self.qapplication_patcher = patch('openlp.core.app.QtGui.QApplication')
- self.mocked_qapplication = self.qapplication_patcher.start()
self.openlp = OpenLP([])
def tearDown(self):
- self.qapplication_patcher.stop()
self.destroy_settings()
del self.openlp
self.openlp = None
+ @skip("This one fails")
def test_exec(self):
"""
Test the exec method
"""
# GIVEN: An app
- self.openlp.shared_memory = MagicMock()
self.mocked_qapplication.exec.return_value = False
# WHEN: exec() is called
@@ -169,76 +161,25 @@
# THEN: The right things should be called
assert self.openlp.is_event_loop_active is True
self.mocked_qapplication.exec.assert_called_once_with()
- self.openlp.shared_memory.detach.assert_called_once_with()
- assert result is False
-
- @patch('openlp.core.app.QtCore.QSharedMemory')
- def test_is_already_running_not_running(self, MockedSharedMemory):
- """
- Test the is_already_running() method when OpenLP is NOT running
- """
- # GIVEN: An OpenLP app and some mocks
- mocked_shared_memory = MagicMock()
- mocked_shared_memory.attach.return_value = False
- MockedSharedMemory.return_value = mocked_shared_memory
-
- # WHEN: is_already_running() is called
- result = self.openlp.is_already_running()
-
- # THEN: The result should be false
- MockedSharedMemory.assert_called_once_with('OpenLP')
- mocked_shared_memory.attach.assert_called_once_with()
- mocked_shared_memory.create.assert_called_once_with(1)
assert result is False
@patch('openlp.core.app.QtWidgets.QMessageBox.critical')
@patch('openlp.core.app.QtWidgets.QMessageBox.StandardButtons')
- @patch('openlp.core.app.QtCore.QSharedMemory')
- def test_is_already_running_is_running_continue(self, MockedSharedMemory, MockedStandardButtons, mocked_critical):
+ def test_is_already_running_is_running(self, MockedStandardButtons, mocked_critical):
"""
Test the is_already_running() method when OpenLP IS running and the user chooses to continue
"""
# GIVEN: An OpenLP app and some mocks
- mocked_shared_memory = MagicMock()
- mocked_shared_memory.attach.return_value = True
- MockedSharedMemory.return_value = mocked_shared_memory
- MockedStandardButtons.return_value = 0
- mocked_critical.return_value = QtWidgets.QMessageBox.Yes
-
- # WHEN: is_already_running() is called
- result = self.openlp.is_already_running()
-
- # THEN: The result should be false
- MockedSharedMemory.assert_called_once_with('OpenLP')
- mocked_shared_memory.attach.assert_called_once_with()
- MockedStandardButtons.assert_called_once_with(QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)
- mocked_critical.assert_called_once_with(None, 'Error', 'OpenLP is already running. Do you wish to continue?', 0)
- assert result is False
-
- @patch('openlp.core.app.QtWidgets.QMessageBox.critical')
- @patch('openlp.core.app.QtWidgets.QMessageBox.StandardButtons')
- @patch('openlp.core.app.QtCore.QSharedMemory')
- def test_is_already_running_is_running_stop(self, MockedSharedMemory, MockedStandardButtons, mocked_critical):
- """
- Test the is_already_running() method when OpenLP IS running and the user chooses to stop
- """
- # GIVEN: An OpenLP app and some mocks
- mocked_shared_memory = MagicMock()
- mocked_shared_memory.attach.return_value = True
- MockedSharedMemory.return_value = mocked_shared_memory
- MockedStandardButtons.return_value = 0
- mocked_critical.return_value = QtWidgets.QMessageBox.No
-
- # WHEN: is_already_running() is called
- result = self.openlp.is_already_running()
-
- # THEN: The result should be false
- MockedSharedMemory.assert_called_once_with('OpenLP')
- mocked_shared_memory.attach.assert_called_once_with()
- MockedStandardButtons.assert_called_once_with(QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)
- mocked_critical.assert_called_once_with(None, 'Error', 'OpenLP is already running. Do you wish to continue?', 0)
- assert result is True
-
+ MockedStandardButtons.return_value = 0
+ mocked_critical.return_value = QtWidgets.QMessageBox.Ok
+
+ # WHEN: is_already_running() is called
+ self.openlp.is_already_running()
+
+ # THEN: The result should be false
+ MockedStandardButtons.assert_called_once_with(QtWidgets.QMessageBox.Ok)
+
+ @skip("This one fails")
def test_process_events(self):
"""
Test that the app.process_events() method simply calls the Qt method
@@ -251,6 +192,7 @@
# THEN: processEvents was called
mocked_processEvents.assert_called_once_with()
+ @skip("This one fails")
def test_set_busy_cursor(self):
"""
Test that the set_busy_cursor() method sets the cursor
@@ -265,6 +207,7 @@
mocked_setOverrideCursor.assert_called_once_with(QtCore.Qt.BusyCursor)
mocked_processEvents.assert_called_once_with()
+ @skip("This one fails")
def test_set_normal_cursor(self):
"""
Test that the set_normal_cursor() method resets the cursor
@@ -279,6 +222,7 @@
mocked_restoreOverrideCursor.assert_called_once_with()
mocked_processEvents.assert_called_once_with()
+ @skip("This one fails")
def test_event(self):
"""
Test the reimplemented event method
@@ -297,6 +241,7 @@
mocked_file_method.assert_called_once_with()
assert self.openlp.args[0] == file_path, "The path should be in args."
+ @skip("This one fails")
@patch('openlp.core.app.is_macosx')
def test_application_activate_event(self, mocked_is_macosx):
"""
@@ -316,6 +261,7 @@
assert result is True, "The method should have returned True."
# assert self.openlp.main_window.isMinimized() is False
+ @skip("This one fails")
@patch('openlp.core.app.get_version')
@patch('openlp.core.app.QtWidgets.QMessageBox.question')
def test_backup_on_upgrade_first_install(self, mocked_question, mocked_get_version):
@@ -340,6 +286,7 @@
assert Settings().value('core/application version') == '2.4.0', 'Version should be the same!'
assert mocked_question.call_count == 0, 'No question should have been asked!'
+ @skip("This one fails")
@patch('openlp.core.app.get_version')
@patch('openlp.core.app.QtWidgets.QMessageBox.question')
def test_backup_on_upgrade(self, mocked_question, mocked_get_version):
=== added file 'tests/functional/openlp_core/test_server.py'
--- tests/functional/openlp_core/test_server.py 1970-01-01 00:00:00 +0000
+++ tests/functional/openlp_core/test_server.py 2018-03-31 08:02:59 +0000
@@ -0,0 +1,120 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2018 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; version 2 of the License. #
+# #
+# 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, write to the Free Software Foundation, Inc., 59 #
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
+###############################################################################
+from unittest import TestCase
+from unittest.mock import MagicMock, patch
+
+from openlp.core.server import Server
+from openlp.core.common.registry import Registry
+
+from tests.helpers.testmixin import TestMixin
+
+
+class TestServer(TestCase, TestMixin):
+ """
+ Test the Server Class used to check if OpenLP is running.
+ """
+ def setUp(self):
+ Registry.create()
+ # self.setup_application()
+ # self.build_settings()
+ # self.openlp = OpenLP([])
+ with patch('PyQt5.QtNetwork.QLocalSocket'):
+ self.server = Server()
+
+ def tearDown(self):
+ # self.destroy_settings()
+ # del self.openlp
+ # self.openlp = None
+ self.server.close_server()
+
+ def test_is_another_instance_running(self):
+ """
+ Run a test as if this was the first time and no instance is running
+ """
+ # GIVEN: A running Server
+
+ # WHEN: I ask for it to start
+ value = self.server.is_another_instance_running()
+
+ # THEN the following is called
+ self.server.out_socket.waitForConnected.assert_called_once_with()
+ self.server.out_socket.connectToServer.assert_called_once_with(self.server.id)
+ assert isinstance(value, MagicMock)
+
+ def test_is_another_instance_running_true(self):
+ """
+ Run a test as if there is another instance running
+ """
+ # GIVEN: A running Server
+ self.server.out_socket.waitForConnected.return_value = True
+
+ # WHEN: I ask for it to start
+ value = self.server.is_another_instance_running()
+
+ # THEN the following is called
+ self.server.out_socket.waitForConnected.assert_called_once_with()
+ self.server.out_socket.connectToServer.assert_called_once_with(self.server.id)
+ assert value is True
+
+ def test_on_read_ready(self):
+ """
+ Test the on_read_ready method calls the service_manager
+ """
+ # GIVEN: A server with a service manager
+ self.server.in_stream = MagicMock()
+ service_manager = MagicMock()
+ Registry().register('service_manager', service_manager)
+
+ # WHEN: a file is added to the socket and the method called
+ file_name = '\\home\\superfly\\'
+ self.server.in_stream.readLine.return_value = file_name
+ self.server._on_ready_read()
+
+ # THEN: the service will be loaded
+ assert service_manager.on_load_service_clicked.call_count == 1
+ service_manager.on_load_service_clicked.assert_called_once_with(file_name)
+
+ @patch("PyQt5.QtCore.QTextStream")
+ def test_post_to_server(self, mocked_stream):
+ """
+ A Basic test with a post to the service
+ :return:
+ """
+ # GIVEN: A server
+ # WHEN: I post to a server
+ self.server.post_to_server(['l', 'a', 'm', 'a', 's'])
+
+ # THEN: the file should be passed out to the socket
+ self.server.out_socket.write.assert_called_once_with(b'lamas')
+
+ @patch("PyQt5.QtCore.QTextStream")
+ def test_post_to_server_openlp(self, mocked_stream):
+ """
+ A Basic test with a post to the service with OpenLP
+ :return:
+ """
+ # GIVEN: A server
+ # WHEN: I post to a server
+ self.server.post_to_server(['l', 'a', 'm', 'a', 's', 'OpenLP'])
+
+ # THEN: the file should be passed out to the socket
+ self.server.out_socket.write.assert_called_once_with(b'lamas')
Follow ups