summaryrefslogtreecommitdiffstats
path: root/packages/meshbay-cli/tests/test_cli_actions.py
diff options
context:
space:
mode:
authorChristophe Besson <cbesson@gmail.com>2026-10-15 01:21:52 +0200
committerChristophe Besson <cbesson@gmail.com>2026-10-15 01:21:52 +0200
commitced66b96f898abccec2526650ab356eb6b82f066 (patch)
tree168eaa6b9b1b2fc9c9a1d932aa6573c0d01e974d /packages/meshbay-cli/tests/test_cli_actions.py
parent382fcc5f675f9942350013780335315757c245c5 (diff)
downloadmeshbay-ced66b96f898abccec2526650ab356eb6b82f066.tar.gz
feat(cli): search across groups
search dials every group through the pool and matches each index here, on the Search page's fields (name, folder, title, artist, album), every word required. A group left out of Search by its operator (search_listed in the sealed ack) is skipped before its index is asked for. A file several groups hold is one result, keyed by its content hash, printed from the reader's own node first, as a path get takes. A group that cannot be searched is named and the others go on; one waiting for this machine's approval names its code instead of holding everything up. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'packages/meshbay-cli/tests/test_cli_actions.py')
-rw-r--r--packages/meshbay-cli/tests/test_cli_actions.py53
1 files changed, 53 insertions, 0 deletions
diff --git a/packages/meshbay-cli/tests/test_cli_actions.py b/packages/meshbay-cli/tests/test_cli_actions.py
index e0b5518..e06fb9c 100644
--- a/packages/meshbay-cli/tests/test_cli_actions.py
+++ b/packages/meshbay-cli/tests/test_cli_actions.py
@@ -457,6 +457,59 @@ def test_rm_deletes_only_what_this_account_may_and_asks_first(node, monkeypatch,
assert not node.files
+def test_search_finds_across_groups_once_per_file(hub, monkeypatch, capsys):
+ from fake_node import FakeNode
+ from meshbay_cli.client.session import DeviceLinkPending
+ family, club, hidden = FakeNode(), FakeNode(), FakeNode()
+ hub.groups += [{**CLUB, "id": "g2"}, {**CLUB, "id": "g3", "name": "Album"},
+ {**CLUB, "id": "g4", "name": "Away"}, {**CLUB, "id": "g5", "name": "New"}]
+ nodes = {"g1": family, "g2": club, "g3": hidden}
+ hidden.ack["search_listed"] = False
+ club.ack["is_node_admin"] = True
+
+ async def open_group(account, group):
+ if group["id"] == "g4":
+ from meshbay_cli.errors import NODE, CliError
+ raise CliError(NODE, "No node serving it is online.")
+ if group["id"] == "g5":
+ raise DeviceLinkPending("ABCD-EFGH", 0)
+ return nodes[group["id"]].session()
+ monkeypatch.setattr(pool, "open_group", open_group)
+ _signed_in(hub, capsys)
+
+ family.add("share/Holidays 2024", "Beach.JPG", b"same bytes")
+ club.add("share/Holidays 2024", "Beach.JPG", b"same bytes") # the same file
+ track = family.add("share/music", "track.flac", b"other")
+ track.update(type="audio", artist="The Holiday Band")
+ family.add("share", "notes 100%.txt", b"n")
+ hidden.add("share", "holiday-secret.jpg", b"s")
+
+ assert main("search", "HOLIDAY") == 4 # two groups not searched
+ out = capsys.readouterr()
+ # The beach photo once, from the reader's own node first; the track by its tag.
+ assert out.out.splitlines() == [
+ "Club%2FPhotos@bob-test/share/Holidays 2024/Beach.JPG",
+ f"Family@{USERNAME}/share/music/track.flac"]
+ assert "holiday-secret" not in out.out
+ assert "not searched: Away@bob-test" in out.err
+ assert "ABCD-EFGH" in out.err
+
+ assert main("--json", "search", "beach", "2024") == 4
+ [hit] = json.loads(capsys.readouterr().out)
+ assert hit["also"] == [f"Family@{USERNAME}/share/Holidays 2024/Beach.JPG"]
+
+ assert main("search", "-l", "-t", "audio", "holiday") == 4
+ line = capsys.readouterr().out.strip()
+ assert line.startswith("audio") and line.endswith("track.flac")
+ assert main("search", "100%") == 4
+ assert capsys.readouterr().out.strip() == f"Family@{USERNAME}/share/notes 100%25.txt"
+ assert main("search", "nothing-like-this") == 4
+
+ hub.groups = [g for g in hub.groups if g["id"] in ("g1", "g2")]
+ assert main("search", "nothing-like-this") == 3
+ assert main("search", "beach") == 0
+
+
def test_every_action_is_run_here():
"""Runs last in this module: every action the parser knows was run above."""
assert RUN == set(cli.ACTIONS), f"never run: {set(cli.ACTIONS) - RUN}"