aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-hub/tests/test_settings_node_detect.py
diff options
context:
space:
mode:
authorChristophe Besson <cbesson@gmail.com>2026-10-07 21:19:11 +0200
committerChristophe Besson <cbesson@gmail.com>2026-10-07 21:19:11 +0200
commitd3bc50cca1c4dfe143c29a522b8cd57eb69ab92e (patch)
treeb953daa0406bdc6d38f991e5e95535e0c61c8bfc /packages/meshbay-hub/tests/test_settings_node_detect.py
parentade41b05cce4a555197116568664220c5b3be9fa (diff)
downloadmeshbay-d3bc50cca1c4dfe143c29a522b8cd57eb69ab92e.tar.gz
fix(hub): keep "add a directory" when one node check is missed
A node busy indexing could miss the single 3 s check after a root was added, and the button stayed hidden until a reload. Ask up to four times before deciding there is no node on this machine. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'packages/meshbay-hub/tests/test_settings_node_detect.py')
-rw-r--r--packages/meshbay-hub/tests/test_settings_node_detect.py87
1 files changed, 87 insertions, 0 deletions
diff --git a/packages/meshbay-hub/tests/test_settings_node_detect.py b/packages/meshbay-hub/tests/test_settings_node_detect.py
new file mode 100644
index 0000000..96e3cc0
--- /dev/null
+++ b/packages/meshbay-hub/tests/test_settings_node_detect.py
@@ -0,0 +1,87 @@
+"""
+The settings page asks the node on this machine again before deciding there is
+none.
+
+`readLocalNode` (group-settings.js) is lifted out and run under node against a
+stub of `platform.node`. One missed 3 s check used to set "no node here", which
+hides "Add a directory", until the page was reloaded: found by a tester adding a
+directory while the node was busy indexing the others.
+"""
+
+import json
+import shutil
+import subprocess
+from pathlib import Path
+
+import pytest
+
+STATIC = Path(__file__).resolve().parents[1] / "src" / "meshbay_hub" / "static"
+
+pytestmark = pytest.mark.skipif(shutil.which("node") is None, reason="node is not available")
+
+
+def _run(tmp_path, stub):
+ src = (STATIC / "group-settings.js").read_text(encoding="utf-8")
+ fn = src[src.index("async function readLocalNode"):]
+ fn = fn[:fn.index("\n}\n") + 2]
+ script = tmp_path / "detect.mjs"
+ script.write_text(fn + stub + """
+const out = { result: await readLocalNode(node, 'g1', 4, 1), detects: node.detects };
+console.log(JSON.stringify(out));
+""", encoding="utf-8")
+ proc = subprocess.run(["node", str(script)], capture_output=True, text=True,
+ encoding="utf-8")
+ assert proc.returncode == 0, proc.stderr
+ return json.loads(proc.stdout)
+
+
+def test_a_node_that_misses_a_check_is_asked_again(tmp_path):
+ out = _run(tmp_path, """
+const node = {
+ detects: 0,
+ async detect() {
+ this.detects++;
+ if (this.detects === 1) return { detected: false, configured: true };
+ return { detected: true, configured: true };
+ },
+ async op() {
+ if (this.detects === 2) throw new Error('mid-reload');
+ return { groups: [{ id: 'g1', name: 'G', roots: [{ name: 'a' }] }] };
+ },
+};
+""")
+ assert out["result"] == {"group": {"id": "g1", "name": "G", "roots": [{"name": "a"}]}}
+ assert out["detects"] == 3
+
+
+def test_a_machine_with_no_node_set_up_is_not_asked_again(tmp_path):
+ out = _run(tmp_path, """
+const node = {
+ detects: 0,
+ async detect() { this.detects++; return { detected: false, configured: false }; },
+ async op() { throw new Error('unreachable'); },
+};
+""")
+ assert out == {"result": None, "detects": 1}
+
+
+def test_a_node_that_never_answers_is_given_up_on(tmp_path):
+ out = _run(tmp_path, """
+const node = {
+ detects: 0,
+ async detect() { this.detects++; return { detected: false, configured: true }; },
+ async op() { throw new Error('unreachable'); },
+};
+""")
+ assert out == {"result": None, "detects": 4}
+
+
+def test_a_node_that_does_not_host_the_group_still_counts_as_a_node(tmp_path):
+ out = _run(tmp_path, """
+const node = {
+ detects: 0,
+ async detect() { this.detects++; return { detected: true, configured: true }; },
+ async op() { return { groups: [{ id: 'other' }] }; },
+};
+""")
+ assert out == {"result": {"group": None}, "detects": 1}