From f1ed3e6be452f6211cee8db1afef8b56473a04db Mon Sep 17 00:00:00 2001 From: Christophe Besson Date: Fri, 25 Sep 2026 10:23:05 +0200 Subject: test(hub): read the search code wherever it is split The Node harnesses take one file or several, and the tests that lift connectToGroup and the pool out of search-page.js as text take them from spa_source, which also reads connection-pool.js once it exists. Co-Authored-By: Claude Opus 5.5 --- .../tests/harness/search_connect_harness.mjs | 5 +++- .../tests/harness/search_fanout_harness.mjs | 5 +++- .../tests/harness/search_pool_harness.mjs | 5 +++- packages/meshbay-hub/tests/spa_source.py | 28 ++++++++++++++++++++++ .../tests/test_search_connect_deadline.py | 5 ++-- packages/meshbay-hub/tests/test_search_fanout.py | 3 ++- packages/meshbay-hub/tests/test_search_pool.py | 3 ++- .../meshbay-hub/tests/test_transport_contracts.py | 5 ++-- 8 files changed, 50 insertions(+), 9 deletions(-) create mode 100644 packages/meshbay-hub/tests/spa_source.py (limited to 'packages/meshbay-hub/tests') diff --git a/packages/meshbay-hub/tests/harness/search_connect_harness.mjs b/packages/meshbay-hub/tests/harness/search_connect_harness.mjs index 2479d46..60cea2b 100644 --- a/packages/meshbay-hub/tests/harness/search_connect_harness.mjs +++ b/packages/meshbay-hub/tests/harness/search_connect_harness.mjs @@ -12,8 +12,11 @@ // // Usage: node search_connect_harness.mjs import { readFileSync } from 'fs'; +import { delimiter } from 'path'; -const src = readFileSync(process.argv[2], 'utf8'); +// One file or several (search-page.js and what it was split into), joined +// with the platform's path delimiter. +const src = process.argv[2].split(delimiter).map((p) => readFileSync(p, 'utf8')).join('\n'); const cfg = JSON.parse(process.argv[3] || '{}'); const { diff --git a/packages/meshbay-hub/tests/harness/search_fanout_harness.mjs b/packages/meshbay-hub/tests/harness/search_fanout_harness.mjs index 5f95ede..f84d90b 100644 --- a/packages/meshbay-hub/tests/harness/search_fanout_harness.mjs +++ b/packages/meshbay-hub/tests/harness/search_fanout_harness.mjs @@ -11,8 +11,11 @@ // // Usage: node search_fanout_harness.mjs import { readFileSync } from 'fs'; +import { delimiter } from 'path'; -const src = readFileSync(process.argv[2], 'utf8'); +// One file or several (search-page.js and what it was split into), joined +// with the platform's path delimiter. +const src = process.argv[2].split(delimiter).map((p) => readFileSync(p, 'utf8')).join('\n'); const cfg = JSON.parse(process.argv[3] || '{}'); const { diff --git a/packages/meshbay-hub/tests/harness/search_pool_harness.mjs b/packages/meshbay-hub/tests/harness/search_pool_harness.mjs index 521a97e..ef18241 100644 --- a/packages/meshbay-hub/tests/harness/search_pool_harness.mjs +++ b/packages/meshbay-hub/tests/harness/search_pool_harness.mjs @@ -10,8 +10,11 @@ // // Usage: node search_pool_harness.mjs import { readFileSync } from 'fs'; +import { delimiter } from 'path'; -const src = readFileSync(process.argv[2], 'utf8'); +// One file or several (search-page.js and what it was split into), joined +// with the platform's path delimiter. +const src = process.argv[2].split(delimiter).map((p) => readFileSync(p, 'utf8')).join('\n'); const cfg = JSON.parse(process.argv[3] || '{}'); const { diff --git a/packages/meshbay-hub/tests/spa_source.py b/packages/meshbay-hub/tests/spa_source.py new file mode 100644 index 0000000..7df98ca --- /dev/null +++ b/packages/meshbay-hub/tests/spa_source.py @@ -0,0 +1,28 @@ +""" +The web client's source, for the hub tests that read it as text. + +A test that lifts a function out of a file by name stops finding it the day +the function moves to another file — or, for an absence, goes on passing +without looking at it. So the tests that read the search code take it from +here, the page and whatever it has been split into. +""" + +from pathlib import Path + +STATIC = Path(__file__).resolve().parents[1] / "src" / "meshbay_hub" / "static" + + +def search_files() -> list[Path]: + """The search page, and the connection pool once it is a module of its own.""" + return [p for p in (STATIC / "search-page.js", STATIC / "connection-pool.js") + if p.exists()] + + +def search_source() -> str: + return "\n".join(p.read_text(encoding="utf-8") for p in search_files()) + + +def search_argv() -> str: + """The same files, as the one argument the Node harnesses take.""" + import os + return os.pathsep.join(str(p) for p in search_files()) diff --git a/packages/meshbay-hub/tests/test_search_connect_deadline.py b/packages/meshbay-hub/tests/test_search_connect_deadline.py index d41cbb5..2d3db06 100644 --- a/packages/meshbay-hub/tests/test_search_connect_deadline.py +++ b/packages/meshbay-hub/tests/test_search_connect_deadline.py @@ -32,6 +32,7 @@ import subprocess from pathlib import Path import pytest +from spa_source import search_argv, search_source STATIC = Path(__file__).resolve().parents[1] / "src" / "meshbay_hub" / "static" SEARCH_PAGE = STATIC / "search-page.js" @@ -47,7 +48,7 @@ CAP_MS = 30000 def _attempt(**cfg) -> dict: proc = subprocess.run( - ["node", str(HARNESS), str(SEARCH_PAGE), json.dumps(cfg)], + ["node", str(HARNESS), search_argv(), json.dumps(cfg)], capture_output=True, text=True) assert proc.returncode == 0, proc.stderr return json.loads(proc.stdout) @@ -59,7 +60,7 @@ def test_the_constants_are_what_these_scenarios_assume(): a change to either without a change here would leave the scenarios asserting about a deadline the code no longer has. """ - code = SEARCH_PAGE.read_text(encoding="utf-8") + code = search_source() assert f"const SEARCH_STALL_MS = {STALL_MS};" in code assert f"const SEARCH_MAX_MS = {CAP_MS};" in code diff --git a/packages/meshbay-hub/tests/test_search_fanout.py b/packages/meshbay-hub/tests/test_search_fanout.py index 196aa5a..fca879a 100644 --- a/packages/meshbay-hub/tests/test_search_fanout.py +++ b/packages/meshbay-hub/tests/test_search_fanout.py @@ -50,6 +50,7 @@ import subprocess from pathlib import Path import pytest +from spa_source import search_argv STATIC = Path(__file__).resolve().parents[1] / "src" / "meshbay_hub" / "static" SEARCH_PAGE = STATIC / "search-page.js" @@ -65,7 +66,7 @@ DEAD_MS = 10000 # a node that does not, to the connection deadline def _sweep(**cfg) -> dict: proc = subprocess.run( - ["node", str(HARNESS), str(SEARCH_PAGE), json.dumps(cfg)], + ["node", str(HARNESS), search_argv(), json.dumps(cfg)], capture_output=True, text=True) assert proc.returncode == 0, proc.stderr return json.loads(proc.stdout) diff --git a/packages/meshbay-hub/tests/test_search_pool.py b/packages/meshbay-hub/tests/test_search_pool.py index 67e66fa..cf9eeb8 100644 --- a/packages/meshbay-hub/tests/test_search_pool.py +++ b/packages/meshbay-hub/tests/test_search_pool.py @@ -22,6 +22,7 @@ import subprocess from pathlib import Path import pytest +from spa_source import search_argv STATIC = Path(__file__).resolve().parents[1] / "src" / "meshbay_hub" / "static" SEARCH_PAGE = STATIC / "search-page.js" @@ -34,7 +35,7 @@ pytestmark = pytest.mark.skipif( def _run(**cfg) -> dict: proc = subprocess.run( - ["node", str(HARNESS), str(SEARCH_PAGE), json.dumps(cfg)], + ["node", str(HARNESS), search_argv(), json.dumps(cfg)], capture_output=True, text=True) assert proc.returncode == 0, proc.stderr return json.loads(proc.stdout) diff --git a/packages/meshbay-hub/tests/test_transport_contracts.py b/packages/meshbay-hub/tests/test_transport_contracts.py index 28d6a10..76e8123 100644 --- a/packages/meshbay-hub/tests/test_transport_contracts.py +++ b/packages/meshbay-hub/tests/test_transport_contracts.py @@ -19,6 +19,7 @@ import re from pathlib import Path import pytest +from spa_source import search_source STATIC = Path(__file__).resolve().parents[1] / "src" / "meshbay_hub" / "static" TRANSPORT = STATIC / "transport.js" @@ -521,7 +522,7 @@ SEARCH_PAGE = STATIC / "search-page.js" def test_search_tries_every_node_the_hub_offers(): - code = _code_only(SEARCH_PAGE.read_text(encoding="utf-8")) + code = _code_only(search_source()) assert "nodes[0]" not in code, "Search takes the head of the node list again" walk = code[code.index("for (const n of nodesData.nodes)"):] walk = walk[:walk.index("throw (lastErr")] @@ -534,7 +535,7 @@ def test_search_connects_in_one_place(): """Two call sites with their own connect is how one of them kept `nodes[0]`, and how the sweep and the warm-up each negotiated the same group: every connection goes through the pool, and only the pool calls `connectToGroup`.""" - code = _code_only(SEARCH_PAGE.read_text(encoding="utf-8")) + code = _code_only(search_source()) assert code.count("transport.connect(") == 1 # The definition, and the pool's one call. assert code.count("connectToGroup(") == 2 -- cgit v1.2.3