diff --git a/tests/test_gc.py b/tests/test_gc.py index a5dcc90..ac1001b 100644 --- a/tests/test_gc.py +++ b/tests/test_gc.py @@ -8,6 +8,8 @@ import xfstestsdb.xunit.gc import tests.xunit +@unittest.mock.patch("xfstestsdb.sqlite.Connection.vacuum") +@unittest.mock.patch("sys.stdout", new_callable=io.StringIO) class TestGC(unittest.TestCase): """Tests the `xfstestsdb xunit gc` command.""" @@ -31,24 +33,26 @@ class TestGC(unittest.TestCase): mock_stdout.seek(0) mock_stdout.truncate(0) - def test_init(self): + def test_init(self, mock_stdout: io.StringIO, + mock_vacuum: unittest.mock.Mock): """Check that the gc command was set up properly.""" self.assertIsInstance(self.gc, xfstestsdb.commands.Command) self.assertIsInstance(self.gc, xfstestsdb.xunit.gc.Command) self.assertEqual(self.xunit.subparser.choices["gc"], self.gc.parser) - @unittest.mock.patch("sys.stdout", new_callable=io.StringIO) - def test_gc_empty(self, mock_stdout: io.StringIO): + def test_gc_empty(self, mock_stdout: io.StringIO, + mock_vacuum: unittest.mock.Mock): """Test garbage collecting an empty database.""" cur = self.xfstestsdb.sql("SELECT runid FROM xfstests_gc_runs") self.assertListEqual([row['runid'] for row in cur.fetchall()], []) self.xfstestsdb.run(["gc"]) self.assertEqual(mock_stdout.getvalue(), "") + mock_vacuum.assert_not_called() - @unittest.mock.patch("sys.stdout", new_callable=io.StringIO) - def test_gc_no_testcases(self, mock_stdout: io.StringIO): + def test_gc_no_testcases(self, mock_stdout: io.StringIO, + mock_vacuum: unittest.mock.Mock): """Test garbage collecting runs with no testcases.""" self.setup_runs(mock_stdout) @@ -61,9 +65,10 @@ class TestGC(unittest.TestCase): cur = self.xfstestsdb.sql("SELECT runid FROM xfstests_runs") self.assertListEqual([row['runid'] for row in cur.fetchall()], [1]) + mock_vacuum.assert_called() - @unittest.mock.patch("sys.stdout", new_callable=io.StringIO) - def test_gc_expired(self, mock_stdout: io.StringIO): + def test_gc_expired(self, mock_stdout: io.StringIO, + mock_vacuum: unittest.mock.Mock): """Test garbage collecting old runs.""" self.setup_runs(mock_stdout) self.xfstestsdb.run(["xunit", "read", "2", str(tests.xunit.XUNIT_1)]) @@ -87,9 +92,10 @@ class TestGC(unittest.TestCase): cur = self.xfstestsdb.sql("SELECT runid FROM xfstests_runs") self.assertListEqual([row['runid'] for row in cur.fetchall()], [2]) + mock_vacuum.assert_called() - @unittest.mock.patch("sys.stdout", new_callable=io.StringIO) - def test_gc_expired_tagged(self, mock_stdout: io.StringIO): + def test_gc_expired_tagged(self, mock_stdout: io.StringIO, + mock_vacuum: unittest.mock.Mock): """Test that we don't garbage collect expired runs that are tagged.""" self.setup_runs(mock_stdout) self.xfstestsdb.run(["xunit", "read", "2", str(tests.xunit.XUNIT_1)]) @@ -109,9 +115,10 @@ class TestGC(unittest.TestCase): cur = self.xfstestsdb.sql("SELECT runid FROM xfstests_runs") self.assertListEqual([row['runid'] for row in cur.fetchall()], [1]) + mock_vacuum.assert_called() - @unittest.mock.patch("sys.stdout", new_callable=io.StringIO) - def test_gc_dry_run(self, mock_stdout: io.StringIO): + def test_gc_dry_run(self, mock_stdout: io.StringIO, + mock_vacuum: unittest.mock.Mock): """Test garbage collecting with the --dry-run option.""" self.setup_runs(mock_stdout) self.xfstestsdb.run(["gc", "--dry-run"]) @@ -121,3 +128,4 @@ class TestGC(unittest.TestCase): cur = self.xfstestsdb.sql("SELECT runid FROM xfstests_runs") self.assertListEqual([row['runid'] for row in cur.fetchall()], [1, 2, 3]) + mock_vacuum.assert_not_called() diff --git a/tests/test_sqlite.py b/tests/test_sqlite.py index 6adb940..1b54754 100644 --- a/tests/test_sqlite.py +++ b/tests/test_sqlite.py @@ -114,6 +114,10 @@ class TestConnection(unittest.TestCase): with self.assertRaises(sqlite3.OperationalError): self.sql("SELECT COUNT(*) FROM other_table") + def test_vacuum(self): + """Test vacuuming the database.""" + self.assertIsInstance(self.sql.vacuum(), sqlite3.Cursor) + def test_close(self): """Check closing the connection.""" self.sql.close() diff --git a/xfstestsdb/gc.py b/xfstestsdb/gc.py index 450ec8e..827fb61 100644 --- a/xfstestsdb/gc.py +++ b/xfstestsdb/gc.py @@ -25,3 +25,10 @@ class Command(commands.Command): if not args.dry_run: self.sql("DELETE FROM xfstests_runs WHERE runid=?", runid) print(f"run #{runid} {how} deleted") + + args.need_vacuum = len(rows) > 0 + + def do_done(self, args: argparse.Namespace) -> None: + """Vacuum the database after deleting.""" + if args.need_vacuum and not args.dry_run: + self.sql.vacuum() diff --git a/xfstestsdb/sqlite.py b/xfstestsdb/sqlite.py index 52d881d..b02b3e8 100644 --- a/xfstestsdb/sqlite.py +++ b/xfstestsdb/sqlite.py @@ -76,3 +76,7 @@ class Connection: cur = self.sql.executescript(f.read()) self.sql.commit() return cur + + def vacuum(self) -> sqlite3.Cursor | None: + """Vacuum the database.""" + return self.sql.execute("VACUUM")