gtk: Add a DateDeviceList listmodel

This contains a list of DeviceRunsList objects for every run on a given
day.

Signed-off-by: Anna Schumaker <anna@nowheycreamery.com>
This commit is contained in:
Anna Schumaker 2023-11-02 15:26:30 -04:00
parent 70274c448c
commit 6fcb4eb5e7
2 changed files with 129 additions and 0 deletions

View File

@ -3,8 +3,10 @@
import datetime import datetime
import unittest import unittest
import xfstestsdb.gtk.tree import xfstestsdb.gtk.tree
import tests.xunit
from gi.repository import GObject from gi.repository import GObject
from gi.repository import Gio from gi.repository import Gio
from gi.repository import Gtk
class TestXfstestsRun(unittest.TestCase): class TestXfstestsRun(unittest.TestCase):
@ -118,3 +120,76 @@ class TestDeviceRunModel(unittest.TestCase):
then = now - datetime.timedelta(seconds=42) then = now - datetime.timedelta(seconds=42)
self.device.add_run(2, then) self.device.add_run(2, then)
self.assertEqual(self.device.get_earliest_run().runid, 2) self.assertEqual(self.device.get_earliest_run().runid, 2)
class TestDateDeviceList(unittest.TestCase):
"""Test case for our listmodel of test devices on a specific day."""
def setUp(self):
"""Set up common variables."""
self.xfstestsdb = xfstestsdb.Command()
with unittest.mock.patch("sys.stdout"):
self.xfstestsdb.run(["new", "/dev/vda2"])
self.xfstestsdb.run(["new", "/dev/vda1"])
self.xfstestsdb.run(["new", "/dev/vda1"])
self.xfstestsdb.run(["new", "/dev/vda3"])
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)])
yesterday = datetime.datetime.now() - datetime.timedelta(days=1)
self.xfstestsdb.sql("""UPDATE xfstests_runs SET timestamp=?
WHERE device=?""", yesterday, "/dev/vda3")
self.today = datetime.date.today()
self.devlist = xfstestsdb.gtk.tree.DateDeviceList(self.xfstestsdb.sql,
self.today)
def test_init(self):
"""Test that the DateDeviceList was set up properly."""
self.assertIsInstance(self.devlist, GObject.GObject)
self.assertIsInstance(self.devlist, Gio.ListModel)
self.assertEqual(self.devlist.date, datetime.date.today())
def test_get_range(self):
"""Test finding the date range for the displayed entries."""
min = datetime.datetime.combine(self.today, datetime.time())
max = min + datetime.timedelta(days=1)
self.assertTupleEqual(self.devlist.get_range(self.today), (min, max))
def test_get_item_type(self):
"""Test the get_item_type() function."""
self.assertEqual(self.devlist.get_item_type(),
xfstestsdb.gtk.tree.DeviceRunsList.__gtype__)
def test_get_n_items(self):
"""Test the get_n_items() function."""
self.assertEqual(self.devlist.get_n_items(), 2)
self.assertEqual(self.devlist.n_items, 2)
def test_get_item(self):
"""Test the get_item() function."""
self.assertIsInstance(self.devlist.get_item(0),
xfstestsdb.gtk.tree.DeviceRunsList)
self.assertIsInstance(self.devlist.get_item(0).get_item(0).timestamp,
datetime.datetime)
self.assertEqual(self.devlist.get_item(0).name, "/dev/vda1")
self.assertEqual(self.devlist.get_item(1).name, "/dev/vda2")
def test_treemodel(self):
"""Test the treemodel property."""
self.assertIsInstance(self.devlist.treemodel, Gtk.TreeListModel)
self.assertFalse(self.devlist.treemodel.props.passthrough)
self.assertTrue(self.devlist.treemodel.props.autoexpand)
tree = self.devlist.treemodel
self.assertEqual(tree[0].get_item().name, "/dev/vda1")
self.assertEqual(tree[1].get_item().runid, 2)
self.assertEqual(tree[2].get_item().runid, 3)
self.assertEqual(tree[3].get_item().name, "/dev/vda2")
self.assertEqual(tree[4].get_item().runid, 1)
with self.assertRaises(IndexError):
self.assertIsNone(tree[5])

View File

@ -5,6 +5,8 @@ import datetime
import typing import typing
from gi.repository import GObject from gi.repository import GObject
from gi.repository import Gio from gi.repository import Gio
from gi.repository import Gtk
from .. import sqlite
class XfstestsRun(GObject.GObject): class XfstestsRun(GObject.GObject):
@ -72,3 +74,55 @@ class DeviceRunsList(GObject.GObject, Gio.ListModel):
def get_earliest_run(self) -> XfstestsRun | None: def get_earliest_run(self) -> XfstestsRun | None:
"""Get the earliest XfstestsRun that we know about.""" """Get the earliest XfstestsRun that we know about."""
return self.__runs[0] if self.n_items > 0 else None return self.__runs[0] if self.n_items > 0 else None
class DateDeviceList(GObject.GObject, Gio.ListModel):
"""A list containing test devices used on a specific day."""
date = GObject.Property(type=GObject.TYPE_PYOBJECT)
n_items = GObject.Property(type=int)
treemodel = GObject.Property(type=Gtk.TreeListModel)
def __init__(self, sql: sqlite.Connection, date: datetime.date) -> None:
"""Initialize our DateDeviceList."""
super().__init__(date=date)
devices = {}
for row in sql("""SELECT DISTINCT runid, device, timestamp
FROM tagged_runs
WHERE timestamp >= ? AND timestamp < ?""",
*self.get_range(date)).fetchall():
if (dev := devices.get(row['device'])) is None:
devices[row['device']] = dev = DeviceRunsList(row['device'])
ts = datetime.datetime.fromisoformat(row['timestamp'])
dev.add_run(row['runid'], ts)
self.__items = sorted(devices.values())
self.n_items = len(self.__items)
self.treemodel = Gtk.TreeListModel.new(root=self, passthrough=False,
autoexpand=True,
create_func=self.__create_func)
def __create_func(self, item: GObject.GObject) -> Gio.ListModel:
if isinstance(item, DeviceRunsList):
return item
return None
def do_get_item_type(self) -> GObject.GType:
"""Get the type of objects in the list."""
return DeviceRunsList.__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) -> DeviceRunsList:
"""Get a specific item in the list."""
return self.__items[n]
def get_range(self, date: datetime.date) -> tuple[datetime.datetime,
datetime.datetime]:
"""Get the minimum and maximum timestamps for the date."""
min = datetime.datetime.combine(date, datetime.time())
max = min + datetime.timedelta(days=1)
return (min, max)