Support durable host-to-isolated workspace migration

This commit is contained in:
ms2k 2026-07-26 00:43:30 +09:00
commit 0dda65fc2e

View file

@ -254,6 +254,25 @@ def atomic_case(case_id, fixture):
require(not (fixture.host / "ignored/destination").exists() and not (fixture.isolated / "ignored/destination").exists(), "destination appeared after EXDEV")
def migration_case(case_id, fixture):
del case_id
write(fixture.host / ".gitignore", b"/target/\n")
source = fixture.mount / "targetAbCd12"
destination = fixture.mount / "target"
payload = b"Signature: 8a477f597d28d172789f06886806bc55\n"
with fixture.start():
source.mkdir()
write(source / "CACHEDIR.TAG", payload)
os.rename(source, destination)
require((destination / "CACHEDIR.TAG").read_bytes() == payload, "published target differs")
expect_errno(errno.EXDEV, lambda: os.rename(destination, fixture.mount / "exported-target"))
require(not (fixture.host / "targetAbCd12").exists(), "host source remained after migration")
require(not (fixture.host / "target").exists(), "isolated target was exported to host")
require((fixture.isolated / "target/CACHEDIR.TAG").read_bytes() == payload, "isolated target missing")
intents = fixture.isolated / ".lazaret-ignored-workspace-transactions"
require(not any(intents.iterdir()), "completed migration retained intent")
def rename_exchange(source, destination):
observed = exchange_paths(source, destination)
if observed == 0:
@ -666,6 +685,7 @@ CASE_GROUPS = {
"live-ignore-publication",
]},
**{name: atomic_case for name in ["cross-route-file-rename", "cross-route-directory-exchange", "cross-route-hard-link"]},
"cargo-target-host-to-isolated-rename": migration_case,
**{name: policy_transition_case for name in ["ignored-becomes-non-ignored", "non-ignored-becomes-ignored"]},
**{name: index_case for name in ["guest-force-add-isolated-only", "host-established-tracked-cutover", "unmediated-inconsistent-index"]},
**{name: open_handle_case for name in ["mmap-policy-transition", "locks-policy-transition", "directory-stream-policy-snapshot"]},