← Back to team overview

openlp-core team mailing list archive

[Merge] lp:~alisonken1/openlp/projector-bugfix-1387223-1386913 into lp:openlp

 

Ken Roberts has proposed merging lp:~alisonken1/openlp/projector-bugfix-1387223-1386913 into lp:openlp.

Requested reviews:
  OpenLP Core (openlp-core)
Related bugs:
  Bug #1386913 in OpenLP: "Remove "Discard" option when selecting source input"
  https://bugs.launchpad.net/openlp/+bug/1386913
  Bug #1387223 in OpenLP: "openlp/core/ui/projector missing __init__.py"
  https://bugs.launchpad.net/openlp/+bug/1387223

For more details, see:
https://code.launchpad.net/~alisonken1/openlp/projector-bugfix-1387223-1386913/+merge/240292

Fix missing __import__.py bugfix #1387223
Remove 'Dismiss' and 'Reset' buttons from source select bugfix #1386913
Add import test

-- 
https://code.launchpad.net/~alisonken1/openlp/projector-bugfix-1387223-1386913/+merge/240292
Your team OpenLP Core is requested to review the proposed merge of lp:~alisonken1/openlp/projector-bugfix-1387223-1386913 into lp:openlp.
=== modified file '.bzrignore'
--- .bzrignore	2014-10-07 19:37:55 +0000
+++ .bzrignore	2014-10-31 16:10:11 +0000
@@ -26,8 +26,7 @@
 openlp.cfg
 .idea
 openlp.pro
-.kdev4
-tests.kdev4
+*.kdev4
 *.nja
 *.orig
 __pycache__

=== added file 'openlp/core/ui/projector/__init__.py'
--- openlp/core/ui/projector/__init__.py	1970-01-01 00:00:00 +0000
+++ openlp/core/ui/projector/__init__.py	2014-10-31 16:10:11 +0000
@@ -0,0 +1,33 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection                                      #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2014 Raoul Snyman                                        #
+# Portions copyright (c) 2008-2014 Tim Bentley, Gerald Britton, Jonathan      #
+# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub,      #
+# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer.   #
+# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru,          #
+# Christian Richter, Philip Ridout, Ken Roberts, Simon Scudder,               #
+# Jeffrey Smith, Maikel Stuivenberg, Martin Thompson, Jon Tibble,             #
+# Dave Warnock, Frode Woldsund, Martin Zibricky, Patrick Zimmermann           #
+# --------------------------------------------------------------------------- #
+# 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                          #
+###############################################################################
+"""
+    :mod: `openlp.core.ui.projector` module
+
+    Provides the functions for projector interface
+"""

=== modified file 'openlp/core/ui/projector/sourceselectform.py'
--- openlp/core/ui/projector/sourceselectform.py	2014-10-23 21:00:06 +0000
+++ openlp/core/ui/projector/sourceselectform.py	2014-10-31 16:10:11 +0000
@@ -286,6 +286,10 @@
                 thistab = self.tabwidget.addTab(tab, PJLINK_DEFAULT_SOURCES[key])
                 if buttonchecked:
                     self.tabwidget.setCurrentIndex(thistab)
