uitests: Centralize object list smoketest handling

This commit is contained in:
Cole Robinson 2018-01-11 09:46:41 -05:00
parent a4e1b64f1a
commit 570ee90c4d
5 changed files with 86 additions and 120 deletions

View File

@ -1,6 +1,3 @@
import dogtail.rawinput
import pyatspi
from tests.uitests import utils as uiutils
@ -32,48 +29,8 @@ class Details(uiutils.UITestCase):
HW panel shows itself without raising any error.
"""
win = self._open_details_window()
# Ensure the Overview page is the first selected
win.find_pattern("Hypervisor Details", "label")
win.find_pattern("Overview", "table cell").click()
# After we hit this number of down presses, start checking for
# widget focus to determine if we hit the end of the list. We
# don't check for widget focus unconditionally because it's slow.
# The seemingly arbitrary number here is because it matches the
# number of devices in test-many-devices at the time of this writing.
check_after = 93
focused = None
old_focused = None
count = 0
while True:
count += 1
dogtail.rawinput.pressKey("Down")
if not win.getState().contains(pyatspi.STATE_ACTIVE):
# Should mean an error dialog popped up
self.app.root.find_pattern("Error", "alert")
raise AssertionError(
"One of the hardware pages raised an error")
if count < check_after:
#time.sleep(.05)
continue
# pylint: disable=not-an-iterable
old_focused = focused
focused = win.focused_nodes()
if old_focused is None:
continue
overlap = [w for w in old_focused if w in focused]
if len(overlap) == len(old_focused):
# Focus didn't change, meaning we hit the end of the HW list,
# so our testing is done
break
return
lst = win.find_pattern("hw-list", "table")
self._walkUIList(win, lst, lambda: False)
def _testRename(self, origname, newname):
win = self._open_details_window(origname)

View File

@ -1,8 +1,3 @@
import time
import dogtail.rawinput
import pyatspi
from tests.uitests import utils as uiutils
@ -25,39 +20,6 @@ class Host(uiutils.UITestCase):
win.find_fuzzy(tab, "page tab").click()
return win
def _checkListEntrys(self, win, check_after):
# After we hit this number of down presses, start checking for
# widget focus to determine if we hit the end of the list. We
# don't check for widget focus unconditionally because it's slow.
focused = None
old_focused = None
count = 0
while True:
count += 1
dogtail.rawinput.pressKey("Down")
if not win.getState().contains(pyatspi.STATE_ACTIVE):
# Should mean an error dialog popped up
self.app.root.find_pattern("Error", "alert")
raise AssertionError(
"One of the pages raised an error")
if count < check_after:
time.sleep(.1)
continue
# pylint: disable=not-an-iterable
old_focused = focused
focused = win.focused_nodes()
if old_focused is None:
continue
overlap = [w for w in old_focused if w in focused]
if len(overlap) == len(old_focused):
# Focus didn't change, meaning we hit the end of the HW list,
# so our testing is done
break
##############
# Test cases #
@ -68,33 +30,24 @@ class Host(uiutils.UITestCase):
Verify that each virtual network displays, without error.
"""
win = self._open_host_window("Virtual Networks")
# Make sure the first item is selected
cell = win.find_pattern("default", "table cell")
self.assertTrue(cell.getState().contains(pyatspi.STATE_SELECTED))
self._checkListEntrys(win, 13)
lst = win.find_pattern("net-list", "table")
errlabel = win.find_pattern("net-error-label", "label")
self._walkUIList(win, lst, lambda: errlabel.showing)
def testHostStorageSmokeTest(self):
"""
Verify that each storage pool displays, without error.
"""
win = self._open_host_window("Storage")
# Make sure the first item is selected
cell = win.find_pattern("cross-pool", "table cell")
self.assertTrue(cell.getState().contains(pyatspi.STATE_SELECTED))
self._checkListEntrys(win, 13)
lst = win.find_pattern("pool-list", "table")
errlabel = win.find_pattern("pool-error-label", "label")
self._walkUIList(win, lst, lambda: errlabel.showing)
def testHostInterfaceSmokeTest(self):
"""
Verify that each storage pool displays, without error.
Verify that each interface displays, without error.
"""
win = self._open_host_window("Network Interfaces")
# Make sure the first item is selected
cell = win.find_pattern("bond0", "table cell")
self.assertTrue(cell.getState().contains(pyatspi.STATE_SELECTED))
self._checkListEntrys(win, 18)
lst = win.find_pattern("interface-list", "table")
errlabel = win.find_pattern("interface-error-label", "label")
self._walkUIList(win, lst, lambda: errlabel.showing)

View File

