From a478ae0a1dcd00e58b7b6a0ed53cd653980b531d Mon Sep 17 00:00:00 2001 From: Vito Sansevero Date: Mon, 26 Oct 2026 03:52:18 -0700 Subject: [PATCH] test(images): bound the shared-listing test waits (#348) A macOS py3.12 run stopped inside the shared-listing tests and sat until the 6 h job limit with no traceback. It does not reproduce locally (about 300 runs on 3.12 and 3.14, pinned to one core). Requests and background settles in TestSharedListing now give up after 30 s, so a recurrence fails with the stuck await instead of hanging the run. --- tests/test_api_images.py | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/tests/test_api_images.py b/tests/test_api_images.py index 8559d9f5..f9357f94 100644 --- a/tests/test_api_images.py +++ b/tests/test_api_images.py @@ -2351,6 +2351,10 @@ class TestRootScopeServing(ImageAPITestCase): await self.assert_no_access(path, scope=token) +# Seconds any single wait in the shared-listing tests may take. +_HANG_LIMIT = 30 + + class _GatedScan: """Wraps the real scan, counts calls and can hold one call after it listed. @@ -2404,8 +2408,13 @@ class TestSharedListing(ImageAPITestCase): self.addCleanup(self.scan.release_all) async def _json(self, method, path, **kwargs): - resp = await self.client.request(method, path, **kwargs) - return resp.status, await resp.json() + # Bounded, like every wait in this class: a stuck walk fails the test + # with a traceback instead of hanging the whole run. + async def call(): + resp = await self.client.request(method, path, **kwargs) + return resp.status, await resp.json() + + return await asyncio.wait_for(call(), _HANG_LIMIT) def _record(self): return self.api._root_listings[str(self.output_dir)] @@ -2418,8 +2427,12 @@ class TestSharedListing(ImageAPITestCase): async def _settle(self): """Wait for every background walk this API started.""" - while self.api._listing_tasks: - await asyncio.gather(*list(self.api._listing_tasks)) + + async def settle(): + while self.api._listing_tasks: + await asyncio.gather(*list(self.api._listing_tasks)) + + await asyncio.wait_for(settle(), _HANG_LIMIT) async def test_concurrent_cold_readers_share_one_walk(self): make_png(self.output_dir / "sub" / "a.png")