516 lines
19 KiB
Python
516 lines
19 KiB
Python
# This work is licensed under the GNU GPLv2 or later.
|
|
# See the COPYING file in the top-level directory.
|
|
|
|
from tests.uitests import utils as uiutils
|
|
import tests.utils
|
|
|
|
|
|
class Details(uiutils.UITestCase):
|
|
"""
|
|
UI tests for virt-manager's VM details window
|
|
"""
|
|
|
|
def _select_hw(self, win, hwname, tabname):
|
|
c = win.find(hwname, "table cell")
|
|
if not c.onscreen:
|
|
hwlist = win.find("hw-list")
|
|
hwlist.click()
|
|
while not c.onscreen:
|
|
self.pressKey("Down")
|
|
c.click()
|
|
tab = win.find(tabname, None)
|
|
uiutils.check_in_loop(lambda: tab.showing)
|
|
return tab
|
|
|
|
def _stop_vm(self, win):
|
|
run = win.find("Run", "push button")
|
|
win.find("Shut Down", "push button").click()
|
|
uiutils.check_in_loop(lambda: run.sensitive)
|
|
|
|
def _start_vm(self, win):
|
|
run = win.find("Run", "push button")
|
|
run.click()
|
|
uiutils.check_in_loop(lambda: not run.sensitive)
|
|
|
|
|
|
##############
|
|
# Test cases #
|
|
##############
|
|
|
|
def testDetailsHardwareSmokeTest(self):
|
|
"""
|
|
Open the VM with all the crazy hardware and just verify that each
|
|
HW panel shows itself without raising any error.
|
|
"""
|
|
win = self._open_details_window(double=True)
|
|
lst = win.find("hw-list", "table")
|
|
self._walkUIList(win, lst, lambda: False)
|
|
|
|
# Select XML editor, and reverse walk the list
|
|
win.find("XML", "page tab").click()
|
|
self._walkUIList(win, lst, lambda: False, reverse=True)
|
|
|
|
def _testRename(self, origname, newname):
|
|
win = self._open_details_window(origname)
|
|
|
|
# Ensure the Overview page is the first selected
|
|
win.find("Hypervisor Details", "label")
|
|
win.find("Overview", "table cell").click()
|
|
|
|
oldcell = self.app.root.find_fuzzy(origname, "table cell")
|
|
win.find("Name:", "text").text = newname
|
|
win.find("config-apply", "push button").click()
|
|
|
|
# Confirm lists were updated
|
|
self.app.root.find("%s on" % newname, "frame")
|
|
self.app.root.find_fuzzy(newname, "table cell")
|
|
|
|
# Make sure the old entry is gone
|
|
uiutils.check_in_loop(lambda: origname not in oldcell.name)
|
|
|
|
def testDetailsRenameSimple(self):
|
|
"""
|
|
Rename a simple VM
|
|
"""
|
|
self._testRename("test-clone-simple", "test-new-name")
|
|
|
|
def testDetailsRenameNVRAM(self):
|
|
"""
|
|
Rename a VM that will trigger the nvram behavior
|
|
"""
|
|
origname = "test-many-devices"
|
|
# Shutdown the VM
|
|
self.app.root.find_fuzzy(origname, "table cell").click()
|
|
b = self.app.root.find("Shut Down", "push button")
|
|
b.click()
|
|
# This insures the VM finished shutting down
|
|
uiutils.check_in_loop(lambda: b.sensitive is False)
|
|
|
|
self._testRename(origname, "test-new-name")
|
|
|
|
def testDetailsEditDomain1(self):
|
|
"""
|
|
Test overview, memory, cpu pages
|
|
"""
|
|
self.app.uri = tests.utils.URIs.kvm
|
|
win = self._open_details_window(vmname="test-many-devices")
|
|
appl = win.find("config-apply", "push button")
|
|
|
|
# Overview description
|
|
tab = self._select_hw(win, "Overview", "overview-tab")
|
|
tab.find("Description:", "text").text = "hey new description"
|
|
tab.find("Title:", "text").text = "hey new title"
|
|
appl.click()
|
|
uiutils.check_in_loop(lambda: not appl.sensitive)
|
|
|
|
|
|
# Memory balloon
|
|
tab = self._select_hw(win, "Memory", "memory-tab")
|
|
tab.find("Current allocation:", "spin button").text = "300"
|
|
tab.find("Maximum allocation:", "spin button").text = "800"
|
|
appl.click()
|
|
uiutils.check_in_loop(lambda: not appl.sensitive)
|
|
|
|
|
|
# CPU hotplug
|
|
tab = self._select_hw(win, "CPUs", "cpu-tab")
|
|
tab.find("Current allocation:", "spin button").text = "2"
|
|
appl.click()
|
|
uiutils.check_in_loop(lambda: not appl.sensitive)
|
|
|
|
# Static CPU config
|
|
self._stop_vm(win)
|
|
# more cpu config: host-passthrough, copy, clear CPU, manual
|
|
tab.find("cpu-model").click_combo_entry()
|
|
tab.find_fuzzy("Clear CPU", "menu item").click()
|
|
appl.click()
|
|
uiutils.check_in_loop(lambda: not appl.sensitive)
|
|
tab.find("cpu-model").click_combo_entry()
|
|
tab.find("coreduo", "menu item").click()
|
|
appl.click()
|
|
uiutils.check_in_loop(lambda: not appl.sensitive)
|
|
tab.find("cpu-model").click_combo_entry()
|
|
tab.find("Application Default", "menu item").click()
|
|
appl.click()
|
|
uiutils.check_in_loop(lambda: not appl.sensitive)
|
|
tab.find_fuzzy("Copy host").click()
|
|
tab.find("cpu-model").click_combo_entry()
|
|
tab.find("Hypervisor Default", "menu item").click()
|
|
appl.click()
|
|
uiutils.check_in_loop(lambda: not appl.sensitive)
|
|
|
|
# CPU topology
|
|
tab.find_fuzzy("Manually set", "check").click()
|
|
tab.find("Sockets:", "spin button").typeText("8")
|
|
tab.find("Cores:", "spin button").typeText("2")
|
|
tab.find("Threads:", "spin button").typeText("2")
|
|
appl.click()
|
|
uiutils.check_in_loop(lambda: not appl.sensitive)
|
|
self.assertTrue(tab.find_fuzzy("Maximum", "spin").text == "32")
|
|
|
|
|
|
def testDetailsEditDomain2(self):
|
|
"""
|
|
Test boot and OS pages
|
|
"""
|
|
win = self._open_details_window(vmname="test-many-devices")
|
|
appl = win.find("config-apply", "push button")
|
|
self._stop_vm(win)
|
|
|
|
|
|
# OS edits
|
|
tab = self._select_hw(win, "OS information", "os-tab")
|
|
entry = tab.find("oslist-entry")
|
|
self.assertEqual(entry.text, "Fedora")
|
|
entry.click()
|
|
self.pressKey("Down")
|
|
popover = win.find("oslist-popover")
|
|
popover.find("include-eol").click()
|
|
entry.text = "fedora12"
|
|
popover.find_fuzzy("fedora12").bring_on_screen().click()
|
|
uiutils.check_in_loop(lambda: not popover.visible)
|
|
self.assertEqual(entry.text, "Fedora 12")
|
|
appl.click()
|
|
uiutils.check_in_loop(lambda: not appl.sensitive)
|
|
self.assertEqual(entry.text, "Fedora 12")
|
|
|
|
|
|
# Boot tweaks
|
|
def check_bootorder(c):
|
|
# Click the bootlist checkbox, which is hard to find in the tree
|
|
import dogtail.rawinput
|
|
x = c.position[0] - 30
|
|
y = c.position[1] + c.size[1] / 2
|
|
button = 1
|
|
dogtail.rawinput.click(x, y, button)
|
|
|
|
tab = self._select_hw(win, "Boot Options", "boot-tab")
|
|
self._stop_vm(win)
|
|
tab.find_fuzzy("Start virtual machine on host", "check box").click()
|
|
tab.find("Enable boot menu", "check box").click()
|
|
check_bootorder(tab.find("SCSI Disk 1", "table cell"))
|
|
tab.find("boot-movedown", "push button").click()
|
|
tab.find("Floppy 1", "table cell").click()
|
|
tab.find("boot-moveup", "push button").click()
|
|
appl.click()
|
|
uiutils.check_in_loop(lambda: not appl.sensitive)
|
|
|
|
# Kernel boot
|
|
tab.find_fuzzy("Direct kernel boot", "toggle button").click_expander()
|
|
tab.find_fuzzy("Enable direct kernel", "check box").click()
|
|
tab.find("kernel-browse", "push button").click()
|
|
browsewin = self.app.root.find("Choose Storage Volume", "frame")
|
|
browsewin.find("default-pool", "table cell").click()
|
|
browsewin.find("bochs-vol", "table cell").click()
|
|
browsewin.find("Choose Volume", "push button").click()
|
|
uiutils.check_in_loop(lambda: win.active)
|
|
self.assertTrue("bochs" in tab.find("Kernel path:", "text").text)
|
|
tab.find("Initrd path:", "text").text = "/tmp/initrd"
|
|
tab.find("DTB path:", "text").text = "/tmp/dtb"
|
|
tab.find("Kernel args:", "text").text = "console=ttyS0"
|
|
appl.click()
|
|
uiutils.check_in_loop(lambda: not appl.sensitive)
|
|
|
|
|
|
def testDetailsEditDiskNet(self):
|
|
"""
|
|
Test disk and network devices
|
|
"""
|
|
win = self._open_details_window(vmname="test-many-devices")
|
|
appl = win.find("config-apply", "push button")
|
|
hwlist = win.find("hw-list")
|
|
self._stop_vm(win)
|
|
|
|
|
|
# Disk options
|
|
tab = self._select_hw(win, "IDE Disk 1", "disk-tab")
|
|
tab.find("Shareable:", "check box").click()
|
|
tab.find("Readonly:", "check box").click()
|
|
tab.find("Advanced options", "toggle button").click_expander()
|
|
tab.find("Storage format:", "text").text = "vmdk"
|
|
tab.find("Serial number:", "text").text = "1234-ABCD"
|
|
tab.find("Disk bus:", "text").text = "usb"
|
|
tab.find("Performance options", "toggle button").click_expander()
|
|
tab.find("IO mode:", "text").text = "threads"
|
|
tab.find("Cache mode:", "text").text = "unsafe"
|
|
appl.click()
|
|
uiutils.check_in_loop(lambda: not appl.sensitive)
|
|
# Device is now 'USB Disk 1'
|
|
c = hwlist.find("USB Disk 1", "table cell")
|
|
self.assertTrue(c.state_selected)
|
|
tab.find("Removable:", "check box").click()
|
|
appl.click()
|
|
uiutils.check_in_loop(lambda: not appl.sensitive)
|
|
|
|
|
|
# Network values
|
|
tab = self._select_hw(win, "NIC :54:32:10", "network-tab")
|
|
src = tab.find("Network source:", "combo box")
|
|
src.click()
|
|
tab.find_fuzzy("macvtap", "menu item").bring_on_screen().click()
|
|
tab.find("Device model:", "combo box").click_combo_entry()
|
|
tab.find("rtl8139", "menu item").click()
|
|
mode = tab.find_fuzzy("Source mode:", "combo box")
|
|
mode.click_combo_entry()
|
|
self.assertTrue(mode.find("Bridge", "menu item").selected)
|
|
self.pressKey("Escape")
|
|
appl.click()
|
|
uiutils.check_in_loop(lambda: not appl.sensitive)
|
|
|
|
# Manual bridge
|
|
src.click()
|
|
tab.find_fuzzy("Specify shared device",
|
|
"menu item").bring_on_screen().click()
|
|
appl.click()
|
|
# Check validation error
|
|
alert = self.app.root.find("vmm dialog", "alert")
|
|
alert.find_fuzzy("Error changing VM configuration", "label")
|
|
alert.find("Close", "push button").click()
|
|
tab.find("Bridge name:", "text").text = "zbr0"
|
|
appl.click()
|
|
uiutils.check_in_loop(lambda: not appl.sensitive)
|
|
|
|
# Network with portops
|
|
src.click()
|
|
self.pressKey("Home")
|
|
tab.find_fuzzy("plainbridge-portgroups",
|
|
"menu item").bring_on_screen().click()
|
|
c = tab.find_fuzzy("Portgroup:", "combo box")
|
|
c.click_combo_entry()
|
|
self.assertTrue(c.find("engineering", "menu item").selected)
|
|
self.pressKey("Escape")
|
|
appl.click()
|
|
uiutils.check_in_loop(lambda: not appl.sensitive)
|
|
|
|
# Network with vport stuff
|
|
src.click()
|
|
tab.find_fuzzy("OpenVSwitch",
|
|
"menu item").bring_on_screen().click()
|
|
t = tab.find("Virtual port", "toggle button")
|
|
t.click()
|
|
t.find("Type:", "text").text = "802.1Qbg"
|
|
t.find("Managerid:", "text").text = "12"
|
|
t.find("Typeid:", "text").text = "1193046"
|
|
t.find("Typeid version:", "text").text = "1"
|
|
t.find("Instance id:", "text").text = (
|
|
"09b11c53-8b5c-4eeb-8f00-d84eaa0aaa3b")
|
|
appl.click()
|
|
uiutils.check_in_loop(lambda: not appl.sensitive)
|
|
|
|
|
|
def testDetailsEditDevices(self):
|
|
"""
|
|
Test all other devices
|
|
"""
|
|
win = self._open_details_window(vmname="test-many-devices")
|
|
appl = win.find("config-apply", "push button")
|
|
self._stop_vm(win)
|
|
|
|
|
|
# Graphics
|
|
tab = self._select_hw(win, "Display VNC", "graphics-tab")
|
|
tab.find("Type:", "combo box").click_combo_entry()
|
|
tab.find("Spice server", "menu item").click()
|
|
appl.click()
|
|
uiutils.check_in_loop(lambda: not appl.sensitive)
|
|
|
|
tab.find("Type:", "combo box").click_combo_entry()
|
|
tab.find("VNC server", "menu item").click()
|
|
appl.click()
|
|
uiutils.check_in_loop(lambda: not appl.sensitive)
|
|
|
|
|
|
# Sound device
|
|
tab = self._select_hw(win, "Sound sb16", "sound-tab")
|
|
tab.find("Model:", "text").text = "ac97"
|
|
appl.click()
|
|
uiutils.check_in_loop(lambda: not appl.sensitive)
|
|
|
|
|
|
# Host device
|
|
tab = self._select_hw(win, "PCI 0000:00:19.0", "host-tab")
|
|
tab.find("ROM BAR:", "check box").click()
|
|
appl.click()
|
|
uiutils.check_in_loop(lambda: not appl.sensitive)
|
|
|
|
|
|
# Video device
|
|
tab = self._select_hw(win, "Video VMVGA", "video-tab")
|
|
tab.find("Model:", "text").text = "virtio"
|
|
tab.find("3D acceleration:", "check box").click()
|
|
appl.click()
|
|
uiutils.check_in_loop(lambda: not appl.sensitive)
|
|
|
|
|
|
# Watchdog
|
|
tab = self._select_hw(win, "Watchdog", "watchdog-tab")
|
|
tab.find("Model:", "text").text = "diag288"
|
|
tab.find("Action:", "text").click()
|
|
self.pressKey("Down")
|
|
appl.click()
|
|
uiutils.check_in_loop(lambda: not appl.sensitive)
|
|
|
|
|
|
# Controller SCSI
|
|
tab = self._select_hw(
|
|
win, "Controller Virtio SCSI 9", "controller-tab")
|
|
tab.find("controller-model", "combo box").click_combo_entry()
|
|
tab.find("Hypervisor default", "menu item").click()
|
|
tab.find("SCSI Disk 1 on 9:0:0:0", "table cell")
|
|
appl.click()
|
|
uiutils.check_in_loop(lambda: not appl.sensitive)
|
|
|
|
# Controller USB
|
|
tab = self._select_hw(win, "Controller USB 0", "controller-tab")
|
|
tab.find("controller-model", "combo box").click_combo_entry()
|
|
tab.find("USB 2", "menu item").click()
|
|
appl.click()
|
|
uiutils.check_in_loop(lambda: not appl.sensitive)
|
|
tab = self._select_hw(win, "Controller USB 0", "controller-tab")
|
|
tab.find("controller-model", "combo box").click_combo_entry()
|
|
tab.find("USB 3", "menu item").click()
|
|
appl.click()
|
|
uiutils.check_in_loop(lambda: not appl.sensitive)
|
|
|
|
|
|
# Filesystem tweaks
|
|
tab = self._select_hw(win, "Filesystem /target/", "filesystem-tab")
|
|
tab.find("Driver:", "combo box").click()
|
|
tab.find("Path", "menu item").click()
|
|
tab.find("Write Policy:", "combo box").click()
|
|
tab.find("Immediate", "menu item").click()
|
|
tab.find("Source path:", "text").text = "/frib1"
|
|
tab.find("Target path:", "text").text = "newtarget"
|
|
tab.find_fuzzy("Export filesystem", "check box").click()
|
|
appl.click()
|
|
uiutils.check_in_loop(lambda: not appl.sensitive)
|
|
|
|
|
|
# Smartcard tweaks
|
|
tab = self._select_hw(win, "Smartcard", "smartcard-tab")
|
|
tab.find("smartcard-mode", "combo box").click_combo_entry()
|
|
tab.find("Passthrough", "menu item").click()
|
|
appl.click()
|
|
uiutils.check_in_loop(lambda: not appl.sensitive)
|
|
|
|
|
|
# vsock tweaks
|
|
tab = self._select_hw(win, "Virtio VSOCK", "vsock-tab")
|
|
addr = tab.find("vsock-cid")
|
|
auto = tab.find("vsock-auto")
|
|
self.assertTrue(addr.text == "5")
|
|
auto.click()
|
|
uiutils.check_in_loop(lambda: not addr.visible)
|
|
appl.click()
|
|
|
|
|
|
def testDetailsMiscEdits(self):
|
|
"""
|
|
Test misc editing behavior, like checking for unapplied
|
|
changes
|
|
"""
|
|
win = self._open_details_window(vmname="test-many-devices",
|
|
double=True)
|
|
hwlist = win.find("hw-list")
|
|
|
|
# Live device removal, see results after shutdown
|
|
disklabel = "SCSI Disk 1"
|
|
tab = self._select_hw(win, disklabel, "disk-tab")
|
|
win.find("config-remove", "push button").click()
|
|
alert = self.app.root.find("vmm dialog", "alert")
|
|
alert.find_fuzzy("Are you sure you want to remove", "label")
|
|
alert.find_fuzzy("Don't ask", "check").click()
|
|
alert.find("Yes", "push button").click()
|
|
|
|
alert = self.app.root.find("vmm dialog", "alert")
|
|
alert.find_fuzzy("Device could not be removed", "label")
|
|
alert.find("OK", "push button").click()
|
|
|
|
c = hwlist.find(disklabel, "table cell")
|
|
self._stop_vm(win)
|
|
self.assertTrue(c.text != disklabel)
|
|
|
|
# Remove a device for offline VM
|
|
tab = self._select_hw(win, "SCSI CDROM 1", "disk-tab")
|
|
win.find("config-remove", "push button").click()
|
|
uiutils.check_in_loop(lambda: win.active)
|
|
|
|
# Cancelling changes
|
|
tab = self._select_hw(win, "IDE Disk 1", "disk-tab")
|
|
share = tab.find("Shareable:", "check box")
|
|
self.assertFalse(share.checked)
|
|
share.click()
|
|
win.find("config-cancel").click()
|
|
self.assertFalse(share.checked)
|
|
|
|
# Unapplied, clicking no
|
|
share = tab.find("Shareable:", "check box")
|
|
share.click()
|
|
hwlist.find("CPUs", "table cell").click()
|
|
alert = self.app.root.find("vmm dialog", "alert")
|
|
alert.find_fuzzy("There are unapplied changes", "label")
|
|
alert.find("No", "push button").click()
|
|
tab = self._select_hw(win, "IDE Disk 1", "disk-tab")
|
|
self.assertFalse(share.checked)
|
|
|
|
# Unapplied changes but clicking yes
|
|
share.click()
|
|
hwlist.find("CPUs", "table cell").click()
|
|
alert = self.app.root.find("vmm dialog", "alert")
|
|
alert.find_fuzzy("There are unapplied changes", "label")
|
|
alert.find_fuzzy("Don't warn", "check box").click()
|
|
alert.find("Yes", "push button").click()
|
|
tab = self._select_hw(win, "IDE Disk 1", "disk-tab")
|
|
self.assertTrue(share.checked)
|
|
|
|
# Make sure no unapplied changes option sticks
|
|
share.click()
|
|
self._select_hw(win, "CPUs", "cpu-tab")
|
|
tab = self._select_hw(win, "IDE Disk 1", "disk-tab")
|
|
self.assertTrue(share.checked)
|
|
|
|
# VM State change doesn't refresh UI
|
|
share.click()
|
|
self._start_vm(win)
|
|
self.assertTrue(not share.checked)
|
|
|
|
# Now apply changes to running VM, ensure they show up on shutdown
|
|
win.find("config-apply").click()
|
|
alert = self.app.root.find("vmm dialog", "alert")
|
|
alert.find_fuzzy("changes will take effect", "label")
|
|
alert.find("OK", "push button").click()
|
|
self.assertTrue(share.checked)
|
|
self._stop_vm(win)
|
|
self.assertTrue(not share.checked)
|
|
|
|
def testDetailsXMLEdit(self):
|
|
"""
|
|
Test XML editing interaction
|
|
"""
|
|
self.app.open(xmleditor_enabled=True)
|
|
win = self._open_details_window(vmname="test-clone-simple")
|
|
finish = win.find("config-apply")
|
|
xmleditor = win.find("XML editor")
|
|
|
|
# Edit vcpu count and verify it's reflected in CPU page
|
|
tab = self._select_hw(win, "CPUs", "cpu-tab")
|
|
win.find("XML", "page tab").click()
|
|
xmleditor.text = xmleditor.text.replace(">5</vcpu", ">8</vcpu")
|
|
finish.click()
|
|
win.find("Details", "page tab").click()
|
|
self.assertEqual(
|
|
tab.find("Current allocation:", "spin button").text, "8")
|
|
|
|
# Make some disk edits
|
|
tab = self._select_hw(win, "IDE Disk 1", "disk-tab")
|
|
win.find("XML", "page tab").click()
|
|
origpath = "/dev/default-pool/test-clone-simple.img"
|
|
newpath = "/path/FOOBAR"
|
|
xmleditor.text = xmleditor.text.replace(origpath, newpath)
|
|
finish.click()
|
|
win.find("Details", "page tab").click()
|
|
self.assertTrue(win.find("disk-source-path").text, newpath)
|
|
|
|
# Do standard xmleditor tests
|
|
self._test_xmleditor_interactions(win, finish)
|