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.



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/342748

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.


lp:~trb143/openlp/localserver (revision 2849)
https://ci.openlp.io/job/Branch-01-Pull/2500/                          [SUCCESS]
https://ci.openlp.io/job/Branch-02a-Linux-Tests/2401/                  [SUCCESS]
https://ci.openlp.io/job/Branch-02b-macOS-Tests/187/                   [FAILURE]
https://ci.openlp.io/job/Branch-03a-Build-Source/99/                   [SUCCESS]
https://ci.openlp.io/job/Branch-03b-Build-macOS/92/                    [SUCCESS]
https://ci.openlp.io/job/Branch-04a-Code-Analysis/1561/                [SUCCESS]
https://ci.openlp.io/job/Branch-04b-Test-Coverage/1374/                [SUCCESS]

-- 
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-04-05 16:37:28 +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-04-05 16:37:28 +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-04-05 16:37:28 +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-04-05 16:37:28 +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-04-05 16:37:28 +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-04-05 16:37:28 +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-04-05 16:37:28 +0000
@@ -41,7 +41,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 +58,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 +75,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 +86,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 false'
     assert args.rargs == [], 'The service file should be blank'
 
 
@@ -113,7 +109,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,7 +126,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'

=== 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-04-05 16:37:28 +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')

_______________________________________________
Mailing list: https://launchpad.net/~openlp-core
Post to     : openlp-core@lists.launchpad.net
Unsubscribe : https://launchpad.net/~openlp-core
More help   : https://help.launchpad.net/ListHelp

Reply via email to