Merge remote-tracking branch 'qubesos/pr/175'

* qubesos/pr/175:
  More fixes to force tests to work
  Tests for Create New VM
  Tests for VM settings
  Fixed spec
  Tests for backup_utils file
  Tests for Qubes Backup
  Test changes related to fixes in https://github.com/QubesOS/qubes-manager/pull/176
  Tests for qube manager
  Tests for global settings
This commit is contained in:
Marek Marczykowski-Górecki 2019-05-24 12:18:26 +02:00
commit 6550070135
No known key found for this signature in database
GPG Key ID: 063938BA42CFA724
8 changed files with 3392 additions and 339 deletions

View File

@ -0,0 +1,697 @@
#!/usr/bin/python3
#
# The Qubes OS Project, https://www.qubes-os.org/
#
# Copyright (C) 2016 Marta Marczykowska-Górecka
# <marmarta@invisiblethingslab.com>
#
# 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
from PyQt4 import QtGui, QtTest, QtCore
from qubesadmin import Qubes, events, utils, exc
from qubesmanager import backup
import quamash
import asyncio
import gc
class BackupTest(unittest.TestCase):
def setUp(self):
super(BackupTest, self).setUp()
# mock up nonexistence of saved backup settings
self.patcher_open = unittest.mock.patch('builtins.open')
self.mock_open = self.patcher_open.start()
self.mock_open.side_effect = FileNotFoundError()
self.addCleanup(self.patcher_open.stop)
# mock up the Backup Thread to avoid accidentally changing system state
self.patcher_thread = unittest.mock.patch(
'qubesmanager.backup.BackupThread')
self.mock_thread = self.patcher_thread.start()
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.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()
super(BackupTest, self).tearDown()
def test_00_window_loads(self):
self.assertTrue(self.dialog.select_vms_widget is not None)
def test_01_vms_load_correctly(self):
all_vms = len([vm for vm in self.qapp.domains
if not vm.features.get('internal', False)])
selected_vms = self.dialog.select_vms_widget.selected_list.count()
available_vms = self.dialog.select_vms_widget.available_list.count()
self.assertEqual(all_vms, available_vms + selected_vms)
def test_02_correct_defaults(self):
# backup is compressed
self.assertTrue(self.dialog.compress_checkbox.isChecked(),
"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)])
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")
# save defaults
self.assertTrue(self.dialog.save_profile_checkbox.isChecked(),
"By default, profile should be saved")
def test_03_select_vms_widget(self):
number_of_all_vms = len([vm for vm in self.qapp.domains
if not vm.features.get('internal', False)])
# select all
self.dialog.select_vms_widget.add_all_button.click()
self.assertEqual(number_of_all_vms,
self.dialog.select_vms_widget.selected_list.count(),
"Add All VMs does not work")
# remove all
self.dialog.select_vms_widget.remove_all_button.click()
self.assertEqual(number_of_all_vms,
self.dialog.select_vms_widget.available_list.count(),
"Remove All VMs does not work")
self._select_vm("work")
self.assertEqual(self.dialog.select_vms_widget.selected_list.count(),
1, "Select a single VM does not work")
def test_04_open_directory(self):
self.dialog.next()
self.assertTrue(self.dialog.currentPage()
is self.dialog.select_dir_page)
with unittest.mock.patch('qubesmanager.backup_utils.'
'select_path_button_clicked') as mock_func:
self.dialog.select_path_button.click()
mock_func.assert_called_once_with(unittest.mock.ANY)
def test_05_running_vms_listed(self):
self.dialog.next()
self.assertTrue(self.dialog.currentPage()
is self.dialog.select_dir_page)
running_vms = [vm.name for vm in self.qapp.domains if vm.is_running()]
listed_vms = []
for i in range(self.dialog.appvm_combobox.count()):
listed_vms.append(self.dialog.appvm_combobox.itemText(i))
self.assertListEqual(sorted(running_vms), sorted(listed_vms),
"Incorrect list of running vms")
def test_06_passphrase_verification(self):
self.dialog.next()
self.assertTrue(self.dialog.currentPage()
is self.dialog.select_dir_page)
# required to check if next button is correctly enabled
self.dialog.dir_line_edit.setText("/home")
next_button = self.dialog.button(self.dialog.NextButton)
# check if next remains inactive for various incorrect
# passphrase/incorrect combinations
self.dialog.passphrase_line_edit.setText("pass")
self.dialog.passphrase_line_edit_verify.setText("fail")
self.assertFalse(next_button.isEnabled(),
"Mismatched passphrase/verification accepted")
self.dialog.passphrase_line_edit.setText("pass")
self.dialog.passphrase_line_edit_verify.setText("")
self.assertFalse(next_button.isEnabled(), "Empty verification accepted")
self.dialog.passphrase_line_edit.setText("")
self.dialog.passphrase_line_edit_verify.setText("fail")
self.assertFalse(next_button.isEnabled(), "Empty passphrase accepted")
self.dialog.passphrase_line_edit.setText("")
self.dialog.passphrase_line_edit_verify.setText("")
self.assertFalse(next_button.isEnabled(),
"Empty passphrase and verification accepted")
# check if next is active for a correct passphrase/verify
# combination
self.dialog.passphrase_line_edit.setText("pass")
self.dialog.passphrase_line_edit_verify.setText("pass")
self.assertTrue(next_button.isEnabled(),
"Matching passphrase/verification not accepted")
def test_07_disk_space_correct(self):
for i in range(self.dialog.select_vms_widget.available_list.count()):
item = self.dialog.select_vms_widget.available_list.item(i)
if item.vm.name == "dom0" or item.vm.get_disk_utilization() > 0:
self.assertGreater(
item.size, 0,
"{} size incorrectly reported as 0".format(item.vm.name))
def test_08_total_size_correct(self):
# select nothing
self.dialog.select_vms_widget.remove_all_button.click()
self.assertEqual(self.dialog.total_size_label.text(), "0",
"Total size of 0 vms incorrectly reported as 0")
current_size = 0
# select a single VM
self._select_vm("sys-net")
current_size += self.qapp.domains["sys-net"].get_disk_utilization()
self.assertEqual(self.dialog.total_size_label.text(),
utils.size_to_human(current_size),
"Size incorrectly listed for a single VM")
# add two more
self._select_vm("sys-firewall")
self._select_vm("work")
current_size += self.qapp.domains["sys-firewall"].get_disk_utilization()
current_size += self.qapp.domains["work"].get_disk_utilization()
self.assertEqual(self.dialog.total_size_label.text(),
utils.size_to_human(current_size),
"Size incorrectly listed for several VMs")
# remove one
self._deselect_vm("sys-net")
current_size -= self.qapp.domains["sys-net"].get_disk_utilization()
self.assertEqual(self.dialog.total_size_label.text(),
utils.size_to_human(current_size),
"Size incorrectly listed for several VMs")
@unittest.mock.patch('qubesmanager.backup_utils.write_backup_profile')
@unittest.mock.patch('qubesadmin.Qubes.qubesd_call',
return_value=b'backup output')
def test_10_first_backup(self, mock_qubesd, mock_write_profile):
self.assertTrue(self.dialog.currentPage()
is self.dialog.select_vms_page)
self.dialog.select_vms_widget.remove_all_button.click()
self._select_vm("work")
self._click_next()
self.assertTrue(self.dialog.currentPage()
is self.dialog.select_dir_page)
# setup backup
self._select_location("dom0")
self.dialog.dir_line_edit.setText("/home")
self.dialog.passphrase_line_edit.setText("pass")
self.dialog.passphrase_line_edit_verify.setText("pass")
self.dialog.save_profile_checkbox.setChecked(True)
self.dialog.turn_off_checkbox.setChecked(False)
self.dialog.compress_checkbox.setChecked(False)
expected_settings = {'destination_vm': "dom0",
'destination_path': "/home",
'include': ["work"],
'passphrase_text': "pass",
'compression': False}
with unittest.mock.patch.object(self.dialog.textEdit, 'setText')\
as mock_set_text:
self._click_next()
# make sure the confirmation is not empty
self.assertTrue(self.dialog.currentPage()
is self.dialog.confirm_page)
mock_write_profile.assert_called_with(expected_settings, True)
mock_qubesd.assert_called_with('dom0', 'admin.backup.Info',
unittest.mock.ANY)
mock_set_text.assert_called_once_with("backup output")
# make sure the backup is executed
self._click_next()
self.mock_thread.assert_called_once_with(self.qapp.domains["dom0"])
self.mock_thread().start.assert_called_once_with()
@unittest.mock.patch('qubesmanager.backup_utils.write_backup_profile')
@unittest.mock.patch('qubesadmin.Qubes.qubesd_call',
return_value=b'backup output')
def test_11_second_backup(self, mock_qubesd, mock_write_profile):
self.assertTrue(self.dialog.currentPage()
is self.dialog.select_vms_page)
self.dialog.select_vms_widget.remove_all_button.click()
self._select_vm("work")
self._select_vm("sys-net")
self._select_vm("dom0")
self._click_next()
self.assertTrue(self.dialog.currentPage()
is self.dialog.select_dir_page)
# setup backup
self._select_location("sys-net")
self.dialog.dir_line_edit.setText("/home")
self.dialog.passphrase_line_edit.setText("longerPassPhrase")
self.dialog.passphrase_line_edit_verify.setText("longerPassPhrase")
self.dialog.save_profile_checkbox.setChecked(False)
self.dialog.turn_off_checkbox.setChecked(False)
self.dialog.compress_checkbox.setChecked(True)
expected_settings = {'destination_vm': "sys-net",
'destination_path': "/home",
'include': ["dom0", "sys-net", "work"],
'passphrase_text': "longerPassPhrase",
'compression': True}
with unittest.mock.patch.object(self.dialog.textEdit, 'setText')\
as mock_set_text:
self._click_next()
# make sure the confirmation is not empty
self.assertTrue(self.dialog.currentPage()
is self.dialog.confirm_page)
mock_write_profile.assert_called_with(expected_settings, True)
mock_qubesd.assert_called_with('dom0', 'admin.backup.Info',
unittest.mock.ANY)
mock_set_text.assert_called_once_with("backup output")
# make sure the backup is executed
self._click_next()
self.mock_thread.assert_called_once_with(self.qapp.domains["sys-net"])
self.mock_thread().start.assert_called_once_with()
@unittest.mock.patch('qubesmanager.backup_utils.load_backup_profile')
def test_20_loading_settings(self, mock_load):
mock_load.return_value = {
'destination_vm': "sys-net",
'destination_path': "/home",
'include': ["dom0", "sys-net", "work"],
'passphrase_text': "longerPassPhrase",
'compression': True
}
self.dialog.hide()
self.dialog.deleteLater()
self.qtapp.processEvents()
self.dialog = backup.BackupVMsWindow(
self.qtapp, self.qapp, self.dispatcher)
self.dialog.show()
# check if settings were loaded
self.assertEqual(self.dialog.appvm_combobox.currentText(), "sys-net",
"Destination VM not loaded")
self.assertEqual(self.dialog.dir_line_edit.text(), "/home",
"Destination path not loaded")
self.assertEqual(self.dialog.passphrase_line_edit.text(),
"longerPassPhrase", "Passphrase not loaded")
self.assertEqual(self.dialog.passphrase_line_edit_verify.text(),
"longerPassPhrase", "Passphrase verify not loaded")
self.assertTrue(self.dialog.compress_checkbox.isChecked())
# check that 'include' vms were not pre-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)])
selected_no = self.dialog.select_vms_widget.selected_list.count()
self.assertEqual(include_in_backups_no, selected_no,
"Incorrect VM list selected")
# check no errors were detected
self.assertFalse(self.dialog.unrecognized_config_label.isVisible())
@unittest.mock.patch('qubesmanager.backup_utils.load_backup_profile')
def test_21_loading_settings_error(self, mock_load):
mock_load.return_value = {
'destination_vm': "incorrect_vm",
}
self.dialog.hide()
self.dialog.deleteLater()
self.qtapp.processEvents()
self.dialog = backup.BackupVMsWindow(
self.qtapp, self.qapp, self.dispatcher)
self.dialog.show()
# check errors were detected
self.assertTrue(self.dialog.unrecognized_config_label.isVisible())
@unittest.mock.patch('qubesmanager.backup_utils.load_backup_profile')
@unittest.mock.patch('PyQt4.QtGui.QMessageBox.information')
def test_22_loading_settings_exc(self, mock_info, mock_load):
mock_load.side_effect = exc.QubesException('Error')
self.dialog.hide()
self.dialog.deleteLater()
self.qtapp.processEvents()
self.dialog = backup.BackupVMsWindow(
self.qtapp, self.qapp, self.dispatcher)
self.dialog.show()
# check error was reported
self.assertEqual(mock_info.call_count, 1, "Warning not shown")
@unittest.mock.patch('qubesmanager.backup_utils.write_backup_profile')
@unittest.mock.patch('qubesadmin.Qubes.qubesd_call',
return_value=b'backup output')
def test_23_cancel_confirm(self, *_args):
self._click_next()
self.assertTrue(self.dialog.currentPage()
is self.dialog.select_dir_page)
self._select_location("dom0")
self.dialog.dir_line_edit.setText("/home")
self.dialog.passphrase_line_edit.setText("pass")
self.dialog.passphrase_line_edit_verify.setText("pass")
self._click_next()
# attempt to cancel
with unittest.mock.patch('os.remove') as mock_remove:
self._click_cancel()
mock_remove.assert_called_once_with(
'/etc/qubes/backup/qubes-manager-backup-tmp.conf')
@unittest.mock.patch('PyQt4.QtGui.QMessageBox.warning')
@unittest.mock.patch('qubesmanager.backup_utils.write_backup_profile')
@unittest.mock.patch('qubesadmin.Qubes.qubesd_call',
return_value=b'backup output')
def test_24_cancel_in_progress(self, mock_call, *_args):
self._click_next()
self.assertTrue(self.dialog.currentPage()
is self.dialog.select_dir_page)
self._select_location("dom0")
self.dialog.dir_line_edit.setText("/home")
self.dialog.passphrase_line_edit.setText("pass")
self.dialog.passphrase_line_edit_verify.setText("pass")
self._click_next()
self._click_next()
# attempt to cancel
with unittest.mock.patch('os.remove') as mock_remove:
self._click_cancel()
mock_call.assert_called_with('dom0', 'admin.backup.Cancel',
'qubes-manager-backup-tmp')
mock_remove.assert_called_once_with(
'/etc/qubes/backup/qubes-manager-backup-tmp.conf')
@unittest.mock.patch('PyQt4.QtGui.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_25_successful_backup(self, _a, _b, mock_remove,
mock_system, mock_warning):
self._click_next()
self.assertTrue(self.dialog.currentPage()
is self.dialog.select_dir_page)
self._select_location("dom0")
self.dialog.dir_line_edit.setText("/home")
self.dialog.passphrase_line_edit.setText("pass")
self.dialog.passphrase_line_edit_verify.setText("pass")
self.dialog.turn_off_checkbox.setChecked(False)
self._click_next()
self._click_next()
# assume backup went correctly
self.mock_thread().msg = None
self.mock_thread().finished.connect.assert_called_once_with(
self.dialog.backup_finished)
self.dialog.backup_finished()
self.assertFalse(self.dialog.button(
self.dialog.CancelButton).isEnabled())
self.assertTrue(self.dialog.button(
self.dialog.FinishButton).isEnabled())
mock_remove.assert_called_once_with(
'/etc/qubes/backup/qubes-manager-backup-tmp.conf')
self.assertEqual(mock_system.call_count, 0,
"System turned off unnecessarily")
self.assertEqual(mock_warning.call_count, 0,
"Backup succeeded but received warning")
@unittest.mock.patch('PyQt4.QtGui.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_26_success_backup_poweroff(
self, _a, _b, mock_remove, mock_system, mock_warning):
self._click_next()
self.assertTrue(self.dialog.currentPage()
is self.dialog.select_dir_page)
self._select_location("dom0")
self.dialog.dir_line_edit.setText("/home")
self.dialog.passphrase_line_edit.setText("pass")
self.dialog.passphrase_line_edit_verify.setText("pass")
self.dialog.turn_off_checkbox.setChecked(True)
self._click_next()
self._click_next()
# assume backup went correctly
self.mock_thread().msg = None
self.mock_thread().finished.connect.assert_called_once_with(
self.dialog.backup_finished)
self.dialog.backup_finished()
self.assertFalse(self.dialog.button(
self.dialog.CancelButton).isEnabled())
self.assertTrue(self.dialog.button(
self.dialog.FinishButton).isEnabled())
mock_remove.assert_called_once_with(
'/etc/qubes/backup/qubes-manager-backup-tmp.conf')
mock_system.assert_called_once_with('systemctl poweroff')
self.assertEqual(mock_warning.call_count, 0,
"Backup succeeded but received warning")
@unittest.mock.patch('PyQt4.QtGui.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_27_failed_backup(
self, _a, _b, mock_remove, mock_system, mock_warn):
self._click_next()
self.assertTrue(self.dialog.currentPage()
is self.dialog.select_dir_page)
self._select_location("dom0")
self.dialog.dir_line_edit.setText("/home")
self.dialog.passphrase_line_edit.setText("pass")
self.dialog.passphrase_line_edit_verify.setText("pass")
self.dialog.turn_off_checkbox.setChecked(True)
self._click_next()
self._click_next()
# assume backup went wrong
self.mock_thread().msg = "Error"
self.mock_thread().finished.connect.assert_called_once_with(
self.dialog.backup_finished)
self.dialog.backup_finished()
self.assertFalse(self.dialog.button(
self.dialog.CancelButton).isEnabled())
self.assertTrue(self.dialog.button(
self.dialog.FinishButton).isEnabled())
mock_remove.assert_called_once_with(
'/etc/qubes/backup/qubes-manager-backup-tmp.conf')
self.assertEqual(mock_system.call_count, 0,
"Attempted shutdown at failed backup")
self.assertEqual(mock_warn.call_count, 1)
@unittest.mock.patch('PyQt4.QtGui.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._click_next()
self.assertTrue(self.dialog.currentPage()
is self.dialog.select_dir_page)
self._select_location("dom0")
self.dialog.dir_line_edit.setText("/home")
self.dialog.passphrase_line_edit.setText("pass")
self.dialog.passphrase_line_edit_verify.setText("pass")
self.dialog.turn_off_checkbox.setChecked(True)
self._click_next()
self._click_next()
# see if backup is correctly in progress
self.assertTrue(self.dialog.button(
self.dialog.CancelButton).isEnabled())
self.assertFalse(self.dialog.button(
self.dialog.FinishButton).isEnabled())
self.assertEqual(self.dialog.progress_bar.value(), 0,
"Progress bar does not start at 0")
# this is not a perfect method, but it is something
self.dialog.on_backup_progress(None, None, progress='23.3123')
self.assertEqual(self.dialog.progress_bar.value(), 23,
"Progress bar does not update correctly")
self.dialog.on_backup_progress(None, None, progress='87.89')
self.assertEqual(self.dialog.progress_bar.value(), 87,
"Progress bar does not update correctly")
def _select_location(self, vm_name):
widget = self.dialog.appvm_combobox
widget.setCurrentIndex(0)
while not widget.currentText() == vm_name:
if widget.currentIndex() == widget.count():
self.skipTest("target VM not found")
widget.setCurrentIndex(widget.currentIndex() + 1)
def _click_next(self):
next_widget = self.dialog.button(QtGui.QWizard.NextButton)
QtTest.QTest.mouseClick(next_widget, QtCore.Qt.LeftButton)
def _click_cancel(self):
cancel_widget = self.dialog.button(QtGui.QWizard.CancelButton)
QtTest.QTest.mouseClick(cancel_widget, QtCore.Qt.LeftButton)
def _select_vm(self, name_starts_with):
for i in range(self.dialog.select_vms_widget.available_list.count()):
item = self.dialog.select_vms_widget.available_list.item(i)
if item.text().startswith(name_starts_with):
item.setSelected(True)
self.dialog.select_vms_widget.add_selected_button.click()
return
def _deselect_vm(self, name_starts_with):
for i in range(self.dialog.select_vms_widget.selected_list.count()):
item = self.dialog.select_vms_widget.selected_list.item(i)
if item.text().startswith(name_starts_with):
item.setSelected(True)
self.dialog.select_vms_widget.remove_selected_button.click()
return
class BackupThreadTest(unittest.TestCase):
def test_01_backup_thread_vm_on(self):
vm = unittest.mock.Mock(spec=['is_running', 'app'],
**{'is_running.return_value': True})
vm.app = unittest.mock.Mock()
thread = backup.BackupThread(vm)
thread.run()
vm.app.qubesd_call.assert_called_with(
'dom0', 'admin.backup.Execute', 'qubes-manager-backup-tmp')
def test_02_backup_thread_vm_off(self):
vm = unittest.mock.Mock(spec=['is_running', 'app', 'start'],
**{'is_running.return_value': False})
vm.app = unittest.mock.Mock()
thread = backup.BackupThread(vm)
thread.run()
vm.app.qubesd_call.assert_called_with(
'dom0', 'admin.backup.Execute', 'qubes-manager-backup-tmp')
vm.start.assert_called_once_with()
def test_03_backup_thread_error(self):
vm = unittest.mock.Mock(spec=['is_running', 'app'],
**{'is_running.return_value': True})
vm.app = unittest.mock.Mock()
vm.app.qubesd_call.side_effect = exc.QubesException('Error')
thread = backup.BackupThread(vm)
thread.run()
self.assertIsNotNone(thread.msg)
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()

View File

@ -1,95 +0,0 @@
#!/usr/bin/python3
#
# The Qubes OS Project, https://www.qubes-os.org/
#
# Copyright (C) 2016 Marta Marczykowska-Górecka
# <marmarta@invisiblethingslab.com>
#
# 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
from PyQt4 import QtGui, QtTest, QtCore
from qubesadmin import Qubes
import qubesmanager.backup as backup_gui
class BackupTest(unittest.TestCase):
def setUp(self):
super(BackupTest, self).setUp()
# mock up nonexistence of saved backup settings
self.patcher = unittest.mock.patch('builtins.open')
self.mock_open = self.patcher.start()
self.mock_open.side_effect = FileNotFoundError()
self.addCleanup(self.patcher.stop)
self.qapp = Qubes()
self.qtapp = QtGui.QApplication(sys.argv)
self.dialog = backup_gui.BackupVMsWindow(self.qtapp, self.qapp)
def tearDown(self):
del self.dialog
del self.qtapp
del self.qapp
super(BackupTest, self).tearDown()
def test_00_window_loads(self):
self.assertTrue(self.dialog.select_vms_widget is not None)
def test_01_vms_load_correctly(self):
all_vms = len([vm for vm in self.qapp.domains
if not vm.features.get('internal', False)])
selected_vms = self.dialog.select_vms_widget.selected_list.count()
available_vms = self.dialog.select_vms_widget.available_list.count()
self.assertEqual(all_vms, available_vms + selected_vms)
def test_02_correct_defaults(self):
# backup is compressed
self.assertTrue(self.dialog.compress_checkbox.isChecked(),
"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)])
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")
# save defaults
self.assertTrue(self.dialog.save_profile_checkbox.isChecked(),
"By default, profile should be saved")
# Check if target vms are selected
# Check if no default file loads correctly - another file??
# TODO: make a separate backup testing file to test various backup defaults
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()

View File

@ -0,0 +1,97 @@
#!/usr/bin/python3
#
# The Qubes OS Project, https://www.qubes-os.org/
#
# Copyright (C) 2016 Marta Marczykowska-Górecka
# <marmarta@invisiblethingslab.com>
#
# 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 unittest.mock
import quamash
import asyncio
import gc
from PyQt4 import QtGui
from qubesadmin import Qubes
from qubesmanager import backup_utils
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)
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()
super(BackupUtilsTest, self).tearDown()
def test_01_fill_apvms(self):
dialog = QtGui.QDialog()
combobox = QtGui.QComboBox()
dialog.appvm_combobox = combobox
dialog.qubes_app = self.qapp
backup_utils.fill_appvms_list(dialog)
# see if the dialog has nothing selected
self.assertEqual(combobox.currentIndex(), 0,
"Incorrect item selected")
# the combobox should contain running VMs that are not internal and
# not template
expected_vm_list = [vm.name for vm in self.qapp.domains
if vm.is_running() and vm.klass != 'TemplateVM'
and not getattr(vm, 'internal', False)]
received_vm_list = []
for i in range(combobox.count()):
received_vm_list.append(combobox.itemText(i))
self.assertListEqual(sorted(expected_vm_list), sorted(received_vm_list),
"VM list not filled correctly")
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()

View File

@ -0,0 +1,318 @@
#!/usr/bin/python3
#
# The Qubes OS Project, https://www.qubes-os.org/
#
# Copyright (C) 2016 Marta Marczykowska-Górecka
# <marmarta@invisiblethingslab.com>
#
# 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 quamash
import asyncio
import unittest
import unittest.mock
import qubesadmin
import gc
from PyQt4 import QtGui, QtTest, QtCore
from qubesadmin import Qubes
from qubesmanager import create_new_vm
class NewVmTest(unittest.TestCase):
def setUp(self):
super(NewVmTest, self).setUp()
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(
'qubesmanager.create_new_vm.CreateVMThread')
self.mock_thread = self.patcher_thread.start()
self.addCleanup(self.patcher_thread.stop)
# mock the progress dialog to speed testing up
self.patcher_progress = unittest.mock.patch(
'PyQt4.QtGui.QProgressDialog')
self.mock_progress = self.patcher_progress.start()
self.addCleanup(self.patcher_progress.stop)
self.dialog = create_new_vm.NewVmDlg(
self.qtapp, self.qapp)
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()
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()
super(NewVmTest, self).tearDown()
def test_00_window_loads(self):
self.assertGreater(self.dialog.template_vm.count(), 0,
"No templates shown")
self.assertGreater(self.dialog.netvm.count(), 0, "No netvm listed")
def test_01_cancel_works(self):
self.__click_cancel()
self.assertEqual(self.mock_thread.call_count, 0,
"Attempted to create VM on cancel")
def test_02_create_simple_vm(self):
self.dialog.name.setText("testvm")
self.__click_ok()
self.mock_thread.assert_called_once_with(
self.qapp, "AppVM", "testvm",
unittest.mock.ANY, qubesadmin.DEFAULT,
{'provides_network': False})
self.mock_thread().start.assert_called_once_with()
def test_03_label(self):
for i in range(self.dialog.label.count()):
if self.dialog.label.itemText(i) == 'blue':
self.dialog.label.setCurrentIndex(i)
break
self.dialog.name.setText("testvm")
self.__click_ok()
self.mock_thread.assert_called_once_with(
self.qapp, "AppVM", "testvm",
self.qapp.labels['blue'], qubesadmin.DEFAULT,
unittest.mock.ANY)
self.mock_thread().start.assert_called_once_with()
def test_04_template(self):
template = None
for i in range(self.dialog.template_vm.count()):
if not self.dialog.template_vm.itemText(i).startswith('default'):
self.dialog.template_vm.setCurrentIndex(i)
template = self.dialog.template_vm.currentText()
break
self.dialog.name.setText("testvm")
self.__click_ok()
self.mock_thread.assert_called_once_with(
self.qapp, "AppVM", "testvm",
unittest.mock.ANY, template,
unittest.mock.ANY)
def test_05_netvm(self):
netvm = None
for i in range(self.dialog.netvm.count()):
if not self.dialog.netvm.itemText(i).startswith('default'):
self.dialog.netvm.setCurrentIndex(i)
netvm = self.dialog.netvm.currentText()
break
self.dialog.name.setText("testvm")
self.__click_ok()
self.mock_thread.assert_called_once_with(
self.qapp, "AppVM", "testvm",
unittest.mock.ANY, unittest.mock.ANY,
{'netvm': netvm, 'provides_network': False})
def test_06_provides_network(self):
self.dialog.provides_network.setChecked(True)
self.dialog.name.setText("testvm")
self.__click_ok()
self.mock_thread.assert_called_once_with(
self.qapp, "AppVM", "testvm",
unittest.mock.ANY, unittest.mock.ANY,
{'provides_network': True})
@unittest.mock.patch('subprocess.check_call')
def test_07_launch_settings(self, mock_call):
self.dialog.launch_settings.setChecked(True)
self.dialog.name.setText("testvm")
self.__click_ok()
# make sure the thread is not reporting an error
self.mock_thread.assert_called_once_with(
self.qapp, "AppVM", "testvm",
unittest.mock.ANY, unittest.mock.ANY,
unittest.mock.ANY)
self.mock_thread().msg = None
self.dialog.create_finished()
mock_call.assert_called_once_with(['qubes-vm-settings', "testvm"])
def test_08_progress_hides(self):
self.dialog.name.setText("testvm")
self.__click_ok()
self.mock_thread.assert_called_once_with(
self.qapp, "AppVM", "testvm",
unittest.mock.ANY, unittest.mock.ANY,
unittest.mock.ANY)
# make sure the thread is not reporting an error
self.mock_thread().start.assert_called_once_with()
self.mock_thread().msg = None
self.mock_progress().show.assert_called_once_with()
self.dialog.create_finished()
self.mock_progress().hide.assert_called_once_with()
def test_09_standalone_clone(self):
self.dialog.name.setText("testvm")
for i in range(self.dialog.vm_type.count()):
opt_text = self.dialog.vm_type.itemText(i).lower()
if "standalone" in opt_text and "template" in opt_text and\
"not based" not in opt_text and "empty" not in opt_text:
self.dialog.vm_type.setCurrentIndex(i)
break
self.__click_ok()
self.mock_thread.assert_called_once_with(
self.qapp, "StandaloneVM", "testvm",
unittest.mock.ANY, unittest.mock.ANY,
unittest.mock.ANY)
@unittest.mock.patch('subprocess.check_call')
def test_10_standalone_empty(self, mock_call):
self.dialog.name.setText("testvm")
for i in range(self.dialog.vm_type.count()):
opt_text = self.dialog.vm_type.itemText(i).lower()
if "standalone" in opt_text and\
("not based" in opt_text or "empty" in opt_text):
self.dialog.vm_type.setCurrentIndex(i)
break
self.__click_ok()
self.mock_thread.assert_called_once_with(
self.qapp, "StandaloneVM", "testvm",
unittest.mock.ANY, None,
unittest.mock.ANY)
self.mock_thread().msg = None
self.dialog.create_finished()
mock_call.assert_called_once_with(['qubes-vm-boot-from-device',
'testvm'])
@unittest.mock.patch('subprocess.check_call')
def test_11_standalone_empty_not_install(self, mock_call):
self.dialog.name.setText("testvm")
for i in range(self.dialog.vm_type.count()):
opt_text = self.dialog.vm_type.itemText(i).lower()
if "standalone" in opt_text and\
("not based" in opt_text or "empty" in opt_text):
self.dialog.vm_type.setCurrentIndex(i)
break
self.dialog.install_system.setChecked(False)
self.__click_ok()
self.mock_thread.assert_called_once_with(
self.qapp, "StandaloneVM", "testvm",
unittest.mock.ANY, None,
unittest.mock.ANY)
self.mock_thread().msg = None
self.dialog.create_finished()
self.assertEqual(mock_call.call_count, 0)
def test_12_setting_change(self):
# cannot install system on a template-based appvm
for i in range(self.dialog.vm_type.count()):
opt_text = self.dialog.vm_type.itemText(i).lower()
if "appvm" in opt_text and "standalone" not in opt_text:
self.dialog.vm_type.setCurrentIndex(i)
break
self.assertFalse(self.dialog.install_system.isEnabled())
self.assertTrue(self.dialog.launch_settings.isEnabled())
self.assertTrue(self.dialog.template_vm.isEnabled())
# or on a standalone vm cloned from a template
for i in range(self.dialog.vm_type.count()):
opt_text = self.dialog.vm_type.itemText(i).lower()
if "standalone" in opt_text and "template" in opt_text and\
"not based" not in opt_text and "empty" not in opt_text:
self.dialog.vm_type.setCurrentIndex(i)
break
self.assertFalse(self.dialog.install_system.isEnabled())
self.assertTrue(self.dialog.launch_settings.isEnabled())
self.assertTrue(self.dialog.template_vm.isEnabled())
# cannot set a template but can install system on a truly empty AppVM
for i in range(self.dialog.vm_type.count()):
opt_text = self.dialog.vm_type.itemText(i).lower()
if "standalone" in opt_text and\
("not based" in opt_text or "empty" in opt_text):
self.dialog.vm_type.setCurrentIndex(i)
break
self.assertTrue(self.dialog.install_system.isEnabled())
self.assertTrue(self.dialog.launch_settings.isEnabled())
self.assertFalse(self.dialog.template_vm.isEnabled())
def __click_ok(self):
okwidget = self.dialog.buttonBox.button(
self.dialog.buttonBox.Ok)
QtTest.QTest.mouseClick(okwidget, QtCore.Qt.LeftButton)
def __click_cancel(self):
cancelwidget = self.dialog.buttonBox.button(
self.dialog.buttonBox.Cancel)
QtTest.QTest.mouseClick(cancelwidget, QtCore.Qt.LeftButton)
# class CreatteVMThreadTest(unittest.TestCase):
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()

View File

@ -20,113 +20,144 @@
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
import logging.handlers
import sys
import quamash
import asyncio
import unittest
import unittest.mock
import gc
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
# sudo systemctl stop qubesd; sudo -E python3 test_backup.py -v ; sudo systemctl start qubesd
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):
class GlobalSettingsTest(unittest.TestCase):
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)
self.qtapp = QtGui.QApplication(["test", "-style", "cleanlooks"])
self.loop = quamash.QEventLoop(self.qtapp)
self.dialog = global_settings.GlobalSettingsWindow(self.qtapp,
self.qapp)
self.setattr_patcher = unittest.mock.patch.object(
type(self.dialog.qvm_collection), "__setattr__")
self.setattr_mock = self.setattr_patcher.start()
self.addCleanup(self.setattr_patcher.stop)
def tearDown(self):
self.tearDownInExecutor()
super(GlobalSettingsTest, self).tearDown()
# process any pending events before destroying the object
self.qtapp.processEvents()
@wrap_in_loop
def tearDownInExecutor(self):
# 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()
super(GlobalSettingsTest, self).tearDown()
@wrap_in_loop
def test_00_settings_started(self):
# non-empty drop-downs
self.assertNotEqual(
self.dialog.default_kernel_combo.currentText(), "")
self.dialog.default_kernel_combo.currentText(), "",
"Default kernel not listed")
self.assertNotEqual(
self.dialog.default_netvm_combo.currentText(), "")
self.dialog.default_netvm_combo.currentText(), "",
"Default netVM not listed")
self.assertNotEqual(
self.dialog.default_template_combo.currentText(),
"")
"", "Default template not listed")
self.assertNotEqual(
self.dialog.clock_vm_combo.currentText(), "")
self.dialog.clock_vm_combo.currentText(), "",
"ClockVM not listed")
self.assertNotEqual(
self.dialog.update_vm_combo.currentText(), "")
self.dialog.update_vm_combo.currentText(), "",
"UpdateVM for dom0 not listed")
self.assertNotEqual(
self.dialog.default_dispvm_combo.currentText(), "",
"Default DispVM not listed")
# not empty memory settings
self.assertTrue(len(self.dialog.min_vm_mem.text()) > 4,
"Too short min mem value")
self.assertTrue(len(self.dialog.dom0_mem_boost.text()) > 4,
"Too short dom0 mem boost value")
@wrap_in_loop
def test_01_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))
str(getattr(self.qapp, 'default_template', '(none)'))),
"Incorrect default template loaded")
# correctly selected default NetVM
selected_default_netvm = \
self.dialog.default_netvm_combo.currentText()
selected_default_netvm = self.dialog.default_netvm_combo.currentText()
self.assertTrue(selected_default_netvm.startswith(
self.app.default_netvm.name))
str(getattr(self.qapp, 'default_netvm', '(none)'))),
"Incorrect default netVM loaded")
# correctly selected default kernel
selected_default_kernel = \
self.dialog.default_kernel_combo.currentText()
selected_default_kernel = self.dialog.default_kernel_combo.currentText()
self.assertTrue(selected_default_kernel.startswith(
self.app.default_kernel))
str(getattr(self.qapp, 'default_kernel', '(none)'))),
"Incorrect default kernel loaded")
# 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))
selected_clockvm = self.dialog.clock_vm_combo.currentText()
correct_clockvm = str(getattr(self.qapp, 'clockvm', "(none)"))
self.assertTrue(selected_clockvm.startswith(correct_clockvm),
"Incorrect clockVM loaded")
# 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))
selected_updatevm = self.dialog.update_vm_combo.currentText()
correct_updatevm = str(getattr(self.qapp, 'updatevm', "(none)"))
self.assertTrue(selected_updatevm.startswith(correct_updatevm),
"Incorrect updateVm loaded")
# correct defaultDispVM
selected_default_dispvm = self.dialog.default_dispvm_combo.currentText()
correct_default_dispvm = \
str(getattr(self.qapp, 'default_dispvm', "(none)"))
self.assertTrue(
selected_default_dispvm.startswith(correct_default_dispvm),
"Incorrect defaultDispVM loaded")
# update vm status
self.assertEqual(self.app.check_updates_vm,
self.dialog.updates_vm.isChecked())
self.assertEqual(self.qapp.check_updates_vm,
self.dialog.updates_vm.isChecked(),
"Incorrect check qube updates value loaded")
@wrap_in_loop
def test_02_dom0_updates_load(self):
# check dom0 updates
try:
dom0_updates = self.app.check_updates_dom0
except AttributeError:
dom0_updates = self.qapp.domains[
'dom0'].features['service.qubes-update-check']
except KeyError:
self.skipTest("check_updates_dom0 property not implemented")
return
self.assertEqual(dom0_updates, self.dialog.updates_dom0.isChecked())
self.assertEqual(bool(dom0_updates),
self.dialog.updates_dom0.isChecked(),
"Incorrect dom0 updates value")
def __set_noncurrent(self, widget):
if widget.count() < 2:
@ -150,178 +181,193 @@ class GlobalSettingsTest(SystemTestCase):
okwidget = self.dialog.buttonBox.button(
self.dialog.buttonBox.Ok)
QtTest.QTest.mouseClick(okwidget,
QtCore.Qt.LeftButton)
QtTest.QTest.mouseClick(okwidget, QtCore.Qt.LeftButton)
def __click_cancel(self):
cancelwidget = self.dialog.buttonBox.button(
self.dialog.buttonBox.Cancel)
QtTest.QTest.mouseClick(cancelwidget, QtCore.Qt.LeftButton)
def test_03_nothing_changed_ok(self):
self.__click_ok()
self.assertEqual(self.setattr_mock.call_count, 0,
"Changes occurred despite no changes being made")
def test_04_nothing_changed_cancel(self):
self.__click_cancel()
self.assertEqual(self.setattr_mock.call_count, 0,
"Changes occurred despite no changes being made")
@wrap_in_loop
def test_10_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)
self.setattr_mock.assert_called_once_with('updatevm', new_updatevm_name)
@wrap_in_loop
def test_11_set_update_vm_to_none(self):
self.__set_none(self.dialog.update_vm_combo)
self.__click_ok()
self.assertIsNone(self.app.updatevm)
self.setattr_mock.assert_called_once_with('updatevm', None)
@wrap_in_loop
def test_12_set_update_vm_to_none2(self):
self.app.updatevm = None
def test_20_set_clock_vm(self):
new_clockvm_name = self.__set_noncurrent(self.dialog.clock_vm_combo)
self.__click_ok()
self.setattr_mock.assert_called_once_with('clockvm', new_clockvm_name)
def test_21_set_clock_vm_to_none(self):
self.__set_none(self.dialog.clock_vm_combo)
self.__click_ok()
self.setattr_mock.assert_called_once_with('clockvm', None)
def test_30_set_default_netvm(self):
new_netvm_name = self.__set_noncurrent(self.dialog.default_netvm_combo)
self.__click_ok()
self.setattr_mock.assert_called_once_with('default_netvm',
new_netvm_name)
def test_31_set_default_netvm_to_none(self):
self.__set_none(self.dialog.default_netvm_combo)
self.__click_ok()
self.setattr_mock.assert_called_once_with('default_netvm', None)
def test_40_set_default_template(self):
new_def_template_name = self.__set_noncurrent(
self.dialog.default_template_combo)
self.__click_ok()
self.setattr_mock.assert_called_once_with('default_template',
new_def_template_name)
def test_50_set_default_kernel(self):
new_def_kernel_name = self.__set_noncurrent(
self.dialog.default_kernel_combo)
self.__click_ok()
self.setattr_mock.assert_called_once_with('default_kernel',
new_def_kernel_name)
def test_51_set_default_kernel_to_none(self):
self.__set_none(self.dialog.default_kernel_combo)
self.__click_ok()
self.setattr_mock.assert_called_once_with('default_kernel',
None)
def test_60_set_dom0_updates_true(self):
current_state = self.dialog.updates_dom0.isChecked()
self.dialog.updates_dom0.setChecked(not current_state)
with unittest.mock.patch.object(
type(self.dialog.qvm_collection.domains['dom0'].features),
'__setitem__') as mock_features:
self.__click_ok()
mock_features.assert_called_once_with('service.qubes-update-check',
not current_state)
def test_70_change_vm_updates(self):
current_state = self.dialog.updates_vm.isChecked()
self.dialog.updates_vm.setChecked(not current_state)
self.__click_ok()
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('qubesadmin.features.Features.__setitem__')
def test_72_set_all_vms_true(self, mock_features, msgbox):
QtTest.QTest.mouseClick(self.dialog.enable_updates_all,
QtCore.Qt.LeftButton)
self.assertEqual(msgbox.call_count, 1,
"Wrong number of confirmation window calls")
call_list_expected = \
[unittest.mock.call('service.qubes-update-check', True) for vm
in self.qapp.domains if vm.klass != 'AdminVM']
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('qubesadmin.features.Features.__setitem__')
def test_73_set_all_vms_false(self, mock_features, msgbox):
QtTest.QTest.mouseClick(self.dialog.disable_updates_all,
QtCore.Qt.LeftButton)
self.assertEqual(msgbox.call_count, 1,
"Wrong number of confirmation window calls")
call_list_expected = \
[unittest.mock.call('service.qubes-update-check', False) for vm
in self.qapp.domains if vm.klass != 'AdminVM']
self.assertListEqual(call_list_expected,
mock_features.call_args_list)
def test_80_set_default_dispvm(self):
new_dispvm_name = self.__set_noncurrent(
self.dialog.default_dispvm_combo)
self.__click_ok()
self.setattr_mock.assert_called_once_with('default_dispvm',
new_dispvm_name)
def test_81_set_default_dispvm_to_none(self):
self.__set_none(self.dialog.default_dispvm_combo)
self.__click_ok()
self.setattr_mock.assert_called_once_with('default_dispvm', None)
@unittest.mock.patch.object(
type(Qubes()), '__getattr__',
side_effect=(lambda x: False if x == 'check_updates_vm' else None))
def test_90_test_all_set_none(self, mock_qubes):
mock_qubes.configure_mock()
self.dialog = global_settings.GlobalSettingsWindow(
self.qtapp, self.qapp)
self.assertEqual(self.dialog.update_vm_combo.currentText(),
"(none) (current)")
@wrap_in_loop
def test_20_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_21_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_22_set_clock_vm_to_none2(self):
self.app.clockvm = None
self.dialog = global_settings.GlobalSettingsWindow(
self.qtapp, self.qapp)
"(none) (current)",
"UpdateVM displays as none incorrectly")
self.assertEqual(self.dialog.clock_vm_combo.currentText(),
"(none) (current)")
@wrap_in_loop
def test_30_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_31_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_32_set_default_netvm_to_none2(self):
self.app.default_netvm = None
self.dialog = global_settings.GlobalSettingsWindow(
self.qtapp, self.qapp)
"(none) (current)",
"ClockVM displays as none incorrectly")
self.assertEqual(self.dialog.default_netvm_combo.currentText(),
"(none) (current)")
@wrap_in_loop
def test_40_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_50_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_51_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_52_set_default_kernel_to_none2(self):
self.app.default_kernel = None
self.dialog = global_settings.GlobalSettingsWindow(
self.qtapp, self.qapp)
"(none) (current)",
"Default NetVM displays as none incorrectly")
self.assertEqual(self.dialog.default_template_combo.currentText(),
"(none) (current)",
"Default template displays as none incorrectly")
self.assertEqual(self.dialog.default_kernel_combo.currentText(),
"(none) (current)")
@wrap_in_loop
def test_60_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_61_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_70_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_71_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_72_set_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_73_set_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'])
"(none) (current)",
"Defautl kernel displays as none incorrectly")
self.assertEqual(self.dialog.default_dispvm_combo.currentText(),
"(none) (current)",
"Default DispVM displays as none incorrectly")
if __name__ == "__main__":
@ -330,3 +376,5 @@ if __name__ == "__main__":
logging.Formatter('%(name)s[%(process)d]: %(message)s'))
logging.root.addHandler(ha_syslog)
unittest.main()
# TODO: add tests for memory settings once memory is handled better

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,605 @@
#!/usr/bin/python3
#
# The Qubes OS Project, https://www.qubes-os.org/
#
# Copyright (C) 2016 Marta Marczykowska-Górecka
# <marmarta@invisiblethingslab.com>
#
# 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 unittest
import unittest.mock
import gc
import quamash
import asyncio
from PyQt4 import QtGui, QtTest, QtCore
from qubesadmin import Qubes
import qubesmanager.settings as vm_settings
class VMSettingsTest(unittest.TestCase):
def setUp(self):
super(VMSettingsTest, self).setUp()
self.mock_qprogress = unittest.mock.patch('PyQt4.QtGui.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)
def tearDown(self):
del self.qapp.domains["testvm"]
# 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.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):
self.vm = self.qapp.add_new_vm("AppVM", "testvm", "red")
self.dialog = vm_settings.VMSettingsWindow(
self.vm, self.qtapp, "basic")
self.assertTrue(
self.dialog.tabWidget.currentWidget() is self.dialog.basic_tab)
self.dialog.deleteLater()
self.dialog = vm_settings.VMSettingsWindow(
self.vm, self.qtapp, "advanced")
self.assertTrue(
self.dialog.tabWidget.currentWidget() is self.dialog.advanced_tab)
self.dialog.deleteLater()
self.dialog = vm_settings.VMSettingsWindow(
self.vm, self.qtapp, "firewall")
self.assertTrue(
self.dialog.tabWidget.currentWidget() is self.dialog.firewall_tab)
self.dialog.deleteLater()
self.dialog = vm_settings.VMSettingsWindow(
self.vm, self.qtapp, "devices")
self.assertTrue(
self.dialog.tabWidget.currentWidget() is self.dialog.devices_tab)
self.dialog.deleteLater()
self.dialog = vm_settings.VMSettingsWindow(
self.vm, self.qtapp, "applications")
self.assertTrue(
self.dialog.tabWidget.currentWidget() is self.dialog.apps_tab)
self.dialog.deleteLater()
self.dialog = vm_settings.VMSettingsWindow(
self.vm, self.qtapp, "services")
self.assertTrue(
self.dialog.tabWidget.currentWidget() is self.dialog.services_tab)
self.dialog.deleteLater()
def test_01_basic_tab_default(self):
self.vm = self.qapp.add_new_vm("AppVM", "testvm", "blue")
# set the vm to have a default template and netvm
self.dialog = vm_settings.VMSettingsWindow(
self.vm, self.qtapp, "basic")
self.assertEqual(self.dialog.vmname.text(), "testvm",
"Name displayed incorrectly")
self.assertTrue("blue" in self.dialog.vmlabel.currentText(),
"Incorrect label displayed")
displayed_template = self.dialog.template_name.currentText()
correct_template = self.vm.template.name
self.assertTrue("current" in displayed_template,
"Template incorrectly not shown as current")
self.assertTrue(correct_template in displayed_template,
"Template not displayed correctly")
displayed_netvm = self.dialog.netVM.currentText()
correct_netvm = self.vm.netvm.name
self.assertTrue("current" in displayed_netvm,
"NetVM incorrectly not shown as current")
self.assertTrue(correct_netvm in displayed_netvm,
"NetVM not displayed correctly")
self.assertEqual(self.dialog.include_in_backups.isChecked(),
self.vm.include_in_backups,
"Incorrect 'include in backups' state")
self.assertEqual(self.dialog.run_in_debug_mode.isChecked(),
self.vm.debug,
"Incorrect 'run in debug mode' state")
self.assertEqual(self.dialog.autostart_vm.isChecked(),
self.vm.autostart,
"Incorrect 'autostart' state")
self.assertEqual(self.dialog.type_label.text(),
self.vm.klass,
"Incorrect class displayed")
self.assertEqual(self.dialog.ip_label.text(),
self.vm.ip,
"Incorrect IP displayed")
self.assertEqual(self.dialog.netmask_label.text(),
self.vm.visible_netmask,
"Incorrect netmask displayed")
self.assertEqual(self.dialog.gateway_label.text(),
self.vm.visible_gateway,
"Incorrect gateway displayed")
self.assertEqual(self.dialog.max_priv_storage.value(),
self.vm.volumes['private'].size // 1024 ** 2,
"Incorrect max private storage size")
self.assertEqual(self.dialog.root_resize.value(),
self.vm.volumes['root'].size // 1024 ** 2,
"Incorrect max private root size")
def test_02_basic_tab_nones(self):
self.vm = self.qapp.add_new_vm("StandaloneVM", "testvm", "blue")
# set the vm to have a default template and netvm
self.vm.netvm = None
self.dialog = vm_settings.VMSettingsWindow(
self.vm, self.qtapp, "basic")
self.assertEqual("", self.dialog.template_name.currentText(),
"No template incorrectly displayed")
displayed_netvm = self.dialog.netVM.currentText()
self.assertTrue("current" in displayed_netvm,
"None NetVM incorrectly not shown as current")
self.assertTrue("none" in displayed_netvm,
"None NetVM not displayed correctly")
self.assertEqual(self.dialog.type_label.text(), "StandaloneVM",
"Type displayed incorrectly for standaloneVM")
self.assertEqual(self.dialog.ip_label.text(),
"---",
"Incorrect IP displayed")
self.assertEqual(self.dialog.netmask_label.text(),
"---",
"Incorrect netmask displayed")
self.assertEqual(self.dialog.gateway_label.text(),
"---",
"Incorrect gateway displayed")
@unittest.expectedFailure
def test_03_change_label(self):
# this test fails due to error where we check whether label is visible
self.vm = self.qapp.add_new_vm("AppVM", "testvm", "blue")
self.dialog = vm_settings.VMSettingsWindow(
self.vm, self.qtapp, "basic")
new_label = self._set_noncurrent(self.dialog.vmlabel)
self._click_ok()
self.assertEqual(str(self.vm.label), new_label,
"Label is not set correctly")
def test_04_change_template(self):
self.vm = self.qapp.add_new_vm("AppVM", "testvm", "blue")
self.dialog = vm_settings.VMSettingsWindow(
self.vm, self.qtapp, "basic")
new_template = self._set_noncurrent(self.dialog.template_name)
self._click_ok()
self.assertEqual(self.vm.template.name, new_template,
"Template is not set correctly")
def test_05_change_networking(self):
self.vm = self.qapp.add_new_vm("AppVM", "testvm", "blue")
self.dialog = vm_settings.VMSettingsWindow(
self.vm, self.qtapp, "basic")
new_netvm = self._set_noncurrent(self.dialog.netVM)
self._click_ok()
self.assertEqual(self.vm.netvm.name, new_netvm,
"NetVM is not set correctly")
def test_06_change_networking_none(self):
self.vm = self.qapp.add_new_vm("AppVM", "testvm", "blue")
self.dialog = vm_settings.VMSettingsWindow(
self.vm, self.qtapp, "basic")
self._set_none(self.dialog.netVM)
self._click_ok()
self.assertIsNone(self.vm.netvm,
"None netVM is not set correctly")
def test_07_change_networking_to_default(self):
self.vm = self.qapp.add_new_vm("AppVM", "testvm", "blue")
for vm in self.qapp.domains:
if getattr(vm, 'provides_network', False)\
and vm != self.qapp.default_netvm:
self.vm.netvm = vm
break
self.dialog = vm_settings.VMSettingsWindow(
self.vm, self.qtapp, "basic")
new_netvm = self._set_default(self.dialog.netVM)
self._click_ok()
self.assertTrue(self.vm.netvm.name in new_netvm,
"NetVM is not set correctly")
self.assertTrue(self.vm.property_is_default('netvm'))
@unittest.expectedFailure
def test_08_basic_checkboxes_true(self):
self.vm = self.qapp.add_new_vm("AppVM", "testvm", "blue")
self.dialog = vm_settings.VMSettingsWindow(
self.vm, self.qtapp, "basic")
self.dialog.include_in_backups.setChecked(True)
self.dialog.autostart_vm.setChecked(True)
self.dialog.run_in_debug_mode.setChecked(True)
self._click_ok()
self.assertTrue(self.vm.include_in_backups,
"Include in backups not set to true")
self.assertTrue(self.vm.autostart,
"Autostart not set to true")
self.assertTrue(self.vm.debug,
"Debug mode not set to true")
@unittest.expectedFailure
def test_09_basic_checkboxes_false(self):
self.vm = self.qapp.add_new_vm("AppVM", "testvm", "blue")
self.dialog = vm_settings.VMSettingsWindow(
self.vm, self.qtapp, "basic")
self.dialog.include_in_backups.setChecked(False)
self.dialog.autostart_vm.setChecked(False)
self.dialog.run_in_debug_mode.setChecked(False)
self._click_ok()
self.assertFalse(self.vm.include_in_backups,
"Include in backups not set to false")
self.assertFalse(self.vm.autostart,
"Autostart not set to false")
self.assertFalse(self.vm.debug,
"Debug mode not set to false")
def test_10_increase_private_storage(self):
self.vm = self.qapp.add_new_vm("AppVM", "testvm", "blue")
self.dialog = vm_settings.VMSettingsWindow(
self.vm, self.qtapp, "basic")
current_storage = self.vm.volumes['private'].size // 1024**2
new_storage = current_storage + 512
self.dialog.max_priv_storage.setValue(new_storage)
self._click_ok()
self.assertEqual(self.vm.volumes['private'].size // 1024**2,
new_storage)
# TODO are dependencies correctly processed
@unittest.mock.patch('PyQt4.QtGui.QProgressDialog')
@unittest.mock.patch('PyQt4.QtGui.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")
self.dialog = vm_settings.VMSettingsWindow(
self.vm, self.qtapp, "basic")
self.assertTrue(self.dialog.rename_vm_button.isEnabled())
mock_input.return_value = ("testvm2", True)
self.dialog.rename_vm_button.click()
mock_thread.assert_called_with(self.vm, "testvm2", unittest.mock.ANY)
mock_thread().start.assert_called_with()
# TODO: thread tests for rename
@unittest.mock.patch('PyQt4.QtGui.QProgressDialog')
@unittest.mock.patch('PyQt4.QtGui.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")
self.dialog = vm_settings.VMSettingsWindow(
self.vm, self.qtapp, "basic")
self.assertTrue(self.dialog.clone_vm_button.isEnabled())
mock_input.return_value = ("testvm2", True)
self.dialog.clone_vm_button.click()
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('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")
self.dialog = vm_settings.VMSettingsWindow(
self.vm, self.qtapp, "basic")
self.assertTrue(self.dialog.delete_vm_button.isEnabled())
# try with a wrong name
mock_input.return_value = ("testvm2", True)
self.dialog.delete_vm_button.click()
self.assertEqual(mock_warning.call_count, 1)
# and now correct one
mock_input.return_value = ("testvm", True)
self.dialog.delete_vm_button.click()
mock_thread.assert_called_with(self.vm)
mock_thread().start.assert_called_with()
# Advanced Tab
def test_20_advanced_loads(self):
self.vm = self.qapp.add_new_vm("AppVM", "testvm", "blue")
self.dialog = vm_settings.VMSettingsWindow(
self.vm, self.qtapp, "advanced")
self.assertEqual(self.dialog.init_mem.value(), self.vm.memory,
"Incorrect initial memory")
# default maxmem
self.assertEqual(self.dialog.max_mem_size.value(),
self.vm.property_get_default('maxmem'),
"Maxmem incorrectly displayed for default value")
self.assertEqual(self.dialog.vcpus.value(), self.vm.vcpus,
"Incorrect number of VCPUs")
self.assertTrue(self.dialog.include_in_balancing.isChecked(),
"Include in memory balancing incorrectly not checked")
# kernel
self.assertTrue(self.vm.kernel in self.dialog.kernel.currentText(),
"Kernel displayed incorrectly")
# default dispvm
self.assertTrue(
str(self.vm.default_dispvm) in
self.dialog.default_dispvm.currentText(),
"Default dispVM incorrectly displayed")
self.assertEqual(self.vm.template_for_dispvms,
self.dialog.dvm_template_checkbox.isChecked(),
"Incorrectly shown to be template for dispvms")
# virtmode
self.assertTrue("default" in self.dialog.virt_mode.currentText())
self.assertTrue("PVH" in self.dialog.virt_mode.currentText())
def test_21_nondefaultmaxmem(self):
self.vm = self.qapp.add_new_vm("AppVM", "testvm", "blue")
self.vm.maxmem = 5000
self.dialog = vm_settings.VMSettingsWindow(
self.vm, self.qtapp, "advanced")
self.assertEqual(self.dialog.max_mem_size.value(), 5000)
self.dialog.include_in_balancing.setChecked(False)
self._click_ok()
self.assertEqual(self.vm.maxmem, 0)
self.dialog.deleteLater()
self.dialog = vm_settings.VMSettingsWindow(
self.vm, self.qtapp, "advanced")
self.assertFalse(self.dialog.include_in_balancing.isChecked())
self.dialog.include_in_balancing.setChecked(True)
self.assertEqual(self.dialog.max_mem_size.value(), 5000)
self._click_ok()
self.assertEqual(self.vm.maxmem, 5000)
def test_22_initmem(self):
self.vm = self.qapp.add_new_vm("AppVM", "testvm", "blue")
self.vm.memory = 500
self.dialog = vm_settings.VMSettingsWindow(
self.vm, self.qtapp, "advanced")
self.assertEqual(self.dialog.init_mem.value(), 500,
"Incorrect initial memory")
self.dialog.init_mem.setValue(600)
self._click_ok()
self.assertEqual(self.vm.memory, 600, "Setting initial memory failed")
def test_23_vcpus(self):
self.vm = self.qapp.add_new_vm("AppVM", "testvm", "blue")
self.vm.vcpus = 1
self.dialog = vm_settings.VMSettingsWindow(
self.vm, self.qtapp, "advanced")
self.assertEqual(self.dialog.vcpus.value(), 1,
"Incorrect number of VCPUs")
self.dialog.vcpus.setValue(2)
self._click_ok()
self.assertEqual(self.vm.vcpus, 2,
"Incorrect number of VCPUs")
def test_24_kernel(self):
self.vm = self.qapp.add_new_vm("AppVM", "testvm", "blue")
self.dialog = vm_settings.VMSettingsWindow(
self.vm, self.qtapp, "advanced")
new_kernel = self._set_noncurrent(self.dialog.kernel)
self._click_ok()
self.assertEqual(self.vm.kernel, new_kernel)
self.dialog.deleteLater()
self.dialog = vm_settings.VMSettingsWindow(
self.vm, self.qtapp, "advanced")
self._set_default(self.dialog.kernel)
self._click_ok()
self.assertTrue(self.vm.property_is_default('kernel'))
def test_25_virtmode_change(self):
self.vm = self.qapp.add_new_vm("AppVM", "testvm", "blue")
modes = ["HVM", "PVH", "PV"]
for mode in modes:
self.dialog = vm_settings.VMSettingsWindow(
self.vm, self.qtapp, "advanced")
self._set_value(self.dialog.virt_mode, mode)
self._click_ok()
self.assertEqual(self.vm.virt_mode.upper(), mode)
self.dialog.deleteLater()
self.dialog = vm_settings.VMSettingsWindow(
self.vm, self.qtapp, "advanced")
self._set_default(self.dialog.virt_mode)
self._click_ok()
self.assertTrue(self.vm.property_is_default('virt_mode'))
def test_26_default_dispvm(self):
self.vm = self.qapp.add_new_vm("AppVM", "testvm", "blue")
self.dialog = vm_settings.VMSettingsWindow(
self.vm, self.qtapp, "advanced")
new_dvm = self._set_noncurrent(self.dialog.default_dispvm)
self._click_ok()
self.assertEqual(self.vm.default_dispvm.name, new_dvm)
self.dialog.deleteLater()
self.dialog = vm_settings.VMSettingsWindow(
self.vm, self.qtapp, "advanced")
self._set_default(self.dialog.default_dispvm)
self._click_ok()
self.assertTrue(self.vm.property_is_default('default_dispvm'))
@unittest.mock.patch('subprocess.check_call')
def test_27_boot_cdrom(self, mock_call):
self.vm = self.qapp.add_new_vm("AppVM", "testvm", "blue")
self.dialog = vm_settings.VMSettingsWindow(
self.vm, self.qtapp, "advanced")
self.dialog.boot_from_device_button.click()
mock_call.assert_called_with(['qubes-vm-boot-from-device', "testvm"])
def _click_ok(self):
okwidget = self.dialog.buttonBox.button(
self.dialog.buttonBox.Ok)
QtTest.QTest.mouseClick(okwidget, QtCore.Qt.LeftButton)
def _click_cancel(self):
cancelwidget = self.dialog.buttonBox.button(
self.dialog.buttonBox.Cancel)
QtTest.QTest.mouseClick(cancelwidget, QtCore.Qt.LeftButton)
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_default(self, widget):
if widget.count() < 2:
self.skipTest("not enough choices for " + widget.objectName())
widget.setCurrentIndex(0)
while "default" not in widget.currentText():
widget.setCurrentIndex(widget.currentIndex() + 1)
return widget.currentText()
def _set_none(self, widget):
if widget.count() < 2:
self.skipTest("not enough choices for " + widget.objectName())
widget.setCurrentIndex(0)
while "none" not in widget.currentText():
widget.setCurrentIndex(widget.currentIndex() + 1)
return widget.currentText()
def _set_value(self, widget, value):
if widget.count() < 2:
self.skipTest("not enough choices for " + widget.objectName())
widget.setCurrentIndex(0)
while value != widget.currentText():
widget.setCurrentIndex(widget.currentIndex() + 1)
return widget.currentText()
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()

View File

@ -123,9 +123,12 @@ rm -rf $RPM_BUILD_ROOT
%{python3_sitelib}/qubesmanager/tests/__pycache__
%{python3_sitelib}/qubesmanager/tests/__init__.py
%{python3_sitelib}/qubesmanager/tests/test_backup_01.py
%{python3_sitelib}/qubesmanager/tests/test_backup.py
%{python3_sitelib}/qubesmanager/tests/test_backup_utils.py
%{python3_sitelib}/qubesmanager/tests/test_global_settings.py
%{python3_sitelib}/qubesmanager/tests/test_qube_manager.py
%{python3_sitelib}/qubesmanager/tests/test_create_new_vm.py
%{python3_sitelib}/qubesmanager/tests/test_vm_settings.py
%dir %{python3_sitelib}/qubesmanager-*.egg-info
%{python3_sitelib}/qubesmanager-*.egg-info/*