diff options
| author | Christophe Besson <cbesson@gmail.com> | 2026-09-18 16:13:53 +0200 |
|---|---|---|
| committer | Christophe Besson <cbesson@gmail.com> | 2026-09-18 16:13:53 +0200 |
| commit | 20b906057d1c1df810cd0c2cfe235c27df9f3e5f (patch) | |
| tree | ef36187c7423ca127a36d57a3ce92fda66496349 /packages/meshbay-node/tests/test_root_writable_policy.py | |
| parent | 5fa158fab709d3d24a33318b3d910f75c051af2e (diff) | |
| download | meshbay-20b906057d1c1df810cd0c2cfe235c27df9f3e5f.tar.gz | |
fix(node): creating and removing a folder are syscalls too
The last two handlers on the loop. Both were synchronous, so a member creating a
folder on a root that had spun down held the node for the spin-up, exactly as a
chunk read did.
Where a check and an act belong together they are now one call rather than two
awaits, and the single disk thread is what makes that atomic: `_mkdir_if_absent`
so two members creating the same name cannot both find nothing there and have
the second `mkdir` raise where a refusal was meant, and `_rmdir_if_empty` for
the reason the caller already re-tested emptiness — the first test happened
before a round trip to the operator's browser, and a file can land in between.
Two awaits would reopen that window one size smaller.
The guard is now the whole class rather than the calls that were fixed. It walks
the module's syntax tree and fails on any filesystem call outside the handful of
functions written to be run through `off_disk` — a new handler that stats a root
inline would pass every measured test, because those exercise the handlers that
exist today. Checked by putting a call back: it names the function and the line.
It leaves ffmpeg's own scratch files out, listed rather than silently allowed:
they are under `tempfile.mkstemp` on the system disk, not on a group root, so
they are not what spins down — but they do read a whole transcode into memory
from the loop, and the day that matters it is a different measurement from this
one.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Diffstat (limited to 'packages/meshbay-node/tests/test_root_writable_policy.py')
| -rw-r--r-- | packages/meshbay-node/tests/test_root_writable_policy.py | 6 |
1 files changed, 3 insertions, 3 deletions
diff --git a/packages/meshbay-node/tests/test_root_writable_policy.py b/packages/meshbay-node/tests/test_root_writable_policy.py index 23b55cb..3c8a837 100644 --- a/packages/meshbay-node/tests/test_root_writable_policy.py +++ b/packages/meshbay-node/tests/test_root_writable_policy.py @@ -121,7 +121,7 @@ async def test_a_member_cannot_create_a_folder_in_a_read_only_root(tmp_path): requires the same root to be writable that adding the file would have. """ session = _session(tmp_path, "member-1", writable=False) - session._do_dir_create({"dir": "shared", "name": "New folder"}) + await session._do_dir_create({"dir": "shared", "name": "New folder"}) refusal = [m for m in session.sent if m.get("type") == "error"] assert refusal and refusal[0].get("code") == "root_read_only" @@ -131,7 +131,7 @@ async def test_a_member_cannot_create_a_folder_in_a_read_only_root(tmp_path): async def test_a_member_can_create_a_folder_in_a_writable_root(tmp_path): """The counter-property: it must stay unprivileged where it is allowed.""" session = _session(tmp_path, "member-1", writable=True) - session._do_dir_create({"dir": "shared", "name": "New folder"}) + await session._do_dir_create({"dir": "shared", "name": "New folder"}) assert not [m for m in session.sent if m.get("type") == "error"] assert (tmp_path / "shared" / "New folder").is_dir() @@ -144,7 +144,7 @@ async def test_an_ejected_root_refuses_a_new_folder(tmp_path): roots.roots[0].ejected = True roots.roots[0].available = False - session._do_dir_create({"dir": "shared", "name": "New folder"}) + await session._do_dir_create({"dir": "shared", "name": "New folder"}) refusal = [m for m in session.sent if m.get("type") == "error"] assert refusal and refusal[0].get("code") == "root_unavailable" assert not (tmp_path / "shared" / "New folder").exists() |