Torture harness: dump all stacks on the first hang; SQLite 3.53 test fix

test_new_memory_database_is_not_scanned_at_registration filled the memory
database with VACUUM INTO, which SQLite 3.53 (the free-threaded 3.14 build)
refuses for an existing in-memory database; it now uses a plain connection.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EwkLo2rJWidpkDVT3HkvNv
This commit is contained in:
Claude 2026-10-04 09:14:38 +00:00
commit 6f875274b0
No known key found for this signature in database
2 changed files with 15 additions and 3 deletions

View file

@ -362,6 +362,15 @@ class Torture:
with self.lock:
self.problems.append({"kind": kind, "message": message[:2000]})
def dump_stacks_once(self, why):
"""Every thread's stack on stderr, the first time something hangs."""
with self.lock:
if getattr(self, "_dumped", False):
return
self._dumped = True
sys.stderr.write(f"\n=== {why}: stacks of all threads ===\n")
faulthandler.dump_traceback(all_threads=True)
def count(self, key):
with self.lock:
self.counts[key] += 1
@ -414,6 +423,7 @@ class Torture:
value = await asyncio.wait_for(awaitable, timeout)
except asyncio.TimeoutError:
self.problem("hang", f"{op} on {group} did not finish in {timeout}s")
self.dump_stacks_once(f"{op} on {group} hung")
return False, None
except asyncio.CancelledError:
raise

View file

@ -619,10 +619,12 @@ async def test_new_memory_database_is_not_scanned_at_registration():
state = memory._watch_state
assert state.scan_future is None
assert state in watcher._pending
# Fill it the way the plugin does
conn = sqlite3.connect(":memory:")
# Fill it from a connection of its own, as the plugin does (it uses
# VACUUM INTO, which newer SQLite versions refuse for an existing
# in-memory database, so a plain connection here)
conn = sqlite3.connect("file:review_fixes_copy?mode=memory&cache=shared", uri=True)
conn.execute("create table copied (id integer)")
conn.execute("VACUUM INTO 'file:review_fixes_copy?mode=memory&cache=shared'")
conn.commit()
conn.close()
# The next request scans it
response = await ds.client.get("/copy.json")