+            self.button_box = QDialogButtonBox(QtGui.QDialogButtonBox.Reset |
+                                               QtGui.QDialogButtonBox.Discard |
+                                               QtGui.QDialogButtonBox.Ok |
+                                               QtGui.QDialogButtonBox.Cancel)
         else:
             for key in keys:
                 (tab, button_count, buttonchecked) = Build_Tab(group=self.button_group,
@@ -297,10 +301,8 @@
                 thistab = self.tabwidget.addTab(tab, PJLINK_DEFAULT_SOURCES[key])
                 if buttonchecked:
                     self.tabwidget.setCurrentIndex(thistab)
-        self.button_box = QDialogButtonBox(QtGui.QDialogButtonBox.Reset |
-                                           QtGui.QDialogButtonBox.Discard |
-                                           QtGui.QDialogButtonBox.Ok |
-                                           QtGui.QDialogButtonBox.Cancel)
+            self.button_box = QDialogButtonBox(QtGui.QDialogButtonBox.Ok |
+                                               QtGui.QDialogButtonBox.Cancel)
         self.button_box.clicked.connect(self.button_clicked)
         self.layout.addWidget(self.button_box)
         set_button_tooltip(self.button_box)
@@ -418,6 +420,10 @@
                     item.setText(source_item.text)
                 self.layout.addRow(PJLINK_DEFAULT_CODES[key], item)
                 self.button_group.append(item)
+            self.button_box = QDialogButtonBox(QtGui.QDialogButtonBox.Reset |
+                                               QtGui.QDialogButtonBox.Discard |
+                                               QtGui.QDialogButtonBox.Ok |
+                                               QtGui.QDialogButtonBox.Cancel)
         else:
             for key in keys:
                 source_text = self.projectordb.get_source_by_code(code=key, projector_id=self.projector.db_item.id)
@@ -427,10 +433,8 @@
                 self.layout.addWidget(button)
                 self.button_group.addButton(button, int(key))
                 button_list.append(key)
-        self.button_box = QDialogButtonBox(QtGui.QDialogButtonBox.Reset |
-                                           QtGui.QDialogButtonBox.Discard |
-                                           QtGui.QDialogButtonBox.Ok |
-                                           QtGui.QDialogButtonBox.Cancel)
+            self.button_box = QDialogButtonBox(QtGui.QDialogButtonBox.Ok |
+                                               QtGui.QDialogButtonBox.Cancel)
         self.button_box.clicked.connect(self.button_clicked)
         self.layout.addWidget(self.button_box)
         self.setMinimumHeight(key_count*25)

=== modified file 'tests/functional/openlp_core_common/test_projector_utilities.py'
--- tests/functional/openlp_core_common/test_projector_utilities.py	2014-10-06 19:10:03 +0000
+++ tests/functional/openlp_core_common/test_projector_utilities.py	2014-10-31 16:10:11 +0000
@@ -33,19 +33,9 @@
 from unittest import TestCase
 
 from openlp.core.common import verify_ip_address, md5_hash, qmd5_hash
-
-salt = '498e4a67'
-pin = 'JBMIAProjectorLink'
-test_hash = '5d8409bc1c3fa39749434aa3a5c38682'
-
-ip4_loopback = '127.0.0.1'
-ip4_local = '192.168.1.1'
-ip4_broadcast = '255.255.255.255'
-ip4_bad = '192.168.1.256'
-
-ip6_loopback = '::1'
-ip6_link_local = 'fe80::223:14ff:fe99:d315'
-ip6_bad = 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff'
+from tests.resources.projector.data import test_salt, test_pin, test_hash, ip4_loopback, \
+    ip4_local, ip4_broadcast, ip4_bad, ip6_loopback, \
+    ip6_link_local, ip6_bad
 
 
 class testProjectorUtilities(TestCase):
@@ -127,7 +117,7 @@
         Test MD5 hash from salt+data pass (python)
         """
         # WHEN: Given a known salt+data
-        hash_ = md5_hash(salt=salt, data=pin)
+        hash_ = md5_hash(salt=test_salt, data=test_pin)
 
         # THEN: Validate return has is same
         self.assertEquals(hash_, test_hash, 'MD5 should have returned a good hash')
@@ -137,7 +127,7 @@
         Test MD5 hash from salt+data fail (python)
         """
         # WHEN: Given a different salt+hash
-        hash_ = md5_hash(salt=pin, data=salt)
+        hash_ = md5_hash(salt=test_pin, data=test_salt)
 
         # THEN: return data is different
         self.assertNotEquals(hash_, test_hash, 'MD5 should have returned a bad hash')
@@ -147,7 +137,7 @@
         Test MD5 hash from salt+data pass (Qt)
         """
         # WHEN: Given a known salt+data
-        hash_ = qmd5_hash(salt=salt, data=pin)
+        hash_ = qmd5_hash(salt=test_salt, data=test_pin)
 
         # THEN: Validate return has is same
         self.assertEquals(hash_, test_hash, 'Qt-MD5 should have returned a good hash')
@@ -157,7 +147,7 @@
         Test MD5 hash from salt+hash fail (Qt)
         """
         # WHEN: Given a different salt+hash
-        hash_ = qmd5_hash(salt=pin, data=salt)
+        hash_ = qmd5_hash(salt=test_pin, data=test_salt)
 
         # THEN: return data is different
         self.assertNotEquals(hash_, test_hash, 'Qt-MD5 should have returned a bad hash')

=== added file 'tests/functional/openlp_core_lib/test_projector.py'
--- tests/functional/openlp_core_lib/test_projector.py	1970-01-01 00:00:00 +0000
+++ tests/functional/openlp_core_lib/test_projector.py	2014-10-31 16:10:11 +0000
@@ -0,0 +1,127 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection                                      #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2014 Raoul Snyman                                        #
+# Portions copyright (c) 2008-2014 Tim Bentley, Gerald Britton, Jonathan      #
+# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub,      #
+# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer.   #
+# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru,          #
+# Christian Richter, Philip Ridout, Ken Roberts, Simon Scudder,               #
+# Jeffrey Smith, Maikel Stuivenberg, Martin Thompson, Jon Tibble,             #
+# Dave Warnock, Frode Woldsund, Martin Zibricky, Patrick Zimmermann           #
+# --------------------------------------------------------------------------- #
+# 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                          #
+###############################################################################
+"""
+    :mod:`test.functional.openlp_core_lib.test_projector` module
+
+    Verify that the projector modules import correctly
+"""
+
+import os
+from unittest import TestCase
+
+
+class TestProjectorImports(TestCase):
+    """
+    Verify that the projector modules import correctly.
+    """
+    def add_projector_constants_import_test(self):
+        """
+        Verify projector constants will import
+        """
+        # WHEN: openlp.core.lib.projector.constants is loaded
+        try:
+            from openlp.core.lib.projector import constants
+        except ImportError:
+            pass
+        # THEN: constants module is available
+        self.assertIn('constants', locals(),
+                      "openlp.core.lib.projector.constants module should have been imported")
+
+    def add_projector_db_import_test(self):
+        """
+        Verify projector db module will import
+        """
+        # WHEN: openlp.core.lib.projector.db module is imported
+        try:
+            from openlp.core.lib.projector import db
+        except ImportError:
+            pass
+        # THEN: projector DB module is available
+        self.assertIn('db', locals(),
+                      "openlp.core.lib.projector.db module should have been imported")
+
+    def add_projector_pjlink1_import_test(self):
+        """
+        Verify projector PJLink1 module will import
+        """
+        # WHEN: openlp.core.lib.projector.pjlink1 is imported
+        try:
+            from openlp.core.lib.projector import pjlink1
+        except ImportError:
+            pass
+        self.assertIn('pjlink1', locals(),
+                      "openlp.core.lib.projector.pljlink1 module should have been imported")
+
+    def add_projector_editform_import_test(self):
+        """
+        Verify projector edit form module will import
+        """
+        # WHEN: openlp.core.ui.projector.editform is imported
+        try:
+            from openlp.core.ui.projector import editform
+        except ImportError:
+            pass
+        self.assertIn('editform', locals(),
+                      "openlp.core.lib.projector.editform module should have been imported")
+
+    def add_projector_manager_import_test(self):
+        """
+        Verify projector manager module will import
+        """
+        # WHEN: Projector manager is imported
+        try:
+            from openlp.core.ui.projector import manager
+        except ImportError:
+            pass
+        self.assertIn('manager', locals(),
+                      "openlp.core.lib.projector.manager module should have been imported")
+
+    def add_projector_sourceselectform_import_test(self):
+        """
+        Verify projector source select edit form will import
+        """
+        # WHEN: Projector source select edit form is imported
+        try:
+            from openlp.core.ui.projector import sourceselectform
+        except ImportError:
+            pass
+        self.assertIn('sourceselectform', locals(),
+                      "openlp.core.lib.projector.sourceselectform module should have been imported")
+
+    def add_projector_tab_import_test(self):
+        """
+        Verify the projector settings tab will import
+        """
+        # WHEN: Projector settings tab form is imported
+        try:
+            from openlp.core.ui.projector import tab
+        except ImportError:
+            pass
+        self.assertIn('tab', locals(),
+                      "openlp.core.lib.projector.tab module should have been imported")

=== modified file 'tests/helpers/__init__.py'
--- tests/helpers/__init__.py	2014-02-27 21:36:33 +0000
+++ tests/helpers/__init__.py	2014-10-31 16:10:11 +0000
@@ -29,3 +29,5 @@
 """
 The :mod:`~tests.helpers` module provides helper classes for use in the tests.
 """
+
+from .projectorserver import PJLink1Server

=== added file 'tests/helpers/projectorserver.py'
--- tests/helpers/projectorserver.py	1970-01-01 00:00:00 +0000
+++ tests/helpers/projectorserver.py	2014-10-31 16:10:11 +0000
@@ -0,0 +1,207 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection                                      #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2014 Raoul Snyman                                        #
+# Portions copyright (c) 2008-2014 Tim Bentley, Gerald Britton, Jonathan      #
+# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub,      #
+# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer.   #
+# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru,          #
+# Christian Richter, Philip Ridout, Ken Roberts, Simon Scudder,               #
+# Jeffrey Smith, Maikel Stuivenberg, Martin Thompson, Jon Tibble,             #
+# Dave Warnock, Frode Woldsund, Martin Zibricky, Patrick Zimmermann           #
+# --------------------------------------------------------------------------- #
+# 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                          #
+###############################################################################
+"""
+    :mod:`test.helpers.projectorserver` module
+
+    Test server to test PJLink1 classes
+"""
+import logging
+log = logging.getLogger(__name__)
+log.debug('projectorserver loaded')
+
+import socket
+from socketserver import BaseRequestHandler, TCPServer, ThreadingMixIn
+from threading import Thread
+
+from openlp.core.lib.projector.constants import PJLINK_PORT, PJLINK_MAX_PACKET
+from openlp.core.lib.projector.pjlink1 import PJLINK_HEADER
+from tests.resources.projector.data import test_salt, test_pin, test_hash
+
+
+def send_data(sock, data, header=True):
+    """
+    Encode data to ascii and send to socket
+
+    :param sock: Socket to use
+    :param data: Data to send
+    :param header: Optionally send PJLink header with data
+    """
+    if header:
+        response = bytes("{}{}".format(PJLINK_HEADER, data), 'ascii')
+    else:
+        response = bytes("{}".format(data), 'ascii')
+    log.debug(str('send_data: sending "{}"'.format(response)))
+    print(str('send_data: sending "{}"'.format(response)))
+    return sock.sendall(response)
+
+
+def get_data(sock):
+    """
+    Decode data from socket and return
+
+    :param sock: Socket to use
+    """
+    response = None
+    while response is None:
+        try:
+            response = str(sock.recv(PJLINK_MAX_PACKET), 'ascii').strip()
+        except socket.timeout:
+            continue
+    log.debug(str('get_data: received "{}"'.format(response)))
+    print(str('get_data: received "{}"'.format(response)))
+    return response
+
+
+def get_command(data):
+    """
+    Break data into cmd, opt strings
+
+    :param data: Data to check
+    """
+    print('get_command(data="{}")'.format(data))
+    if data is None or data == "":
+        return None, None
+    cmd, opts = data.split()
+    return cmd[2:], opts
+
+
+def process_command(cmd, opt):
+    """
+    Return a response based on cmd and opt
+
+    Since this is a test server, we will assume that the set commands contain valid
+    options.
+
+    :param cmd: Command to process
+    :param opt: Option for command
+    """
+    check = cmd.upper()
+    if check == "AVMT":
+        response = "30" if opt == "?" else "OK"
+    elif check == "CLSS":
+        response = "1" if opt == "?" else "ERR2"
+    elif check == "ERST":
+        response = '000000'
+    elif check == "NAME" or check == "INF1" or check == "INF2" or check == "INFO":
+        response = ""
+    elif check == "INPT":
+        response = "11" if opt == "?" else "OK"
+    elif check == "INST":
+        response = "11"
+    elif check == "LAMP":
+        response = "0 0"
+    elif check == "POWR":
+        response = "0" if opt == "?" else "OK"
+    return response
+
+
+class ThreadedTCPServer(ThreadingMixIn, TCPServer):
+    """
+    Generic class for threaded server
+    """
+    pass
+
+
+class PJLink1PlainHandler(BaseRequestHandler):
+    """
+    Handle plain connection.
+    """
+    def handle(self):
+        self.request.settimeout(1)  # 1 second timeout on socket
+        if hasattr(self, "authenticate"):
+            log.debug('PJLink1PLainHandler: Handling authenticated connection')
+            # Send hash and check response
+            send_data(self.request, 'PJLink 1 {}'.format(test_salt), header=False)
+            rdata = get_data(self.request)
+            if rdata.startswith(test_hash):
+                    data = rdata[len(test_hash):]
+            else:
+                send_data(self.sock, "%1CLSS=ERRA")
+                return
+        else:
+            # Plain login
+            log.debug('PJLink1PLainHandler: Handling plain connection')
+            send_data(self.request, "PJLink 0", header=False)
+            cmd, opt = get_command(get_data(self.request))
+            if cmd is None or cmd == "":
+                # Lost connection ?
+                return
+            if opt.startswith('ERR'):
+                send_data(self.request, '{}={}'.format(cmd, opt))
+            else:
+                send_data(self.request, '{}={}'.format(cmd, process_command(cmd, opt)))
+        while self.server.running:
+            data = get_data(self.request)
+            if data is None or data == "":
+                # Connection closed on other end?
+                break
+            cmd, opt = get_command(data)
+            send_data(self.request, '{}={}'.format(cmd, process_command(cmd, opt)))
+
+
+class PJLink1AuthHandler(PJLink1PlainHandler):
+    """
+    Handle authenticated connection
+    """
+    def handle(self):
+        """
+        Method to handle connection. This sets self.authenticate and calls
+        the super class to handle the actual processing.
+        """
+        self.authenticate = True
+        super(PJLink1AuthHandler, self).handle()
+
+
+class PJLink1Server:
+    """
+    Class to initialize a socket server for PJLink1 testing
+    """
+    def __init__(self, authenticate=False):
+        """
+        Initialize the server and get ready for threading
+        """
+        self.running = False
+        self.authenticate = authenticate
+        if self.authenticate:
+            self.server = ThreadedTCPServer(('127.0.0.1', PJLINK_PORT), PJLink1AuthHandler)
+        else:
+            self.server = ThreadedTCPServer(('127.0.0.1', PJLINK_PORT), PJLink1PlainHandler)
+
+    def run(self):
+        if not self.running:
+            self.running = True
+            self.server.running = True
+            self.server_thread = Thread(target=self.server.serve_forever)
+            self.server_thread.daemon = True
+            self.server_thread.start()
+
+    def stop(self):
+        self.server.running = False
+        self.server.shutdown()
+        self.running = False

=== modified file 'tests/resources/projector/data.py'
--- tests/resources/projector/data.py	2014-10-06 21:19:08 +0000
+++ tests/resources/projector/data.py	2014-10-31 16:10:11 +0000
@@ -32,7 +32,19 @@
 
 from openlp.core.lib.projector.db import Projector
 
-# Test data
+test_salt = '498e4a67'
+test_pin = 'JBMIAProjectorLink'
+test_hash = '5d8409bc1c3fa39749434aa3a5c38682'
+
+ip4_loopback = '127.0.0.1'
+ip4_local = '192.168.1.1'
+ip4_broadcast = '255.255.255.255'
+ip4_bad = '192.168.1.256'
+
+ip6_loopback = '::1'
+ip6_link_local = 'fe80::223:14ff:fe99:d315'
+ip6_bad = 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff'
+
 TEST1_DATA = Projector(ip='111.111.111.111',
                        port='1111',
                        pin='1111',


Follow ups