From 1556e3620848d6c660b6a930efd31d682fc34680 Mon Sep 17 00:00:00 2001 From: Pluto Yang Date: Sun, 1 Nov 2026 18:39:03 +0800 Subject: [PATCH] Size the relay test's payload from the pipe capacity test_pipeline_writer_relay_lends_only_while_a_producer_waits hardcoded a 280000-byte payload and a 200000-byte first read, assuming the 64 KiB pipes of a 4 KiB-page system. A pipe holds a fixed number of pages, so a 16 KiB-page kernel has 256 KiB pipes and a 64 KiB-page one 1 MiB pipes. There the relay drains the whole payload into the consumer's pipe before the child has to wait, no lend happens, and the test asserts a lend that was never needed. cmd2 itself behaves correctly; only the test's assumption depends on the page size. Size the payload from the consumer pipe's capacity, reported by F_GETPIPE_SZ where the kernel has it, and fall back to the 64 KiB that macOS and the BSDs cap a pipe at elsewhere. The consumer's first read leaves more than a pipe's worth pending, so part of the payload is still in the relay when cmd2 writes after it, and the rest fits in the pipes, so the child can finish. --- tests/test_utils.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/tests/test_utils.py b/tests/test_utils.py index 299cacade..aaedc708c 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -478,14 +478,19 @@ def test_pipeline_writer_relay_lends_only_while_a_producer_waits(pauses) -> None waiting, command code gets the terminal back, whether or not the consumer has read all its output yet. That is as between cmd2's own writes. """ + import fcntl import subprocess import threading - # More than the relay and both pipes hold, so the child blocks until the consumer reads. What remains after the consumer's - # first read fits, so the child can then finish. - payload = b"x" * 280000 - first_read = 200000 if pauses else len(payload) read_fd, write_fd = os.pipe() + # Size the payload from the consumer's pipe. Linux reports its capacity, which follows the page size (16 pages by + # default); macOS and the BSDs cap a pipe at 64 KiB. + capacity = fcntl.fcntl(write_fd, fcntl.F_GETPIPE_SZ) if hasattr(fcntl, "F_GETPIPE_SZ") else 65536 + # More than the relay and both pipes hold, so the child blocks until the consumer reads. What remains after the consumer's + # first read fits, so the child can then finish. It is also more than the consumer's pipe holds, so part of it is still + # in the relay when cmd2 writes after it. + payload = b"x" * (2 * capacity + 2 * 65536) + first_read = len(payload) - capacity - 16384 if pauses else len(payload) received = bytearray() lent = threading.Event() resume = threading.Event()