Files
vm/packages/sdk/test/unit/filesystem.test.ts
zeekayandHanzo Dev 51a68b9311 Rebrand shuru as Hanzo VM
Crates keep their history: vm (lib, was shuru-vm), hanzo-vm (CLI package
and binary, was shuru-cli), vm-guest, vm-proto, vm-proxy, vm-sdk,
vm-store, vm-darwin, vm-linux; all at 0.1.0, Apache-2.0, hanzoai/vm.
Config is vm.json, data lives in ~/.hanzo/vm (HANZO_VM_HOME), env vars
are HANZO_VM_*, the guest runs as /usr/bin/vm-guest, and assets download
from hanzoai/vm releases. The TypeScript SDK is @hanzo/vm. NOTICE
credits shuru as the origin. prepare-rootfs.sh builds the image natively
on arm64 Linux with mke2fs -d and re-execs in Docker only on macOS.
Includes rustfmt over the tree and fixes for clippy 1.98 lints.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-01 11:49:10 -07:00

186 lines
3.9 KiB
TypeScript

import { afterAll, beforeAll, describe, expect, test } from "bun:test";
import { resolve } from "node:path";
import { Sandbox } from "../../src/sandbox";
const MOCK_BIN = `bun ${resolve(import.meta.dir, "mock-vm.ts")}`;
describe("mkdir", () => {
let sb: Sandbox;
beforeAll(async () => {
sb = await Sandbox.start({ bin: MOCK_BIN });
}, 10_000);
afterAll(async () => {
await sb?.stop();
}, 5_000);
test("creates directory", async () => {
await sb.mkdir("/tmp/test");
});
test("recursive defaults to true", async () => {
await sb.mkdir("/tmp/a/b/c");
});
test("explicit recursive false", async () => {
await sb.mkdir("/tmp/single", { recursive: false });
});
test("throws on failure", async () => {
await expect(sb.mkdir("/fail")).rejects.toThrow("Permission denied");
});
});
describe("readDir", () => {
let sb: Sandbox;
beforeAll(async () => {
sb = await Sandbox.start({ bin: MOCK_BIN });
}, 10_000);
afterAll(async () => {
await sb?.stop();
}, 5_000);
test("returns entries with name, type, size", async () => {
const entries = await sb.readDir("/tmp");
expect(entries).toHaveLength(3);
expect(entries[0]).toEqual({ name: "file.txt", type: "file", size: 42 });
expect(entries[1]).toEqual({
name: "subdir",
type: "dir",
size: 4096,
});
expect(entries[2]).toEqual({ name: "link", type: "symlink", size: 10 });
});
test("throws on nonexistent path", async () => {
await expect(sb.readDir("/nonexistent")).rejects.toThrow(
"No such file or directory",
);
});
});
describe("stat", () => {
let sb: Sandbox;
beforeAll(async () => {
sb = await Sandbox.start({ bin: MOCK_BIN });
}, 10_000);
afterAll(async () => {
await sb?.stop();
}, 5_000);
test("returns metadata with camelCase fields", async () => {
const s = await sb.stat("/tmp/file.txt");
expect(s.size).toBe(1024);
expect(s.mode).toBe(0o100644);
expect(s.mtime).toBe(1700000000);
expect(s.isDir).toBe(false);
expect(s.isFile).toBe(true);
expect(s.isSymlink).toBe(false);
});
test("throws on nonexistent path", async () => {
await expect(sb.stat("/nonexistent")).rejects.toThrow(
"No such file or directory",
);
});
});
describe("remove", () => {
let sb: Sandbox;
beforeAll(async () => {
sb = await Sandbox.start({ bin: MOCK_BIN });
}, 10_000);
afterAll(async () => {
await sb?.stop();
}, 5_000);
test("removes file", async () => {
await sb.remove("/tmp/file.txt");
});
test("removes directory recursively", async () => {
await sb.remove("/tmp/dir", { recursive: true });
});
});
describe("rename", () => {
let sb: Sandbox;
beforeAll(async () => {
sb = await Sandbox.start({ bin: MOCK_BIN });
}, 10_000);
afterAll(async () => {
await sb?.stop();
}, 5_000);
test("renames file", async () => {
await sb.rename("/tmp/old.txt", "/tmp/new.txt");
});
});
describe("copy", () => {
let sb: Sandbox;
beforeAll(async () => {
sb = await Sandbox.start({ bin: MOCK_BIN });
}, 10_000);
afterAll(async () => {
await sb?.stop();
}, 5_000);
test("copies file", async () => {
await sb.copy("/tmp/src.txt", "/tmp/dst.txt");
});
test("copies directory recursively", async () => {
await sb.copy("/tmp/srcdir", "/tmp/dstdir", { recursive: true });
});
});
describe("chmod", () => {
let sb: Sandbox;
beforeAll(async () => {
sb = await Sandbox.start({ bin: MOCK_BIN });
}, 10_000);
afterAll(async () => {
await sb?.stop();
}, 5_000);
test("changes permissions", async () => {
await sb.chmod("/tmp/file.txt", 0o755);
});
});
describe("exists", () => {
let sb: Sandbox;
beforeAll(async () => {
sb = await Sandbox.start({ bin: MOCK_BIN });
}, 10_000);
afterAll(async () => {
await sb?.stop();
}, 5_000);
test("returns true for existing path", async () => {
const result = await sb.exists("/tmp/file.txt");
expect(result).toBe(true);
});
test("returns false for nonexistent path", async () => {
const result = await sb.exists("/nonexistent");
expect(result).toBe(false);
});
});