summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-10-01 09:54:20 -0300
committerGabriel Schneider <[email protected]>2026-10-01 10:16:45 -0300
commitcaa8ed077e8b9b67d18f18b3ec46891bd8d310a7 (patch)
tree05c09ee65e1a68aacffd90b137690d5b39ed9457 /test
parenteda60572013d046d08e253e5847a0ba588c10339 (diff)
downloadpardes-caa8ed077e8b9b67d18f18b3ec46891bd8d310a7.tar.gz
pardes-caa8ed077e8b9b67d18f18b3ec46891bd8d310a7.zip
A command line runs when its newline comes, or at its open's close, never because a write was short: a long line cut by a mount is one line
A write shorter than its message, and not a multiple of 4096, was taken as whole, its tail a line. 9ns cuts a FUSE write of up to 512 KiB into 65512-byte Twrites, the last one short, so a 600 KiB `Edit ,c/.../` arrived cut and its tail ran as an unknown control message; the 1 MiB refusal failed the same way. Each open now holds a partial line until its newline, or its release, which ends the last line; an Edit block is whole when it closes, as before. A name write with a NUL still fails its write at once. selfmount writes a 600 KiB Edit line and a 1.1 MiB line through a real 9ns mount; building.typ says how lines are cut. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'test')
-rw-r--r--test/fs.py15
-rw-r--r--test/selfmount.py13
2 files changed, 19 insertions, 9 deletions
diff --git a/test/fs.py b/test/fs.py
index 52ac61c8..0e1e44df 100644
--- a/test/fs.py
+++ b/test/fs.py
@@ -1034,20 +1034,17 @@ def test(binary, quic=False):
with Client(address, msize=256) as small:
assert set(small.list('/os' + str(listing))) == {
f'entry-{number:02}' for number in range(24)}
- # 64 KiB frames: a ctl line with no newline, whole in its one
- # Twrite, runs with it however long -- the cutoff for a write
- # that may go on is the frame the client asked for, less 24.
+ # 64 KiB frames: a ctl line with no newline is held whatever the
+ # size of its write -- a mount cuts lines anywhere -- and runs at
+ # the close, its failure then in the log.
with Client(address, msize=65536) as big:
assert big.msize == 65536
ctl = big.open('/pane/1/ctl', 1)
line = b'bogus' + b'x' * 20000
- try:
- big.rpc(118, struct.pack('<IQI', ctl, 0, len(line)) + line)
- except OSError:
- pass # refused with its write (a line over 1024 bytes), not held
- else:
- raise AssertionError('a whole 20000-byte line waited for a newline')
+ big.rpc(118, struct.pack('<IQI', ctl, 0, len(line)) + line)
+ assert b'ctl: unknown control message' not in client.read('/log')
big.close(ctl)
+ assert b'ctl: unknown control message' in client.read('/log')
frozen = client.open('/screen')
before = bytearray(client.read_fid(frozen, count=31))
diff --git a/test/selfmount.py b/test/selfmount.py
index 6b9d8740..ddfb77dc 100644
--- a/test/selfmount.py
+++ b/test/selfmount.py
@@ -169,6 +169,19 @@ def run(binary):
check(run(f'python3 -c "{maker}" > {mount}/pane/{scratch}/ctl\n'.encode()) == '0', 'a 50 KB Edit block written through the mount')
body = client.read(f'/pane/{scratch}/body').decode().splitlines()
check(body == ['line %05d of the block' % i for i in range(2500)], f'it ran once, whole ({len(body)} lines)')
+ # One 600 KiB line: 9ns sends it as 65512-byte Twrites, the last
+ # one short, and none is taken for a whole line by its size.
+ errs = client.read('/log').decode().count('\nerr ')
+ long_edit = "import sys; sys.stdout.write('Edit ,c/' + 'q' * 600000 + '/\\n')"
+ check(run(f'python3 -c "{long_edit}" > {mount}/pane/{scratch}/ctl\n'.encode()) == '0', 'a 600 KiB Edit line written through the mount')
+ check(client.read(f'/pane/{scratch}/body') == b'q' * 600000, 'it ran once, whole')
+ check(client.read('/log').decode().count('\nerr ') == errs, 'no piece of it was refused as a line of its own')
+ # Over 1 MiB: refused once, its tail dropped through its newline.
+ too_long = "import sys; sys.stdout.write('Msg ' + 'z' * 1150000 + '\\nMsg after-long\\n')"
+ run(f'python3 -c "{too_long}" > {mount}/exec\n'.encode())
+ log = client.read('/log').decode()
+ check(log.count('over 1 MiB') == 1 and 'unknown control message' not in log and 'after-long' in log,
+ 'a 1.1 MiB line is refused once, its tail never a line, the next line runs')
# Forty event reads held through the mount, a follower each, and
# the mount still answers the rest: 9ns keeps workers past what
# the editor holds (128), so `cat layout` is not queued behind