gtk: Add a TestCaseList Gio.ListModel

This is a list model designed to show xfstests results for a given
runid. I create a new one whenever the Application changes the runid.

Signed-off-by: Anna Schumaker <anna@nowheycreamery.com>
This commit is contained in:
Anna Schumaker 2023-08-01 13:16:26 -04:00
parent 15cee521c2
commit 7adbb5938d
4 changed files with 116 additions and 6 deletions

View File

@ -1,8 +1,10 @@
# Copyright 2023 (c) Anna Schumaker.
"""Tests our Testcase Gio.ListModel."""
import unittest
import tests.xunit
import xfstestsdb.gtk.model
from gi.repository import GObject
from gi.repository import Gio
class TestXunitResult(unittest.TestCase):
@ -67,3 +69,55 @@ class TestTestCase(unittest.TestCase):
self.assertEqual(xunit.message, "")
self.assertEqual(xunit.stdout, "")
self.assertEqual(xunit.stderr, "")
class TestCaseList(unittest.TestCase):
"""Tests our TestCaseList Gio.ListModel."""
def setUp(self):
"""Set up common variables."""
self.xfstestsdb = xfstestsdb.Command()
with unittest.mock.patch("sys.stdout"):
self.xfstestsdb.run(["new", "/dev/vda1"])
self.xfstestsdb.run(["xunit", "read", "--name", "xunit-1",
"1", str(tests.xunit.XUNIT_1)])
self.xfstestsdb.run(["xunit", "read", "--name", "xunit-2",
"1", str(tests.xunit.XUNIT_1)])
self.tclist = xfstestsdb.gtk.model.TestCaseList(self.xfstestsdb.sql, 1)
def test_init(self):
"""Test that the TestCaseList was set up properly."""
self.assertIsInstance(self.tclist, GObject.GObject)
self.assertIsInstance(self.tclist, Gio.ListModel)
self.assertEqual(self.tclist.runid, 1)
def test_get_item_type(self):
"""Test the get_item_type() function."""
self.assertEqual(self.tclist.get_item_type(),
xfstestsdb.gtk.model.TestCase.__gtype__)
def test_get_n_items(self):
"""Test the get_n_items() function."""
self.assertEqual(self.tclist.get_n_items(), 10)
self.assertEqual(self.tclist.n_items, 10)
def test_get_item(self):
"""Test the get_item() function."""
testcase = self.tclist.get_item(0)
self.assertIsInstance(testcase, xfstestsdb.gtk.model.TestCase)
self.assertEqual(testcase.name, "test/01")
for xunit in ["xunit-1", "xunit-2"]:
with self.subTest(xunit=xunit):
self.assertEqual(testcase[xunit].name, xunit)
self.assertEqual(testcase[xunit].status, "passed")
self.assertEqual(testcase[xunit].time, 1)
self.assertEqual(testcase[xunit].message, "")
self.assertEqual(testcase[xunit].stdout, "")
self.assertEqual(testcase[xunit].stderr, "")
self.assertIsNone(self.tclist.get_item(10))
def test_get_xunits(self):
"""Test the get_xunits() function."""
self.assertListEqual(self.tclist.get_xunits(), ["xunit-1", "xunit-2"])

View File

@ -14,7 +14,8 @@ class TestApplication(unittest.TestCase):
def setUp(self):
"""Set up common variables."""
self.application = xfstestsdb.gtk.Application()
self.xfstestsdb = xfstestsdb.Command()
self.application = xfstestsdb.gtk.Application(self.xfstestsdb.sql)
def test_init(self):
"""Check that the Gtk Application was set up properly."""
@ -24,6 +25,7 @@ class TestApplication(unittest.TestCase):
self.assertEqual(self.application.get_flags(),
Gio.ApplicationFlags.HANDLES_COMMAND_LINE)
self.assertEqual(self.application.runid, 0)
self.assertIsNone(self.application.model)
@unittest.mock.patch("gi.repository.Adw.Application.activate")
@unittest.mock.patch("gi.repository.Adw.Application.do_command_line")
@ -38,6 +40,7 @@ class TestApplication(unittest.TestCase):
mock_cmd.get_arguments.assert_called()
mock_activate.assert_called()
self.assertEqual(self.application.runid, 0)
self.assertIsNone(self.application.model)
mock_command_line.reset_mock()
mock_activate.reset_mock()
@ -49,6 +52,9 @@ class TestApplication(unittest.TestCase):
mock_cmd.get_arguments.assert_called()
mock_activate.assert_called()
self.assertEqual(self.application.runid, 42)
self.assertIsInstance(self.application.model,
xfstestsdb.gtk.model.TestCaseList)
self.assertEqual(self.application.model.runid, 42)
@unittest.mock.patch("gi.repository.Adw.Application.add_window")
@unittest.mock.patch("gi.repository.Adw.Application.do_startup")
@ -121,7 +127,7 @@ class TestGtk(unittest.TestCase):
"""Check running `xfstestsdb gtk` with the --runid option."""
self.xfstestsdb.run(["new", "/dev/vda1"])
self.xfstestsdb.run(["gtk", "1"])
mock_app.assert_called()
mock_app.assert_called_with(self.xfstestsdb.sql)
mock_app.return_value.run.assert_called_with(["runid=1"])
@unittest.mock.patch("sys.stderr", new_callable=io.StringIO)

