From e14667691a975a49424aeed0096a049d21691caf Mon Sep 17 00:00:00 2001 From: Anna Schumaker Date: Mon, 14 Aug 2023 11:35:27 -0400 Subject: [PATCH] gtk: Add a SummaryList Gio.ListModel This is a list model designed to show a summary of xfstests results for a given runid. I create a new one whenever the Application changes the runid. Signed-off-by: Anna Schumaker --- tests/gtk/test_model.py | 51 ++++++++++++++++++++++++++++++++++++++ tests/test_gtk.py | 4 +++ xfstestsdb/gtk/__init__.py | 2 ++ xfstestsdb/gtk/model.py | 41 ++++++++++++++++++++++++++++++ 4 files changed, 98 insertions(+) diff --git a/tests/gtk/test_model.py b/tests/gtk/test_model.py index e087dcf..527f21b 100644 --- a/tests/gtk/test_model.py +++ b/tests/gtk/test_model.py @@ -271,3 +271,54 @@ class TestSummary(unittest.TestCase): self.assertSetEqual(self.summary.get_results(), {"1 unit"}) self.summary.add_xunit("xunit-2", 2, "unit") self.assertSetEqual(self.summary.get_results(), {"1 unit", "2 units"}) + + +class TestSummaryList(unittest.TestCase): + """Test case for our summary list.""" + + 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.summary = xfstestsdb.gtk.model.SummaryList(self.xfstestsdb.sql, 1) + + def test_init(self): + """Test that the SummaryList was set up properly.""" + self.assertIsInstance(self.summary, GObject.GObject) + self.assertIsInstance(self.summary, Gio.ListModel) + self.assertEqual(self.summary.runid, 1) + + def test_get_item_type(self): + """Test the get_item_type() function.""" + self.assertEqual(self.summary.get_item_type(), + xfstestsdb.gtk.model.Summary.__gtype__) + + def test_get_n_items(self): + """Test the get_n_items() function.""" + self.assertEqual(self.summary.get_n_items(), 4) + self.assertEqual(self.summary.n_items, 4) + + def test_get_item(self): + """Test the get_item() function.""" + for i, field in enumerate(["passed", "failed", "skipped", "time"]): + with self.subTest(i=i, field=field): + summary = self.summary[i] + self.assertIsInstance(summary, xfstestsdb.gtk.model.Summary) + self.assertEqual(summary.name, field) + + match field: + case "passed": expected = {"6 testcases"} + case "failed": expected = {"1 testcase"} + case "skipped": expected = {"3 testcases"} + case "time": expected = {"43 seconds"} + self.assertSetEqual(summary.get_results(), expected) + + def test_get_xunits(self): + """Test the get_xunits() function.""" + self.assertListEqual(self.summary.get_xunits(), ["xunit-1", "xunit-2"]) diff --git a/tests/test_gtk.py b/tests/test_gtk.py index f6efec2..2d229d2 100644 --- a/tests/test_gtk.py +++ b/tests/test_gtk.py @@ -28,6 +28,7 @@ class TestApplication(unittest.TestCase): xfstestsdb.gtk.gsetup.RESOURCE_PATH) self.assertEqual(self.application.runid, 0) self.assertIsNone(self.application.model) + self.assertIsNone(self.application.summary) @unittest.mock.patch("gi.repository.Adw.Application.activate") @unittest.mock.patch("gi.repository.Adw.Application.do_command_line") @@ -43,6 +44,7 @@ class TestApplication(unittest.TestCase): mock_activate.assert_called() self.assertEqual(self.application.runid, 0) self.assertIsNone(self.application.model) + self.assertIsNone(self.application.summary) mock_command_line.reset_mock() mock_activate.reset_mock() @@ -56,6 +58,8 @@ class TestApplication(unittest.TestCase): self.assertEqual(self.application.runid, 42) self.assertIsInstance(self.application.model, xfstestsdb.gtk.model.TestCaseList) + self.assertIsInstance(self.application.summary, + xfstestsdb.gtk.model.SummaryList) self.assertEqual(self.application.model.runid, 42) @unittest.mock.patch("xfstestsdb.gtk.gsetup.add_style") diff --git a/xfstestsdb/gtk/__init__.py b/xfstestsdb/gtk/__init__.py index 859360b..c5f20f5 100644 --- a/xfstestsdb/gtk/__init__.py +++ b/xfstestsdb/gtk/__init__.py @@ -18,6 +18,7 @@ class Application(Adw.Application): """Our Adw.Application for displaying xfstests results.""" runid = GObject.Property(type=int) + summary = GObject.Property(type=model.SummaryList) model = GObject.Property(type=model.TestCaseList) win = GObject.Property(type=window.Window) view = GObject.Property(type=view.XfstestsView) @@ -40,6 +41,7 @@ class Application(Adw.Application): case "runid": self.runid = int(split[1]) self.model = model.TestCaseList(self.sql, self.runid) + self.summary = model.SummaryList(self.sql, self.runid) self.activate() return 0 diff --git a/xfstestsdb/gtk/model.py b/xfstestsdb/gtk/model.py index a8344df..1e42fa8 100644 --- a/xfstestsdb/gtk/model.py +++ b/xfstestsdb/gtk/model.py @@ -173,3 +173,44 @@ class Summary(GObject.GObject): def get_results(self) -> set[str]: """Get a set of results for each added xunit.""" return {str(value) for value in self.__xunits.values()} + + +class SummaryList(GObject.GObject, Gio.ListModel): + """A list summarizing the results of 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 SummaryList.""" + super().__init__(runid=runid) + self.__xunits = set() + + results = {} + cur = sql("""SELECT name AS xunit, passed, failed, skipped, time + FROM xunits_view WHERE runid=?""", runid) + for row in cur.fetchall(): + for field in ["passed", "failed", "skipped", "time"]: + summary = results.setdefault(field, Summary(field)) + summary.add_xunit(row["xunit"], row[field], + "second" if field == "time" else "testcase") + self.__xunits.add(row["xunit"]) + + self.__items = sorted(results.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 Summary.__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) -> Summary | 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)