test(albok): sshfs pathname-withdrawal test for the .browse/ view passes (unit 4.3 exposure gate)
Replica of a browse view on nh3-albok, Linux sshfs 3.7.3 client in an ephemeral container on nh3-dev, N=5 per condition. Fresh open of a never-opened child through a cached listing: ENOENT 5/5 with sshfs defaults and 5/5 with hour-long client caches. Null control (no rename) opens 5/5; held fd and failed-rename positive controls read 5/5. Replica removed afterwards. Also closes the post-clear checks in persistent-memory: fv-ml1 GPU 0/1 plateau, nh3-nas usage, and the mislabelled sfsrv-ana pre-pbs4 item.
This commit is contained in:
+51
@@ -0,0 +1,51 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Build a replica of an albok browse view on the share host (nh3-albok).
|
||||
|
||||
Run ON the server as infra-ops, no sudo:
|
||||
ssh infra-ops@10.100.50.44 python3 - < setup-replica.py > manifest.json
|
||||
|
||||
Why a replica and not the live view: the test renames `.browse/` away. On a live
|
||||
wing that rename races albok-service's own link()/unlink() calls, and a failed
|
||||
mandatory unlink withholds the wing (BROWSE_WITHHELD marker + a failed write
|
||||
transaction). The replica has the same shape as the real view
|
||||
(`<wing>/.browse/<locator>` -> relative symlink `../../<id[:2]>/<id>/<blob>`), sits
|
||||
on the same filesystem (root ext4), and is served by the same sftp-server, which
|
||||
is what the withdrawal property depends on.
|
||||
|
||||
Content is deterministic per object, so the client can verify bytes without
|
||||
fetching a reference copy.
|
||||
"""
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
import uuid
|
||||
|
||||
ROOT = "/home/infra-ops/albok-browse-test/wing"
|
||||
COUNT = 60
|
||||
SIZE = 1 << 20 # 1 MiB: larger than FUSE readahead, so a late read must reach the server
|
||||
|
||||
|
||||
def content(i: int, oid: str) -> bytes:
|
||||
line = f"replica object {i} {oid}\n".encode()
|
||||
return (line * (SIZE // len(line) + 1))[:SIZE]
|
||||
|
||||
|
||||
os.makedirs(ROOT, exist_ok=False) # refuse to run over an existing replica
|
||||
link_dir = os.path.join(ROOT, ".browse", "stash")
|
||||
os.makedirs(link_dir)
|
||||
objs = []
|
||||
for i in range(COUNT):
|
||||
oid = uuid.uuid4().hex
|
||||
obj_dir = os.path.join(ROOT, oid[:2], oid)
|
||||
os.makedirs(obj_dir)
|
||||
name = f"doc{i:02d}.md"
|
||||
blob = os.path.join(obj_dir, name)
|
||||
data = content(i, oid)
|
||||
with open(blob, "wb") as f:
|
||||
f.write(data)
|
||||
os.chmod(blob, 0o640)
|
||||
os.symlink(os.path.relpath(blob, link_dir), os.path.join(link_dir, name))
|
||||
objs.append({"i": i, "id": oid, "name": name, "size": SIZE,
|
||||
"sha256": hashlib.sha256(data).hexdigest()})
|
||||
|
||||
print(json.dumps({"root": ROOT, "size": SIZE, "objects": objs}))
|
||||
Reference in New Issue
Block a user