Test runner: retry the SQLite teardown on Windows PermissionError (local-only nicety)

On local Windows + SQLite, DiscoverRunner's teardown ends in
os.remove(test_db.sqlite3), which raises PermissionError [WinError 32] when
another handle still holds the file (a concurrent run, a lingering connection,
AV / Search indexer) — crashing an otherwise-green run at the very end.

RobustCompressorTestRunner.teardown_databases now retries super() up to 10x with
a 0.1s sleep, then leaves the stale file for the next run to overwrite rather
than fail. Mirrors the _robust_save PermissionError retry already in the runner.

CI-neutral: CI is Postgres on Linux — teardown is DROP DATABASE (no file remove),
and Linux unlinks open files without error — so the loop never triggers there.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Disco DeDisco
2026-06-05 15:08:55 -04:00
parent 2c2ec16f08
commit 75301ca84d

View File

@@ -96,4 +96,21 @@ class RobustCompressorTestRunner(DiscoverRunner):
"WHERE datname = %s AND pid <> pg_backend_pid()", "WHERE datname = %s AND pid <> pg_backend_pid()",
[test_db_name], [test_db_name],
) )
# On local Windows + SQLite, super() ends in os.remove(test_db.sqlite3),
# which raises PermissionError [WinError 32] when another handle still
# holds the file (a concurrent run, a lingering connection, AV / Search
# indexer). Retry briefly, then leave the stale file for the next run to
# overwrite rather than crash an otherwise-green run. CI is Postgres on
# Linux — DROP DATABASE, no file remove, and Linux unlinks open files
# without error — so this loop never triggers there. Mirrors
# _robust_save's PermissionError retry.
for attempt in range(10):
try:
super().teardown_databases(old_config, **kwargs) super().teardown_databases(old_config, **kwargs)
return
except PermissionError:
if attempt == 9:
print("teardown_databases: test DB file still locked after "
"retries — leaving it for the next run to overwrite.")
return
time.sleep(0.1)