report-xfstests.py: Convert test properties into a Gtk.Stack

And use a Gtk.ColumnView to display the results instead of packing
everything into a Gtk.Grid

Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
This commit is contained in:
Anna Schumaker 2022-02-02 11:10:07 -05:00
parent b47955fe5a
commit 6f3c37e568
4 changed files with 109 additions and 64 deletions

View File

@ -15,42 +15,6 @@ from gi.repository import Gio
XFSTESTS = pathlib.Path(xdg.BaseDirectory.xdg_data_home) / "xfstests" / "date"
class TestProperty():
def __init__(self, name):
self.name = name
self.prop = dict()
def __lt__(self, rhs):
return self.name.upper() < rhs.name.upper()
def __getitem__(self, key):
return self.prop[key]
def __setitem__(self, key, val):
self.prop[key] = val
class PropertyPage(Gtk.ScrolledWindow):
def __init__(self, name, results):
Gtk.ScrolledWindow.__init__(self, vscrollbar_policy=Gtk.PolicyType.NEVER)
self.set_child(Gtk.Grid())
res = { p.name : p[name] for p in results.properties }
passed = int(res['tests']) - (int(res['skipped']) + int(res['failures']))
res["RESULTS"] = f"Ran {res['tests']} tests in {res['time']} seconds: " \
f"{passed} passed, {res['failures']} failed, {res['skipped']} skipped"
fields = [ "PLATFORM", "timestamp", "FSTYP", "MOUNT_OPTIONS", "CHECK_OPTIONS",
"TEST_DIR", "TEST_DEV", "SCRATCH_DEV", "SCRATCH_MNT", "RESULTS" ]
for i, field in enumerate(fields):
key = Gtk.Label.new(field.upper() + " = ")
key.set_xalign(100)
val = Gtk.Label.new(res[field])
val.set_xalign(0)
self.get_child().get_child().attach(key, 0, i, 1, 1)
self.get_child().get_child().attach(val, 1, i, 1, 1)
class TestCase(GObject.GObject):
def __init__(self, name):
GObject.GObject.__init__(self)
@ -88,7 +52,6 @@ class TestCase(GObject.GObject):
class TestResultsModel(GObject.GObject, Gio.ListModel):
def __init__(self):
GObject.GObject.__init__(self)
self.properties = [ ]
self.tests = [ ]
self.columns = [ "Test Name" ]
@ -98,13 +61,6 @@ class TestResultsModel(GObject.GObject, Gio.ListModel):
def get_n_columns(self): return len(self.columns)
def get_column_name(self, n): return self.columns[n]
def find_property(self, name):
for prop in self.properties:
if prop.name == name:
return prop
self.properties.append(TestProperty(name))
return self.properties[-1]
def find_testcase(self, name):
i = bisect.bisect(self.tests, name, key=str)
if i > 0 and self.tests[i-1].name == name:
@ -115,24 +71,16 @@ class TestResultsModel(GObject.GObject, Gio.ListModel):
def set_tests(self, path):
rm = len(self.tests)
self.columns = [ "Test Name" ]
self.properties.clear()
self.tests.clear()
for file in sorted(path.iterdir() if path else []):
self.columns.append(file.stem)
root = xml.etree.ElementTree.parse(file).getroot()
for prop in root.attrib.keys():
self.find_property(prop)[file.stem] = root.attrib[prop]
for elm in root:
if elm.tag == "testcase":
testcase = self.find_testcase(elm.attrib["name"])
testcase[file.stem] = elm
elif elm.tag == "properties":
for prop in elm:
name = prop.attrib["name"]
value = prop.attrib["value"]
self.find_property(name)[file.stem] = value
self.emit("items-changed", 0, rm, len(self.tests))
@ -224,7 +172,6 @@ class TestWindow(Gtk.ScrolledWindow):
self.filter = Gtk.FilterListModel.new(self.results, TestResultsFilter())
self.selection = Gtk.NoSelection.new(self.filter)
self.view = Gtk.ColumnView.new(self.selection)
self.notebook = Gtk.Notebook()
self.set_child(self.view)
if len(sys.argv) > 1:
self.set_tests(pathlib.Path(sys.argv[1]))
@ -241,23 +188,19 @@ class TestWindow(Gtk.ScrolledWindow):
def set_tests(self, path):
for column in [ c for c in self.view.get_columns() ]:
self.view.remove_column(column)
for n in range(self.notebook.get_n_pages()):
self.notebook.remove_page(0)
self.results.set_tests(path)
for n in range(self.results.get_n_columns()):
name = self.results.get_column_name(n)
col = Gtk.ColumnViewColumn.new(name, TestResultsFactory(name))
col.set_expand(n > 0)
self.view.append_column(col)
if n > 0:
self.notebook.append_page(PropertyPage(name, self.results),
Gtk.Label.new(name))
class Window(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="Xfstests Results")
self.chooser = reporter.TestChooser()
self.testview = reporter.TestView()
self.passing = Gtk.Switch(halign=Gtk.Align.CENTER, active=True)
self.lpass = Gtk.Label.new("Show Passing Tests")
self.skipped = Gtk.Switch(halign=Gtk.Align.CENTER, active=True)
@ -274,7 +217,7 @@ class Window(Gtk.Window):
self.left.attach(self.lskip, 1, 2, 1, 1)
self.right = Gtk.Box.new(Gtk.Orientation.VERTICAL, 5)
self.right.append(self.xfstests.notebook)
self.right.append(self.testview)
self.right.append(self.search)
self.right.append(self.xfstests)
@ -282,8 +225,6 @@ class Window(Gtk.Window):
self.child.append(self.left)
self.child.append(self.right)
reporter.common.SizeGroup.add_widget(self.xfstests.notebook)
self.lskip.set_xalign(0)
self.lpass.set_xalign(0)
self.set_default_size(1100, 750)
@ -295,9 +236,8 @@ class Window(Gtk.Window):
self.search.connect("search-changed", self.search_changed)
def test_changed(self, window, file):
self.testview.set_test_result(file)
self.xfstests.set_tests(file.path if file else None)
if file and file.get_is_test_result():
results = reporter.testresults.TestResults(file.path)
def show_passing(self, passing, param):
self.xfstests.set_show_passing(passing.get_active())

