diff options
Diffstat (limited to 'packages/meshbay-node/tests')
| -rw-r--r-- | packages/meshbay-node/tests/conftest.py | 23 | ||||
| -rw-r--r-- | packages/meshbay-node/tests/test_cli_dispatch.py | 21 | ||||
| -rw-r--r-- | packages/meshbay-node/tests/test_cli_golden.py | 8 | ||||
| -rw-r--r-- | packages/meshbay-node/tests/test_root_paths_are_operator_only.py | 10 | ||||
| -rw-r--r-- | packages/meshbay-node/tests/test_roster_pairing.py | 4 |
5 files changed, 55 insertions, 11 deletions
diff --git a/packages/meshbay-node/tests/conftest.py b/packages/meshbay-node/tests/conftest.py index 2ca0c8a..9ef23a3 100644 --- a/packages/meshbay-node/tests/conftest.py +++ b/packages/meshbay-node/tests/conftest.py @@ -92,3 +92,26 @@ def opened_ack(session, msg: dict) -> dict: ctx = session._group_ctx() return file_upload_ack_payload(ctx["gek"], session._group_id or "", msg) + + +def patch_cli(monkeypatch, name: str, value) -> None: + """Replace `name` wherever `meshbay-node`'s command line reads it. + + Each module of `meshbay_node.cli` imports what it uses by name, so a helper + like `_daemon_api` is bound once in every module that calls it, and patching + the one that defines it leaves the verbs calling the real thing — which + talks to whatever node is running on this machine. `daemon` is included: + its `main()` still reads the config path when no verb is given. + """ + import importlib + import pkgutil + + import meshbay_node.cli as cli + from meshbay_node import daemon + + modules = [daemon] + [importlib.import_module(f"meshbay_node.cli.{m.name}") + for m in pkgutil.iter_modules(cli.__path__)] + holders = [m for m in modules if hasattr(m, name)] + assert holders, f"no module of the CLI has {name!r} to patch" + for module in holders: + monkeypatch.setattr(module, name, value) diff --git a/packages/meshbay-node/tests/test_cli_dispatch.py b/packages/meshbay-node/tests/test_cli_dispatch.py index 26ffb05..5b16fbe 100644 --- a/packages/meshbay-node/tests/test_cli_dispatch.py +++ b/packages/meshbay-node/tests/test_cli_dispatch.py @@ -20,6 +20,8 @@ import pytest from meshbay_node import daemon as daemon_mod from node_source import cli_source +from conftest import patch_cli + # Each verb, with the arguments that reach its branch. `--yes` where the command # would otherwise stop for a confirmation nobody can type in a test. VERBS = [ @@ -107,12 +109,12 @@ def stub_daemon(monkeypatch, tmp_path): "encrypted_messages": 0, "max_age_days": 30, } - monkeypatch.setattr(daemon_mod, "_daemon_api", fake_api) - monkeypatch.setattr(daemon_mod, "_resolve_group", lambda cfg, g: "g" * 32) + patch_cli(monkeypatch, "_daemon_api", fake_api) + patch_cli(monkeypatch, "_resolve_group", lambda cfg, g: "g" * 32) conf = tmp_path / "node.toml" conf.write_text('[hub]\nurl = "https://example.invalid"\n') - monkeypatch.setattr(daemon_mod, "DEFAULT_CONFIG_PATH", conf) + patch_cli(monkeypatch, "DEFAULT_CONFIG_PATH", conf) # And a home of its own: the data directory (where `member invite` and # `operator pair` write their code, where `status` finds the run token of # a live node) and the keystore's default path are both derived from it. @@ -192,6 +194,19 @@ def test_the_verb_list_here_matches_the_parser(monkeypatch, capsys): assert "ui" not in declared, "the `ui` verb came back" +def test_every_verb_the_parser_accepts_runs_something(): + """ + A verb the parser accepts and the dispatch table does not name would not + fail: `run()` would report nothing to run, and `main()` would go on and + start the daemon. + """ + from meshbay_node.cli.dispatch import VERBS + from meshbay_node.cli.parser import build_parser + + command = next(a for a in build_parser()._actions if a.dest == "command") + assert set(command.choices) == set(VERBS) + + @pytest.mark.skipif(sys.platform == "win32", reason="systemd lifecycle; Windows uses the loopback API / " "Startup-folder launcher, covered by test_platform.py") diff --git a/packages/meshbay-node/tests/test_cli_golden.py b/packages/meshbay-node/tests/test_cli_golden.py index ddaa82f..3d7b0c0 100644 --- a/packages/meshbay-node/tests/test_cli_golden.py +++ b/packages/meshbay-node/tests/test_cli_golden.py @@ -27,6 +27,8 @@ from meshbay_node import config as config_mod from meshbay_node import daemon as daemon_mod from test_cli_dispatch import VERBS +from conftest import patch_cli + GOLDEN = Path(__file__).parent / "golden" / "cli.json" # The verbs that ask first, asked and answered "no": test_cli_dispatch.py # passes --yes to all of them. @@ -78,9 +80,9 @@ def _run(argv: list[str], tmp_path: Path, capsys) -> dict: conf.write_text('[hub]\nurl = "https://example.invalid"\n') code = 0 with pytest.MonkeyPatch.context() as mp: - mp.setattr(daemon_mod, "_daemon_api", fake_api) - mp.setattr(daemon_mod, "_resolve_group", lambda cfg, g: "g" * 32) - mp.setattr(daemon_mod, "DEFAULT_CONFIG_PATH", conf) + patch_cli(mp, "_daemon_api", fake_api) + patch_cli(mp, "_resolve_group", lambda cfg, g: "g" * 32) + patch_cli(mp, "DEFAULT_CONFIG_PATH", conf) # The data directory and the keystore's default path come from these; # left real, `status` would record the developer's own node. mp.setenv("HOME", str(tmp_path / "home")) diff --git a/packages/meshbay-node/tests/test_root_paths_are_operator_only.py b/packages/meshbay-node/tests/test_root_paths_are_operator_only.py index a18e9fa..e00f1cf 100644 --- a/packages/meshbay-node/tests/test_root_paths_are_operator_only.py +++ b/packages/meshbay-node/tests/test_root_paths_are_operator_only.py @@ -26,6 +26,8 @@ from meshbay_node import daemon as daemon_mod from meshbay_node import ops from meshbay_node.roots import RootSet +from conftest import patch_cli + def _roots(tmp_path: Path) -> RootSet: for name in ("Films", "Albums"): @@ -116,12 +118,14 @@ def test_the_cli_only_reads_fields_the_payload_carries(monkeypatch, tmp_path, ca return super().get(key, default) gid = "g" * 32 - monkeypatch.setattr(daemon_mod, "_daemon_api", lambda cfg, path, **kw: { + patch_cli(monkeypatch, "_daemon_api", lambda cfg, path, **kw: { "groups": [{"id": gid, "roots": [_Recording(offered)]}]}) - monkeypatch.setattr(daemon_mod, "_resolve_group", lambda cfg, g: gid) + patch_cli(monkeypatch, "_resolve_group", lambda cfg, g: gid) conf = tmp_path / "node.toml" conf.write_text('[hub]\nurl = "https://example.invalid"\n') - monkeypatch.setattr(daemon_mod, "DEFAULT_CONFIG_PATH", conf) + patch_cli(monkeypatch, "DEFAULT_CONFIG_PATH", conf) + # A stub missed would otherwise reach the node running on this machine. + monkeypatch.setenv("HOME", str(tmp_path / "home")) monkeypatch.setattr(sys, "argv", ["meshbay-node", "root", "list"]) daemon_mod.main() diff --git a/packages/meshbay-node/tests/test_roster_pairing.py b/packages/meshbay-node/tests/test_roster_pairing.py index ba16317..a2d0f8b 100644 --- a/packages/meshbay-node/tests/test_roster_pairing.py +++ b/packages/meshbay-node/tests/test_roster_pairing.py @@ -25,7 +25,7 @@ from meshbay_node.roster import Roster, hash_code, normalize_code from meshbay_node.transport.webrtc_server import WebRTCPeerSession from node_source import daemon_source, session_method, webrtc_source -from conftest import one_root +from conftest import one_root, patch_cli # ── Fixtures ────────────────────────────────────────────────────────────────── @@ -823,7 +823,7 @@ def _run_cli(monkeypatch, tmp_path, argv, responses): return value return {} - monkeypatch.setattr(_daemon, "_daemon_api", fake_api) + patch_cli(monkeypatch, "_daemon_api", fake_api) conf = tmp_path / "node.toml" tp = tmp_path.as_posix() # a raw Windows path is a TOML escape error |