Skip to content

Size the relay test's payload from the pipe capacity - #1801

Merged
tleonhardt merged 1 commit into
python-cmd2:mainfrom
setarcos:fix/relay-test-pipe-capacity
Nov 2, 2026
Merged

tleonhardt merged 1 commit into
python-cmd2:mainfrom
setarcos:fix/relay-test-pipe-capacity

Conversation

@setarcos

@setarcos setarcos commented Nov 1, 2026 •

Copy link
Copy Markdown
Contributor

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.

@codecov

codecov Bot commented Nov 1, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.75%. Comparing base (5ffe145) to head (1556e36).

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #1801   +/-   ##
=======================================
  Coverage   99.75%   99.75%           
=======================================
  Files          23       23           
  Lines        6593     6593           
=======================================
  Hits         6577     6577           
  Misses         16       16           
Flag Coverage Δ
unittests 99.75% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

setarcos added a commit to lcpu-club/loongarch-packages that referenced this pull request Nov 1, 2026
* Size the relay test's payload from the pipe capacity.
  See also: python-cmd2/cmd2#1801

@tleonhardt tleonhardt left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@setarcos
Thanks for tracking this down. Sizing the payload from F_GETPIPE_SZ is the right fix, and it stops the lend assertion from failing on large-page kernels. One side effect: on Linux, the test no longer covers the ordering case at its end ("cmd2's own writes follow what the child wrote, which is still pending").

With first_read = len(payload) - capacity, exactly one pipe's worth is left after the pause, so the relay can move all of it into the consumer's pipe before writer.write(b"end"). flush() then has nothing to wait for. I wrapped _DescriptorRelay.flush() to record how many bytes the relay still held when it was called (pauses=True, 5 runs each, same result every run):

Platform This PR With the suggestion below
macOS (arm64) 49152 65536
Linux amd64, 4 KiB pages 0 16384
Linux arm64, 4 KiB pages 0 16384

macOS only looks fine because the relay writes in PIPE_BUF (512-byte) chunks, which keep the consumer's pipe at 16 KiB rather than 64 KiB. With the old 280000/200000 sizes, about 14 KiB stayed in the relay on 64 KiB pipes, and the suggestion below brings that back. The test passes with it on all three platforms, but I have no 16 KiB- or 64 KiB-page kernel to try it on. Could you confirm it passes on yours?

Two other relay tests make the same 64 KiB assumption. They're outside this diff and won't fail on large-page kernels, but there they pass without testing anything:

  • test_pipeline_writer_relay_lends_only_to_a_consumer_waiting_for_the_terminal (262144 bytes) expects the relay's pipe to fill up. With 1 MiB pipes, the consumer's pipe alone holds the payload.
  • test_pipeline_writer_relay_leaves_the_terminal_after_a_producer_finishes (70000 bytes) is meant to be "more than the consumer's pipe holds". With 256 KiB pipes it isn't.

A small module-level helper for the capacity lookup, used by all three tests, would cover them: e.g. capacity + 4096 and 4 * capacity, which roughly match today's sizes on 64 KiB pipes. If you scale the 262144 one, scale its os.read(read_fd, 16384) too (say capacity // 4). Otherwise, with 1 MiB pipes, the test makes 256 reads × 0.15 s and runs past its 30 s timeout. I'm happy to take that as a follow-up if you'd rather keep this PR small.

Minor and optional: the 2 * 65536 in the payload stands in for the relay's
os.read(self._in_fd, 65536) in cmd2/utils.py. A shared constant would keep the two from drifting apart.

Comment thread tests/test_utils.py Resolved
Comment thread tests/test_utils.py Resolved
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.
@setarcos
setarcos force-pushed the fix/relay-test-pipe-capacity branch from 4a0e4df to 1556e36 Compare November 2, 2026 09:09
@setarcos

setarcos commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor Author

I ran it on Linux loongarch64(16 KiB pages) and it passes there too.
I'd rather keep this PR small, so please go ahead and take the other two relay tests (262144/70000) and the shared 65536 constant as the follow-up you offered — happy to test it on my machine.

@tleonhardt

Copy link
Copy Markdown
Member

@setarcos Thanks for fixing that main issue. I created #1803 for the follow-up work.

@tleonhardt
tleonhardt merged commit 8d20b7b into python-cmd2:main Nov 2, 2026
32 checks passed
@setarcos
setarcos deleted the fix/relay-test-pipe-capacity branch November 3, 2026 04:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants