aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-hub/tests/test_settings_node_detect.py
blob: 96e3cc0a63c7adbea3c165a35469fe592d68158c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
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}