@ -24,6 +24,37 @@ class UITestCase(unittest.TestCase):
def tearDown(self):
self.app.stop()
def _walkUIList(self, win, lst, error_cb):
"""
Toggle down through a UI list like addhardware, net/storage/iface
lists, and ensure an error isn't raised.
"""
# Walk the lst UI and find all labelled table cells, these are
# the actual list entries
all_cells = lst.findChildren(lambda w: w.roleName == "table cell")
all_cells[0].click()
cells_per_selection = len([c for c in all_cells if c.focused])
idx = 0
while idx < len(all_cells):
cell = all_cells[idx]
self.assertTrue(cell.state_selected)
dogtail.rawinput.pressKey("Down")
if not win.active:
# Should mean an error dialog popped up
self.app.root.find_pattern("Error", "alert")
raise AssertionError("Error dialog raised?")
if error_cb():
raise AssertionError("Error found on a page")
idx += cells_per_selection
if idx >= len(all_cells):
# Last cell, selection shouldn't have changed
self.assertTrue(cell.state_selected)
else:
self.assertTrue(not cell.state_selected)
class _FuzzyPredicate(dogtail.predicate.Predicate):
"""
@ -43,7 +74,7 @@ class _FuzzyPredicate(dogtail.predicate.Predicate):
def describeSearchResult(self, node=None):
if not node:
return ""
return node_string(node)
return node.node_string()
def satisfiedByNode(self, node):
"""
@ -93,6 +124,10 @@ class VMMDogtailNode(dogtail.tree.Node):
"""
return self.getState().contains(pyatspi.STATE_ACTIVE)
@property
def state_selected(self):
return self.getState().contains(pyatspi.STATE_SELECTED)
#########################
# Widget search helpers #
@ -147,7 +182,7 @@ class VMMDogtailNode(dogtail.tree.Node):
return msg
def print_nodes(root):
def print_nodes(self):
"""
Helper to print the entire node tree for the passed root. Useful
if to figure out the roleName for the object you are looking for
@ -160,19 +195,6 @@ class VMMDogtailNode(dogtail.tree.Node):
self.findChildren(_walk, isLambda=True)
def focused_nodes(self):
"""
Return a list of all focused nodes. Useful for debugging
"""
def _walk(node):
try:
if node.focused:
return node
except Exception as e:
print("got exception: %s" % e)
return self.findChildren(_walk, isLambda=True)
# This is the same hack dogtail uses to extend the Accessible class.
_bases = list(pyatspi.Accessibility.Accessible.__bases__)

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.20.0 -->
<!-- Generated with glade 3.20.2 -->
<interface>
<requires lib="gtk+" version="3.14"/>
<object class="GtkAccelGroup" id="accelgroup1"/>
@ -391,11 +391,12 @@
<child>
<object class="GtkScrolledWindow" id="scrolledwindow7">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="can_focus">False</property>
<property name="hscrollbar_policy">never</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkTreeView" id="net-list">
<property name="width_request">134</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="headers_visible">False</property>
@ -404,6 +405,11 @@
<signal name="changed" handler="on_net_list_changed" swapped="no"/>
</object>
</child>
<child internal-child="accessible">
<object class="AtkObject" id="net-list-atkobject">
<property name="AtkObject::accessible-name">net-list</property>
</object>
</child>
</object>
</child>
</object>
@ -1238,6 +1244,11 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label">some error here</property>
<child internal-child="accessible">
<object class="AtkObject" id="network-error-label-atkobject">
<property name="AtkObject::accessible-name">net-error-label</property>
</object>
</child>
</object>
<packing>
<property name="position">1</property>
@ -1474,6 +1485,11 @@
<signal name="changed" handler="on_interface_list_changed" swapped="no"/>
</object>
</child>
<child internal-child="accessible">
<object class="AtkObject" id="interface-list-atkobject">
<property name="AtkObject::accessible-name">interface-list</property>
</object>
</child>
</object>
</child>
</object>
@ -1904,6 +1920,11 @@
<property name="label">some message
here</property>
<property name="justify">center</property>
<child internal-child="accessible">
<object class="AtkObject" id="interface-error-label-atkobject">
<property name="AtkObject::accessible-name">interface-error-label</property>
</object>
</child>
</object>
<packing>
<property name="position">1</property>
@ -2096,6 +2117,9 @@ here</property>
</child>
</object>
</child>
<child type="titlebar">
<placeholder/>
</child>
</object>
<object class="GtkImage" id="image3">
<property name="visible">True</property>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.20.0 -->
<!-- Generated with glade 3.20.2 -->
<interface>
<requires lib="gtk+" version="3.14"/>
<object class="GtkImage" id="image3">
@ -231,6 +231,11 @@
<child internal-child="selection">
<object class="GtkTreeSelection" id="treeview-selection"/>
</child>
<child internal-child="accessible">
<object class="AtkObject" id="pool-list-atkobject">
<property name="AtkObject::accessible-name">pool-list</property>
</object>
</child>
</object>
</child>
</object>
@ -577,6 +582,11 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label">some error here</property>
<child internal-child="accessible">
<object class="AtkObject" id="storage-error-label-atkobject">
<property name="AtkObject::accessible-name">pool-error-label</property>
</object>
</child>
</object>
<packing>
<property name="position">1</property>