View File

@ -7,6 +7,7 @@ from . import gsetup
from gi.repository import GObject
from gi.repository import Gio
from gi.repository import Adw
from . import model
from . import window
from .. import commands
from .. import sqlite
@ -16,12 +17,15 @@ class Application(Adw.Application):
"""Our Adw.Application for displaying xfstests results."""
runid = GObject.Property(type=int)
model = GObject.Property(type=model.TestCaseList)
win = GObject.Property(type=window.Window)
sql = GObject.Property(type=GObject.TYPE_PYOBJECT)
def __init__(self):
def __init__(self, sql: sqlite.Connection):
"""Initialize the application."""
super().__init__(application_id=gsetup.APPLICATION_ID,
flags=Gio.ApplicationFlags.HANDLES_COMMAND_LINE)
flags=Gio.ApplicationFlags.HANDLES_COMMAND_LINE,
sql=sql)
def do_command_line(self, cmd_line: Gio.ApplicationCommandLine) -> int:
"""Handle the Adw.Application::command-line signal."""
@ -30,7 +34,9 @@ class Application(Adw.Application):
for arg in cmd_line.get_arguments():
split = arg.split("=")
match split[0]:
case "runid": self.runid = int(split[1])
case "runid":
self.runid = int(split[1])
self.model = model.TestCaseList(self.sql, self.runid)
self.activate()
return 0
@ -74,4 +80,4 @@ class Command(commands.Command):
file=sys.stderr)
sys.exit(errno.ENOENT)
Application().run(app_args)
Application(self.sql).run(app_args)

View File

@ -2,6 +2,8 @@
"""Our Testcase Gio.ListModel."""
import typing
from gi.repository import GObject
from gi.repository import Gio
from .. import sqlite
class XunitResult(GObject.GObject):
@ -43,3 +45,45 @@ class TestCase(GObject.GObject):
self.__xunits[name] = XunitResult(name=name, status=status, time=time,
message=message, stdout=stdout,
stderr=stderr)
class TestCaseList(GObject.GObject, Gio.ListModel):
"""A list of TestCases for a specific Xfstests Run."""
runid = GObject.Property(type=int)
n_items = GObject.Property(type=int)
def __init__(self, sql: sqlite.Connection, runid: int) -> None:
"""Initialize a TestCaseList."""
super().__init__(runid=runid)
self.__xunits = set()
cases = {}
cur = sql("""SELECT testcase, xunit, status,
time, message, stdout, stderr
FROM testcases_view WHERE runid=?""", runid)
for row in cur.fetchall():
testcase = cases.setdefault(row["testcase"],
TestCase(row["testcase"]))
testcase.add_xunit(row["xunit"], row["status"], row["time"],
row["message"], row["stdout"], row["stderr"])
self.__xunits.add(row["xunit"])
self.__items = sorted(cases.values())
self.n_items = len(self.__items)
def do_get_item_type(self) -> GObject.GType:
"""Get the type of the objects in the list."""
return TestCase.__gtype__
def do_get_n_items(self) -> int:
"""Get the number of items in the list."""
return self.n_items
def do_get_item(self, n: int) -> TestCase | None:
"""Get a specific item on the list."""
return self.__items[n] if n < self.n_items else None
def get_xunits(self) -> list[str]:
"""Get a list of xunits attached to this xfstests run."""
return sorted(self.__xunits)