summaryrefslogtreecommitdiff
path: root/test/selfmount.py
diff options
context:
space:
mode:
Diffstat (limited to 'test/selfmount.py')
-rw-r--r--test/selfmount.py39
1 files changed, 35 insertions, 4 deletions
diff --git a/test/selfmount.py b/test/selfmount.py
index 6534aa25..86c32fa8 100644
--- a/test/selfmount.py
+++ b/test/selfmount.py
@@ -20,6 +20,7 @@ import signal
import struct
import sys
import termios
+import threading
import time
sys.path.insert(0, str(Path(__file__).resolve().parent))
@@ -127,12 +128,42 @@ def run(binary):
return exits[-1].split()[2]
time.sleep(.1)
return 'timeout'
+ # Followed from before the burst: a fresh open of the log reads
+ # only what its 64 KiB ring still holds, which a burst this size
+ # outgrows, and a follower the ring outruns reads `lost N`, so
+ # every line is either heard once, in order, or a loss is said.
+ heard = []
+
+ def follow():
+ with Client(sock) as follower:
+ fid = follower.open('/log', 2)
+ start = len(follower.read_fid(fid))
+ follower.rpc(118, struct.pack('<IQI', fid, 0, len(b'follow new\n')) + b'follow new\n')
+ ready.set()
+ deadline = time.monotonic() + 60
+ while time.monotonic() < deadline:
+ record = follower.read_fid(fid, start).decode()
+ heard.append(record)
+ if 'mnt-0999' in record:
+ return
+ ready = threading.Event()
+ reader = threading.Thread(target=follow, daemon=True)
+ reader.start()
+ check(ready.wait(10), 'a follower of the log is waiting')
got = run(f"seq -f 'Msg mnt-%04g' 0 999 > {mount}/exec\n".encode())
check(got == '0', f'a 1000-line burst written through the mount ({got!r})')
- log = client.read('/log').decode()
- said = [line.split(' ', 2)[2] for line in log.splitlines() if line.startswith('msg ') and 'mnt-' in line]
- check(said == ['mnt-%04d' % i for i in range(1000)], f'each line of it ran once, whole ({len(said)} said)')
- check('exit 127' not in log, 'no piece of a line ran as a command')
+ reader.join(60)
+ for r in heard:
+ if r.startswith(('err ', 'exit ')):
+ print(' heard: ' + r.rstrip())
+ said = [r.rstrip('\n').split(' ', 2)[2] for r in heard if r.startswith('msg ') and 'mnt-' in r]
+ lost = [r for r in heard if r.startswith('lost ')]
+ numbers = [int(s[4:]) for s in said]
+ check(numbers == list(range(numbers[0] if numbers else 0, 1000)),
+ f'each line it heard ran once, whole, in order, through the last ({len(said)} heard)')
+ check(len(said) == 1000 or (lost and heard.index(lost[0]) < heard.index(next(r for r in heard if 'mnt-' in r))),
+ f'no line was lost unsaid ({len(said)} heard, {lost!r})')
+ check(not any('exit 127' in r for r in heard), 'no piece of a line ran as a command')
scratch = int(client.read('/pane/new'))
maker = "import sys; sys.stdout.write('Edit ,a\\n' + ''.join('line %05d of the block\\n' % i for i in range(2500)) + '.\\n')"
check(run(f'python3 -c "{maker}" > {mount}/pane/{scratch}/ctl\n'.encode()) == '0', 'a 50 KB Edit block written through the mount')