test(browser): keep the reset scratch database in /dev/shm when there is one (#384)

Throttled runs still waited on the runner's disk while creating and
rewriting the scratch database, whose pages were under writeback.
This commit is contained in:
Vito Sansevero
2026-10-27 07:14:49 -07:00
parent c160b186d7
commit f707a1abe5
2 changed files with 48 additions and 6 deletions
+31 -4
View File
@@ -20,8 +20,10 @@ instead of being overwritten (``PRAGMA data_version``).
from __future__ import annotations
import hashlib
import os
import shutil
import sqlite3
import tempfile
import weakref
from pathlib import Path
from typing import Any, Callable, TypeVar
@@ -32,6 +34,8 @@ T = TypeVar("T")
# proof, tests/browser/reset_equivalence.py, compares both ways).
SEED_ON_LIVE_ENV = "PM_TEST_SEED_ON_LIVE"
SCRATCH_SCHEMA = "reset_seed"
# Linux's shared-memory tmpfs (present in the Playwright image and on runners).
MEMORY_ROOT = Path("/dev/shm")
def _quote(name: str) -> str:
@@ -100,9 +104,18 @@ class _SeedApi:
class ScratchSeeder:
"""Seed into a scratch copy and publish the changed tables in one commit."""
def __init__(self, api: Any, directory: Path, *, on_live: bool = False) -> None:
def __init__(
self,
api: Any,
directory: Path,
*,
on_live: bool = False,
memory_root: Path | None = MEMORY_ROOT,
) -> None:
self._api = api
self._directory = Path(directory)
self._fallback = Path(directory)
self._memory_root = memory_root
self._directory: Path | None = None
self._on_live = on_live
self._scratch = None
self._unsynced: "weakref.WeakSet[sqlite3.Connection]" = weakref.WeakSet()
@@ -137,7 +150,7 @@ class ScratchSeeder:
if self._scratch is None:
from database.operations import PromptDatabase
self._directory.mkdir(parents=True, exist_ok=True)
self._directory = self._scratch_directory()
self._scratch = PromptDatabase(str(self._directory / "seed.db"))
return self._scratch
@@ -201,4 +214,18 @@ class ScratchSeeder:
if self._scratch is not None:
self._scratch.close_all()
self._scratch = None
shutil.rmtree(self._directory, ignore_errors=True)
if self._directory is not None:
shutil.rmtree(self._directory, ignore_errors=True)
self._directory = None
def _scratch_directory(self) -> Path:
"""A folder in memory (tmpfs) where there is one, else ``directory``.
Even unsynced, scratch writes on the runner's disk wait whenever the
kernel is writing back the pages they rewrite.
"""
root = self._memory_root
if root is not None and root.is_dir() and os.access(root, os.W_OK):
return Path(tempfile.mkdtemp(prefix="pm-reset-", dir=root))
self._fallback.mkdir(parents=True, exist_ok=True)
return self._fallback
+17 -2
View File
@@ -70,7 +70,7 @@ class TestScratchSeeder(unittest.TestCase):
self.addCleanup(assert_closed, self, self.tmp.name)
self.live = self.database("live.db")
self.api = types.SimpleNamespace(db=self.live, marker="live api")
self.seeder = ScratchSeeder(self.api, self.root / "scratch")
self.seeder = ScratchSeeder(self.api, self.root / "scratch", memory_root=None)
self.addCleanup(self.seeder.close)
# Rows from "earlier tests": AUTOINCREMENT positions have moved on.
for index in range(5):
@@ -229,7 +229,9 @@ class TestScratchSeeder(unittest.TestCase):
self.assertEqual(conn.execute("PRAGMA foreign_key_check").fetchall(), [])
def test_on_live_mode_runs_the_seed_on_the_live_api(self):
seeder = ScratchSeeder(self.api, self.root / "unused", on_live=True)
seeder = ScratchSeeder(
self.api, self.root / "unused", on_live=True, memory_root=self.root
)
self.addCleanup(seeder.close)
expected = self.oracle(reseed)
seen = []
@@ -240,6 +242,19 @@ class TestScratchSeeder(unittest.TestCase):
self.assertEqual(digests(self.live), expected)
self.assertFalse((self.root / "unused").exists())
def test_the_scratch_lives_under_the_memory_root_when_there_is_one(self):
memory = self.root / "memory"
memory.mkdir()
seeder = ScratchSeeder(self.api, self.root / "fallback", memory_root=memory)
self.addCleanup(seeder.close)
expected = self.oracle(reseed)
seeder.run(reseed)
self.assertEqual(digests(self.live), expected)
self.assertEqual(len(list(memory.glob("pm-reset-*/seed.db"))), 1)
self.assertFalse((self.root / "fallback").exists())
seeder.close()
self.assertEqual(list(memory.iterdir()), [])
def test_close_releases_the_scratch_files(self):
self.seeder.run(reseed)
self.seeder.close()