diff options
| author | Christophe Besson <cbesson@gmail.com> | 2026-09-08 13:54:53 +0200 |
|---|---|---|
| committer | Christophe Besson <cbesson@gmail.com> | 2026-09-08 13:54:53 +0200 |
| commit | 28f1b5686c7ab200aeda6782f5f6e829c24759dd (patch) | |
| tree | bba1349896700d67d57f4aa28575b79649b408de /packages/meshbay-node | |
| parent | db69d0e351b59f6fd9335995c7994bd2933f668a (diff) | |
| download | meshbay-28f1b5686c7ab200aeda6782f5f6e829c24759dd.tar.gz | |
test(node): close the eleven failures, and the order-dependence behind seven
Nine of the eleven were defects in the suite, two were assertions describing
behaviour the code had deliberately changed. None was a bug in the node.
Seven had one cause. `check_media_tools()` writes two module globals;
`monkeypatch` restores what a test patched and knows nothing about what the
call under test then wrote, so a test that pointed `shutil.which` at
"/opt/bin/{n}.exe" left `_ffprobe_path` there — a Windows path, on Linux — for
the rest of the session. Every later test that actually runs ffprobe died on
FileNotFoundError, in two files about video transcoding, for a reason nowhere
near themselves. Run those files alone and they passed; that is what made it
look like an environment problem for so long.
The autouse `_restore_media_tool_paths` fixture in conftest.py puts both back
after every test. That closes the class, not just this instance: any future test
that resolves media tools is undone whether it remembers to or not, which is the
only way an order-dependent suite stops being one. Verified by removing the
call-site guard entirely and running the whole suite — green, so the fixture is
carrying it, and the call site keeps a pointer rather than a second copy of the
explanation.
The other four:
- two service tests were the only ones in test_platform.py that never set
`sys.platform` to "win32", so they hit "service mode is Windows-only";
- test_apps_enabled_policy expected `["chat"]` where `roster.enabled_apps`
inserts "files" at the front on read (and `ops.set_enabled_apps` on write),
because Settings is the one way back if every app were turned off. The code
is right; the assertion predates the guard, and is now ["files", "chat"];
- test_invite_then_join_delivers_the_gek passed a bare Path as a group's
`roots` two lines below building a RootSet for the transport. The handshake
died on `'PosixPath' object has no attribute 'describe'` and answered `error`
— scaffolding that never followed the move to several named roots (draft v6,
change 1).
1081 passed, 4 skipped, 0 failed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HCGdheDLxGReuKHga3BtST
Diffstat (limited to 'packages/meshbay-node')
| -rw-r--r-- | packages/meshbay-node/tests/conftest.py | 22 | ||||
| -rw-r--r-- | packages/meshbay-node/tests/test_apps_enabled_policy.py | 9 | ||||
| -rw-r--r-- | packages/meshbay-node/tests/test_platform.py | 10 | ||||
| -rw-r--r-- | packages/meshbay-node/tests/test_webrtc_transport.py | 9 |
4 files changed, 47 insertions, 3 deletions
diff --git a/packages/meshbay-node/tests/conftest.py b/packages/meshbay-node/tests/conftest.py index ba86c13..692a118 100644 --- a/packages/meshbay-node/tests/conftest.py +++ b/packages/meshbay-node/tests/conftest.py @@ -17,6 +17,28 @@ needs_subprocess = pytest.mark.skipif( "SelectorEventLoop for aiortc", ) +@pytest.fixture(autouse=True) +def _restore_media_tool_paths(): + """Put `platform`'s resolved ffmpeg/ffprobe paths back after every test. + + `check_media_tools()` writes two module globals. `monkeypatch` restores what + a test patched, and knows nothing about what the code under test then wrote + — so a test that patched `shutil.which` to a Windows path and called + `check_media_tools()` left `_ffprobe_path` at "/opt/bin/ffprobe.exe" for the + rest of the session. Seven tests in two files about video transcoding then + died on FileNotFoundError, for a reason nowhere near themselves, and only + when the whole suite ran: run those two files alone and they passed. + + The instance is fixed at the call site as well; this closes the class. Any + future test that resolves media tools is undone here whether it remembers to + or not, which is the only way an order-dependent suite stops being one. + """ + from meshbay_node import platform as _plat + before = (_plat._ffmpeg_path, _plat._ffprobe_path) + yield + _plat._ffmpeg_path, _plat._ffprobe_path = before + + # Windows-only gaps still to close (see devel/windows-devel.md §5/§6). win32_todo = pytest.mark.skipif( sys.platform == "win32", diff --git a/packages/meshbay-node/tests/test_apps_enabled_policy.py b/packages/meshbay-node/tests/test_apps_enabled_policy.py index ac44ab3..40c7cc8 100644 --- a/packages/meshbay-node/tests/test_apps_enabled_policy.py +++ b/packages/meshbay-node/tests/test_apps_enabled_policy.py @@ -123,14 +123,19 @@ async def test_the_setting_lives_on_the_node_and_survives_a_restart(tmp_path): "absent must mean every registered app, or an upgrade hides one " "for every existing group") await roster.set_enabled_apps("g1", ["chat"], set_by="op") - assert await roster.enabled_apps("g1") == ["chat"] + # Files comes back whatever was stored: `enabled_apps` inserts it at + # the front on read, and `ops.set_enabled_apps` does the same on write, + # because Settings is the one way back if everything else were turned + # off. The assertion predates that guard -- the code is right and the + # test was describing the older behaviour. + assert await roster.enabled_apps("g1") == ["files", "chat"] finally: await roster.close() reopened = Roster(db_path=tmp_path / "roster.db") await reopened.open() try: - assert await reopened.enabled_apps("g1") == ["chat"] + assert await reopened.enabled_apps("g1") == ["files", "chat"] assert sorted(await reopened.enabled_apps("g2")) == ["chat", "files"], ( "one group's setting must not answer for another") finally: diff --git a/packages/meshbay-node/tests/test_platform.py b/packages/meshbay-node/tests/test_platform.py index 92e74df..3fb27f3 100644 --- a/packages/meshbay-node/tests/test_platform.py +++ b/packages/meshbay-node/tests/test_platform.py @@ -71,6 +71,10 @@ def test_check_media_tools_raises_when_ffmpeg_is_missing(monkeypatch): def test_check_media_tools_stores_the_resolved_paths(monkeypatch): + # This call writes two module globals, and what undoes them is the autouse + # `_restore_media_tool_paths` fixture in conftest.py -- see it for what went + # wrong when nothing did. Deliberately not repeated here: one mechanism, one + # explanation, or the two drift. monkeypatch.setattr(plat.shutil, "which", lambda n: f"/opt/bin/{n}.exe") plat.check_media_tools("ffmpeg", "ffprobe") @@ -365,6 +369,9 @@ def test_service_install_uses_s4u_not_a_stored_password(monkeypatch): credential validation, and omitting /rp registers "Interactive only", which never runs at boot or on demand. See platform.py's service mode comment for the full story.""" + # Service mode is Windows-only and refuses outright anywhere else; + # every other test in this file says so, these two never did. + monkeypatch.setattr(sys, "platform", "win32") monkeypatch.setattr(plat, "_current_user", lambda: "DOMAIN\\user") calls = [] monkeypatch.setattr( @@ -388,6 +395,9 @@ def test_service_install_tolerates_no_startup_launcher_present(win_startup, monk def test_service_install_raises_with_powershells_error_message(monkeypatch): + # Service mode is Windows-only and refuses outright anywhere else; + # every other test in this file says so, these two never did. + monkeypatch.setattr(sys, "platform", "win32") monkeypatch.setattr(plat, "_current_user", lambda: "DOMAIN\\user") monkeypatch.setattr( plat.subprocess, "run", diff --git a/packages/meshbay-node/tests/test_webrtc_transport.py b/packages/meshbay-node/tests/test_webrtc_transport.py index c1a5287..284c461 100644 --- a/packages/meshbay-node/tests/test_webrtc_transport.py +++ b/packages/meshbay-node/tests/test_webrtc_transport.py @@ -1226,7 +1226,14 @@ async def test_invite_then_join_delivers_the_gek(sk_node, sk_hub, gek, shared_di transport._ctx["roster"] = roster transport._ctx["has_admin_authority"] = True transport._ctx["groups"] = { - TEST_GROUP: {"gek": gek, "roots": shared_dir, "index": indexer.index}, + # A RootSet, like the transport two lines up and like the code under + # test expects: a group's content became several named roots (draft v6, + # change 1) and this one line kept passing the bare Path. The handshake + # died on `'PosixPath' object has no attribute 'describe'` and answered + # `error` instead of `handshake_ack`, which is a scaffolding that never + # followed the change, not a defect in the flow being tested. + TEST_GROUP: {"gek": gek, "roots": one_root(shared_dir), + "index": indexer.index}, } # `create_invite` registers the invitee as a hub member *before* writing the # invite, and fails the whole operation if it cannot: `/v1/groups/mine` |