mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-07 03:15:56 +00:00
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:
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]
|
||||
|
||||
Reference in new issue
Block a user