summaryrefslogtreecommitdiffstats
path: root/packages/meshbay-cli/tests/test_e2e_local.py
diff options
context:
space:
mode:
authorChristophe Besson <cbesson@gmail.com>2026-10-15 01:12:16 +0200
committerChristophe Besson <cbesson@gmail.com>2026-10-15 01:12:16 +0200
commit382fcc5f675f9942350013780335315757c245c5 (patch)
treea24ed8732c6d3971b071ed6af3c399d6142b79f4 /packages/meshbay-cli/tests/test_e2e_local.py
parent6f68bb6c1970e26de1f66c073ea5d7fecd21840d (diff)
downloadmeshbay-382fcc5f675f9942350013780335315757c245c5.tar.gz
feat(cli): rm, and Delete in the interactive mode
rm deletes files, resolved as get resolves paths and patterns, with the node's rule (design §5.4): the uploading account's devices, or the node's operator account. The whole run is checked against the index first (the entry's uploader_id, the role the join result gives this key): a file outside the rule, or a folder, refuses it before anything is asked or sent. Then one confirmation, or --yes. The node's challenge is checked against what was asked before it is signed. In the interactive mode, Delete on the right pane does the same, asked once per batch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'packages/meshbay-cli/tests/test_e2e_local.py')
-rw-r--r--packages/meshbay-cli/tests/test_e2e_local.py44
1 files changed, 42 insertions, 2 deletions
diff --git a/packages/meshbay-cli/tests/test_e2e_local.py b/packages/meshbay-cli/tests/test_e2e_local.py
index 9cac392..988fb38 100644
--- a/packages/meshbay-cli/tests/test_e2e_local.py
+++ b/packages/meshbay-cli/tests/test_e2e_local.py
@@ -529,12 +529,14 @@ def test_a_machine_with_no_identity_there_is_linked_as_a_device(world):
async def test_the_interactive_mode_against_the_real_node(world, monkeypatch, tmp_path):
- """The panes, opened on a real group, and F5 bringing a file back."""
+ """The panes, opened on a real group: F5 bringing a file back, F5 sending one,
+ and Delete taking that one away again."""
from meshbay_cli import __main__ as main_module
from meshbay_cli.commands.context import Context
from meshbay_cli.tui.app import MeshBayApp
- from meshbay_cli.tui.panes import RemotePane
+ from meshbay_cli.tui.panes import LocalPane, RemotePane
from meshbay_cli.tui.screens import MainScreen
+ from meshbay_cli.tui.widgets import Choice
# Browser access off, whichever test ran before: this machine must be linked.
await world["app"].withdraw_bundle()
@@ -585,6 +587,26 @@ async def test_the_interactive_mode_against_the_real_node(world, monkeypatch, tm
await until(pilot, lambda: (tmp_path / "notes.txt").exists()
and (tmp_path / "notes.txt").read_text() == "hello\n")
+ # Sent from the left, then deleted from the right: it was this
+ # account's upload, so the node lets it go, from its disk too.
+ (tmp_path / "tui-upload.txt").write_text("sent from the panes\n")
+ local = app.screen.query_one(LocalPane)
+ local.action_refresh()
+ await until(pilot, lambda: "tui-upload.txt" in names(local))
+ local.table.move_cursor(row=names(local).index("tui-upload.txt"))
+ local.table.focus()
+ await pilot.press("f5")
+ await until(pilot, lambda: "tui-upload.txt" in names(remote))
+ assert (world["share"] / "tui-upload.txt").exists()
+ remote.table.move_cursor(row=names(remote).index("tui-upload.txt"))
+ remote.table.focus()
+ await pilot.press("delete")
+ await until(pilot, lambda: isinstance(app.screen, Choice))
+ await pilot.click("#choice-delete")
+ await until(pilot, lambda: "tui-upload.txt" not in names(remote))
+ assert not (world["share"] / "tui-upload.txt").exists()
+ assert (world["share"] / "notes.txt").exists()
+
# ── The application's half of linking, in a real Chrome ──────────────────────
#
@@ -833,6 +855,24 @@ def test_a_member_joins_links_devices_shares_with_browsers_and_leaves(world):
assert r.returncode == 0, r.stderr
assert bob(world, "bob3", "ls", group).returncode == 5 # a stranger again
+ # rm: what bob uploaded, from another of his machines too; nothing of the
+ # owner's, whose share bob did not upload.
+ up = world["root"] / "bob-upload.txt"
+ up.write_text("from bob\n")
+ assert bob(world, "bob1", "put", str(up), f"{group}/share").returncode == 0
+ deadline = time.monotonic() + 30 # indexed once the node has written it
+ while "bob-upload.txt" not in bob(world, "bob1", "ls", f"{group}/share").stdout:
+ assert time.monotonic() < deadline, "the upload never reached the index"
+ time.sleep(1)
+ r = bob(world, "bob1", "rm", f"{group}/share/bob-upload.txt")
+ assert r.returncode == 1 and "--yes" in r.stderr # no terminal to ask on
+ r = bob(world, "bob1", "rm", "--yes", f"{group}/share/notes.txt")
+ assert r.returncode == 8 and "did not upload" in r.stderr, r.stderr
+ r = bob(world, "bob2", "rm", "--yes", f"{group}/share/bob-upload.txt")
+ assert r.returncode == 0, r.stderr
+ assert "bob-upload.txt" not in bob(world, "bob1", "ls", f"{group}/share").stdout
+ assert (world["share"] / "notes.txt").exists()
+
# Leaving: asked first, then the group is gone from the account.
assert bob(world, "bob1", "leave", group).returncode == 1
r = bob(world, "bob1", "leave", "--yes", group)