mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-19 22:10:51 +00:00
89 lines
2.9 KiB
TypeScript
89 lines
2.9 KiB
TypeScript
import fs from "node:fs/promises";
|
|
import os from "node:os";
|
|
import path from "node:path";
|
|
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
import { createSandboxTestContext } from "../../../src/agents/sandbox/test-fixtures.js";
|
|
import type { OpenShellSandboxBackend } from "./backend.js";
|
|
import { createOpenShellFsBridge } from "./fs-bridge.js";
|
|
|
|
const tempDirs: string[] = [];
|
|
|
|
async function makeTempDir() {
|
|
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-openshell-fs-"));
|
|
tempDirs.push(dir);
|
|
return dir;
|
|
}
|
|
|
|
afterEach(async () => {
|
|
await Promise.all(tempDirs.splice(0).map((dir) => fs.rm(dir, { recursive: true, force: true })));
|
|
});
|
|
|
|
function createBackendMock(): OpenShellSandboxBackend {
|
|
return {
|
|
id: "openshell",
|
|
runtimeId: "openshell-test",
|
|
runtimeLabel: "openshell-test",
|
|
workdir: "/sandbox",
|
|
env: {},
|
|
remoteWorkspaceDir: "/sandbox",
|
|
remoteAgentWorkspaceDir: "/agent",
|
|
buildExecSpec: vi.fn(),
|
|
runShellCommand: vi.fn(),
|
|
runRemoteShellScript: vi.fn().mockResolvedValue({
|
|
stdout: Buffer.alloc(0),
|
|
stderr: Buffer.alloc(0),
|
|
code: 0,
|
|
}),
|
|
syncLocalPathToRemote: vi.fn().mockResolvedValue(undefined),
|
|
} as unknown as OpenShellSandboxBackend;
|
|
}
|
|
|
|
describe("openshell fs bridge", () => {
|
|
it("writes locally and syncs the file to the remote workspace", async () => {
|
|
const workspaceDir = await makeTempDir();
|
|
const backend = createBackendMock();
|
|
const sandbox = createSandboxTestContext({
|
|
overrides: {
|
|
backendId: "openshell",
|
|
workspaceDir,
|
|
agentWorkspaceDir: workspaceDir,
|
|
containerWorkdir: "/sandbox",
|
|
},
|
|
});
|
|
|
|
const bridge = createOpenShellFsBridge({ sandbox, backend });
|
|
await bridge.writeFile({
|
|
filePath: "nested/file.txt",
|
|
data: "hello",
|
|
mkdir: true,
|
|
});
|
|
|
|
expect(await fs.readFile(path.join(workspaceDir, "nested", "file.txt"), "utf8")).toBe("hello");
|
|
expect(backend.syncLocalPathToRemote).toHaveBeenCalledWith(
|
|
path.join(workspaceDir, "nested", "file.txt"),
|
|
"/sandbox/nested/file.txt",
|
|
);
|
|
});
|
|
|
|
it("maps agent mount paths when the sandbox workspace is read-only", async () => {
|
|
const workspaceDir = await makeTempDir();
|
|
const agentWorkspaceDir = await makeTempDir();
|
|
await fs.writeFile(path.join(agentWorkspaceDir, "note.txt"), "agent", "utf8");
|
|
const backend = createBackendMock();
|
|
const sandbox = createSandboxTestContext({
|
|
overrides: {
|
|
backendId: "openshell",
|
|
workspaceDir,
|
|
agentWorkspaceDir,
|
|
workspaceAccess: "ro",
|
|
containerWorkdir: "/sandbox",
|
|
},
|
|
});
|
|
|
|
const bridge = createOpenShellFsBridge({ sandbox, backend });
|
|
const resolved = bridge.resolvePath({ filePath: "/agent/note.txt" });
|
|
expect(resolved.hostPath).toBe(path.join(agentWorkspaceDir, "note.txt"));
|
|
expect(await bridge.readFile({ filePath: "/agent/note.txt" })).toEqual(Buffer.from("agent"));
|
|
});
|
|
});
|