From 6f73ef21633b46cae1a384fbd56a8e85359ead92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marta=20Marczykowska-G=C3=B3recka?= Date: Tue, 15 Oct 2019 00:00:18 +0200 Subject: [PATCH] Fixed manager tests to use Qt5 Also due to old workarounds not working around anymore, switched over to "single QApplication object" model. --- qubesmanager/tests/__init__.py | 16 +++ qubesmanager/tests/test_backup.py | 65 ++++-------- qubesmanager/tests/test_backup_utils.py | 41 +++----- qubesmanager/tests/test_create_new_vm.py | 40 ++------ qubesmanager/tests/test_global_settings.py | 42 ++------ qubesmanager/tests/test_qube_manager.py | 110 ++++++++------------- qubesmanager/tests/test_vm_settings.py | 53 +++------- 7 files changed, 121 insertions(+), 246 deletions(-) diff --git a/qubesmanager/tests/__init__.py b/qubesmanager/tests/__init__.py index e69de29..4a0faa3 100644 --- a/qubesmanager/tests/__init__.py +++ b/qubesmanager/tests/__init__.py @@ -0,0 +1,16 @@ +import asyncio +import sys + +import quamash +from PyQt5 import QtWidgets + +qtapp = None +loop = None + +def init_qtapp(): + global qtapp, loop + if qtapp is None: + qtapp = QtWidgets.QApplication(sys.argv) + loop = quamash.QEventLoop(qtapp) + asyncio.set_event_loop(loop) + return qtapp, loop diff --git a/qubesmanager/tests/test_backup.py b/qubesmanager/tests/test_backup.py index 45f8b3c..341d1b5 100644 --- a/qubesmanager/tests/test_backup.py +++ b/qubesmanager/tests/test_backup.py @@ -20,21 +20,20 @@ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # import logging.handlers -import sys import unittest import unittest.mock -from PyQt4 import QtGui, QtTest, QtCore +from PyQt5 import QtTest, QtCore, QtWidgets from qubesadmin import Qubes, events, utils, exc from qubesmanager import backup -import quamash +from qubesmanager.tests import init_qtapp import asyncio -import gc class BackupTest(unittest.TestCase): def setUp(self): super(BackupTest, self).setUp() + self.qtapp, self.loop = init_qtapp() # mock up nonexistence of saved backup settings self.patcher_open = unittest.mock.patch('builtins.open') @@ -49,43 +48,16 @@ class BackupTest(unittest.TestCase): self.addCleanup(self.patcher_thread.stop) self.qapp = Qubes() - self.qtapp = QtGui.QApplication(["test", "-style", "cleanlooks"]) - self.dispatcher = events.EventsDispatcher(self.qapp) - self.loop = quamash.QEventLoop(self.qtapp) - self.dialog = backup.BackupVMsWindow( self.qtapp, self.qapp, self.dispatcher) - self.dialog.show() def tearDown(self): - self.dialog.hide() - # process any pending events before destroying the object + self.dialog.close() self.qtapp.processEvents() - - # queue destroying the QApplication object, do that for any other QT - # related objects here too - self.qtapp.deleteLater() - self.dialog.deleteLater() - - # process any pending events (other than just queued destroy), - # just in case - self.qtapp.processEvents() - - # execute main loop, which will process all events, _ - # including just queued destroy_ - self.loop.run_until_complete(asyncio.sleep(0)) - - # at this point it QT objects are destroyed, cleanup all remaining - # references; - # del other QT object here too - self.loop.close() - del self.dialog - del self.qtapp - del self.loop - gc.collect() + yield from asyncio.sleep(1) super(BackupTest, self).tearDown() def test_00_window_loads(self): @@ -106,16 +78,17 @@ class BackupTest(unittest.TestCase): "Compress backup should be checked by default") # correct VMs are selected - include_in_backups_no = len([vm for vm in self.qapp.domains - if not vm.features.get('internal', False) - and getattr(vm, 'include_in_backups', True)]) + include_in_backups_no = len( + [vm for vm in self.qapp.domains + if not vm.features.get('internal', False) + and getattr(vm, 'include_in_backups', True)]) selected_no = self.dialog.select_vms_widget.selected_list.count() self.assertEqual(include_in_backups_no, selected_no, "Incorrect VMs selected by default") # passphrase is empty self.assertEqual(self.dialog.passphrase_line_edit.text(), "", - "Passphrase should be empty") + "Passphrase should be empty") # save defaults self.assertTrue(self.dialog.save_profile_checkbox.isChecked(), @@ -399,7 +372,7 @@ class BackupTest(unittest.TestCase): self.assertTrue(self.dialog.unrecognized_config_label.isVisible()) @unittest.mock.patch('qubesmanager.backup_utils.load_backup_profile') - @unittest.mock.patch('PyQt4.QtGui.QMessageBox.information') + @unittest.mock.patch('PyQt5.QtWidgets.QMessageBox.information') def test_22_loading_settings_exc(self, mock_info, mock_load): mock_load.side_effect = exc.QubesException('Error') @@ -436,7 +409,7 @@ class BackupTest(unittest.TestCase): mock_remove.assert_called_once_with( '/etc/qubes/backup/qubes-manager-backup-tmp.conf') - @unittest.mock.patch('PyQt4.QtGui.QMessageBox.warning') + @unittest.mock.patch('PyQt5.QtWidgets.QMessageBox.warning') @unittest.mock.patch('qubesmanager.backup_utils.write_backup_profile') @unittest.mock.patch('qubesadmin.Qubes.qubesd_call', return_value=b'backup output') @@ -461,7 +434,7 @@ class BackupTest(unittest.TestCase): mock_remove.assert_called_once_with( '/etc/qubes/backup/qubes-manager-backup-tmp.conf') - @unittest.mock.patch('PyQt4.QtGui.QMessageBox.warning') + @unittest.mock.patch('PyQt5.QtWidgets.QMessageBox.warning') @unittest.mock.patch('os.system') @unittest.mock.patch('os.remove') @unittest.mock.patch('qubesmanager.backup_utils.write_backup_profile') @@ -501,7 +474,7 @@ class BackupTest(unittest.TestCase): self.assertEqual(mock_warning.call_count, 0, "Backup succeeded but received warning") - @unittest.mock.patch('PyQt4.QtGui.QMessageBox.warning') + @unittest.mock.patch('PyQt5.QtWidgets.QMessageBox.warning') @unittest.mock.patch('os.system') @unittest.mock.patch('os.remove') @unittest.mock.patch('qubesmanager.backup_utils.write_backup_profile') @@ -540,7 +513,7 @@ class BackupTest(unittest.TestCase): self.assertEqual(mock_warning.call_count, 0, "Backup succeeded but received warning") - @unittest.mock.patch('PyQt4.QtGui.QMessageBox.warning') + @unittest.mock.patch('PyQt5.QtWidgets.QMessageBox.warning') @unittest.mock.patch('os.system') @unittest.mock.patch('os.remove') @unittest.mock.patch('qubesmanager.backup_utils.write_backup_profile') @@ -578,14 +551,14 @@ class BackupTest(unittest.TestCase): "Attempted shutdown at failed backup") self.assertEqual(mock_warn.call_count, 1) - @unittest.mock.patch('PyQt4.QtGui.QMessageBox.warning') + @unittest.mock.patch('PyQt5.QtWidgets.QMessageBox.warning') @unittest.mock.patch('os.system') @unittest.mock.patch('os.remove') @unittest.mock.patch('qubesmanager.backup_utils.write_backup_profile') @unittest.mock.patch('qubesadmin.Qubes.qubesd_call', return_value=b'backup output') def test_28_progress( - self, _a, _b, mock_remove, mock_system, mock_warn): + self, _a, _b, _mock_remove, _mock_system, _mock_warn): self._click_next() self.assertTrue(self.dialog.currentPage() is self.dialog.select_dir_page) @@ -626,11 +599,11 @@ class BackupTest(unittest.TestCase): widget.setCurrentIndex(widget.currentIndex() + 1) def _click_next(self): - next_widget = self.dialog.button(QtGui.QWizard.NextButton) + next_widget = self.dialog.button(QtWidgets.QWizard.NextButton) QtTest.QTest.mouseClick(next_widget, QtCore.Qt.LeftButton) def _click_cancel(self): - cancel_widget = self.dialog.button(QtGui.QWizard.CancelButton) + cancel_widget = self.dialog.button(QtWidgets.QWizard.CancelButton) QtTest.QTest.mouseClick(cancel_widget, QtCore.Qt.LeftButton) def _select_vm(self, name_starts_with): diff --git a/qubesmanager/tests/test_backup_utils.py b/qubesmanager/tests/test_backup_utils.py index 13465e0..ae125c7 100644 --- a/qubesmanager/tests/test_backup_utils.py +++ b/qubesmanager/tests/test_backup_utils.py @@ -23,48 +23,31 @@ import logging.handlers import unittest.mock import quamash import asyncio -import gc -from PyQt4 import QtGui +import sys +from PyQt5 import QtWidgets from qubesadmin import Qubes from qubesmanager import backup_utils +qtapp = QtWidgets.QApplication(sys.argv) +loop = quamash.QEventLoop(qtapp) +asyncio.set_event_loop(loop) + class BackupUtilsTest(unittest.TestCase): def setUp(self): super(BackupUtilsTest, self).setUp() self.qapp = Qubes() - self.qtapp = QtGui.QApplication(["test", "-style", "cleanlooks"]) - self.loop = quamash.QEventLoop(self.qtapp) + self.loop = quamash.QEventLoop(qtapp) def tearDown(self): - # process any pending events before destroying the object - self.qtapp.processEvents() - - # queue destroying the QApplication object, do that for any other QT - # related objects here too - self.qtapp.deleteLater() - - # process any pending events (other than just queued destroy), - # just in case - self.qtapp.processEvents() - - # execute main loop, which will process all events, _ - # including just queued destroy_ - self.loop.run_until_complete(asyncio.sleep(0)) - - # at this point it QT objects are destroyed, cleanup all remaining - # references; - # del other QT object here too - self.loop.close() - del self.qtapp - del self.loop - gc.collect() + qtapp.processEvents() + yield from loop.sleep(1) super(BackupUtilsTest, self).tearDown() def test_01_fill_apvms(self): - dialog = QtGui.QDialog() - combobox = QtGui.QComboBox() + dialog = QtWidgets.QDialog() + combobox = QtWidgets.QComboBox() dialog.appvm_combobox = combobox dialog.qubes_app = self.qapp @@ -87,8 +70,6 @@ class BackupUtilsTest(unittest.TestCase): "VM list not filled correctly") - - if __name__ == "__main__": ha_syslog = logging.handlers.SysLogHandler('/dev/log') ha_syslog.setFormatter( diff --git a/qubesmanager/tests/test_create_new_vm.py b/qubesmanager/tests/test_create_new_vm.py index 878ee61..06d836f 100644 --- a/qubesmanager/tests/test_create_new_vm.py +++ b/qubesmanager/tests/test_create_new_vm.py @@ -20,25 +20,22 @@ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # import logging.handlers -import quamash -import asyncio import unittest import unittest.mock import qubesadmin -import gc -from PyQt4 import QtGui, QtTest, QtCore +from PyQt5 import QtTest, QtCore from qubesadmin import Qubes +from qubesmanager.tests import init_qtapp from qubesmanager import create_new_vm class NewVmTest(unittest.TestCase): def setUp(self): super(NewVmTest, self).setUp() + self.qtapp, self.loop = init_qtapp() self.qapp = Qubes() - self.qtapp = QtGui.QApplication(["test", "-style", "cleanlooks"]) - self.loop = quamash.QEventLoop(self.qtapp) # mock up the Create VM Thread to avoid changing system state self.patcher_thread = unittest.mock.patch( @@ -48,39 +45,16 @@ class NewVmTest(unittest.TestCase): # mock the progress dialog to speed testing up self.patcher_progress = unittest.mock.patch( - 'PyQt4.QtGui.QProgressDialog') + 'PyQt5.QtWidgets.QProgressDialog') self.mock_progress = self.patcher_progress.start() self.addCleanup(self.patcher_progress.stop) - self.dialog = create_new_vm.NewVmDlg( - self.qtapp, self.qapp) + self.dialog = create_new_vm.NewVmDlg(self.qtapp, self.qapp) def tearDown(self): - # process any pending events before destroying the object + self.dialog.close() self.qtapp.processEvents() - - # queue destroying the QApplication object, do that for any other QT - # related objects here too - self.qtapp.deleteLater() - self.dialog.deleteLater() - - # process any pending events (other than just queued destroy), - # just in case - self.qtapp.processEvents() - - # execute main loop, which will process all events, _ - # including just queued destroy_ - self.loop.run_until_complete(asyncio.sleep(0)) - - # at this point it QT objects are destroyed, cleanup all remaining - # references; - # del other QT object here too - self.loop.close() - del self.dialog - del self.qtapp - del self.loop - gc.collect() - + yield from self.loop.sleep(1) super(NewVmTest, self).tearDown() def test_00_window_loads(self): diff --git a/qubesmanager/tests/test_global_settings.py b/qubesmanager/tests/test_global_settings.py index b9bc167..9e17be8 100644 --- a/qubesmanager/tests/test_global_settings.py +++ b/qubesmanager/tests/test_global_settings.py @@ -20,24 +20,21 @@ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # import logging.handlers -import quamash -import asyncio import unittest import unittest.mock -import gc -from PyQt4 import QtGui, QtTest, QtCore +from PyQt5 import QtTest, QtCore, QtWidgets from qubesadmin import Qubes +from qubesmanager.tests import init_qtapp import qubesmanager.global_settings as global_settings class GlobalSettingsTest(unittest.TestCase): def setUp(self): super(GlobalSettingsTest, self).setUp() + self.qtapp, self.loop = init_qtapp() self.qapp = Qubes() - self.qtapp = QtGui.QApplication(["test", "-style", "cleanlooks"]) - self.loop = quamash.QEventLoop(self.qtapp) self.dialog = global_settings.GlobalSettingsWindow(self.qtapp, self.qapp) @@ -47,30 +44,9 @@ class GlobalSettingsTest(unittest.TestCase): self.addCleanup(self.setattr_patcher.stop) def tearDown(self): - # process any pending events before destroying the object + self.dialog.close() self.qtapp.processEvents() - - # queue destroying the QApplication object, do that for any other QT - # related objects here too - self.qtapp.deleteLater() - self.dialog.deleteLater() - - # process any pending events (other than just queued destroy), - # just in case - self.qtapp.processEvents() - - # execute main loop, which will process all events, _ - # including just queued destroy_ - self.loop.run_until_complete(asyncio.sleep(0)) - - # at this point it QT objects are destroyed, cleanup all remaining - # references; - # del other QT object here too - self.loop.close() - del self.dialog - del self.qtapp - del self.loop - gc.collect() + yield from self.loop.sleep(1) super(GlobalSettingsTest, self).tearDown() def test_00_settings_started(self): @@ -290,8 +266,8 @@ class GlobalSettingsTest(unittest.TestCase): self.setattr_mock.assert_called_once_with('check_updates_vm', not current_state) - @unittest.mock.patch("PyQt4.QtGui.QMessageBox.question", - return_value=QtGui.QMessageBox.Yes) + @unittest.mock.patch("PyQt5.QtWidgets.QMessageBox.question", + return_value=QtWidgets.QMessageBox.Yes) @unittest.mock.patch('qubesadmin.features.Features.__setitem__') def test_72_set_all_vms_true(self, mock_features, msgbox): @@ -308,8 +284,8 @@ class GlobalSettingsTest(unittest.TestCase): self.assertListEqual(call_list_expected, mock_features.call_args_list) - @unittest.mock.patch("PyQt4.QtGui.QMessageBox.question", - return_value=QtGui.QMessageBox.Yes) + @unittest.mock.patch("PyQt5.QtWidgets.QMessageBox.question", + return_value=QtWidgets.QMessageBox.Yes) @unittest.mock.patch('qubesadmin.features.Features.__setitem__') def test_73_set_all_vms_false(self, mock_features, msgbox): diff --git a/qubesmanager/tests/test_qube_manager.py b/qubesmanager/tests/test_qube_manager.py index 03bca2b..92f62e2 100644 --- a/qubesmanager/tests/test_qube_manager.py +++ b/qubesmanager/tests/test_qube_manager.py @@ -22,64 +22,39 @@ import asyncio import contextlib import logging.handlers -import sys import unittest import unittest.mock -import gc import subprocess import datetime import time -import quamash -from PyQt4 import QtGui, QtTest, QtCore +from PyQt5 import QtTest, QtCore, QtWidgets from qubesadmin import Qubes, events, exc import qubesmanager.qube_manager as qube_manager - +from qubesmanager.tests import init_qtapp class QubeManagerTest(unittest.TestCase): def setUp(self): super(QubeManagerTest, self).setUp() + self.qtapp, self.loop = init_qtapp() - self.mock_qprogress = unittest.mock.patch('PyQt4.QtGui.QProgressDialog') + self.mock_qprogress = unittest.mock.patch( + 'PyQt5.QtWidgets.QProgressDialog') self.mock_qprogress.start() self.addCleanup(self.mock_qprogress.stop) self.qapp = Qubes() - self.qtapp = QtGui.QApplication(["test", "-style", "cleanlooks"]) self.dispatcher = events.EventsDispatcher(self.qapp) - self.loop = quamash.QEventLoop(self.qtapp) - self.dialog = qube_manager.VmManagerWindow( self.qtapp, self.qapp, self.dispatcher) def tearDown(self): - # process any pending events before destroying the object + self.dialog.close() self.qtapp.processEvents() - - # queue destroying the QApplication object, do that for any other QT - # related objects here too - self.qtapp.deleteLater() - self.dialog.deleteLater() - - # process any pending events (other than just queued destroy), - # just in case - self.qtapp.processEvents() - - # execute main loop, which will process all events, _ - # including just queued destroy_ - self.loop.run_until_complete(asyncio.sleep(0)) - - # at this point it QT objects are destroyed, cleanup all remaining - # references; - # del other QT object here too - self.loop.close() - del self.dialog - del self.qtapp - del self.loop - gc.collect() + yield from self.loop.sleep(1) super(QubeManagerTest, self).tearDown() def test_000_window_loads(self): @@ -262,8 +237,9 @@ class QubeManagerTest(unittest.TestCase): mock_settings.side_effect = ( lambda x, *args, **kwargs: settings_result_dict.get(x)) - with unittest.mock.patch('PyQt4.QtCore.QSettings.value', mock_settings),\ - unittest.mock.patch('PyQt4.QtGui.QMessageBox.warning')\ + with unittest.mock.patch('PyQt5.QtCore.QSettings.value', + mock_settings),\ + unittest.mock.patch('PyQt5.QtWidgets.QMessageBox.warning')\ as mock_warning: self.dialog = qube_manager.VmManagerWindow( self.qtapp, self.qapp, self.dispatcher) @@ -357,8 +333,8 @@ class QubeManagerTest(unittest.TestCase): self.assertFalse(self.dialog.action_set_keyboard_layout.isEnabled()) - @unittest.mock.patch("PyQt4.QtGui.QMessageBox.question", - return_value=QtGui.QMessageBox.Yes) + @unittest.mock.patch("PyQt5.QtWidgets.QMessageBox.question", + return_value=QtWidgets.QMessageBox.Yes) def test_207_update_vm_not_running(self, _): selected_vm = self._select_templatevm(running=False) self.assertIsNotNone(selected_vm, "No valid template VM found") @@ -387,7 +363,7 @@ class QubeManagerTest(unittest.TestCase): mock_update.assert_called_once_with(selected_vm) mock_update().start.assert_called_once_with() - @unittest.mock.patch("PyQt4.QtGui.QInputDialog.getText", + @unittest.mock.patch("PyQt5.QtWidgets.QInputDialog.getText", return_value=("command to run", True)) def test_209_run_command_in_vm(self, _): selected_vm = self._select_non_admin_vm() @@ -408,7 +384,7 @@ class QubeManagerTest(unittest.TestCase): self.assertFalse(self.dialog.action_run_command_in_vm.isEnabled(), "Should not be able to run commands for dom0") - @unittest.mock.patch("PyQt4.QtGui.QMessageBox.warning") + @unittest.mock.patch("PyQt5.QtWidgets.QMessageBox.warning") def test_211_pausevm(self, mock_warn): selected_vm = self._select_non_admin_vm(running=True) @@ -446,9 +422,9 @@ class QubeManagerTest(unittest.TestCase): self._select_non_admin_vm(running=True) self.assertFalse(self.dialog.action_resumevm.isEnabled()) - @unittest.mock.patch("PyQt4.QtGui.QMessageBox.question", - return_value=QtGui.QMessageBox.Yes) - @unittest.mock.patch('PyQt4.QtCore.QTimer.singleShot') + @unittest.mock.patch("PyQt5.QtWidgets.QMessageBox.question", + return_value=QtWidgets.QMessageBox.Yes) + @unittest.mock.patch('PyQt5.QtCore.QTimer.singleShot') @unittest.mock.patch('qubesmanager.qube_manager.VmShutdownMonitor') def test_214_shutdownvm(self, mock_monitor, mock_timer, _): selected_vm = self._select_non_admin_vm(running=True) @@ -484,7 +460,7 @@ class QubeManagerTest(unittest.TestCase): self.assertFalse(self.dialog.action_removevm.isEnabled()) - @unittest.mock.patch("PyQt4.QtGui.QMessageBox") + @unittest.mock.patch("PyQt5.QtWidgets.QMessageBox") @unittest.mock.patch('qubesadmin.utils.vm_dependencies') def test_218_remove_vm_dependencies(self, mock_dependencies, mock_msgbox): action = self.dialog.action_removevm @@ -496,8 +472,8 @@ class QubeManagerTest(unittest.TestCase): action.trigger() mock_msgbox().show.assert_called_with() - @unittest.mock.patch('PyQt4.QtGui.QMessageBox.warning') - @unittest.mock.patch("PyQt4.QtGui.QInputDialog.getText") + @unittest.mock.patch('PyQt5.QtWidgets.QMessageBox.warning') + @unittest.mock.patch("PyQt5.QtWidgets.QInputDialog.getText") @unittest.mock.patch('qubesadmin.utils.vm_dependencies') def test_219_remove_vm_no_depencies( self, mock_dependencies, mock_input, mock_warning): @@ -531,10 +507,10 @@ class QubeManagerTest(unittest.TestCase): self._select_non_admin_vm(running=False) self.assertFalse(self.dialog.action_restartvm.isEnabled()) - @unittest.mock.patch('PyQt4.QtCore.QTimer.singleShot') + @unittest.mock.patch('PyQt5.QtCore.QTimer.singleShot') @unittest.mock.patch('qubesmanager.qube_manager.VmShutdownMonitor') - @unittest.mock.patch("PyQt4.QtGui.QMessageBox.question", - return_value=QtGui.QMessageBox.Yes) + @unittest.mock.patch("PyQt5.QtWidgets.QMessageBox.question", + return_value=QtWidgets.QMessageBox.Yes) def test_221_restartvm_running_vm(self, _msgbox, mock_monitor, _qtimer): selected_vm = self._select_non_admin_vm(running=True) @@ -550,8 +526,8 @@ class QubeManagerTest(unittest.TestCase): unittest.mock.ANY, True, unittest.mock.ANY) @unittest.mock.patch('qubesmanager.qube_manager.StartVMThread') - @unittest.mock.patch("PyQt4.QtGui.QMessageBox.question", - return_value=QtGui.QMessageBox.Yes) + @unittest.mock.patch("PyQt5.QtWidgets.QMessageBox.question", + return_value=QtWidgets.QMessageBox.Yes) def test_222_restartvm_shutdown_meantime(self, _, mock_thread): selected_vm = self._select_non_admin_vm(running=True) @@ -577,8 +553,8 @@ class QubeManagerTest(unittest.TestCase): self.dialog.clear_threads) mock_thread().start.assert_called_once_with() - @unittest.mock.patch("PyQt4.QtGui.QMessageBox.question", - return_value=QtGui.QMessageBox.Yes) + @unittest.mock.patch("PyQt5.QtWidgets.QMessageBox.question", + return_value=QtWidgets.QMessageBox.Yes) @unittest.mock.patch('qubesmanager.qube_manager.UpdateVMThread') def test_224_updatevm_halted(self, mock_thread, _): selected_vm = self._select_non_admin_vm(running=False) @@ -590,8 +566,8 @@ class QubeManagerTest(unittest.TestCase): self.dialog.clear_threads) mock_thread().start.assert_called_once_with() - @unittest.mock.patch("PyQt4.QtGui.QMessageBox.question", - return_value=QtGui.QMessageBox.Yes) + @unittest.mock.patch("PyQt5.QtWidgets.QMessageBox.question", + return_value=QtWidgets.QMessageBox.Yes) def test_224_killvm(self, _): selected_vm = self._select_non_admin_vm(running=True) action = self.dialog.action_killvm @@ -600,8 +576,8 @@ class QubeManagerTest(unittest.TestCase): action.trigger() mock_kill.assert_called_once_with() - @unittest.mock.patch("PyQt4.QtGui.QMessageBox.question", - return_value=QtGui.QMessageBox.Cancel) + @unittest.mock.patch("PyQt5.QtWidgets.QMessageBox.question", + return_value=QtWidgets.QMessageBox.Cancel) def test_225_killvm_cancel(self, _): selected_vm = self._select_non_admin_vm(running=True) action = self.dialog.action_killvm @@ -659,7 +635,7 @@ class QubeManagerTest(unittest.TestCase): mock_subprocess.assert_called_once_with('qubes-template-manager') @unittest.mock.patch('qubesmanager.common_threads.CloneVMThread') - @unittest.mock.patch('PyQt4.QtGui.QInputDialog.getText') + @unittest.mock.patch('PyQt5.QtWidgets.QInputDialog.getText') def test_232_clonevm(self, mock_input, mock_thread): action = self.dialog.action_clonevm @@ -714,7 +690,7 @@ class QubeManagerTest(unittest.TestCase): "Incorrect number of vms shown for cleared search box") def test_235_hide_show_toolbars(self): - with unittest.mock.patch('PyQt4.QtCore.QSettings.setValue')\ + with unittest.mock.patch('PyQt5.QtCore.QSettings.setValue')\ as mock_setvalue: self.dialog.action_menubar.trigger() mock_setvalue.assert_called_with('view/menubar_visible', False) @@ -741,8 +717,8 @@ class QubeManagerTest(unittest.TestCase): self.assertEqual(expected_number, actual_number, "Incorrect number of vms shown for cleared search box") - @unittest.mock.patch('PyQt4.QtGui.QMessageBox.information') - @unittest.mock.patch('PyQt4.QtGui.QMessageBox.warning') + @unittest.mock.patch('PyQt5.QtWidgets.QMessageBox.information') + @unittest.mock.patch('PyQt5.QtWidgets.QMessageBox.warning') def test_300_clear_threads(self, mock_warning, mock_info): mock_thread_finished_ok = unittest.mock.Mock( spec=['isFinished', 'msg', 'msg_is_success'], @@ -1422,8 +1398,8 @@ class QubeManagerThreadTest(unittest.TestCase): class VMShutdownMonitorTest(unittest.TestCase): - @unittest.mock.patch('PyQt4.QtGui.QMessageBox.question') - @unittest.mock.patch('PyQt4.QtCore.QTimer') + @unittest.mock.patch('PyQt5.QtWidgets.QMessageBox.question') + @unittest.mock.patch('PyQt5.QtCore.QTimer') def test_01_vm_shutdown_correct(self, mock_timer, mock_question): mock_vm = unittest.mock.Mock() mock_vm.is_running.return_value = False @@ -1437,9 +1413,9 @@ class VMShutdownMonitorTest(unittest.TestCase): self.assertEqual(mock_timer.call_count, 0) monitor.restart_vm_if_needed.assert_called_once_with() - @unittest.mock.patch('PyQt4.QtGui.QMessageBox.question', + @unittest.mock.patch('PyQt5.QtWidgets.QMessageBox.question', return_value=1) - @unittest.mock.patch('PyQt4.QtCore.QTimer.singleShot') + @unittest.mock.patch('PyQt5.QtCore.QTimer.singleShot') def test_02_vm_not_shutdown_wait(self, mock_timer, mock_question): mock_vm = unittest.mock.Mock() mock_vm.is_running.return_value = True @@ -1453,9 +1429,9 @@ class VMShutdownMonitorTest(unittest.TestCase): self.assertEqual(mock_question.call_count, 1) self.assertEqual(mock_timer.call_count, 1) - @unittest.mock.patch('PyQt4.QtGui.QMessageBox.question', + @unittest.mock.patch('PyQt5.QtWidgets.QMessageBox.question', return_value=0) - @unittest.mock.patch('PyQt4.QtCore.QTimer.singleShot') + @unittest.mock.patch('PyQt5.QtCore.QTimer.singleShot') def test_03_vm_kill(self, mock_timer, mock_question): mock_vm = unittest.mock.Mock() mock_vm.is_running.return_value = True @@ -1472,9 +1448,9 @@ class VMShutdownMonitorTest(unittest.TestCase): mock_vm.kill.assert_called_once_with() monitor.restart_vm_if_needed.assert_called_once_with() - @unittest.mock.patch('PyQt4.QtGui.QMessageBox.question', + @unittest.mock.patch('PyQt5.QtWidgets.QMessageBox.question', return_value=0) - @unittest.mock.patch('PyQt4.QtCore.QTimer.singleShot') + @unittest.mock.patch('PyQt5.QtCore.QTimer.singleShot') def test_04_check_later(self, mock_timer, mock_question): mock_vm = unittest.mock.Mock() mock_vm.is_running.return_value = True diff --git a/qubesmanager/tests/test_vm_settings.py b/qubesmanager/tests/test_vm_settings.py index 3a15c5b..d5ca782 100644 --- a/qubesmanager/tests/test_vm_settings.py +++ b/qubesmanager/tests/test_vm_settings.py @@ -24,56 +24,35 @@ import unittest import unittest.mock import gc -import quamash import asyncio -from PyQt4 import QtGui, QtTest, QtCore +from PyQt5 import QtTest, QtCore, QtWidgets from qubesadmin import Qubes import qubesmanager.settings as vm_settings +from qubesmanager.tests import init_qtapp class VMSettingsTest(unittest.TestCase): def setUp(self): super(VMSettingsTest, self).setUp() + self.qtapp, self.loop = init_qtapp() - self.mock_qprogress = unittest.mock.patch('PyQt4.QtGui.QProgressDialog') + self.mock_qprogress = unittest.mock.patch( + 'PyQt5.QtWidgets.QProgressDialog') self.mock_qprogress.start() self.addCleanup(self.mock_qprogress.stop) self.qapp = Qubes() - self.qtapp = QtGui.QApplication(["test", "-style", "cleanlooks"]) - self.loop = quamash.QEventLoop(self.qtapp) + + if "testvm" in self.qapp.domains: + del self.qapp.domains["testvm"] def tearDown(self): del self.qapp.domains["testvm"] - - # process any pending events before destroying the object self.qtapp.processEvents() + yield from self.loop.sleep(1) - # queue destroying the QApplication object, do that for any other QT - # related objects here too - self.dialog.deleteLater() - self.qtapp.deleteLater() - - # process any pending events (other than just queued destroy), - # just in case - self.qtapp.processEvents() - self.qtapp.processEvents() - self.qtapp.processEvents() - - # execute main loop, which will process all events, _ - # including just queued destroy_ - self.loop.run_until_complete(asyncio.sleep(0)) - - # at this point it QT objects are destroyed, cleanup all remaining - # references; - # del other QT object here too - self.loop.close() - del self.dialog - del self.qtapp - del self.loop - gc.collect() super(VMSettingsTest, self).tearDown() def test_00_load_correct_tab(self): @@ -325,8 +304,8 @@ class VMSettingsTest(unittest.TestCase): # TODO are dependencies correctly processed - @unittest.mock.patch('PyQt4.QtGui.QProgressDialog') - @unittest.mock.patch('PyQt4.QtGui.QInputDialog.getText') + @unittest.mock.patch('PyQt5.QtWidgets.QProgressDialog') + @unittest.mock.patch('PyQt5.QtWidgets.QInputDialog.getText') @unittest.mock.patch('qubesmanager.settings.RenameVMThread') def test_11_rename_vm(self, mock_thread, mock_input, _): self.vm = self.qapp.add_new_vm("AppVM", "testvm", "blue") @@ -343,8 +322,8 @@ class VMSettingsTest(unittest.TestCase): # TODO: thread tests for rename - @unittest.mock.patch('PyQt4.QtGui.QProgressDialog') - @unittest.mock.patch('PyQt4.QtGui.QInputDialog.getText') + @unittest.mock.patch('PyQt5.QtWidgets.QProgressDialog') + @unittest.mock.patch('PyQt5.QtWidgets.QInputDialog.getText') @unittest.mock.patch('qubesmanager.common_threads.CloneVMThread') def test_12_clone_vm(self, mock_thread, mock_input, _): self.vm = self.qapp.add_new_vm("AppVM", "testvm", "blue") @@ -359,9 +338,9 @@ class VMSettingsTest(unittest.TestCase): mock_thread.assert_called_with(self.vm, "testvm2") mock_thread().start.assert_called_with() - @unittest.mock.patch('PyQt4.QtGui.QMessageBox.warning') - @unittest.mock.patch('PyQt4.QtGui.QProgressDialog') - @unittest.mock.patch('PyQt4.QtGui.QInputDialog.getText') + @unittest.mock.patch('PyQt5.QtWidgets.QMessageBox.warning') + @unittest.mock.patch('PyQt5.QtWidgets.QProgressDialog') + @unittest.mock.patch('PyQt5.QtWidgets.QInputDialog.getText') @unittest.mock.patch('qubesmanager.common_threads.RemoveVMThread') def test_13_remove_vm(self, mock_thread, mock_input, _, mock_warning): self.vm = self.qapp.add_new_vm("AppVM", "testvm", "blue")