View File

@ -1,6 +1,7 @@
#!/usr/bin/python
from . import common
from . import testchooser
from . import testproperties
from . import testresults
from gi.repository import GObject
from gi.repository import Gtk
@ -18,3 +19,17 @@ class TestChooser(Gtk.Box):
@GObject.Signal(arg_types=(testchooser.Path,))
def test_selected(self, path): pass
class TestView(Gtk.Box):
def __init__(self):
Gtk.Box.__init__(self, orientation=Gtk.Orientation.VERTICAL)
self.stack = testproperties.Stack()
self.append(Gtk.StackSwitcher(stack=self.stack, halign=Gtk.Align.CENTER))
self.append(self.stack)
def set_test_result(self, file):
self.stack.clear()
if file and file.get_is_test_result():
results = testresults.TestResults(file.path)
self.stack.show_properties(results)

View File

@ -0,0 +1,90 @@
#!/usr/bin/python
from . import common
from gi.repository import GObject
from gi.repository import Gio
from gi.repository import Gtk
PROPERTIES = [ "PLATFORM", "TIMESTAMP", "FSTYP", "MOUNT_OPTIONS", "CHECK_OPTIONS",
"TEST_DIR", "TEST_DEV", "SCRATCH_DEV", "SCRATCH_MNT" ] #, "RESULTS" ]
class Property(GObject.GObject):
def __init__(self, key, value):
GObject.GObject.__init__(self)
self.key = key
self.value = value
class Results(Property):
def __init__(self, properties):
total = properties["TESTS"]
time = properties["TIME"]
failed = properties["FAILURES"]
skipped = properties["SKIPPED"]
passed = int(total) - (int(skipped) + int(failed))
Property.__init__(self, "RESULTS",
f"Ran {total} tests in {time} seconds: " \
f"{passed} passed, {failed} failed, {skipped} skipped")
class Model(GObject.GObject, Gio.ListModel):
def __init__(self, properties):
GObject.GObject.__init__(self)
self.properties = [ Property(p, properties[p]) for p in PROPERTIES ]
self.properties.append(Results(properties))
def do_get_item_type(self): return GObject.TYPE_PYOBJECT
def do_get_n_items(self): return len(self.properties)
def do_get_item(self, i): return self.properties[i]
class Factory(Gtk.SignalListItemFactory):
def __init__(self, column):
Gtk.SignalListItemFactory.__init__(self)
self.column = column
self.connect("setup", self.on_setup)
self.connect("bind", self.on_bind)
self.connect("unbind", self.on_unbind)
self.connect("teardown", self.on_teardown)
def on_setup(self, factory, listitem):
listitem.set_child(Gtk.Label(xalign=0))
def on_bind(self, factory, listitem):
label = listitem.get_child()
match self.column:
case "Property": label.set_text(listitem.get_item().key)
case "Value": label.set_text(listitem.get_item().value)
case _: label.set_text("=")
def on_unbind(self, factory, listitem):
listitem.get_child().set_text("")
def on_teardown(self, factory, listitem):
listitem.set_child(None)
class View(Gtk.ColumnView):
def __init__(self, properties):
self.selection = Gtk.NoSelection.new(Model(properties))
Gtk.ColumnView.__init__(self, model=self.selection)
self.add_css_class("data-table")
for title in [ "Property", "=", "Value" ]:
self.append_column(Gtk.ColumnViewColumn.new(title, Factory(title)))
class Stack(Gtk.Stack):
def __init__(self):
Gtk.Stack.__init__(self, transition_type=Gtk.StackTransitionType.OVER_LEFT_RIGHT)
common.SizeGroup.add_widget(self)
def clear(self):
pages = self.get_pages()
children = [ pages.get_item(i).get_child() for i in range(pages.get_n_items()) ]
for child in children:
self.remove(child)
def show_properties(self, results):
for version in results.versions:
window = Gtk.ScrolledWindow(vscrollbar_policy=Gtk.PolicyType.NEVER,
child=View(results.properties[version]))
self.add_titled(window, version, version)

View File

@ -61,7 +61,7 @@ class TestResults:
self.add_testcase(elm.attrib["name"], file.stem, result)
def set_property(self, name, vers, value):
self.properties.setdefault(name.upper(), dict())[vers] = value
self.properties.setdefault(vers, dict())[name.upper()] = value
def add_testcase(self, name, vers, result):
self.tests.setdefault(name, TestCase(name))[vers] = result