summaryrefslogtreecommitdiff
path: root/test/fs.py
diff options
context:
space:
mode:
Diffstat (limited to 'test/fs.py')
-rw-r--r--test/fs.py91
1 files changed, 89 insertions, 2 deletions
diff --git a/test/fs.py b/test/fs.py
index 3c0ece79..36ba180d 100644
--- a/test/fs.py
+++ b/test/fs.py
@@ -622,11 +622,11 @@ def workflow_canary(binary):
rows = client.read(f'/pane/{grep}/body').decode()
assert 'a.txt:2' in rows and 'b.txt:2' in rows, rows
client.remove(f'/pane/{grep}')
- execute_refused(client, a, 'Grep zzqqnomatch', 'grep: pattern not found')
+ execute_refused(client, a, 'Grep zzqqnomatch', 'Grep: pattern not found')
found = made_by(a, b'Find b.txt\n')
assert 'b.txt' in client.read(f'/pane/{found}/body').decode()
client.remove(f'/pane/{found}')
- execute_refused(client, a, 'Find zzqqnomatch', 'find: name not found')
+ execute_refused(client, a, 'Find zzqqnomatch', 'Find: name not found')
# A plain word looked at is found in the pane, after its dot.
client.write(f'/pane/{a}/dot', b' 0 0 ')
@@ -953,6 +953,20 @@ 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.
+ 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.close(ctl)
frozen = client.open('/screen')
before = bytearray(client.read_fid(frozen, count=31))
@@ -1224,6 +1238,79 @@ def test(binary, quic=False):
cell[0] for cell in local.screen()['cells'])
assert client.read('/index') == before
+ # --wait (acme's E): a launch inside a pane lasts until the pane it
+ # 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):
+ 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'])
+ edited = root / 'wait edit.txt'
+ edited.write_bytes(b'edit me\n')
+
+ def serials():
+ return {int(row.split()[0]) for row in client.read('/index').splitlines()}
+
+ def launch(flag):
+ before = serials()
+ child = subprocess.Popen([binary, flag, str(edited)], cwd=root, env=env,
+ stdout=subprocess.DEVNULL, stderr=subprocess.PIPE)
+ deadline = time.monotonic() + 3
+ while child.poll() is None and not serials() - before and time.monotonic() < deadline:
+ time.sleep(.01)
+ return child
+
+ first = launch('--wait')
+ opened, = serials() - {1}
+ second = launch('-w')
+ time.sleep(.5)
+ assert first.poll() is None and second.poll() is None, (first.stderr.read(), second.stderr.read())
+ assert serials() == {1, opened}
+ client.write(f'/pane/{opened}/body', b'edited\n', truncate=True)
+ execute(client, opened, 'Save')
+ client.remove(f'/pane/{opened}')
+ deleted = time.monotonic()
+ assert first.wait(timeout=5) == 0
+ # Woken by the `del` record, not a poll.
+ assert time.monotonic() - deleted < .05, time.monotonic() - deleted
+ assert second.wait(timeout=5) == 0
+ assert edited.read_bytes() == b'edited\n'
+ # A name not there yet opens a pane named it, as acme's B does,
+ # and Save creates it: git's and fish's temporary files are.
+ fresh = root / 'wait new.txt'
+ before = serials()
+ made = subprocess.Popen([binary, '--wait', fresh.name], cwd=root, env=env,
+ stdout=subprocess.DEVNULL, stderr=subprocess.PIPE)
+ deadline = time.monotonic() + 3
+ while not serials() - before:
+ assert made.poll() is None, made.stderr.read()
+ assert time.monotonic() < deadline, 'a new name opened no pane'
+ time.sleep(.01)
+ named, = serials() - before
+ assert str(fresh).encode() in client.read('/index')
+ client.write(f'/pane/{named}/body', b'new\n')
+ execute(client, named, 'Save')
+ client.remove(f'/pane/{named}')
+ assert made.wait(timeout=5) == 0
+ assert fresh.read_bytes() == b'new\n'
+ orphan = launch('--wait')
+ assert orphan.poll() is None
+ assert orphan.wait(timeout=5) == 1
+
+ # A launch with no terminal to draw on (a pty that is no one's
+ # controlling terminal) says so and exits 1, no error trace.
+ master, slave = os.openpty()
+ try:
+ env = {k: v for k, v in os.environ.items() if not k.startswith('PARDES_')}
+ env.update(HOME=str(root), XDG_RUNTIME_DIR=str(root), TERM='xterm-256color')
+ result = subprocess.run([binary, '--tty', 'x.txt'], cwd=root, env=env, stdin=slave, stdout=slave,
+ stderr=subprocess.PIPE, start_new_session=True, timeout=10)
+ finally:
+ os.close(master)
+ os.close(slave)
+ assert result.returncode == 1, result
+ assert b'pardes: no terminal to draw on' in result.stderr and b'.zig:' not in result.stderr, result.stderr
+
for tty in [False, True]:
name = 'lsp-tty' if tty else 'lsp-detached'
with session(binary, root, name, tty=tty) as (client, _):