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:
commit
6550070135
697
qubesmanager/tests/test_backup.py
Normal file
697
qubesmanager/tests/test_backup.py
Normal 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()
|
@ -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()
|
97
qubesmanager/tests/test_backup_utils.py
Normal file
97
qubesmanager/tests/test_backup_utils.py
Normal 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()
|
318
qubesmanager/tests/test_create_new_vm.py
Normal file
318
qubesmanager/tests/test_create_new_vm.py
Normal 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()
|
@ -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
605
qubesmanager/tests/test_vm_settings.py
Normal file
605
qubesmanager/tests/test_vm_settings.py
Normal 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()
|
@ -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/*
|
||||
|
Loading…
Reference in New Issue
Block a user