From a4efccb00b09820d5198b1ec1089547d82042be0 Mon Sep 17 00:00:00 2001 From: Ken Roberts Date: Tue, 6 Jan 2015 14:37:18 -0800 Subject: [PATCH 1/9] Replace remote Registry().execute(event) next/previous with Qt signal --- openlp/core/ui/servicemanager.py | 2 ++ openlp/plugins/remotes/lib/httprouter.py | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index 575005b27..dd851b946 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -338,6 +338,8 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtGui.QWidget, Ui_ServiceManage self.setup_ui(self) # Need to use event as called across threads and UI is updated QtCore.QObject.connect(self, QtCore.SIGNAL('servicemanager_set_item'), self.on_set_item) + QtCore.QObject.connect(self, QtCore.SIGNAL('servicemanager_next_item'), self.next_item) + QtCore.QObject.connect(self, QtCore.SIGNAL('servicemanager_previous_item'), self.previous_item) def bootstrap_post_set_up(self): """ diff --git a/openlp/plugins/remotes/lib/httprouter.py b/openlp/plugins/remotes/lib/httprouter.py index 695ecce85..f644fb35d 100644 --- a/openlp/plugins/remotes/lib/httprouter.py +++ b/openlp/plugins/remotes/lib/httprouter.py @@ -582,7 +582,8 @@ class HttpRouter(RegistryProperties): return self.do_http_error() self.service_manager.emit(QtCore.SIGNAL(event), data) else: - Registry().execute(event) + # Registry().execute(event) + self.service_manager.emit(QtCore.SIGNAL(event)) self.do_json_header() return json.dumps({'results': {'success': True}}).encode() From 3f3c4cf80b1358970bb93931df360fbd59679877 Mon Sep 17 00:00:00 2001 From: Ken Roberts Date: Thu, 8 Jan 2015 10:07:36 -0800 Subject: [PATCH 2/9] remote next/previous call test --- openlp/plugins/remotes/lib/httprouter.py | 1 - .../openlp_plugins/remotes/test_router.py | 44 ++++++++++++++++++- 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/openlp/plugins/remotes/lib/httprouter.py b/openlp/plugins/remotes/lib/httprouter.py index f644fb35d..7902e6606 100644 --- a/openlp/plugins/remotes/lib/httprouter.py +++ b/openlp/plugins/remotes/lib/httprouter.py @@ -582,7 +582,6 @@ class HttpRouter(RegistryProperties): return self.do_http_error() self.service_manager.emit(QtCore.SIGNAL(event), data) else: - # Registry().execute(event) self.service_manager.emit(QtCore.SIGNAL(event)) self.do_json_header() return json.dumps({'results': {'success': True}}).encode() diff --git a/tests/functional/openlp_plugins/remotes/test_router.py b/tests/functional/openlp_plugins/remotes/test_router.py index b4092eb2b..d5b7e7a24 100644 --- a/tests/functional/openlp_plugins/remotes/test_router.py +++ b/tests/functional/openlp_plugins/remotes/test_router.py @@ -32,8 +32,9 @@ This module contains tests for the lib submodule of the Remotes plugin. import os import urllib.request from unittest import TestCase - +from PyQt4 import QtCore from openlp.core.common import Settings, Registry +from openlp.core.ui import ServiceManager from openlp.plugins.remotes.lib.httpserver import HttpRouter from urllib.parse import urlparse from tests.functional import MagicMock, patch, mock_open @@ -61,9 +62,12 @@ class TestRouter(TestCase, TestMixin): """ Create the UI """ + Registry.create() self.setup_application() self.build_settings() Settings().extend_default_settings(__default_settings__) + self.service_manager = ServiceManager() + self.service_manager = Registry().service_list['service_manager'] = self.service_manager self.router = HttpRouter() def tearDown(self): @@ -299,3 +303,41 @@ class TestRouter(TestCase, TestMixin): mocked_image_manager.assert_called_any(os.path.normpath('thumbnails\\another test'), 'slide1.png', None, '120x90') mocked_image_manager.assert_called_any(os.path.normpath('thumbnails\\another test'), 'slide1.png', '120x90') + + def remote_next_test(self): + """ + Test service manager receives remote next click properly (bug 1407445) + """ + # GIVEN: initial setup and mocks + self.router.routes = [(r'^/api/service/(.*)$', {'function': self.router.service, 'secure': False})] + self.router.request_data = False + mocked_next_item = MagicMock() + self.service_manager.next_item = mocked_next_item + with patch.object(self.service_manager, 'setup_ui'), \ + patch.object(self.router, 'do_json_header'): + self.service_manager.bootstrap_initialise() + self.app.processEvents() + # WHEN: Remote next is received + self.router.service(action='next') + self.app.processEvents() + # THEN: service_manager.next_item() should have been called + self.assertTrue(mocked_next_item.called, 'next_item() should have been called in service_manager') + + def remote_previous_test(self): + """ + Test service manager receives remote previous click properly (bug 1407445) + """ + # GIVEN: initial setup and mocks + self.router.routes = [(r'^/api/service/(.*)$', {'function': self.router.service, 'secure': False})] + self.router.request_data = False + mocked_previous_item = MagicMock() + self.service_manager.previous_item = mocked_previous_item + with patch.object(self.service_manager, 'setup_ui'), \ + patch.object(self.router, 'do_json_header'): + self.service_manager.bootstrap_initialise() + self.app.processEvents() + # WHEN: Remote next is received + self.router.service(action='previous') + self.app.processEvents() + # THEN: service_manager.next_item() should have been called + self.assertTrue(mocked_previous_item.called, 'previous_item() should have been called in service_manager') From 7277e3e92a7b5b6c8c8b95a21e01acdbecfa22ea Mon Sep 17 00:00:00 2001 From: Ken Roberts Date: Thu, 8 Jan 2015 10:55:26 -0800 Subject: [PATCH 3/9] Remove unneeded Registry modification --- tests/functional/openlp_plugins/remotes/test_router.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/functional/openlp_plugins/remotes/test_router.py b/tests/functional/openlp_plugins/remotes/test_router.py index d5b7e7a24..b04dc4040 100644 --- a/tests/functional/openlp_plugins/remotes/test_router.py +++ b/tests/functional/openlp_plugins/remotes/test_router.py @@ -67,7 +67,6 @@ class TestRouter(TestCase, TestMixin): self.build_settings() Settings().extend_default_settings(__default_settings__) self.service_manager = ServiceManager() - self.service_manager = Registry().service_list['service_manager'] = self.service_manager self.router = HttpRouter() def tearDown(self): From e0fa70e47e710ecb9d162d78a6c99e7dabf95825 Mon Sep 17 00:00:00 2001 From: Phill Ridout Date: Thu, 8 Jan 2015 22:05:32 +0000 Subject: [PATCH 4/9] Set the last file location in the file dialog box Fixes: https://launchpad.net/bugs/1397606 --- openlp/core/ui/themeform.py | 12 +- .../openlp_core_ui/test_themeform.py | 103 ++++++++++++++++++ 2 files changed, 112 insertions(+), 3 deletions(-) create mode 100644 tests/functional/openlp_core_ui/test_themeform.py diff --git a/openlp/core/ui/themeform.py b/openlp/core/ui/themeform.py index 9c24a2b67..ec6559a8c 100644 --- a/openlp/core/ui/themeform.py +++ b/openlp/core/ui/themeform.py @@ -58,6 +58,12 @@ class ThemeForm(QtGui.QWizard, Ui_ThemeWizard, RegistryProperties): :param parent: The QWidget-derived parent of the wizard. """ super(ThemeForm, self).__init__(parent) + self._setup() + + def _setup(self): + """ + Set up the class. This method is mocked out by the tests. + """ self.setupUi(self) self.registerFields() self.update_theme_allowed = True @@ -429,10 +435,10 @@ class ThemeForm(QtGui.QWizard, Ui_ThemeWizard, RegistryProperties): """ images_filter = get_images_filter() images_filter = '%s;;%s (*.*)' % (images_filter, UiStrings().AllFiles) - filename = QtGui.QFileDialog.getOpenFileName(self, translate('OpenLP.ThemeWizard', 'Select Image'), '', - images_filter) + filename = QtGui.QFileDialog.getOpenFileName(self, translate('OpenLP.ThemeWizard', 'Select Image'), + self.image_file_edit.text(), images_filter) if filename: - self.theme.background_filename = str(filename) + self.theme.background_filename = filename self.set_background_page_values() def on_image_file_edit_editing_finished(self): diff --git a/tests/functional/openlp_core_ui/test_themeform.py b/tests/functional/openlp_core_ui/test_themeform.py new file mode 100644 index 000000000..0541c2d83 --- /dev/null +++ b/tests/functional/openlp_core_ui/test_themeform.py @@ -0,0 +1,103 @@ +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2015 Raoul Snyman # +# Portions copyright (c) 2008-2015 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, 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 # +############################################################################### +""" +Package to test the openlp.core.ui.themeform package. +""" + +from unittest import TestCase + +from openlp.core.ui import ThemeForm + +from tests.interfaces import MagicMock, patch + + +class TestThemeManager(TestCase): + """ + Test the functions in the ThemeManager Class + """ + def select_image_file_dialog_cancelled_test(self): + """ + Test the select image file dialog when the user presses cancel + """ + # GIVEN: An instance of Theme Form and mocked QFileDialog which returns an empty string (similating a user + # pressing cancel) + with patch('openlp.core.ui.ThemeForm._setup'),\ + patch('openlp.core.ui.themeform.get_images_filter', + **{'return_value': 'Image Files (*.bmp; *.gif)(*.bmp *.gif)'}),\ + patch('openlp.core.ui.themeform.QtGui.QFileDialog.getOpenFileName', + **{'return_value': ''}) as mocked_get_open_file_name,\ + patch('openlp.core.ui.themeform.translate', **{'return_value': 'Translated String'}),\ + patch('openlp.core.ui.ThemeForm.set_background_page_values') as mocked_set_background_page_values: + + instance = ThemeForm(None) + mocked_image_file_edit = MagicMock() + mocked_image_file_edit.text.return_value = '/original_path/file.ext' + instance.image_file_edit = mocked_image_file_edit + + # WHEN: on_image_browse_button is clicked + instance.on_image_browse_button_clicked() + + + # THEN: The QFileDialog getOpenFileName and set_background_page_values moethods should have been called + # with known arguments + mocked_get_open_file_name.assert_called_once_with(instance, 'Translated String', '/original_path/file.ext', + 'Image Files (*.bmp; *.gif)(*.bmp *.gif);;All Files (*.*)' + ) + mocked_set_background_page_values.assert_called_once_with() + + def select_image_file_dialog_new_file_test(self): + """ + Test the select image file dialog when the user presses ok + """ + # GIVEN: An instance of Theme Form and mocked QFileDialog which returns a file path + with patch('openlp.core.ui.ThemeForm._setup'),\ + patch('openlp.core.ui.themeform.get_images_filter', + **{'return_value': 'Image Files (*.bmp; *.gif)(*.bmp *.gif)'}),\ + patch('openlp.core.ui.themeform.QtGui.QFileDialog.getOpenFileName', + **{'return_value': '/new_path/file.ext'}) as mocked_get_open_file_name,\ + patch('openlp.core.ui.themeform.translate', **{'return_value': 'Translated String'}),\ + patch('openlp.core.ui.ThemeForm.set_background_page_values') as mocked_background_page_values: + + instance = ThemeForm(None) + mocked_image_file_edit = MagicMock() + mocked_image_file_edit.text.return_value = '/original_path/file.ext' + instance.image_file_edit = mocked_image_file_edit + instance.theme = MagicMock() + + # WHEN: on_image_browse_button is clicked + instance.on_image_browse_button_clicked() + + # THEN: The QFileDialog getOpenFileName and set_background_page_values moethods should have been called + # with known arguments and theme.background_filename should be set + mocked_get_open_file_name.assert_called_once_with(instance, 'Translated String', '/original_path/file.ext', + 'Image Files (*.bmp; *.gif)(*.bmp *.gif);;All Files (*.*)' + ) + self.assertEqual(instance.theme.background_filename, '/new_path/file.ext', + 'theme.background_filename should be set to the path that the file dialog returns') + mocked_background_page_values.assert_called_once_with() From ac19e018fae5f752c307a5905230f7203290f4c5 Mon Sep 17 00:00:00 2001 From: Ken Roberts Date: Fri, 9 Jan 2015 07:38:10 -0800 Subject: [PATCH 5/9] Fix retries on connection timeout error --- openlp/core/utils/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openlp/core/utils/__init__.py b/openlp/core/utils/__init__.py index ece8011ac..257351758 100644 --- a/openlp/core/utils/__init__.py +++ b/openlp/core/utils/__init__.py @@ -401,7 +401,7 @@ def get_web_page(url, header=None, update_openlp=False): req.add_header(header[0], header[1]) page = None log.debug('Downloading URL = %s' % url) - retries = 0 + retries = 1 while True: try: page = urllib.request.urlopen(req, timeout=CONNECTION_TIMEOUT) @@ -411,6 +411,7 @@ def get_web_page(url, header=None, update_openlp=False): log.exception('The web page could not be downloaded') raise else: + retries += 1 time.sleep(0.1) continue break From d2fb2d47ebb0d9d9200a87958ce465937f2a7fea Mon Sep 17 00:00:00 2001 From: Ken Roberts Date: Fri, 9 Jan 2015 10:46:50 -0800 Subject: [PATCH 6/9] Tests for bug 1409031 --- .../openlp_core_utils/test_first_time.py | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 tests/functional/openlp_core_utils/test_first_time.py diff --git a/tests/functional/openlp_core_utils/test_first_time.py b/tests/functional/openlp_core_utils/test_first_time.py new file mode 100644 index 000000000..8c4cd23be --- /dev/null +++ b/tests/functional/openlp_core_utils/test_first_time.py @@ -0,0 +1,62 @@ +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2015 Raoul Snyman # +# Portions copyright (c) 2008-2015 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, 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 # +############################################################################### +""" +Package to test the openlp.core.utils.__init__ package. +""" + +from unittest import TestCase +import urllib.request +import urllib.error +import urllib.parse + +from tests.functional import MagicMock, patch +from tests.helpers.testmixin import TestMixin + +from openlp.core.utils import CONNECTION_TIMEOUT, CONNECTION_RETRIES, get_web_page + + +class TestFirstTimeWizard(TestMixin, TestCase): + """ + Test First Time Wizard import functions + """ + def webpage_connection_retry_test(self): + """ + Test get_web_page will attempt CONNECTION_RETRIES+1 connections - bug 1409031 + """ + # GIVEN: Initial settings and mocks + with patch.object(urllib.request, 'urlopen') as mocked_urlopen: + mocked_urlopen.side_effect = ConnectionError + # WHEN: A webpage is requested + try: + get_web_page(url='http://localhost') + except: + pass + # THEN: urlopen should have been called CONNECTION_RETRIES + 1 count + self.assertEquals(mocked_urlopen.call_count, CONNECTION_RETRIES + 1, + 'get_web_page() should have tried {} times'.format(CONNECTION_RETRIES)) From 0b2445b9a2273a9cee39e4770194a2b20f3ff445 Mon Sep 17 00:00:00 2001 From: Ken Roberts Date: Fri, 9 Jan 2015 10:53:36 -0800 Subject: [PATCH 7/9] Fix spacing --- tests/functional/openlp_plugins/remotes/test_router.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/functional/openlp_plugins/remotes/test_router.py b/tests/functional/openlp_plugins/remotes/test_router.py index b04dc4040..d7bb55d3f 100644 --- a/tests/functional/openlp_plugins/remotes/test_router.py +++ b/tests/functional/openlp_plugins/remotes/test_router.py @@ -316,9 +316,11 @@ class TestRouter(TestCase, TestMixin): patch.object(self.router, 'do_json_header'): self.service_manager.bootstrap_initialise() self.app.processEvents() + # WHEN: Remote next is received self.router.service(action='next') self.app.processEvents() + # THEN: service_manager.next_item() should have been called self.assertTrue(mocked_next_item.called, 'next_item() should have been called in service_manager') @@ -335,8 +337,10 @@ class TestRouter(TestCase, TestMixin): patch.object(self.router, 'do_json_header'): self.service_manager.bootstrap_initialise() self.app.processEvents() + # WHEN: Remote next is received self.router.service(action='previous') self.app.processEvents() + # THEN: service_manager.next_item() should have been called self.assertTrue(mocked_previous_item.called, 'previous_item() should have been called in service_manager') From 5c7777fd5a313d06d1276b13078a1d767186ee1d Mon Sep 17 00:00:00 2001 From: Ken Roberts Date: Fri, 9 Jan 2015 10:55:46 -0800 Subject: [PATCH 8/9] Fix line spacing --- tests/functional/openlp_core_utils/test_first_time.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/functional/openlp_core_utils/test_first_time.py b/tests/functional/openlp_core_utils/test_first_time.py index 8c4cd23be..d7e2d9bbb 100644 --- a/tests/functional/openlp_core_utils/test_first_time.py +++ b/tests/functional/openlp_core_utils/test_first_time.py @@ -52,11 +52,13 @@ class TestFirstTimeWizard(TestMixin, TestCase): # GIVEN: Initial settings and mocks with patch.object(urllib.request, 'urlopen') as mocked_urlopen: mocked_urlopen.side_effect = ConnectionError + # WHEN: A webpage is requested try: get_web_page(url='http://localhost') except: pass + # THEN: urlopen should have been called CONNECTION_RETRIES + 1 count self.assertEquals(mocked_urlopen.call_count, CONNECTION_RETRIES + 1, 'get_web_page() should have tried {} times'.format(CONNECTION_RETRIES)) From dac71856927a4ead9926ebc26a37ce7029ddbdc7 Mon Sep 17 00:00:00 2001 From: Phill Ridout Date: Fri, 9 Jan 2015 19:51:39 +0000 Subject: [PATCH 9/9] Remove extra line --- tests/functional/openlp_core_ui/test_themeform.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/functional/openlp_core_ui/test_themeform.py b/tests/functional/openlp_core_ui/test_themeform.py index 0541c2d83..f902aff51 100644 --- a/tests/functional/openlp_core_ui/test_themeform.py +++ b/tests/functional/openlp_core_ui/test_themeform.py @@ -63,7 +63,6 @@ class TestThemeManager(TestCase): # WHEN: on_image_browse_button is clicked instance.on_image_browse_button_clicked() - # THEN: The QFileDialog getOpenFileName and set_background_page_values moethods should have been called # with known arguments mocked_get_open_file_name.assert_called_once_with(instance, 'Translated String', '/original_path/file.ext',