mirror of
https://github.com/virt-manager/virt-manager.git
synced 2025-01-22 22:03:58 +03:00
uitests: More work to drop sleeping and hacks
Signed-off-by: Cole Robinson <crobinso@redhat.com>
This commit is contained in:
parent
ba08f84b34
commit
092a62552c
@ -2,7 +2,6 @@
|
||||
# See the COPYING file in the top-level directory.
|
||||
|
||||
import re
|
||||
import time
|
||||
|
||||
from gi.repository import Gdk
|
||||
|
||||
@ -17,16 +16,20 @@ class _FuzzyPredicate(dogtail.predicate.Predicate):
|
||||
"""
|
||||
Object dogtail/pyatspi want for node searching.
|
||||
"""
|
||||
def __init__(self, name=None, roleName=None, labeller_text=None):
|
||||
def __init__(self, name=None, roleName=None, labeller_text=None,
|
||||
focusable=False, onscreen=False):
|
||||
"""
|
||||
:param name: Match node.name or node.labeller.text if
|
||||
labeller_text not specified
|
||||
:param roleName: Match node.roleName
|
||||
:param labeller_text: Match node.labeller.text
|
||||
:param focusable: Ensure node is focusable
|
||||
"""
|
||||
self._name = name
|
||||
self._roleName = roleName
|
||||
self._labeller_text = labeller_text
|
||||
self._focusable = focusable
|
||||
self._onscreen = onscreen
|
||||
|
||||
self._name_pattern = None
|
||||
self._role_pattern = None
|
||||
@ -67,6 +70,12 @@ class _FuzzyPredicate(dogtail.predicate.Predicate):
|
||||
if (self._labeller_text and
|
||||
not self._labeller_pattern.match(labeller)):
|
||||
return
|
||||
if (self._focusable and not
|
||||
(node.focusable and
|
||||
node.onscreen and
|
||||
node.sensitive and
|
||||
node.roleName not in ["page tab list", "radio button"])):
|
||||
return False
|
||||
return True
|
||||
except Exception as e:
|
||||
log.debug(
|
||||
@ -74,6 +83,16 @@ class _FuzzyPredicate(dogtail.predicate.Predicate):
|
||||
self._name, self._roleName, self._labeller_text, e)
|
||||
|
||||
|
||||
def _debug_decorator(fn):
|
||||
def _cb(self, *args, **kwargs):
|
||||
try:
|
||||
return fn(self, *args, **kwargs)
|
||||
except Exception:
|
||||
print("node=%s\nstates=%s" % (self, self.print_states()))
|
||||
raise
|
||||
return _cb
|
||||
|
||||
|
||||
class _VMMDogtailNode(dogtail.tree.Node):
|
||||
"""
|
||||
Our extensions to the dogtail node wrapper class.
|
||||
@ -106,18 +125,28 @@ class _VMMDogtailNode(dogtail.tree.Node):
|
||||
self.position[1] >= 0 and
|
||||
self.position[1] + self.size[1] < screen.get_height())
|
||||
|
||||
@_debug_decorator
|
||||
def check_onscreen(self):
|
||||
"""
|
||||
Check in a loop that the widget is onscreen
|
||||
"""
|
||||
utils.check(lambda: self.onscreen)
|
||||
|
||||
@_debug_decorator
|
||||
def check_not_onscreen(self):
|
||||
"""
|
||||
Check in a loop that the widget is not onscreen
|
||||
"""
|
||||
utils.check(lambda: not self.onscreen)
|
||||
|
||||
@_debug_decorator
|
||||
def check_focused(self):
|
||||
"""
|
||||
Check in a loop that the widget is focused
|
||||
"""
|
||||
utils.check(lambda: self.focused)
|
||||
|
||||
@_debug_decorator
|
||||
def check_sensitive(self):
|
||||
"""
|
||||
Check whether interactive widgets are sensitive or not
|
||||
@ -192,16 +221,6 @@ class _VMMDogtailNode(dogtail.tree.Node):
|
||||
clickX, clickY = self.title_coordinates()
|
||||
dogtail.rawinput.click(clickX, clickY, button)
|
||||
|
||||
def drag(self, x, y):
|
||||
"""
|
||||
Drag a window to the x/y coordinates
|
||||
"""
|
||||
time.sleep(.5)
|
||||
self.click_title()
|
||||
time.sleep(.5)
|
||||
clickX, clickY = self.title_coordinates()
|
||||
dogtail.rawinput.drag((clickX, clickY), (x, y))
|
||||
|
||||
def click(self, *args, **kwargs):
|
||||
"""
|
||||
click wrapper, give up to a second for widget to appear on
|
||||
@ -243,32 +262,45 @@ class _VMMDogtailNode(dogtail.tree.Node):
|
||||
|
||||
def window_maximize(self):
|
||||
assert self.roleName in ["frame", "dialog"]
|
||||
utils.check(lambda: self.active)
|
||||
self.click_title()
|
||||
self.grab_focus()
|
||||
s1 = self.size
|
||||
self.keyCombo("<alt>F10")
|
||||
utils.check(lambda: self.size != s1)
|
||||
self.grabFocus()
|
||||
self.grab_focus()
|
||||
|
||||
def window_close(self):
|
||||
assert self.roleName in ["frame", "alert", "dialog"]
|
||||
self.click_title()
|
||||
utils.check(lambda: self.active)
|
||||
assert self.roleName in ["frame", "alert", "dialog", "file chooser"]
|
||||
self.grab_focus()
|
||||
self.keyCombo("<alt>F4")
|
||||
utils.check(lambda: not self.showing)
|
||||
|
||||
def window_find_focusable_child(self):
|
||||
return self.find(None, focusable=True)
|
||||
|
||||
def grab_focus(self):
|
||||
if self.roleName in ["frame", "alert", "dialog", "file chooser"]:
|
||||
child = self.window_find_focusable_child()
|
||||
child.grab_focus()
|
||||
utils.check(lambda: self.active)
|
||||
return
|
||||
|
||||
self.check_onscreen()
|
||||
assert self.focusable
|
||||
self.grabFocus()
|
||||
self.check_focused()
|
||||
|
||||
|
||||
#########################
|
||||
# Widget search helpers #
|
||||
#########################
|
||||
|
||||
def find(self, name, roleName=None, labeller_text=None,
|
||||
check_active=True, recursive=True):
|
||||
check_active=True, recursive=True, focusable=False):
|
||||
"""
|
||||
Search root for any widget that contains the passed name/role regex
|
||||
strings.
|
||||
"""
|
||||
pred = _FuzzyPredicate(name, roleName, labeller_text)
|
||||
pred = _FuzzyPredicate(name, roleName, labeller_text, focusable)
|
||||
|
||||
try:
|
||||
ret = self.findChild(pred, recursive=recursive)
|
||||
|
@ -229,13 +229,16 @@ class VMMDogtailApp(object):
|
||||
self.open()
|
||||
return self._topwin
|
||||
|
||||
def error_if_already_running(self):
|
||||
# Ensure virt-manager isn't already running
|
||||
def has_dbus(self):
|
||||
dbus = Gio.DBusProxy.new_sync(
|
||||
Gio.bus_get_sync(Gio.BusType.SESSION, None), 0, None,
|
||||
"org.freedesktop.DBus", "/org/freedesktop/DBus",
|
||||
"org.freedesktop.DBus", None)
|
||||
if "org.virt-manager.virt-manager" in dbus.ListNames():
|
||||
return "org.virt-manager.virt-manager" in dbus.ListNames()
|
||||
|
||||
def error_if_already_running(self):
|
||||
# Ensure virt-manager isn't already running
|
||||
if self.has_dbus():
|
||||
raise RuntimeError("virt-manager is already running. "
|
||||
"Close it before running this test suite.")
|
||||
|
||||
|
@ -14,7 +14,7 @@ def testShowNewVM(app):
|
||||
uri="test:///default",
|
||||
extra_opts=["--show-domain-creator"])
|
||||
lib.utils.check(lambda: app.topwin.name == "New VM")
|
||||
app.topwin.keyCombo("<alt>F4")
|
||||
app.topwin.window_close()
|
||||
app.wait_for_exit()
|
||||
|
||||
|
||||
@ -26,7 +26,7 @@ def testShowHost(app):
|
||||
lib.utils.check(lambda: app.topwin.name == "test default - Connection Details")
|
||||
nametext = app.topwin.find_fuzzy("Name:", "text")
|
||||
lib.utils.check(lambda: nametext.text == "test default")
|
||||
app.topwin.keyCombo("<alt>F4")
|
||||
app.topwin.window_close()
|
||||
app.wait_for_exit()
|
||||
|
||||
|
||||
@ -39,7 +39,7 @@ def testShowDetails(app):
|
||||
lib.utils.check(lambda: not rlabel.showing)
|
||||
addhw = app.topwin.find_fuzzy("add-hardware", "button")
|
||||
lib.utils.check(lambda: addhw.showing)
|
||||
app.topwin.keyCombo("<alt>F4")
|
||||
app.topwin.window_close()
|
||||
app.wait_for_exit()
|
||||
|
||||
|
||||
@ -80,7 +80,6 @@ def testShowDelete(app):
|
||||
app.wait_for_exit()
|
||||
|
||||
|
||||
|
||||
def testShowRemoteDBusConnect(app):
|
||||
"""
|
||||
Test the remote app dbus connection
|
||||
@ -130,14 +129,12 @@ def testShowCLIError(app):
|
||||
def testCLIFirstRunURIGood(app):
|
||||
# Emulate first run with a URI that will succeed
|
||||
app.open(use_uri=False, firstrun_uri="test:///default")
|
||||
app.sleep(1)
|
||||
app.root.find("test default", "table cell")
|
||||
|
||||
|
||||
def testCLIFirstRunURIBad(app):
|
||||
# Emulate first run with a URI that will not succeed
|
||||
app.open(use_uri=False, firstrun_uri="bad:///uri")
|
||||
app.sleep(1)
|
||||
app.topwin.find("bad uri", "table cell")
|
||||
app.click_alert_button("bad:///uri", "Close")
|
||||
|
||||
@ -158,27 +155,25 @@ def testCLIFirstRunNoLibvirtd(app):
|
||||
def testCLITraceLibvirt(app):
|
||||
# Just test this for code coverage
|
||||
app.open(keyfile="allstats.ini",
|
||||
extra_opts=["--trace-libvirt=mainloop"])
|
||||
# Give it a little time to work
|
||||
app.sleep(2)
|
||||
extra_opts=["--trace-libvirt=mainloop",
|
||||
"--test-options=short-poll"])
|
||||
app.sleep(.5) # Give time for polling to trigger
|
||||
lib.utils.check(lambda: app.topwin.active)
|
||||
|
||||
|
||||
def testCLILeakDebug(app):
|
||||
# Just test this for code coverage
|
||||
app.open(keyfile="allstats.ini",
|
||||
extra_opts=["--test-options=leak-debug"])
|
||||
app.sleep(2)
|
||||
# Give it a little time to work
|
||||
lib.utils.check(lambda: app.topwin.active)
|
||||
app.topwin.keyCombo("<alt>F4")
|
||||
extra_opts=["--test-options=leak-debug",
|
||||
"--test-options=short-poll"])
|
||||
app.sleep(.5) # Give time for polling to trigger
|
||||
app.topwin.window_close()
|
||||
app.wait_for_exit()
|
||||
|
||||
|
||||
def testCLINoFirstRun(app):
|
||||
# Test a simple case of loading without any config override
|
||||
app.open(first_run=False, enable_libguestfs=None, use_uri=False)
|
||||
app.sleep(2)
|
||||
lib.utils.check(lambda: app.topwin.showing)
|
||||
|
||||
|
||||
@ -187,10 +182,8 @@ def testCLINoFork(app):
|
||||
app.open(first_run=False, enable_libguestfs=None,
|
||||
use_uri=False, no_fork=False)
|
||||
app.wait_for_exit()
|
||||
lib.utils.check(lambda: app.topwin.showing)
|
||||
app.topwin.keyCombo("<alt>F4")
|
||||
# Wait for app to exit, we don't have any other way
|
||||
app.sleep(2)
|
||||
app.topwin.window_close()
|
||||
lib.utils.check(lambda: not app.has_dbus())
|
||||
|
||||
|
||||
def testCLIGTKArgs(app):
|
||||
|
@ -98,24 +98,27 @@ def testCloneMulti(app):
|
||||
# Clone 'test-clone', check some results, make sure clone works
|
||||
manager = app.topwin
|
||||
manager.window_maximize()
|
||||
|
||||
# Shutdown this VM to prep for later
|
||||
manager.find("test-many-devices").click()
|
||||
sbutton = manager.find("Shut Down", "push button")
|
||||
sbutton.click()
|
||||
lib.utils.check(lambda: not sbutton.sensitive)
|
||||
|
||||
# Do a basic clone
|
||||
win = app.manager_open_clone("test-clone")
|
||||
win.find("Clone", "push button").click()
|
||||
lib.utils.check(lambda: not win.showing)
|
||||
app.topwin.find("test-clone1", "table cell")
|
||||
manager.find("test-clone1", "table cell")
|
||||
|
||||
# Check test-many-devices which will not work, but confirm
|
||||
# it errors gracefully
|
||||
app.topwin.find("test-many-devices").click()
|
||||
sbutton = app.topwin.find("Shut Down", "push button")
|
||||
sbutton.click()
|
||||
lib.utils.check(lambda: not sbutton.sensitive)
|
||||
app.sleep(.5)
|
||||
win = app.manager_open_clone("test-many-devices")
|
||||
win.find("Clone", "push button").click()
|
||||
app.click_alert_button("No such file or", "Close")
|
||||
|
||||
# Ensure disconnecting will close the dialog
|
||||
manager.click_title()
|
||||
manager.grab_focus()
|
||||
app.manager_conn_disconnect("test testdriver.xml")
|
||||
lib.utils.check(lambda: not win.showing)
|
||||
|
||||
@ -190,8 +193,7 @@ def testCloneError(app):
|
||||
win = app.manager_open_clone("test-clone-full")
|
||||
win.find("Clone", "push button").click()
|
||||
app.click_alert_button("not enough free space", "Close")
|
||||
lib.utils.check(lambda: win.showing)
|
||||
win.keyCombo("<alt>F4")
|
||||
win.window_close()
|
||||
|
||||
win = app.manager_open_clone("test-clone-simple")
|
||||
badname = "test/foo"
|
||||
@ -229,8 +231,7 @@ def testCloneNonmanaged(app):
|
||||
win.find("Details", "page tab").click()
|
||||
disksrc = win.find("disk-source-path")
|
||||
lib.utils.check(lambda: disksrc.text == newpath)
|
||||
win.keyCombo("<alt>F4")
|
||||
lib.utils.check(lambda: not win.active)
|
||||
win.window_close()
|
||||
|
||||
lib.utils.check(lambda: manager.active)
|
||||
win = app.manager_open_clone("test-clone-simple")
|
||||
|
@ -25,17 +25,17 @@ def testConnectionBlacklist(app):
|
||||
_delete_vm("test-arm-kernel")
|
||||
_delete_vm("test-clone-full")
|
||||
_delete_vm("test-clone-simple")
|
||||
app.sleep(.5)
|
||||
app.sleep(.5) # Give events time to register to hit full blacklist path
|
||||
lib.utils.check(
|
||||
lambda: "test-many-devices" not in app.topwin.fmt_nodes())
|
||||
|
||||
|
||||
def testConnectionConnCrash(app):
|
||||
app.open(
|
||||
extra_opts=["--test-options=conn-crash"])
|
||||
extra_opts=["--test-options=conn-crash",
|
||||
"--test-options=short-poll"])
|
||||
manager = app.topwin
|
||||
|
||||
app.sleep(1)
|
||||
manager.find(r"^test testdriver.xml - Not Connected", "table cell")
|
||||
lib.utils.check(lambda: manager.active)
|
||||
|
||||
@ -43,9 +43,10 @@ def testConnectionConnCrash(app):
|
||||
def testConnectionFakeEvents(app):
|
||||
app.open(
|
||||
extra_opts=["--test-options=fake-nodedev-event=computer",
|
||||
"--test-options=fake-agent-event=test-many-devices"])
|
||||
"--test-options=fake-agent-event=test-many-devices",
|
||||
"--test-options=short-poll"])
|
||||
manager = app.topwin
|
||||
app.sleep(2.5)
|
||||
app.sleep(1.2) # needs a second to hit both nodedev/agent event paths
|
||||
lib.utils.check(lambda: manager.active)
|
||||
|
||||
|
||||
|
@ -18,20 +18,36 @@ def _open_newvm(app):
|
||||
return app.find_window("New VM")
|
||||
|
||||
|
||||
def _forward(newvm, check=True):
|
||||
def _nav(newvm, forward, back, check):
|
||||
pagenumlabel = newvm.find("pagenum-label")
|
||||
oldtext = pagenumlabel.text
|
||||
newvm.find_fuzzy("Forward", "button").click()
|
||||
ignore = back
|
||||
|
||||
# Clicking is tough to manage, because when clicking
|
||||
# rapidly in succession the create wizard has a few
|
||||
# cases of stealing focus to better help the user
|
||||
# navigate the wizard, but this is very racy and
|
||||
# tough to deal with hear. Luckily accelerators
|
||||
# don't care too much about focus
|
||||
if forward:
|
||||
button = newvm.find("Forward", "push button")
|
||||
combo = "<alt>f"
|
||||
else:
|
||||
button = newvm.find("Back", "push button")
|
||||
combo = "<alt>b"
|
||||
|
||||
button.check_onscreen()
|
||||
button.keyCombo(combo)
|
||||
if check:
|
||||
lib.utils.check(lambda: pagenumlabel.text != oldtext)
|
||||
|
||||
|
||||
def _forward(newvm, check=True):
|
||||
_nav(newvm, forward=True, back=False, check=check)
|
||||
|
||||
|
||||
def _back(newvm, check=True):
|
||||
pagenumlabel = newvm.find("pagenum-label")
|
||||
oldtext = pagenumlabel.text
|
||||
newvm.find_fuzzy("Back", "button").click()
|
||||
if check:
|
||||
lib.utils.check(lambda: pagenumlabel.text != oldtext)
|
||||
_nav(newvm, forward=False, back=True, check=check)
|
||||
|
||||
|
||||
############################################
|
||||
@ -51,7 +67,7 @@ def testNewVMMultiConnection(app):
|
||||
app.manager_conn_disconnect("test testdriver.xml")
|
||||
newvm = _open_newvm(app)
|
||||
newvm.find_fuzzy("No active connection to install on")
|
||||
newvm.keyCombo("<alt>F4")
|
||||
newvm.window_close()
|
||||
lib.utils.check(lambda: manager.active)
|
||||
|
||||
# Check the xen PV only startup warning
|
||||
@ -63,18 +79,14 @@ def testNewVMMultiConnection(app):
|
||||
_add_conn(tests.utils.URIs.kvm + _capsopt("test-empty.xml"))
|
||||
newvm = _open_newvm(app)
|
||||
newvm.find(".*No hypervisor options were found.*KVM kernel modules.*")
|
||||
newvm.click()
|
||||
newvm.click_title()
|
||||
newvm.keyCombo("<alt>F4")
|
||||
newvm.window_close()
|
||||
app.manager_conn_disconnect("QEMU/KVM")
|
||||
|
||||
_add_conn(tests.utils.URIs.kvm_session +
|
||||
_capsopt("test-qemu-no-kvm.xml"))
|
||||
newvm = _open_newvm(app)
|
||||
newvm.find(".*KVM is not available.*")
|
||||
newvm.click()
|
||||
newvm.click_title()
|
||||
newvm.keyCombo("<alt>F4")
|
||||
newvm.window_close()
|
||||
|
||||
_add_conn(tests.utils.URIs.lxc)
|
||||
_add_conn(tests.utils.URIs.test_full)
|
||||
@ -100,8 +112,7 @@ def testNewVMMultiConnection(app):
|
||||
_forward(newvm)
|
||||
|
||||
# Back up, select test:///default, verify media-combo is now empty
|
||||
newvm.click_title()
|
||||
newvm.keyCombo("<alt>F4")
|
||||
newvm.window_close()
|
||||
newvm = _open_newvm(app)
|
||||
newvm.combo_select("create-conn", ".*test default.*")
|
||||
_forward(newvm)
|
||||
@ -137,22 +148,13 @@ def testNewVMManualDefault(app):
|
||||
lib.utils.check(lambda: osentry.text == "Generic OS")
|
||||
|
||||
# Verify back+forward still keeps Generic selected
|
||||
app.sleep(.5)
|
||||
_back(newvm)
|
||||
app.sleep(.5)
|
||||
_forward(newvm)
|
||||
app.sleep(.5)
|
||||
lib.utils.check(lambda: "Generic" in osentry.text)
|
||||
osentry.check_onscreen()
|
||||
|
||||
# The sleeps shouldn't be required, but this test continues to be
|
||||
# flakey, so this is an attempt to fix it.
|
||||
_forward(newvm)
|
||||
app.sleep(.5)
|
||||
_forward(newvm)
|
||||
app.sleep(.5)
|
||||
_forward(newvm)
|
||||
app.sleep(.5)
|
||||
|
||||
|
||||
# Empty triggers a specific codepath
|
||||
@ -236,8 +238,13 @@ def testNewVMCDROMRegular(app):
|
||||
|
||||
# Catch validation error
|
||||
entry = newvm.find("media-entry")
|
||||
lib.utils.check(lambda: "/dev/sr0" in entry.text)
|
||||
entry.click()
|
||||
entry.set_text("")
|
||||
# Something about entry.set_text is flakey with focus,
|
||||
# this stuff is to try and fix focus
|
||||
app.rawinput.pressKey("Escape")
|
||||
newvm.click_title()
|
||||
_forward(newvm, check=False)
|
||||
app.click_alert_button("media selection is required", "OK")
|
||||
|
||||
@ -428,7 +435,7 @@ def testNewVMURL(app):
|
||||
lib.utils.check(lambda: not newvm.showing)
|
||||
|
||||
# Re-run the newvm wizard, check that URL was remembered
|
||||
details.keyCombo("<alt>F4")
|
||||
details.window_close()
|
||||
newvm = _open_newvm(app)
|
||||
newvm.find_fuzzy("Network Install", "radio").click()
|
||||
_forward(newvm)
|
||||
@ -643,12 +650,9 @@ def testNewVMArmKernel(app):
|
||||
local = newvm.find_fuzzy("Local", "radio")
|
||||
lib.utils.check(lambda: not local.sensitive)
|
||||
newvm.find_fuzzy("Machine Type", "combo").click()
|
||||
app.sleep(.2)
|
||||
newvm.find_fuzzy("canon", "menu item").click()
|
||||
newvm.find_fuzzy("Machine Type", "combo").click()
|
||||
app.sleep(.2)
|
||||
newvm.find("virt", "menu item").click()
|
||||
app.sleep(.5)
|
||||
importradio = newvm.find("Import", "radio")
|
||||
importradio.click()
|
||||
lib.utils.check(lambda: importradio.checked)
|
||||
@ -1181,14 +1185,13 @@ def testNewVMSession(app):
|
||||
newvm.find_fuzzy("Finish", "button").click()
|
||||
details = app.find_details_window("vm1")
|
||||
lib.utils.check(lambda: not newvm.showing)
|
||||
app.sleep(1)
|
||||
details.window_close()
|
||||
|
||||
# Ensure disconnecting will close the dialog
|
||||
manager = app.topwin
|
||||
manager.window_maximize()
|
||||
newvm = _open_newvm(app)
|
||||
manager.click_title()
|
||||
manager.grab_focus()
|
||||
app.manager_conn_disconnect(".*session.*")
|
||||
lib.utils.check(lambda: not newvm.showing)
|
||||
|
||||
|
@ -79,7 +79,7 @@ def testCreateVolMisc(app):
|
||||
browsewin.find("Browse Local", "push button").click()
|
||||
chooser = app.root.find(
|
||||
"Locate existing storage", "file chooser")
|
||||
chooser.keyCombo("<alt>F4")
|
||||
chooser.window_close()
|
||||
app.select_storagebrowser_volume(
|
||||
"default-pool", "bochs-vol", doubleclick=True)
|
||||
backingstore = win.find("backing-store")
|
||||
|
@ -211,7 +211,6 @@ def testDeleteSkipStorage(app):
|
||||
browser = _open_storage_browser(app)
|
||||
browser.find_fuzzy("default-pool", "table cell").click()
|
||||
browser.find("vol-refresh", "push button").click()
|
||||
app.sleep(.5)
|
||||
browser.find("overlay.img", "table cell")
|
||||
browser.find("sharevol.img", "table cell")
|
||||
|
||||
@ -237,13 +236,11 @@ def testDeleteDeviceNoStorage(app):
|
||||
chk = delete.find("Delete associated", "check box")
|
||||
lib.utils.check(lambda: not chk.checked)
|
||||
_finish(app, delete, [])
|
||||
details.click()
|
||||
details.keyCombo("<alt>F4")
|
||||
details.window_close()
|
||||
|
||||
browser = _open_storage_browser(app)
|
||||
browser.find_fuzzy("default-pool", "table cell").click()
|
||||
browser.find("vol-refresh", "push button").click()
|
||||
app.sleep(.5)
|
||||
browser.find("overlay.img", "table cell")
|
||||
|
||||
|
||||
@ -271,8 +268,7 @@ def testDeleteDeviceWithStorage(app):
|
||||
path = "/dev/default-pool/overlay.img"
|
||||
delete.find_fuzzy(path)
|
||||
_finish(app, delete, [path])
|
||||
details.click()
|
||||
details.keyCombo("<alt>F4")
|
||||
details.window_close()
|
||||
|
||||
browser = _open_storage_browser(app)
|
||||
browser.find_fuzzy("default-pool", "table cell").click()
|
||||
@ -304,12 +300,10 @@ def testDeleteDeviceFail(app):
|
||||
delete.find_fuzzy(path)
|
||||
_finish(app, delete, [path], expect_fail=True)
|
||||
app.click_alert_button("Storage will not be.*deleted", "OK")
|
||||
details.click()
|
||||
details.keyCombo("<alt>F4")
|
||||
details.window_close()
|
||||
|
||||
# Verify file still exists
|
||||
browser = _open_storage_browser(app)
|
||||
browser.find_fuzzy("default-pool", "table cell").click()
|
||||
browser.find("vol-refresh", "push button").click()
|
||||
app.sleep(.5)
|
||||
browser.find("overlay.img", "table cell")
|
||||
|
@ -64,8 +64,7 @@ def testDetailsHardwareSmokeTestAlternate(app):
|
||||
win = _testSmokeTest(app, "test alternate devs title")
|
||||
win.find("Details", "page tab").click()
|
||||
_select_hw(app, win, "Performance", "performance-tab")
|
||||
# Wait for perf signals to trigger, to cover more code
|
||||
app.sleep(2)
|
||||
app.sleep(.2) # wait for polling to trigger perf updates
|
||||
|
||||
|
||||
def _testRename(app, win, origname, newname):
|
||||
@ -128,8 +127,7 @@ def testDetailsStateMisc(app):
|
||||
# View Manager option
|
||||
win.find("File", "menu").click()
|
||||
win.find("View Manager", "menu item").click()
|
||||
lib.utils.check(lambda: app.topwin.active)
|
||||
app.topwin.keyCombo("<alt>F4")
|
||||
app.topwin.window_close()
|
||||
lib.utils.check(lambda: win.active)
|
||||
|
||||
# Make a change and then trigger unapplied change warning
|
||||
@ -443,9 +441,8 @@ def testDetailsNetIPAddress(app):
|
||||
tab.find("IP address:", "push button").click()
|
||||
check_ip("10.0.0.3")
|
||||
|
||||
win.keyCombo("<alt>F4")
|
||||
lib.utils.check(lambda: not win.showing)
|
||||
app.topwin.click_title()
|
||||
win.window_close()
|
||||
app.topwin.grab_focus()
|
||||
|
||||
# Tests the fake qemu guest agent path
|
||||
win = app.manager_open_details("test alternate devs title")
|
||||
|
@ -174,7 +174,7 @@ def testHostConn(app):
|
||||
manager.find("FOOBAR", "table cell")
|
||||
|
||||
# Close the manager
|
||||
manager.keyCombo("<alt>F4")
|
||||
manager.window_close()
|
||||
lib.utils.check(lambda: win.active)
|
||||
|
||||
# Quit app from the file menu
|
||||
|
@ -40,8 +40,7 @@ def testInspectionMock(app):
|
||||
tab.find("Refresh", "push button").click()
|
||||
lib.utils.check(lambda: apps.fmt_nodes() != nodestr1)
|
||||
|
||||
details.keyCombo("<alt>F4")
|
||||
lib.utils.check(lambda: not details.showing)
|
||||
details.window_close()
|
||||
|
||||
# Open a VM with no disks which will report an inspection error
|
||||
app.root.find_fuzzy("test\n", "table cell").doubleClick()
|
||||
@ -53,8 +52,10 @@ def testInspectionMock(app):
|
||||
|
||||
# Closing and reopening a connection triggers some libguest
|
||||
# cache reading
|
||||
details.keyCombo("<alt>F4")
|
||||
details.window_close()
|
||||
manager.click()
|
||||
c = manager.find("test testdriver.xml", "table cell")
|
||||
app.manager_conn_disconnect("test testdriver.xml")
|
||||
lib.utils.check(lambda: "Not Connected" in c.text)
|
||||
app.manager_conn_connect("test testdriver.xml")
|
||||
app.sleep(2)
|
||||
lib.utils.check(lambda: "Not Connected" not in c.text)
|
||||
|
@ -62,6 +62,7 @@ def _checkConsoleStandard(app, dom):
|
||||
"""
|
||||
Shared logic for general console handling
|
||||
"""
|
||||
ignore = dom
|
||||
win = app.topwin
|
||||
con = win.find("console-gfx-viewport")
|
||||
lib.utils.check(lambda: con.showing)
|
||||
@ -134,17 +135,7 @@ def _checkConsoleStandard(app, dom):
|
||||
scalemenu.point()
|
||||
scalemenu.find("Only", "radio menu item").click()
|
||||
|
||||
# Check that modifiers don't work
|
||||
win.click()
|
||||
app.sleep(1)
|
||||
win.keyCombo("<ctrl>w")
|
||||
lib.utils.check(lambda: win.showing)
|
||||
dom.destroy()
|
||||
win.find("Guest is not running.")
|
||||
win.click_title()
|
||||
app.sleep(1)
|
||||
win.keyCombo("<ctrl>w")
|
||||
lib.utils.check(lambda: not win.showing)
|
||||
win.window_close()
|
||||
|
||||
|
||||
@_vm_wrapper("uitests-vnc-standard")
|
||||
@ -157,6 +148,37 @@ def testConsoleSpiceStandard(app, dom):
|
||||
return _checkConsoleStandard(app, dom)
|
||||
|
||||
|
||||
def _checkConsoleFocus(app, dom):
|
||||
"""
|
||||
Shared logic for console keyboard grab handling
|
||||
"""
|
||||
win = app.topwin
|
||||
con = win.find("console-gfx-viewport")
|
||||
lib.utils.check(lambda: con.showing)
|
||||
|
||||
# Check that modifiers don't work when console grabs pointer
|
||||
win.click()
|
||||
app.sleep(.5) # make sure window code has time to adjust modifiers
|
||||
win.keyCombo("<ctrl>w")
|
||||
lib.utils.check(lambda: win.showing)
|
||||
dom.destroy()
|
||||
win.find("Guest is not running.")
|
||||
win.grab_focus()
|
||||
app.sleep(.5) # make sure window code has time to adjust modifiers
|
||||
win.keyCombo("<ctrl>w")
|
||||
lib.utils.check(lambda: not win.showing)
|
||||
|
||||
|
||||
@_vm_wrapper("uitests-vnc-standard")
|
||||
def testConsoleVNCFocus(app, dom):
|
||||
return _checkConsoleFocus(app, dom)
|
||||
|
||||
|
||||
@_vm_wrapper("uitests-spice-standard")
|
||||
def testConsoleSpiceFocus(app, dom):
|
||||
return _checkConsoleFocus(app, dom)
|
||||
|
||||
|
||||
def _checkPassword(app):
|
||||
"""
|
||||
Shared logic for password handling
|
||||
@ -247,8 +269,7 @@ def testConsoleVNCSocket(app, dom):
|
||||
vmenu.click()
|
||||
tmenu = win.find("Consoles", "menu")
|
||||
tmenu.point()
|
||||
# We need to sleep to give the menu time to dynamically populate
|
||||
app.sleep(.5)
|
||||
app.sleep(.5) # give console menu time to dynamically populate
|
||||
tmenu.find(msg, "radio menu item").click()
|
||||
|
||||
# A bit of an extra test, make sure selecting Graphical Console works
|
||||
@ -270,10 +291,14 @@ def testConsoleAutoconnect(app, dom):
|
||||
vmenu.click()
|
||||
vmenu.find("Autoconnect").click()
|
||||
dom.destroy()
|
||||
app.sleep(1)
|
||||
label = win.find("Guest is not running.")
|
||||
label.check_onscreen()
|
||||
dom.create()
|
||||
label.check_not_onscreen()
|
||||
button = win.find("Connect to console", "push button")
|
||||
button.check_onscreen()
|
||||
lib.utils.check(lambda: not con.showing)
|
||||
win.find("Connect to console", "push button").click()
|
||||
button.click()
|
||||
lib.utils.check(lambda: con.showing)
|
||||
|
||||
|
||||
@ -282,7 +307,6 @@ def testConsoleLXCSerial(app, dom):
|
||||
"""
|
||||
Ensure LXC has serial open, and we can send some data
|
||||
"""
|
||||
ignore = dom
|
||||
win = app.topwin
|
||||
term = win.find("Serial Terminal")
|
||||
lib.utils.check(lambda: term.showing)
|
||||
@ -308,7 +332,7 @@ def testConsoleLXCSerial(app, dom):
|
||||
textmenu = view.find("Consoles", "menu")
|
||||
textmenu.point()
|
||||
lib.utils.check(lambda: textmenu.showing)
|
||||
app.sleep(.5)
|
||||
app.sleep(.5) # give console menu time to dynamically populate
|
||||
item = textmenu.find("Text Console 1")
|
||||
lib.utils.check(lambda: not item.sensitive)
|
||||
|
||||
@ -324,8 +348,9 @@ def testConsoleLXCSerial(app, dom):
|
||||
lib.utils.check(lambda: win.showing)
|
||||
# Shut it down, ensure <ctrl>w works again
|
||||
_destroy(app, win)
|
||||
lib.utils.check(lambda: not dom.isActive())
|
||||
win.click_title()
|
||||
app.sleep(1)
|
||||
app.sleep(.3) # make sure window code has time to adjust modifiers
|
||||
win.keyCombo("<ctrl>w")
|
||||
lib.utils.check(lambda: not win.showing)
|
||||
|
||||
@ -368,6 +393,7 @@ def testConsoleSpiceSpecific(app, dom):
|
||||
smenu.point()
|
||||
smenu.find("Auto resize VM", "check menu item").click()
|
||||
_click_auto()
|
||||
win.click_title()
|
||||
win.window_maximize()
|
||||
_click_auto()
|
||||
win.click_title()
|
||||
|
@ -50,16 +50,8 @@ def testVMLifecycle(app):
|
||||
|
||||
|
||||
def testVMNoEventsLifecycle(app):
|
||||
app.open(extra_opts=["--test-options=no-events"])
|
||||
|
||||
# Change preferences timeout to 1 second
|
||||
app.root.find("Edit", "menu").click()
|
||||
app.root.find("Preferences", "menu item").click()
|
||||
win = app.find_window("Preferences")
|
||||
win.find("Polling", "page tab").click()
|
||||
win.find("cpu-poll").set_text("1")
|
||||
win.find("Close", "push button").click()
|
||||
|
||||
app.open(extra_opts=["--test-options=no-events",
|
||||
"--test-options=short-poll"])
|
||||
_testVMLifecycle(app)
|
||||
|
||||
|
||||
@ -161,14 +153,14 @@ def testManagerQEMUSetTime(app):
|
||||
smenu.click()
|
||||
save.click()
|
||||
lib.utils.check(lambda: run.sensitive)
|
||||
app.sleep(1)
|
||||
app.sleep(1) # give settime thread time to run
|
||||
run.click()
|
||||
lib.utils.check(lambda: not run.sensitive)
|
||||
app.sleep(1)
|
||||
app.sleep(1) # give settime thread time to run
|
||||
smenu.click()
|
||||
save.click()
|
||||
lib.utils.check(lambda: run.sensitive)
|
||||
app.sleep(1)
|
||||
app.sleep(1) # give settime thread time to run
|
||||
|
||||
|
||||
def testManagerVMRunFail(app):
|
||||
@ -239,7 +231,7 @@ def testManagerWindowReposition(app):
|
||||
manager.window_maximize()
|
||||
newx = manager.position[0]
|
||||
newy = manager.position[1]
|
||||
manager.keyCombo("<alt>F4")
|
||||
manager.window_close()
|
||||
host.click_title()
|
||||
host.find("File", "menu").click()
|
||||
host.find("View Manager", "menu item").click()
|
||||
@ -253,14 +245,7 @@ def testManagerWindowCleanup(app):
|
||||
Open migrate, clone, delete, newvm, details, host windows, close the
|
||||
connection, make sure they all disappear
|
||||
"""
|
||||
def _drag(win):
|
||||
"""
|
||||
Drag a window so it's not obscuring the manager window
|
||||
"""
|
||||
win.drag(1000, 1000)
|
||||
|
||||
manager = app.topwin
|
||||
app.sleep(1)
|
||||
manager.window_maximize()
|
||||
|
||||
# Open delete window hitting a special code path, then close it
|
||||
@ -268,8 +253,7 @@ def testManagerWindowCleanup(app):
|
||||
manager.find("Edit", "menu").click()
|
||||
manager.find("Delete", "menu item").click()
|
||||
delete = app.root.find_fuzzy("Delete", "frame")
|
||||
app.sleep(.5)
|
||||
delete.click_title()
|
||||
delete.find("storage-list").grab_focus()
|
||||
delete.window_close()
|
||||
|
||||
# Open Clone window hitting a special code path, then close it
|
||||
@ -277,30 +261,22 @@ def testManagerWindowCleanup(app):
|
||||
app.rawinput.pressKey("Menu")
|
||||
app.root.find("Clone...", "menu item").click()
|
||||
clone = app.find_window("Clone Virtual Machine")
|
||||
app.sleep(.5)
|
||||
clone.click_title()
|
||||
clone.window_close()
|
||||
|
||||
# Open host
|
||||
manager.grab_focus()
|
||||
c = manager.find_fuzzy("testdriver.xml", "table cell")
|
||||
c.click()
|
||||
app.sleep(.5)
|
||||
c.doubleClick()
|
||||
host = app.find_window("test testdriver.xml - Connection Details")
|
||||
_drag(host)
|
||||
|
||||
# Open details
|
||||
manager.grab_focus()
|
||||
c = manager.find("test-many-devices", "table cell")
|
||||
c.click()
|
||||
app.sleep(.5)
|
||||
c.doubleClick()
|
||||
details = app.find_details_window("test-many-devices")
|
||||
_drag(details)
|
||||
|
||||
# Close the connection
|
||||
app.sleep(.5)
|
||||
manager.click_title()
|
||||
app.sleep(.5)
|
||||
manager.grab_focus()
|
||||
app.manager_conn_disconnect("test testdriver.xml")
|
||||
|
||||
# Ensure all those windows aren't showing
|
||||
|
@ -108,8 +108,7 @@ def testMigrateConnMismatch(app):
|
||||
mig.find("conn-combo").find("No usable", "menu item")
|
||||
|
||||
# Test explicit dialog 'delete'
|
||||
mig.keyCombo("<alt>F4")
|
||||
lib.utils.check(lambda: not mig.showing)
|
||||
mig.window_close()
|
||||
|
||||
# Ensure disconnecting will close the dialog
|
||||
manager.click_title()
|
||||
|
@ -92,7 +92,6 @@ def testPrefsAll(app):
|
||||
|
||||
def testPrefsXMLEditor(app):
|
||||
managerwin = app.topwin
|
||||
managerwin.drag(0, 200)
|
||||
detailswin = app.manager_open_details("test-clone-simple")
|
||||
finish = detailswin.find("config-apply")
|
||||
xmleditor = detailswin.find("XML editor")
|
||||
@ -104,8 +103,7 @@ def testPrefsXMLEditor(app):
|
||||
xmleditor.typeText("1234abcd")
|
||||
lib.utils.check(lambda: xmleditor.text == origtext)
|
||||
|
||||
managerwin.click_title()
|
||||
managerwin.grabFocus()
|
||||
managerwin.grab_focus()
|
||||
managerwin.find("Edit", "menu").click()
|
||||
managerwin.find("Preferences", "menu item").click()
|
||||
prefswin = app.find_window("Preferences")
|
||||
@ -113,8 +111,8 @@ def testPrefsXMLEditor(app):
|
||||
prefswin.find_fuzzy("Close", "push button").click()
|
||||
lib.utils.check(lambda: prefswin.visible is False)
|
||||
|
||||
managerwin.keyCombo("<alt>F4")
|
||||
detailswin.click()
|
||||
managerwin.window_close()
|
||||
detailswin.grab_focus()
|
||||
newtext = xmleditor.text.replace(">", "><title>FOOTITLE</title>", 1)
|
||||
xmleditor.set_text(newtext)
|
||||
finish.click()
|
||||
|
@ -12,19 +12,19 @@ from . import lib
|
||||
def testSystrayFake(app):
|
||||
app.open(
|
||||
keyfile="systray.ini",
|
||||
extra_opts=["--test-options=fake-systray"],
|
||||
window_name="Virtual Machine Manager")
|
||||
extra_opts=["--test-options=fake-systray"])
|
||||
|
||||
manager = app.topwin
|
||||
systray = app.root.find("vmm-fake-systray", check_active=False)
|
||||
manager.drag(1000, 1000)
|
||||
systray.grab_focus()
|
||||
manager = app.root.find("Virtual Machine Manager", check_active=False)
|
||||
|
||||
# Add a connection to trigger systray update
|
||||
uri = tests.utils.URIs.kvm
|
||||
manager.grab_focus()
|
||||
app.manager_createconn(uri=uri)
|
||||
|
||||
# Hide the manager
|
||||
systray.click_title()
|
||||
systray.grab_focus()
|
||||
systray.click()
|
||||
lib.utils.check(lambda: not manager.showing)
|
||||
lib.utils.check(lambda: app.is_running())
|
||||
@ -81,12 +81,13 @@ def testSystrayFake(app):
|
||||
_check_vm_action("QEMU/KVM", "test-arm-kernel", "Resume")
|
||||
|
||||
# Reshow the manager
|
||||
systray.grab_focus()
|
||||
systray.click()
|
||||
lib.utils.check(lambda: manager.showing)
|
||||
lib.utils.check(lambda: app.is_running())
|
||||
|
||||
# Close from the menu
|
||||
systray.click_title()
|
||||
systray.grab_focus()
|
||||
systray.click(button=3)
|
||||
menu = app.root.find("vmm-systray-menu")
|
||||
menu.find("Quit", "menu item").click()
|
||||
@ -97,21 +98,22 @@ def testSystrayFake(app):
|
||||
def testSystrayToggle(app):
|
||||
app.open(
|
||||
keyfile="systray.ini",
|
||||
extra_opts=["--test-options=fake-systray"],
|
||||
window_name="Virtual Machine Manager")
|
||||
extra_opts=["--test-options=fake-systray"])
|
||||
|
||||
manager = app.topwin
|
||||
systray = app.root.find("vmm-fake-systray", check_active=False)
|
||||
systray.grab_focus()
|
||||
manager = app.root.find("Virtual Machine Manager", check_active=False)
|
||||
manager.grab_focus()
|
||||
|
||||
manager.find("Edit", "menu").click()
|
||||
manager.find("Preferences", "menu item").click()
|
||||
prefs = app.find_window("Preferences")
|
||||
|
||||
# Close the system tray
|
||||
prefs.click_title()
|
||||
prefs.grab_focus()
|
||||
prefs.find_fuzzy("Enable system tray", "check").click()
|
||||
lib.utils.check(lambda: not systray.showing)
|
||||
|
||||
# Close the manager
|
||||
manager.click_title()
|
||||
manager.keyCombo("<alt>F4")
|
||||
manager.window_close()
|
||||
lib.utils.check(lambda: not app.is_running())
|
||||
|
@ -432,6 +432,8 @@ class vmmConfig(object):
|
||||
def get_stats_history_length(self):
|
||||
return 120
|
||||
def get_stats_update_interval(self):
|
||||
if self.CLITestOptions.short_poll:
|
||||
return .1
|
||||
interval = self.conf.get("/stats/update-interval")
|
||||
return max(interval, 1)
|
||||
def set_stats_update_interval(self, interval):
|
||||
|
@ -73,7 +73,7 @@ def schedule_fake_agent_event(conn, cb):
|
||||
dom = backend.lookupByName(vmname)
|
||||
cb(backend, dom, state, reason, None)
|
||||
|
||||
conn.timeout_add(1000, time_cb)
|
||||
conn.timeout_add(500, time_cb)
|
||||
|
||||
|
||||
def schedule_fake_nodedev_event(conn, lifecycle_cb, update_cb):
|
||||
@ -91,8 +91,8 @@ def schedule_fake_nodedev_event(conn, lifecycle_cb, update_cb):
|
||||
nodedev = backend.nodeDeviceLookupByName(nodename)
|
||||
update_cb(backend, nodedev, None)
|
||||
|
||||
conn.timeout_add(1000, lifecycle_cb_wrapper)
|
||||
conn.timeout_add(2000, update_cb_wrapper)
|
||||
conn.timeout_add(500, lifecycle_cb_wrapper)
|
||||
conn.timeout_add(1000, update_cb_wrapper)
|
||||
|
||||
|
||||
def fake_openauth(conn, cb, data):
|
||||
@ -167,6 +167,8 @@ class CLITestOptionsClass:
|
||||
for testing the TCP URI auth dialog
|
||||
* fake-session-error: Fake a connection open error that
|
||||
triggers logind session lookup
|
||||
* short-poll: Use a polling interval of only .1 seconds to speed
|
||||
up the uitests a bit
|
||||
"""
|
||||
def __init__(self, test_options_str):
|
||||
optset = set()
|
||||
@ -211,6 +213,7 @@ class CLITestOptionsClass:
|
||||
self.fake_nodedev_event = _get_value("fake-nodedev-event")
|
||||
self.fake_openauth = _get("fake-openauth")
|
||||
self.fake_session_error = _get("fake-session-error")
|
||||
self.short_poll = _get("short-poll")
|
||||
|
||||
if optset: # pragma: no cover
|
||||
raise RuntimeError("Unknown --test-options keys: %s" % optset)
|
||||
|
@ -804,7 +804,7 @@ class vmmManager(vmmGObjectUI):
|
||||
|
||||
def popup_vm_menu_key(self, widget_ignore, event):
|
||||
if Gdk.keyval_name(event.keyval) != "Menu":
|
||||
return False
|
||||
return False # pragma: no cover
|
||||
|
||||
model, treeiter = self.widget("vm-list").get_selection().get_selected()
|
||||
self.popup_vm_menu(model, treeiter, event)
|
||||
|
@ -166,17 +166,13 @@ class _SystrayWindow(_Systray):
|
||||
self._init_ui()
|
||||
|
||||
def _init_ui(self):
|
||||
image = Gtk.Image()
|
||||
image.set_from_stock(Gtk.STOCK_ADD, Gtk.IconSize.DIALOG)
|
||||
|
||||
box = Gtk.EventBox()
|
||||
box.add(image)
|
||||
box.connect("button-press-event", self._popup_cb)
|
||||
button = Gtk.Button.new_from_stock(Gtk.STOCK_ADD)
|
||||
button.connect("button-press-event", self._popup_cb)
|
||||
|
||||
self._window = Gtk.Window()
|
||||
self._window.set_size_request(100, 100)
|
||||
self._window.get_accessible().set_name("vmm-fake-systray")
|
||||
self._window.add(box)
|
||||
self._window.add(button)
|
||||
|
||||
def is_embedded(self):
|
||||
return self._window.is_visible()
|
||||
|
Loading…
x
Reference in New Issue
Block a user