diff options
Diffstat (limited to 'test')
| -rw-r--r-- | test/fs.py | 90 | ||||
| -rw-r--r-- | test/selfmount.py | 10 | ||||
| -rw-r--r-- | test/snapshots/nested-optout.golden | 60 |
3 files changed, 145 insertions, 15 deletions
@@ -479,6 +479,22 @@ def run_file(binary): assert run(client, term, b'fi\n') == b'error not run\n' # a syntax error runs nothing assert run(client, term, b"echo 'open\n") == b'error not run\n' # nor does an open quote assert run(client, term, b'true\n') == b'exit 0\n' # ...and the shell is clear after + # A paging command run through pty/run does not wait in less: the + # terminal's PAGER is `pardes -`, and its text is a +Pager pane. + if shutil.which('git'): + repo = root / 'pagedrepo' + repo.mkdir() + git = ['git', '-C', str(repo), '-c', 'user.name=p', '-c', 'user.email=p@x'] + subprocess.run(git + ['init', '-q'], check=True, env=dict(os.environ, HOME=str(root))) + (repo / 'f').write_text('x\n') + subprocess.run(git + ['add', 'f'], check=True, env=dict(os.environ, HOME=str(root))) + subprocess.run(git + ['commit', '-qm', 'paged-commit-subject'], check=True, env=dict(os.environ, HOME=str(root))) + assert run(client, term, b'git -C pagedrepo log\n').startswith(b'exit 0\n') + pager = [r.split()[0].decode() for r in client.read('/index').splitlines() if r.split()[3:4] == [f'{repo}/+Pager'.encode()]] # git -C runs it in the repo + assert len(pager) == 1, client.read('/index') + assert b'paged-commit-subject' in client.read(f'/pane/{pager[0]}/body') + assert b'\x1b' not in client.read(f'/pane/{pager[0]}/body') + client.remove(f'/pane/{pager[0]}') # A pty is not given one row (it loses the prompt's input mark, # and the shell would read busy for ever): refused, and said. try: @@ -1306,6 +1322,32 @@ def test(binary, quic=False): # opened is deleted, as an $EDITOR must; one on a file already open # waits on that pane; a session that goes away ends it with 1. with session(binary, root, 'wait') as (client, address): + # A command run from a pane's tag gets acme's $winid, that pane; + # one from the workspace's tag, none. + def command_body(node, line): + client.write(node, line) + serial = int(client.read(node).split()[-1]) + deadline = time.monotonic() + 10 + while True: + log = client.read('/log').decode() + ran = log.rfind(f'\nrun {serial} ') + if ran >= 0 and f'\nexit {serial} ' in log[ran:]: + body = client.read(f'/pane/{serial}/body').decode().split('% echo winid')[-1] + client.remove(f'/pane/{serial}') + return body + assert time.monotonic() < deadline, log[-400:] + time.sleep(.05) + first_pane = min(int(row.split()[0]) for row in client.read('/index').splitlines()) + assert f'winid={first_pane}\n' in command_body(f'/pane/{first_pane}/tagexec', b'echo winid=$winid\n') + assert 'winid=\n' in command_body('/tagexec', b'echo winid=$winid\n') + # A second --detach of a name a live session holds: said, exit 1, + # no Zig error trace. + second_env = {k: v for k, v in os.environ.items() if not k.startswith('PARDES_')} + second_env.update(HOME=str(root), XDG_RUNTIME_DIR=str(root)) + second = subprocess.run([binary, '--detach=wait'], cwd=root, env=second_env, + stdout=subprocess.DEVNULL, stderr=subprocess.PIPE, timeout=20) + assert second.returncode == 1, second + assert second.stderr == b'pardes: a session named wait is already running\n', second.stderr status = dict(line.split(maxsplit=1) for line in client.read('/status').decode().splitlines()) env = {k: v for k, v in os.environ.items() if k != 'PARDES_FORWARD_LOOK'} env.update(PARDES_9P=str(address), PARDES_PANE='1', PARDES_PID=status['pid']) @@ -1395,6 +1437,30 @@ def test(binary, quic=False): # A pane address the session has not is refused in words, exit # 1, no pane made for a file of that name; one it has is looked # at. A name with a newline is said in words, not an error name. + # `pardes -` (a terminal's PAGER): stdin, its escapes stripped, in a + # +Pager pane of the session, clean, and back at once. + fed = subprocess.run([binary, '-'], cwd=root, env=env, input=b'\x1b[1mbold\x1b[0m text\n', + stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=10) + assert fed.returncode == 0, fed.stderr + made_now, = serials() - before + assert client.read(f'/pane/{made_now}/name') == f'{root}/+Pager\n'.encode() + assert client.read(f'/pane/{made_now}/body') == b'bold text\n' + row = [r for r in client.read('/index').splitlines() if r.split()[0] == str(made_now).encode()][0] + assert row.split()[2] == b'0', row # clean: nothing to ask at Exit + client.remove(f'/pane/{made_now}') + # A new name in a directory there but not writable: refused now, + # not a pane that only fails at Save. + shut = root / 'shut-dir' + shut.mkdir() + shut.chmod(0o500) + try: + refused = subprocess.run([binary, 'shut-dir/new.txt'], cwd=root, env=env, + stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=10) + assert refused.returncode == 1, refused + assert b'may not be read or written' in refused.stderr, refused.stderr + assert serials() == before, (serials(), before) + finally: + shut.chmod(0o755) for word, said in (('@p999:1', b'pardes: @p999:1: this session has no such pane'), ('two\nlines.txt', b'a file name is one line')): refused = subprocess.run([binary, word], cwd=root, env=env, @@ -1411,6 +1477,30 @@ def test(binary, quic=False): assert orphan.poll() is None assert orphan.wait(timeout=5) == 1 + # `pardes -` outside a session: an editor whose first pane is a + # +Pager of stdin, as `vim -`; here a detached one, to read it. + outside_env = {k: v for k, v in os.environ.items() if not k.startswith('PARDES_')} + outside_env.update(HOME=str(root), XDG_RUNTIME_DIR=str(root), PARDES_NOTIME='1') + boot = subprocess.Popen([binary, '--detach=stdinboot', '-'], cwd=root, env=outside_env, + stdin=subprocess.PIPE, stdout=subprocess.DEVNULL, stderr=subprocess.PIPE, + start_new_session=True) + try: + boot.stdin.write(b'\x1b[32mfrom stdin\x1b[m\nsecond\n') + boot.stdin.close() + sock = root / 'pardes-9p-stdinboot.sock' + deadline = time.monotonic() + 10 + while not sock.exists(): + assert boot.poll() is None, boot.stderr.read() + assert time.monotonic() < deadline, 'the stdin boot never listened' + time.sleep(.05) + with Client(str(sock)) as booted: + first = booted.read('/index').split(b'\n')[0].split() + assert first[3] == f'{root}/+Pager'.encode(), first + assert booted.read(f'/pane/{first[0].decode()}/body') == b'from stdin\nsecond\n' + finally: + boot.terminate() + boot.wait(timeout=10) + # Killed with SIGTERM or SIGHUP, a tty editor puts its terminal # back (main screen, cooked mode) before it dies: a nested one # killed in a pane leaves that pane usable. diff --git a/test/selfmount.py b/test/selfmount.py index 86c32fa8..dd59083c 100644 --- a/test/selfmount.py +++ b/test/selfmount.py @@ -176,6 +176,16 @@ def run(binary): held = run(f"for i in $(seq 40); do cat {mount}/pane/{first}/event > /dev/null & done; " f"sleep 1; timeout 10 cat {mount}/layout > /dev/null; st=$?; kill $(jobs -p); exit $st\n".encode()) check(held == '0', f'cat layout answers beside 40 held event reads ({held!r})') + # fs.md's follow recipe, as written, with plain cat, its output + # a pipe (where coreutils cat splices): it hears a record made + # after it started. + recipe = Path(f'/tmp/{name}.follow') + ran = run(f"exec 3<>{mount}/log; echo follow >&3; " + f"(sleep 1; echo 'Msg recipe-heard' > {mount}/exec) & " + f"timeout 5 cat <&3 | cat > {recipe}; exit 0\n".encode()) + followed = recipe.read_text() if recipe.exists() else '' + recipe.unlink(missing_ok=True) + check(ran == '0' and 'recipe-heard' in followed, f'the log follow recipe with cat hears a new record ({followed[-120:]!r})') client.write('/exec', b'Msg still here\n') text = ''.join(cell[0] for cell in client.screen()['cells']) check('still here' in text, 'the editor answers after all of that') diff --git a/test/snapshots/nested-optout.golden b/test/snapshots/nested-optout.golden index 1fa7cbe5..3539a16c 100644 --- a/test/snapshots/nested-optout.golden +++ b/test/snapshots/nested-optout.golden @@ -1,24 +1,54 @@ == snap optout-file grid=100x31 cursor=9,6 -|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Exit -|New Tty Find Grep Joincol -|$ /tmp/pardes-snap/nested-optout/cwd Save Tty Del Togglettymode Filter Collapse -| Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Exit -| New Tty Find Grep Joincol -| /tmp/pardes-snap/nested-optout/cwd/nested.txt Save Tty Del Collapse +|Newcol Joincol Find Grep Help Changelog Tutor Dump Themes Config Debug Exit +| New Tty Find Grep Joincol Delcol +|$ /tmp/pardes-snap/nested-optout/cwd Tty+bash Save Mode Filter Collapse Del +| Newcol Joincol Find Grep Help Changelog Tutor Dump Themes Config Debug Exit +| New Tty Find Grep Joincol Delcol +| /tmp/pardes-snap/nested-optout/cwd/nested.txt Save Tty Collapse Del | 1 optout-marker | 2 second-optout-line | 3 +| +| +| +| +| +| +| +| +| +| +| +| +| /tmp/pardes-snap/nested-optout/cwd/+New Save Tty Collapse Del +| 1 == snap inner-shell grid=100x31 cursor=6,6 -|Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Exit -|New Tty Find Grep Joincol -|$ /tmp/pardes-snap/nested-optout/cwd Save Tty Del Togglettymode Filter Collapse -| Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Exit -| New Tty Find Grep Joincol -| $ /tmp/pardes-snap/nested-optout/cwd/innerdir Save Tty Del Togglettymode Filter Collapse +|Newcol Joincol Find Grep Help Changelog Tutor Dump Themes Config Debug Exit +| New Tty Find Grep Joincol Delcol +|$ /tmp/pardes-snap/nested-optout/cwd Tty+bash Save Mode Filter Collapse Del +| Newcol Joincol Find Grep Help Changelog Tutor Dump Themes Config Debug Exit +| New Tty Find Grep Joincol Delcol +| $ /tmp/pardes-snap/nested-optout/cwd/innerdir Tty+bash Save Mode Filter Collapse Del | $ +| +| +| +| +| +| +| +| +| +| /tmp/pardes-snap/nested-optout/cwd/innerdir/+New Save Tty Collapse Del +| 1 +| +| +| +| /tmp/pardes-snap/nested-optout/cwd/+New Save Tty Collapse Del +| 1 == snap inner-launch grid=100x31 cursor=11,9 -|6: Newcol Joincol Find Grep Help Changelog Tutor Dump NextColor Debug Exit -|7: New Tty Find Grep Joincol -|8: /tmp/pardes-snap/nested-optout/cwd/innerdir/deeper.txt Save Tty Del Collapse +|6: Newcol Joincol Find Grep Help Changelog Tutor Dump Themes Config Debug Exit +|7: New Tty Find Grep Joincol Delcol +|8: /tmp/pardes-snap/nested-optout/cwd/innerdir/deeper.txt Save Tty Collapse Del |9: 1 deepest-marker |10: 2 |
