test(web-app-stalwart): decide the IMAP parallelism instead of racing it

`test_parallel_sessions_append_every_message_once` asserted that more than
one of four sessions had appended something. ThreadPoolExecutor promises a
thread count, never that every worker takes an item from a shared iterator,
so a loaded host where one thread drains all 40 messages before its
siblings start fails the assertion with nothing broken. CI did exactly that
in run 40023932276; 25 local runs pinned to a single CPU did not.

The sessions now meet at a barrier before their first append. A pool that
runs them concurrently releases all four, and a serialised one reaches the
timeout and leaves the later sessions empty, which the assertion still
catches: with max_workers forced to 1 the test fails with the same
"1 not greater than 1" CI reported.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
kevinveenbirkenbachandClaude Opus 5 committed 2026-10-24 00:06:52 +02:00
1 parent eee73c0181
commit 657015852a
1 file changed
+20 -1
@@ -1,7 +1,9 @@
import contextlib
import importlib.util
import os
import sys
import tempfile
import threading
import time
import unittest
from pathlib import Path
@@ -74,7 +76,23 @@ class _FakeImap:
class _SlowImap(_FakeImap):
"""A session that waits for its siblings before it appends anything.
`ThreadPoolExecutor` promises a thread count, never that every worker
receives an item from a shared iterator, so counting the sessions that
happened to append is a race rather than a check.
"""
def __init__(self, barrier=None, **kwargs):
super().__init__(**kwargs)
self._barrier = barrier
self._waited = False
def append(self, mailbox, flags, date_time, message):
if self._barrier is not None and not self._waited:
self._waited = True
with contextlib.suppress(threading.BrokenBarrierError):
self._barrier.wait(timeout=10)
time.sleep(0.002)
return super().append(mailbox, flags, date_time, message)
@@ -141,7 +159,8 @@ class TestMigrateAccount(unittest.TestCase):
(self.account / "cur" / "99.host:2,").write_bytes(
b"Message-ID: <5@x>\r\n\r\nduplicate"
)
imaps = [_SlowImap() for _ in range(4)]
barrier = threading.Barrier(4)
imaps = [_SlowImap(barrier=barrier) for _ in range(4)]
stats = self.m.AccountStats()
self.m.migrate_account(imaps, self.account, stats)
appended = [entry for imap in imaps for entry in imap.appended]