fix(tests): close leaked sqlite connections; gate ResourceWarning as error (refs #618)
zot Db.__init__ leak on schema-parity raise; test fixtures not closing raw Db/create_db connections; cli comments _build_bib_helpers cache connection never closed. Gate: error::ResourceWarning (coverage's own sqlitedb warning ignored). Root causes tracemalloc-verified; most per-test attributions in #618 were GC-timing misattribution across xdist workers.
This commit is contained in:
@@ -207,6 +207,10 @@ testpaths = ["tests"]
|
|||||||
markers = [
|
markers = [
|
||||||
"stub: marks tests that report stub vs implemented status (deselect with '-m \"not stub\"')",
|
"stub: marks tests that report stub vs implemented status (deselect with '-m \"not stub\"')",
|
||||||
]
|
]
|
||||||
|
filterwarnings = [
|
||||||
|
"error::ResourceWarning",
|
||||||
|
"ignore::ResourceWarning:coverage.*",
|
||||||
|
]
|
||||||
|
|
||||||
[tool.coverage.run]
|
[tool.coverage.run]
|
||||||
# Required for reliable pytest-cov + pytest-xdist combining: each worker
|
# Required for reliable pytest-cov + pytest-xdist combining: each worker
|
||||||
|
|||||||
@@ -50,15 +50,17 @@ def _build_bib_helpers(use_bib: bool, attach: bool):
|
|||||||
|
|
||||||
db = str(path("db.bib"))
|
db = str(path("db.bib"))
|
||||||
con = sqlite3.connect(db, check_same_thread=False)
|
con = sqlite3.connect(db, check_same_thread=False)
|
||||||
|
try:
|
||||||
cache: dict[str, tuple[str, str]] = {}
|
cache: dict[str, tuple[str, str]] = {}
|
||||||
for row in con.execute(
|
for row in con.execute(
|
||||||
"SELECT key, url, abstract FROM items "
|
"SELECT key, url, abstract FROM items "
|
||||||
"WHERE url LIKE 'https://www.regulations.gov/comment/%'"
|
"WHERE url LIKE 'https://www.regulations.gov/comment/%'"
|
||||||
):
|
):
|
||||||
cid = (row[1] or "").rsplit("/", 1)[-1]
|
cid = (row[1] or "").rsplit("/", 1)[-1]
|
||||||
if cid:
|
if cid:
|
||||||
cache[cid] = (row[0], row[2] or "")
|
cache[cid] = (row[0], row[2] or "")
|
||||||
|
finally:
|
||||||
|
con.close()
|
||||||
|
|
||||||
def body_lookup(comment_id: str) -> str:
|
def body_lookup(comment_id: str) -> str:
|
||||||
return cache.get(comment_id, ("", ""))[1]
|
return cache.get(comment_id, ("", ""))[1]
|
||||||
|
|||||||
@@ -293,10 +293,14 @@ class Db:
|
|||||||
def __init__(self, path: str) -> None:
|
def __init__(self, path: str) -> None:
|
||||||
self.path = path
|
self.path = path
|
||||||
self.con = sqlite3.connect(path)
|
self.con = sqlite3.connect(path)
|
||||||
self.con.row_factory = sqlite3.Row
|
try:
|
||||||
self.con.execute("PRAGMA journal_mode=WAL")
|
self.con.row_factory = sqlite3.Row
|
||||||
self.con.execute("PRAGMA foreign_keys=ON")
|
self.con.execute("PRAGMA journal_mode=WAL")
|
||||||
self._verify_schema_parity()
|
self.con.execute("PRAGMA foreign_keys=ON")
|
||||||
|
self._verify_schema_parity()
|
||||||
|
except Exception:
|
||||||
|
self.con.close()
|
||||||
|
raise
|
||||||
|
|
||||||
def _verify_schema_parity(self) -> None:
|
def _verify_schema_parity(self) -> None:
|
||||||
"""Fail fast if Zotero's live schema disagrees with our maps.
|
"""Fail fast if Zotero's live schema disagrees with our maps.
|
||||||
|
|||||||
@@ -182,6 +182,7 @@ def extractor(zotero_db) -> Extractor:
|
|||||||
ex = Extractor(db)
|
ex = Extractor(db)
|
||||||
yield ex
|
yield ex
|
||||||
ex.close()
|
ex.close()
|
||||||
|
db.close()
|
||||||
|
|
||||||
|
|
||||||
class TestExtractorQuotes:
|
class TestExtractorQuotes:
|
||||||
|
|||||||
@@ -35,26 +35,31 @@ class TestCreateDb:
|
|||||||
con = create_db()
|
con = create_db()
|
||||||
count = con.execute("SELECT count(*) FROM itemTypes").fetchone()[0]
|
count = con.execute("SELECT count(*) FROM itemTypes").fetchone()[0]
|
||||||
assert count == 40
|
assert count == 40
|
||||||
|
con.close()
|
||||||
|
|
||||||
def test_fields_seeded(self):
|
def test_fields_seeded(self):
|
||||||
con = create_db()
|
con = create_db()
|
||||||
count = con.execute("SELECT count(*) FROM fields").fetchone()[0]
|
count = con.execute("SELECT count(*) FROM fields").fetchone()[0]
|
||||||
assert count == 123
|
assert count == 123
|
||||||
|
con.close()
|
||||||
|
|
||||||
def test_creator_types_seeded(self):
|
def test_creator_types_seeded(self):
|
||||||
con = create_db()
|
con = create_db()
|
||||||
count = con.execute("SELECT count(*) FROM creatorTypes").fetchone()[0]
|
count = con.execute("SELECT count(*) FROM creatorTypes").fetchone()[0]
|
||||||
assert count == 37
|
assert count == 37
|
||||||
|
con.close()
|
||||||
|
|
||||||
def test_item_type_fields_seeded(self):
|
def test_item_type_fields_seeded(self):
|
||||||
con = create_db()
|
con = create_db()
|
||||||
count = con.execute("SELECT count(*) FROM itemTypeFields").fetchone()[0]
|
count = con.execute("SELECT count(*) FROM itemTypeFields").fetchone()[0]
|
||||||
assert count == 770
|
assert count == 770
|
||||||
|
con.close()
|
||||||
|
|
||||||
def test_base_field_mappings_seeded(self):
|
def test_base_field_mappings_seeded(self):
|
||||||
con = create_db()
|
con = create_db()
|
||||||
count = con.execute("SELECT count(*) FROM baseFieldMappings").fetchone()[0]
|
count = con.execute("SELECT count(*) FROM baseFieldMappings").fetchone()[0]
|
||||||
assert count == 72
|
assert count == 72
|
||||||
|
con.close()
|
||||||
|
|
||||||
def test_library_exists(self):
|
def test_library_exists(self):
|
||||||
con = create_db()
|
con = create_db()
|
||||||
|
|||||||
Reference in New Issue
Block a user