diff --git a/openlp/core/api/deploy.py b/openlp/core/api/deploy.py index 29ffb4939..d198382b5 100644 --- a/openlp/core/api/deploy.py +++ b/openlp/core/api/deploy.py @@ -23,6 +23,7 @@ Download and "install" the remote web client """ import json import logging +import re from datetime import date from zipfile import ZipFile @@ -34,6 +35,7 @@ from openlp.core.common.registry import Registry from openlp.core.threading import ThreadWorker, run_thread REMOTE_URL = 'https://get.openlp.org/remote/' +LOCAL_VERSION = re.compile(r'appVersion.*=.*\'(.*?)\';') log = logging.getLogger(__name__) @@ -117,7 +119,7 @@ def get_latest_size(): return version_info['latest']['size'] -def download_and_check(callback=None, can_update_range=True): +def download_and_install(callback=None, can_update_range=True): """ Download the web site and deploy it. """ @@ -151,3 +153,18 @@ def check_for_remote_update(main_window): # TODO: Use this to figure out if there's an Internet connection? # worker.no_internet.connect(main_window.on_no_internet) run_thread(worker, 'remote-version') + + +def get_installed_version(): + """ + Get the version of the remote that is installed, or None if there is no remote + """ + version_file = AppLocation.get_section_data_path('remotes') / 'assets' / 'version.js' + if not version_file.exists(): + return None + version_read = version_file.read() + print(version_read) + match = LOCAL_VERSION.search(version_read) + if not match: + return None + return match.group(1) diff --git a/openlp/core/api/tab.py b/openlp/core/api/tab.py index cd134ae45..7e1f094c0 100644 --- a/openlp/core/api/tab.py +++ b/openlp/core/api/tab.py @@ -30,7 +30,7 @@ from time import sleep from PyQt5 import QtCore, QtGui, QtWidgets -from openlp.core.api.deploy import download_and_check, download_version_info +from openlp.core.api.deploy import download_and_install, download_version_info, get_installed_version from openlp.core.common import get_network_interfaces from openlp.core.common.i18n import translate from openlp.core.common.registry import Registry @@ -50,7 +50,8 @@ class ApiTab(SettingsTab): def __init__(self, parent): self.icon_path = UiIcons().remote advanced_translated = translate('OpenLP.APITab', 'API') - self._master_version = None + self._available_version = None + self._installed_version = None super(ApiTab, self).__init__(parent, 'api', advanced_translated) def setup_ui(self): @@ -138,25 +139,25 @@ class ApiTab(SettingsTab): self.web_remote_group_box.setObjectName('web_remote_group_box') self.web_remote_layout = QtWidgets.QGridLayout(self.web_remote_group_box) self.web_remote_layout.setObjectName('web_remote_layout') - self.current_version_label = QtWidgets.QLabel(self.web_remote_group_box) - self.web_remote_layout.addWidget(self.current_version_label, 0, 0) - self.current_version_label.setObjectName('current_version_label') - self.current_version_value = QtWidgets.QLabel(self.web_remote_group_box) - self.current_version_value.setObjectName('current_version_value') - self.web_remote_layout.addWidget(self.current_version_value, 0, 1) - self.upgrade_button = QtWidgets.QPushButton(self.web_remote_group_box) - self.upgrade_button.setEnabled(False) - self.upgrade_button.setObjectName('upgrade_button') - self.web_remote_layout.addWidget(self.upgrade_button, 0, 2) - self.master_version_label = QtWidgets.QLabel(self.web_remote_group_box) - self.master_version_label.setObjectName('master_version_label') - self.web_remote_layout.addWidget(self.master_version_label, 1, 0) - self.master_version_value = QtWidgets.QLabel(self.web_remote_group_box) - self.master_version_value.setObjectName('master_version_value') - self.web_remote_layout.addWidget(self.master_version_value, 1, 1) - self.check_version_button = QtWidgets.QPushButton(self.web_remote_group_box) - self.check_version_button.setObjectName('check_version_button') - self.web_remote_layout.addWidget(self.check_version_button, 1, 2) + self.installed_version_label = QtWidgets.QLabel(self.web_remote_group_box) + self.web_remote_layout.addWidget(self.installed_version_label, 0, 0) + self.installed_version_label.setObjectName('installed_version_label') + self.installed_version_value = QtWidgets.QLabel(self.web_remote_group_box) + self.installed_version_value.setObjectName('installed_version_value') + self.web_remote_layout.addWidget(self.installed_version_value, 0, 1) + self.check_for_updates_button = QtWidgets.QPushButton(self.web_remote_group_box) + self.check_for_updates_button.setObjectName('check_for_updates_button') + self.web_remote_layout.addWidget(self.check_for_updates_button, 0, 2) + self.available_version_label = QtWidgets.QLabel(self.web_remote_group_box) + self.available_version_label.setObjectName('available_version_label') + self.web_remote_layout.addWidget(self.available_version_label, 1, 0) + self.available_version_value = QtWidgets.QLabel(self.web_remote_group_box) + self.available_version_value.setObjectName('available_version_value') + self.web_remote_layout.addWidget(self.available_version_value, 1, 1) + self.install_button = QtWidgets.QPushButton(self.web_remote_group_box) + self.install_button.setEnabled(False) + self.install_button.setObjectName('install_button') + self.web_remote_layout.addWidget(self.install_button, 1, 2) self.left_layout.addWidget(self.web_remote_group_box) self.app_group_box = QtWidgets.QGroupBox(self.right_column) self.app_group_box.setObjectName('app_group_box') @@ -199,8 +200,8 @@ class ApiTab(SettingsTab): self.twelve_hour_check_box.stateChanged.connect(self.on_twelve_hour_check_box_changed) self.thumbnails_check_box.stateChanged.connect(self.on_thumbnails_check_box_changed) self.address_edit.textChanged.connect(self.set_urls) - self.upgrade_button.clicked.connect(self.on_upgrade_button_clicked) - self.check_version_button.clicked.connect(self.on_check_version_button_clicked) + self.install_button.clicked.connect(self.on_install_button_clicked) + self.check_for_updates_button.clicked.connect(self.on_check_for_updates_button_clicked) def retranslate_ui(self): self.tab_title_visible = translate('RemotePlugin.RemoteTab', 'Remote Interface') @@ -221,12 +222,13 @@ class ApiTab(SettingsTab): translate('RemotePlugin.RemoteTab', 'Scan the QR code to open the remote view on your mobile device')) self.user_login_group_box.setTitle(translate('RemotePlugin.RemoteTab', 'User Authentication')) self.web_remote_group_box.setTitle(translate('RemotePlugin.RemoteTab', 'Web Remote')) - self.check_version_button.setText(translate('RemotePlugin.RemoteTab', 'Check for Updates')) - self.upgrade_button.setText(translate('RemotePlugin.RemoteTab', 'Upgrade')) + self.check_for_updates_button.setText(translate('RemotePlugin.RemoteTab', 'Check for Updates')) + self.install_button.setText(translate('RemotePlugin.RemoteTab', 'Install')) self.user_id_label.setText(translate('RemotePlugin.RemoteTab', 'User id:')) self.password_label.setText(translate('RemotePlugin.RemoteTab', 'Password:')) - self.current_version_label.setText(translate('RemotePlugin.RemoteTab', 'Current version:')) - self.master_version_label.setText(translate('RemotePlugin.RemoteTab', 'Latest version:')) + self.installed_version_label.setText(translate('RemotePlugin.RemoteTab', 'Installed version:')) + self._not_installed_version = translate('RemotePlugin.RemoteTab', '(not installed)') + self.available_version_label.setText(translate('RemotePlugin.RemoteTab', 'Latest version:')) self._unknown_version = translate('RemotePlugin.RemoteTab', '(unknown)') self.server_state_group_box.setTitle(translate('RemotePlugin.RemoteTab', 'Server Status')) self.server_http_state_title.setText(translate('RemotePlugin.RemoteTab', 'HTTP Server:')) @@ -237,34 +239,49 @@ class ApiTab(SettingsTab): self._server_disabled = translate('RemotePlugin.RemoteTab', 'Disabled', 'Server is disabled') @property - def master_version(self): + def available_version(self): """ - Property getter for the remote master version + Property getter for the available version """ - return self._master_version + return self._available_version - @master_version.setter - def master_version(self, value): + @available_version.setter + def available_version(self, value): """ - Property setter for the remote master version + Property setter for the available version """ - self._master_version = value - self.master_version_value.setText(self._master_version or self._unknown_version) - self.upgrade_button.setEnabled(self.can_enable_upgrade_button()) + self._available_version = value + self.available_version_value.setText(self._available_version or self._unknown_version) + self.install_button.setEnabled(self.can_enable_install_button()) - def can_enable_upgrade_button(self): + @property + def installed_version(self): """ - Do a couple checks to set the upgrade button state + Property getter for the installed version """ - return self.master_version_value.text() != self._unknown_version and \ - self.master_version_value.text() != self.current_version_value.text() + return self._installed_version - def set_master_version(self): + @installed_version.setter + def installed_version(self, value): + """ + Property setter for the installed version + """ + self._installed_version = value + self.installed_version_value.setText(self._installed_version or self._not_installed_version) + + def can_enable_install_button(self): + """ + Do a couple checks to set the install button state + """ + return self.available_version_value.text() != self._unknown_version and \ + self.available_version_value.text() != self.installed_version_value.text() + + def validate_available_version(self): """ Check if the master version is not set, and set it to None to invoke the "unknown version" label """ - if not self._master_version: - self.master_version = None + if not self._available_version: + self.available_version = None def set_urls(self): """ @@ -281,7 +298,7 @@ class ApiTab(SettingsTab): image = QtGui.QPixmap.fromImage(img) self.app_qr_code_label.setPixmap(image) - def get_server_states(self): + def set_server_states(self): """ Update the display with the current state of the servers """ @@ -333,10 +350,13 @@ class ApiTab(SettingsTab): self.user_login_group_box.setChecked(self.settings.value('api/authentication enabled')) self.user_id.setText(self.settings.value('api/user id')) self.password.setText(self.settings.value('api/password')) - self.current_version_value.setText(self.settings.value('api/download version')) - self.set_master_version() + self.installed_version = get_installed_version() + # TODO: Left in for backwards compatibilty, remove eventually + if not self.installed_version: + self.installed_version = self.settings.value('api/download version') + self.validate_available_version() self.set_urls() - self.get_server_states() + self.set_server_states() def save(self): """ @@ -376,7 +396,7 @@ class ApiTab(SettingsTab): if check_state == QtCore.Qt.Checked: self.thumbnails = True - def on_check_version_button_clicked(self): + def on_check_for_updates_button_clicked(self): """ Check for the latest version on the server """ @@ -385,28 +405,31 @@ class ApiTab(SettingsTab): app.process_events() version_info = download_version_info() app.process_events() - self.master_version = version_info['latest']['version'] + self.available_version = version_info['latest']['version'] app.process_events() app.set_normal_cursor() app.process_events() - if self.can_enable_upgrade_button(): - Registry().get('main_window').information_message('New version available!', - 'There\'s a new version of the web remote available.') + if self.can_enable_install_button(): + Registry().get('main_window').information_message( + translate('OpenLP.APITab', 'New version available!'), + translate('OpenLP.APITab', 'There\'s a new version of the web remote available.') + ) - def on_upgrade_button_clicked(self): + def on_install_button_clicked(self): """ - Download/upgrade the web remote + Download/install the web remote """ app = Registry().get('application') progress = DownloadProgressDialog(self, app) progress.show() app.process_events() sleep(0.5) - downloaded_version = download_and_check(progress) + downloaded_version = download_and_install(progress) app.process_events() sleep(0.5) progress.close() app.process_events() - self.current_version_value.setText(downloaded_version) + self.installed_version = downloaded_version + # TODO: Left in for backwards compatibilty for versions of the remote prior to 0.9.8, and versions + # of OpenLP prior to 2.9.5. We need to remove this eventually. self.settings.setValue('api/download version', downloaded_version) - self.upgrade_button.setEnabled(self.can_enable_upgrade_button()) diff --git a/openlp/core/common/settings.py b/openlp/core/common/settings.py index c5984408a..6b1aa425a 100644 --- a/openlp/core/common/settings.py +++ b/openlp/core/common/settings.py @@ -208,7 +208,7 @@ class Settings(QtCore.QSettings): 'api/authentication enabled': False, 'api/ip address': '0.0.0.0', 'api/thumbnails': True, - 'api/download version': '0.0', + 'api/download version': None, 'api/last version test': '', 'api/update check': True, 'bibles/db type': 'sqlite', diff --git a/openlp/core/ui/firsttimeform.py b/openlp/core/ui/firsttimeform.py index 0ffa401d5..b08ef6c06 100644 --- a/openlp/core/ui/firsttimeform.py +++ b/openlp/core/ui/firsttimeform.py @@ -32,7 +32,7 @@ from tempfile import gettempdir from PyQt5 import QtCore, QtWidgets, QtGui -from openlp.core.api.deploy import get_latest_size, download_and_check +from openlp.core.api.deploy import get_latest_size, download_and_install from openlp.core.common import trace_error_handler from openlp.core.common.applocation import AppLocation from openlp.core.common.httputils import DownloadWorker, download_file, get_url_file_size, get_web_page @@ -539,7 +539,7 @@ class FirstTimeForm(QtWidgets.QWizard, UiFirstTimeWizard, RegistryProperties): if self.remote_page.can_download_remote: self._increment_progress_bar(self.downloading.format(name='Web Remote'), 0) self.previous_size = 0 - remote_version = download_and_check(self, can_update_range=False) + remote_version = download_and_install(self, can_update_range=False) if remote_version: self.settings.setValue('api/download version', remote_version) else: diff --git a/tests/openlp_core/api/test_deploy.py b/tests/openlp_core/api/test_deploy.py index f35dfb19b..9ca333881 100644 --- a/tests/openlp_core/api/test_deploy.py +++ b/tests/openlp_core/api/test_deploy.py @@ -22,7 +22,8 @@ import json from pathlib import Path from unittest.mock import MagicMock, patch -from openlp.core.api.deploy import REMOTE_URL, deploy_zipfile, download_version_info, download_and_check +from openlp.core.api.deploy import REMOTE_URL, deploy_zipfile, download_version_info, download_and_install, \ + get_installed_version CONFIG_FILE = '{"latest": {"version": "0.1", "filename": "remote-0.1.zip", "sha256": "", "size": 854039}}' @@ -100,15 +101,15 @@ def test_download_version_info(mocked_get_web_page, mocked_get_openlp_user_agent @patch('openlp.core.api.deploy.log.warning') @patch('openlp.core.api.deploy.download_version_info') -def test_download_and_check_log_warning(mocked_download_version_info, mocked_warning): +def test_download_and_install_log_warning(mocked_download_version_info, mocked_warning): """ Test that when the version info fails, a warning is logged """ # GIVEN: A few mocks, and a version info of None mocked_download_version_info.return_value = None - # WHEN: download_and_check is run - result = download_and_check(None) + # WHEN: download_and_install is run + result = download_and_install(None) # THEN: None is returned and a warning is logged assert result is None, 'The result should be None' @@ -118,8 +119,8 @@ def test_download_and_check_log_warning(mocked_download_version_info, mocked_war @patch('openlp.core.api.deploy.AppLocation.get_section_data_path') @patch('openlp.core.api.deploy.download_file') @patch('openlp.core.api.deploy.download_version_info') -def test_download_and_check_download_fails(mocked_download_version_info, mocked_download_file, - mocked_get_section_data_path): +def test_download_and_install_download_fails(mocked_download_version_info, mocked_download_file, + mocked_get_section_data_path): """ Test that when the version info fails, a warning is logged """ @@ -129,8 +130,8 @@ def test_download_and_check_download_fails(mocked_download_version_info, mocked_ mocked_download_file.return_value = False mocked_get_section_data_path.return_value = Path('.') - # WHEN: download_and_check is run - result = download_and_check(mocked_callback) + # WHEN: download_and_install is run + result = download_and_install(mocked_callback) # THEN: None is returned and a warning is logged assert result is None, 'The result should be None' @@ -140,8 +141,8 @@ def test_download_and_check_download_fails(mocked_download_version_info, mocked_ @patch('openlp.core.api.deploy.deploy_zipfile') @patch('openlp.core.api.deploy.download_file') @patch('openlp.core.api.deploy.download_version_info') -def test_download_and_check(mocked_download_version_info, mocked_download_file, mocked_deploy_zipfile, - mocked_get_section_data_path): +def test_download_and_install(mocked_download_version_info, mocked_download_file, mocked_deploy_zipfile, + mocked_get_section_data_path): # GIVEN: A bunch of mocks mocked_callback = MagicMock() mocked_download_version_info.return_value = CONFIG_DICT @@ -150,10 +151,60 @@ def test_download_and_check(mocked_download_version_info, mocked_download_file, mocked_remote_zip = mocked_remote_path / 'remote.zip' mocked_get_section_data_path.return_value = mocked_remote_path - # WHEN: download_and_check() is called - result = download_and_check(mocked_callback) + # WHEN: download_and_install() is called + result = download_and_install(mocked_callback) # THEN: The correct things should have been done assert result == CONFIG_DICT['latest']['version'], 'The correct version is returned' mocked_download_file.assert_called_once_with(mocked_callback, REMOTE_URL + '0.1/remote-0.1.zip', mocked_remote_zip) mocked_deploy_zipfile.assert_called_once_with(mocked_remote_path, 'remote.zip') + + +@patch('openlp.core.api.deploy.AppLocation.get_section_data_path') +def test_get_installed_version_not_installed(mocked_get_section_data_path): + """Test that if there is no remote installed, None is returned""" + # GIVEN: A mocked AppLocation and no file installed + mocked_version_file = MagicMock() + mocked_version_file.__truediv__.return_value = mocked_version_file + mocked_version_file.exists.return_value = False + mocked_get_section_data_path.return_value = mocked_version_file + + # WHEN: get_installed_version() is called but there is no version file + result = get_installed_version() + + # THEN: The result should be None + assert result is None + + +@patch('openlp.core.api.deploy.AppLocation.get_section_data_path') +def test_get_installed_version_no_version(mocked_get_section_data_path): + """Test that if there is no matching version number, None is returned""" + # GIVEN: A mocked AppLocation and no file installed + mocked_version_file = MagicMock() + mocked_version_file.__truediv__.return_value = mocked_version_file + mocked_version_file.exists.return_value = True + mocked_version_file.read.return_value = 'let app_version = 0.9.7;' + mocked_get_section_data_path.return_value = mocked_version_file + + # WHEN: get_installed_version() is called but there is no version in the file + result = get_installed_version() + + # THEN: The result should be None + assert result is None + + +@patch('openlp.core.api.deploy.AppLocation.get_section_data_path') +def test_get_installed_version(mocked_get_section_data_path): + """Test that get_installed_version returns the version number""" + # GIVEN: A mocked AppLocation and no file installed + mocked_version_file = MagicMock() + mocked_version_file.__truediv__.return_value = mocked_version_file + mocked_version_file.exists.return_value = True + mocked_version_file.read.return_value = 'let appVersion = \'0.9.7\';' + mocked_get_section_data_path.return_value = mocked_version_file + + # WHEN: get_installed_version() is called but there is no version file + result = get_installed_version() + + # THEN: The result should be None + assert result == '0.9.7' diff --git a/tests/openlp_core/api/test_tab.py b/tests/openlp_core/api/test_tab.py index a40d3bf3a..6a6cec739 100644 --- a/tests/openlp_core/api/test_tab.py +++ b/tests/openlp_core/api/test_tab.py @@ -24,6 +24,7 @@ This module contains tests for the lib submodule of the Remotes plugin. import hashlib import pytest import re +from unittest.mock import MagicMock, patch from PyQt5 import QtWidgets @@ -114,22 +115,217 @@ def test_address_revert_button_clicked(api_tab, settings): assert api_tab.address_edit.text() == settings.get_default_value('api/ip address') -def test_save(api_tab, settings): +@patch('openlp.core.api.tab.QtWidgets.QMessageBox.information') +def test_save(mocked_information, api_tab, registry, settings): """ - Test the IP revert function works + Test the save method works correctly """ - # GIVEN: The ip address text set to a non default value - api_tab.address_edit.setText(settings.value('api/ip address')) + # GIVEN: Various settings are set on the form and a mocked settings form + mocked_settings_form = MagicMock() + registry.remove('settings_form') + registry.register('settings_form', mocked_settings_form) + settings.setValue('api/ip address', '0.0.0.0') + api_tab.address_edit.setText('192.168.1.1') api_tab.twelve_hour = True api_tab.thumbnails = True api_tab.user_login_group_box.setChecked(True) api_tab.user_id.setText('user id thing') api_tab.password.setText('user password thing') + # WHEN: save is called api_tab.save() + # THEN: The text should have been changed to the default value + mocked_information.assert_called_once_with(api_tab, 'Restart Required', + 'This change will only take effect once OpenLP has been restarted.') + mocked_settings_form.register_post_process.called_once_with('remotes_config_updated') assert settings.value('api/twelve hour') is True assert settings.value('api/thumbnails') is True assert settings.value('api/authentication enabled') is True assert settings.value('api/user id') == 'user id thing' assert settings.value('api/password') == 'user password thing' + + +def test_available_version_property_get_none(api_tab): + """Test that the available version property is None on init""" + # GIVEN: An uninitialised API tab + + # WHEN: the available version is GET'ed + result = api_tab.available_version + + # THEN: The result is None + assert result is None + + +def test_available_version_property_set(api_tab): + """Test that the available version property is set correctly""" + # GIVEN: An uninitialised API tab + available_version = '0.9.7' + + # WHEN: the available version is SET + api_tab.available_version = available_version + + # THEN: The internal value should be set, and the right methods should have been called + assert api_tab._available_version == available_version + assert api_tab.available_version_value.text() == available_version + + +def test_available_version_property_set_none(api_tab): + """Test that the available version property is set correctly""" + # GIVEN: An uninitialised API tab + available_version = None + + # WHEN: the available version is SET + api_tab.available_version = available_version + + # THEN: The internal value should be set, and the right methods should have been called + assert api_tab._available_version == available_version + assert api_tab.available_version_value.text() == '(unknown)' + + +def test_installed_version_property_get_none(api_tab): + """Test that the installed version property is None on init""" + # GIVEN: An uninitialised API tab + + # WHEN: the installed version is GET'ed + result = api_tab.installed_version + + # THEN: The result is None + assert result is None + + +def test_installed_version_property_set(api_tab): + """Test that the installed version property is set correctly""" + # GIVEN: An uninitialised API tab + installed_version = '0.9.7' + + # WHEN: the installed version is SET + api_tab.installed_version = installed_version + + # THEN: The internal value should be set, and the right methods should have been called + assert api_tab._installed_version == installed_version + assert api_tab.installed_version_value.text() == installed_version + + +def test_installed_version_property_set_none(api_tab): + """Test that the installed version property is set correctly""" + # GIVEN: An uninitialised API tab + installed_version = None + + # WHEN: the installed version is SET + api_tab.installed_version = installed_version + + # THEN: The internal value should be set, and the right methods should have been called + assert api_tab._installed_version == installed_version + assert api_tab.installed_version_value.text() == '(not installed)' + + +def test_validate_available_version(api_tab): + """Test that the validate_available_version() method sets the label correctly""" + # GIVEN: An uninitialised API tab + + # WHEN: validate_available_version() is run + api_tab.validate_available_version() + + # THEN: The label should say "(unknown)" + assert api_tab.available_version_value.text() == '(unknown)' + + +@patch('openlp.core.api.tab.is_thread_finished') +def test_set_server_states_up(mock_is_thread_finished, registry, settings, api_tab): + """Test getting the server states when the servers are up""" + # GIVEN: An API tab and some mocks + mock_is_thread_finished.return_value = False + + # WHEN: set_server_states() is called + api_tab.set_server_states() + + # THEN: The servers should all be "up" + assert api_tab.server_http_state.text() == 'Active' + assert api_tab.server_websocket_state.text() == 'Active' + assert api_tab.server_zeroconf_state.text() == 'Active' + + +@patch('openlp.core.api.tab.is_thread_finished') +def test_set_server_states_disabled(mock_is_thread_finished, registry, settings, api_tab): + """Test getting the server states when the servers are disabled""" + # GIVEN: An API tab and some mocks + mock_is_thread_finished.return_value = True + registry.set_flag('no_web_server', True) + + # WHEN: set_server_states() is called + api_tab.set_server_states() + + # THEN: The servers should all be "up" + assert api_tab.server_http_state.text() == 'Disabled' + assert api_tab.server_websocket_state.text() == 'Disabled' + assert api_tab.server_zeroconf_state.text() == 'Disabled' + + +@patch('openlp.core.api.tab.is_thread_finished') +def test_set_server_states_down(mock_is_thread_finished, registry, settings, api_tab): + """Test getting the server states when the servers are down""" + # GIVEN: An API tab and some mocks + mock_is_thread_finished.return_value = True + registry.set_flag('no_web_server', False) + + # WHEN: set_server_states() is called + api_tab.set_server_states() + + # THEN: The servers should all be "up" + assert api_tab.server_http_state.text() == 'Failed' + assert api_tab.server_websocket_state.text() == 'Failed' + assert api_tab.server_zeroconf_state.text() == 'Failed' + + +@patch('openlp.core.api.tab.download_version_info') +def test_on_check_for_updates_button_clicked(mocked_download_version_info, mocked_qapp, registry, settings, api_tab): + """Test that the correct methods are called when the Check for Updates button is clicked""" + # GIVEN: An API tab and a couple of mocks + mocked_download_version_info.return_value = {'latest': {'version': '0.9.5'}} + mocked_main_window = MagicMock() + registry.register('main_window', mocked_main_window) + registry.remove('application') + registry.register('application', mocked_qapp) + + # WHEN: The Check for Updates button is clicked + with patch.object(api_tab, 'can_enable_install_button') as mocked_can_enable_install_button: + mocked_can_enable_install_button.return_value = True + api_tab.on_check_for_updates_button_clicked() + assert mocked_can_enable_install_button.call_count == 2 + + # THEN: The correct methods were called + mocked_qapp.set_busy_cursor.assert_called_once() + assert mocked_qapp.process_events.call_count == 4 + mocked_qapp.set_normal_cursor.assert_called_once() + mocked_download_version_info.assert_called_once() + mocked_main_window.information_message.assert_called_once_with( + 'New version available!', 'There\'s a new version of the web remote available.' + ) + assert api_tab.available_version == '0.9.5' + + +@patch('openlp.core.api.tab.DownloadProgressDialog') +@patch('openlp.core.api.tab.download_and_install') +@patch('openlp.core.api.tab.sleep') +def test_on_install_button_clicked(mocked_sleep, mocked_download_and_install, MockDownloadProgressDialog, + mocked_qapp, registry, settings, api_tab): + """Test that the correct methods are called when the Check for Updates button is clicked""" + # GIVEN: An API tab and a couple of mocks + mocked_download_and_install.return_value = '0.9.6' + mocked_progress = MagicMock() + MockDownloadProgressDialog.return_value = mocked_progress + registry.remove('application') + registry.register('application', mocked_qapp) + + # WHEN: The Check for Updates button is clicked + api_tab.on_install_button_clicked() + + # THEN: The correct methods were called + assert mocked_qapp.process_events.call_count == 3 + MockDownloadProgressDialog.assert_called_once_with(api_tab, mocked_qapp) + mocked_progress.show.assert_called_once() + mocked_progress.close.assert_called_once() + mocked_download_and_install.assert_called_once_with(mocked_progress) + assert api_tab.installed_version == '0.9.6' + assert settings.value('api/download version') == '0.9.6'