aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-node/tests/test_cli_dispatch.py
diff options
context:
space:
mode:
Diffstat (limited to 'packages/meshbay-node/tests/test_cli_dispatch.py')
-rw-r--r--packages/meshbay-node/tests/test_cli_dispatch.py66
1 files changed, 66 insertions, 0 deletions
diff --git a/packages/meshbay-node/tests/test_cli_dispatch.py b/packages/meshbay-node/tests/test_cli_dispatch.py
index f58c020..cf91564 100644
--- a/packages/meshbay-node/tests/test_cli_dispatch.py
+++ b/packages/meshbay-node/tests/test_cli_dispatch.py
@@ -26,6 +26,15 @@ VERBS = [
["status"],
["group", "list"],
["group", "add"], # missing --dir: usage, then exit
+ ["group", "add", "g", "--dir", "/tmp/media", "--no-writable"],
+ ["root", "list"],
+ ["root", "add"], # missing path: usage, then exit
+ ["root", "add", "/tmp/media", "--writable", "--removable"],
+ ["root", "remove", "media", "--yes"],
+ ["root", "set", "media", "--no-writable"],
+ ["root", "set", "media"], # nothing to change: usage, then exit
+ ["root", "eject", "media"],
+ ["root", "plug", "media"],
["gek", "init"],
["gek", "rotate", "--yes"],
["gek-init"],
@@ -33,6 +42,9 @@ VERBS = [
["member", "invite", "bob"],
["member", "revoke", "bob"],
["member", "unpin", "bob"],
+ # Removed, and it has to say so rather than offering a username for a verb
+ # that no longer takes one.
+ ["member", "upload"],
["operator", "pair"],
["file", "list"],
["file", "rm", "abc", "--yes"],
@@ -224,3 +236,57 @@ def test_a_bare_invocation_with_no_config_yet_exits_cleanly(monkeypatch, tmp_pat
assert "meshbay-node init" in capsys.readouterr().out
assert not missing_config.parent.exists(), (
"a fresh, unprovisioned start must not create anything on disk")
+
+
+def test_a_removed_verb_says_what_replaced_it():
+ """
+ `member upload` used to set a group-wide switch that no longer exists. It
+ reached the usage line for the *other* member verbs — "usage: meshbay-node
+ member upload <username>" — which advertises a removed feature and sends
+ the operator looking for a username it would then reject.
+
+ Naming it costs three lines and is the difference between an operator
+ finding `root set --writable` and concluding the CLI is broken.
+ """
+ import inspect
+ source = inspect.getsource(daemon_mod.main)
+ start = source.index('if args.command == "member":')
+ block = source[start:source.index('if args.command == "group":', start)]
+
+ assert 'sub == "upload"' in block, (
+ "`member upload` falls through to the generic usage line")
+ guidance = block[block.index('sub == "upload"'):]
+ guidance = guidance[:guidance.index("sys.exit")]
+ assert "root set" in guidance and "--writable" in guidance, (
+ "the message does not name what replaced it")
+
+
+def test_there_is_no_way_to_create_a_group_in_the_old_shape():
+ """
+ `--upload-dir` is gone, and documenting it as deprecated was the wrong
+ answer — which is what it got at first.
+
+ It wrote `upload_dir` into a brand-new `[[groups]]` block, and
+ `GroupConfig.__post_init__` reads that by forcing *every other root
+ read-only* and appending that path as the one writable one. So
+ `group add --dir X --writable --upload-dir Y` silently made X read-only:
+ two mechanisms deciding which directories accept uploads, one of them
+ invisible, in a group created after the model that replaced it.
+
+ Reading it stays — an existing node.toml must keep working, and that is the
+ only legitimate use. Writing it does not.
+ """
+ import inspect
+ source = inspect.getsource(daemon_mod.main)
+ assert "--upload-dir" not in source, (
+ "the CLI can still create a group in the pre-RO/RW shape")
+
+ from meshbay_node import ops
+ params = inspect.signature(ops.attach_group).parameters
+ assert "upload_dir" not in params, (
+ "attach_group still writes the legacy key")
+
+ # The read path is deliberately untouched.
+ from meshbay_node.config import GroupConfig
+ assert "upload_dir" in inspect.getsource(GroupConfig), (
+ "an existing node.toml using upload_dir would stop working")