openlp-core team mailing list archive
-
openlp-core team
-
Mailing list archive
-
Message #24552
[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