diff --git a/qubesmanager/tests/__init__.py b/qubesmanager/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/qubesmanager/tests/test_global_settings.py b/qubesmanager/tests/test_global_settings.py new file mode 100644 index 0000000..e489d11 --- /dev/null +++ b/qubesmanager/tests/test_global_settings.py @@ -0,0 +1,331 @@ +#!/usr/bin/python3 +# +# The Qubes OS Project, https://www.qubes-os.org/ +# +# Copyright (C) 2016 Marek Marczykowski-Górecki +# +# +# 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; either version 2 of the License, or +# (at your option) any later version. +# +# 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., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +import logging.handlers +import sys +import unittest +import unittest.mock + +import time +from PyQt4 import QtGui, QtTest, QtCore +from qubesadmin import Qubes +from qubes.tests import SystemTestCase +import qubesmanager.global_settings as global_settings +import concurrent.futures + + +def wrap_in_loop(func): + def wrapped(self): + self.loop.run_until_complete( + self.loop.run_in_executor(self.executor, + func, self)) + return wrapped + + +class GlobalSettingsTest(SystemTestCase): + def setUp(self): + super(GlobalSettingsTest, self).setUp() + + self.qtapp = QtGui.QApplication(sys.argv) + self.executor = concurrent.futures.ThreadPoolExecutor(max_workers=1) + self.setUpInExecutor() + + @wrap_in_loop + def setUpInExecutor(self): + self.qapp = Qubes() + self.dialog = global_settings.GlobalSettingsWindow( + self.qtapp, self.qapp) + + def tearDown(self): + self.tearDownInExecutor() + super(GlobalSettingsTest, self).tearDown() + + @wrap_in_loop + def tearDownInExecutor(self): + del self.dialog + del self.qtapp + + @wrap_in_loop + def test_settings_started(self): + # non-empty drop-downs + self.assertNotEqual( + self.dialog.default_kernel_combo.currentText(), "") + self.assertNotEqual( + self.dialog.default_netvm_combo.currentText(), "") + self.assertNotEqual( + self.dialog.default_template_combo.currentText(), + "") + self.assertNotEqual( + self.dialog.clock_vm_combo.currentText(), "") + self.assertNotEqual( + self.dialog.update_vm_combo.currentText(), "") + + @wrap_in_loop + def test_load_correct_defs(self): + # correctly selected default template + selected_default_template = \ + self.dialog.default_template_combo.currentText() + self.assertTrue( + selected_default_template.startswith( + self.app.default_template.name)) + + # correctly selected default NetVM + selected_default_netvm = \ + self.dialog.default_netvm_combo.currentText() + self.assertTrue(selected_default_netvm.startswith( + self.app.default_netvm.name)) + + # correctly selected default kernel + selected_default_kernel = \ + self.dialog.default_kernel_combo.currentText() + self.assertTrue(selected_default_kernel.startswith( + self.app.default_kernel)) + + # correct ClockVM + selected_clockvm = \ + self.dialog.clock_vm_combo.currentText() + correct_clockvm = self.app.clockvm.name if self.app.clockvm \ + else "(none)" + self.assertTrue(selected_clockvm.startswith(correct_clockvm)) + + # correct updateVM + selected_updatevm = \ + self.dialog.update_vm_combo.currentText() + correct_updatevm = \ + self.app.updatevm.name if self.app.updatevm else "(none)" + self.assertTrue(selected_updatevm.startswith(correct_updatevm)) + + # update vm status + self.assertEqual(self.app.check_updates_vm, + self.dialog.updates_vm.isChecked()) + + def test_dom0_updates_load(self): + # check dom0 updates + try: + dom0_updates = self.app.check_updates_dom0 + except AttributeError: + self.skipTest("check_updates_dom0 property not implemented") + return + + self.assertEqual(dom0_updates, self.dialog.updates_dom0.isChecked()) + + def __set_noncurrent(self, widget): + if widget.count() < 2: + self.skipTest("not enough choices for " + widget.objectName()) + + widget.setCurrentIndex(0) + while widget.currentText().endswith("(current)") \ + or widget.currentText().startswith("(none)"): + widget.setCurrentIndex(widget.currentIndex() + 1) + + return widget.currentText() + + def __set_none(self, widget): + widget.setCurrentIndex(0) + while not widget.currentText().startswith("(none)"): + if widget.currentIndex() == widget.count(): + self.skipTest("none not available for " + widget.objectName()) + widget.setCurrentIndex(widget.currentIndex() + 1) + + def __click_ok(self): + okwidget = self.dialog.buttonBox.button( + self.dialog.buttonBox.Ok) + + QtTest.QTest.mouseClick(okwidget, + QtCore.Qt.LeftButton) + + @wrap_in_loop + def test_set_update_vm(self): + new_updatevm_name = self.__set_noncurrent(self.dialog.update_vm_combo) + self.__click_ok() + + self.assertEqual(self.app.updatevm.name, new_updatevm_name) + + @wrap_in_loop + def test_set_update_vm_to_none(self): + self.__set_none(self.dialog.update_vm_combo) + self.__click_ok() + + self.assertIsNone(self.app.updatevm) + + @wrap_in_loop + def test_set_update_vm_to_none2(self): + self.app.updatevm = None + self.dialog = global_settings.GlobalSettingsWindow( + self.qtapp, self.qapp) + + self.assertEqual(self.dialog.update_vm_combo.currentText(), + "(none) (current)") + + @wrap_in_loop + def test_set_clock_vm(self): + new_clockvm_name = self.__set_noncurrent(self.dialog.clock_vm_combo) + self.__click_ok() + + self.assertEqual(self.app.clockvm.name, new_clockvm_name) + + @wrap_in_loop + def test_set_clock_vm_to_none(self): + self.__set_none(self.dialog.clock_vm_combo) + self.__click_ok() + + self.assertIsNone(self.app.clockvm) + + @wrap_in_loop + def test_set_clock_vm_to_none2(self): + self.app.clockvm = None + self.dialog = global_settings.GlobalSettingsWindow( + self.qtapp, self.qapp) + + self.assertEqual(self.dialog.clock_vm_combo.currentText(), + "(none) (current)") + + @wrap_in_loop + def test_set_default_netvm(self): + new_netvm_name = self.__set_noncurrent(self.dialog.default_netvm_combo) + self.__click_ok() + + self.assertEqual(self.app.default_netvm.name, new_netvm_name) + + @wrap_in_loop + def test_set_default_netvm_to_none(self): + self.__set_none(self.dialog.default_netvm_combo) + self.__click_ok() + + self.assertIsNone(self.app.default_netvm) + + @wrap_in_loop + def test_set_default_netvm_to_none2(self): + self.app.default_netvm = None + self.dialog = global_settings.GlobalSettingsWindow( + self.qtapp, self.qapp) + + self.assertEqual(self.dialog.default_netvm_combo.currentText(), + "(none) (current)") + + @wrap_in_loop + def test_set_default_template(self): + new_def_template_name = self.__set_noncurrent( + self.dialog.default_template_combo) + self.__click_ok() + + self.assertEqual(self.app.default_template.name, new_def_template_name) + + @wrap_in_loop + def test_set_default_kernel(self): + new_def_kernel_name = self.__set_noncurrent( + self.dialog.default_kernel_combo) + self.__click_ok() + + self.assertEqual(self.app.default_kernel, new_def_kernel_name) + + @wrap_in_loop + def test_set_default_kernel_to_none(self): + self.__set_none(self.dialog.default_kernel_combo) + self.__click_ok() + + self.assertEqual(self.app.default_kernel, '') + + @wrap_in_loop + def test_set_default_kernel_to_none2(self): + self.app.default_kernel = None + self.dialog = global_settings.GlobalSettingsWindow( + self.qtapp, self.qapp) + + self.assertEqual(self.dialog.default_kernel_combo.currentText(), + "(none) (current)") + + @wrap_in_loop + def test_set_dom0_updates_true(self): + self.dialog.updates_dom0.setChecked(True) + self.__click_ok() + + if not hasattr(self.app, 'check_updates_dom0'): + self.skipTest("check_updates_dom0 property not implemented") + + self.assertTrue(self.app.check_updates_dom0) + + @wrap_in_loop + def test_set_dom0_updates_false(self): + self.dialog.updates_dom0.setChecked(False) + self.__click_ok() + + if not hasattr(self.app, 'check_updates_dom0'): + self.skipTest("check_updates_dom0 property not implemented") + + self.assertFalse(self.app.check_updates_dom0) + + @wrap_in_loop + def test_set_vm_updates_true(self): + self.dialog.updates_vm.setChecked(True) + self.__click_ok() + + self.assertTrue(self.app.check_updates_vm) + + @wrap_in_loop + def test_set_vm_updates_false(self): + self.dialog.updates_vm.setChecked(False) + self.__click_ok() + + self.assertFalse(self.app.check_updates_vm) + + @wrap_in_loop + def test_00set_all_vms_true(self): + + with unittest.mock.patch("PyQt4.QtGui.QMessageBox.question", + return_value=QtGui.QMessageBox.Yes) as msgbox: + + QtTest.QTest.mouseClick(self.dialog.enable_updates_all, + QtCore.Qt.LeftButton) + + msgbox.assert_called_once_with( + self.dialog, + "Change state of all qubes", + "Are you sure you want to set all qubes to check for updates?", + unittest.mock.ANY) + + for vm in self.app.domains: + self.assertTrue(vm.features['check-updates']) + + @wrap_in_loop + def test_00set_all_vms_false(self): + with unittest.mock.patch("PyQt4.QtGui.QMessageBox.question", + return_value=QtGui.QMessageBox.Yes) as msgbox: + QtTest.QTest.mouseClick(self.dialog.disable_updates_all, + QtCore.Qt.LeftButton) + + msgbox.assert_called_once_with( + self.dialog, + "Change state of all qubes", + "Are you sure you want to set all qubes to not check " + "for updates?", + unittest.mock.ANY) + + for vm in self.app.domains: + self.assertFalse(vm.features['check-updates']) + + +if __name__ == "__main__": + ha_syslog = logging.handlers.SysLogHandler('/dev/log') + ha_syslog.setFormatter( + logging.Formatter('%(name)s[%(process)d]: %(message)s')) + logging.root.addHandler(ha_syslog) + unittest.main() diff --git a/setup.py b/setup.py index 721284c..f0388a8 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ if __name__ == '__main__': description='Qubes OS Manager', license='GPL2+', url='https://www.qubes-os.org/', - packages=setuptools.find_packages(), + packages=setuptools.find_packages(exclude=['qubesmanager.tests']), package_data={ 'qubesmanager': ['i18n/*'] },