aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-hub/tests/test_indexing_dock.py
diff options
context:
space:
mode:
authorChristophe Besson <cbesson@gmail.com>2026-10-12 00:17:32 +0200
committerChristophe Besson <cbesson@gmail.com>2026-10-12 00:17:32 +0200
commit14911aae21ec4975f7a805b91e3c4867cb41974b (patch)
tree8c00230a88053905fd77938f3a9539efeb4c3094 /packages/meshbay-hub/tests/test_indexing_dock.py
parentf6f107e02c7a4aa7326c9a82310a239327d81ed6 (diff)
downloadmeshbay-14911aae21ec4975f7a805b91e3c4867cb41974b.tar.gz
feat: let the operator pause and resume a root's indexing (MNP 6.2)
A whole-root walk now checks its root before every file: removed or ejected, it stops instead of reading the drive to the end; paused, it finishes from the hash cache alone. A paused root is not watched, not swept by reconcile and survives a restart (roster), its indexed files stay served. Resume runs the reconcile sweep over the root, so entries and their enrichment are kept. Signed root_pause / root_resume over MNP, loopback routes, CLI `root pause|resume`, a pause button on the indexing dock and pause/resume in the roots table of Group settings. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'packages/meshbay-hub/tests/test_indexing_dock.py')
-rw-r--r--packages/meshbay-hub/tests/test_indexing_dock.py34
1 files changed, 33 insertions, 1 deletions
diff --git a/packages/meshbay-hub/tests/test_indexing_dock.py b/packages/meshbay-hub/tests/test_indexing_dock.py
index e960950..1619b57 100644
--- a/packages/meshbay-hub/tests/test_indexing_dock.py
+++ b/packages/meshbay-hub/tests/test_indexing_dock.py
@@ -51,15 +51,18 @@ def _job(**over) -> dict:
return job
-def _frames(tmp_path, frames: list[tuple[int, list[dict]]], hide_at: int | None = None):
+def _frames(tmp_path, frames: list[tuple[int, list[dict]]], hide_at: int | None = None,
+ pause_at: int | None = None):
"""Feed dockRows a sequence of (time ms, jobs) and return each frame's rows."""
return _run(tmp_path, f"""
const frames = {json.dumps(frames)};
const hideAt = {json.dumps(hide_at)};
+ const pauseAt = {json.dumps(pause_at)};
let memory = {{}};
const out = [];
for (const [now, jobs] of frames) {{
if (hideAt === now) memory = m.hideRow(memory, 'g1');
+ if (pauseAt === now) memory = m.pauseRow(memory, 'g1');
const r = m.dockRows(jobs, memory, now);
memory = r.memory;
out.push(r.rows.map((row) => [row.groupId, row.state]));
@@ -120,6 +123,24 @@ def test_a_hidden_row_stays_hidden_until_the_group_is_idle(tmp_path):
# ── Where it comes from ─────────────────────────────────────────────────────
@needs_node
+def test_a_paused_walk_leaves_at_once_and_is_not_called_finished(tmp_path):
+ """The node takes a moment to stop: its next reports still say scanning."""
+ idle = _job(scanning=False, kind="")
+ assert _frames(tmp_path, [
+ (0, [_job()]), (1000, [_job()]), (2000, [_job()]), (3000, [idle]),
+ ], pause_at=1000) == [[["g1", "running"]], [], [], []]
+
+
+@needs_node
+def test_pausing_one_root_does_not_hide_the_next_one_queued(tmp_path):
+ first = _job(root="results", queued=["archive"])
+ second = _job(root="archive")
+ assert _frames(tmp_path, [
+ (0, [first]), (1000, [first]), (2000, [second]),
+ ], pause_at=1000) == [[["g1", "running"]], [], [["g1", "running"]]]
+
+
+@needs_node
def test_the_loopback_answer_wins_and_the_hub_names_the_group(tmp_path):
out = _run(tmp_path, """
const local = { g1: m.fromLoopback({ group_id: 'g1', group_name: 'node name',
@@ -173,6 +194,17 @@ def test_only_an_operator_connection_feeds_the_dock():
"a member's connection must keep the sidebar dot only")
+def test_the_pause_button_reaches_the_node_by_either_door():
+ """The local node over loopback; any other through the page's connection,
+ signed by its operator — the dock holds no transport of its own."""
+ dock = DOCK.read_text(encoding="utf-8")
+ assert "node.op('pauseRoot'" in dock
+ page = GROUP_PAGE.read_text(encoding="utf-8")
+ assert "transport.pauseRoot(groupId, rootName, transport.signFn)" in page
+ for at in [m.start() for m in re.finditer(r"reportIndexPush\(groupId, (?!null)", page)]:
+ assert "pauseFromDock" in page[at:at + 140]
+
+
def test_leaving_a_group_clears_its_row():
page = GROUP_PAGE.read_text(encoding="utf-8")
cleanup = page[page.index(" return () => {\n cancelled = true;"):]