File size: 4,057 Bytes
f778c12 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | // Proves a fresh dev gateway can replace the synthetic implicit roster through real config IO.
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 { resetConfigRuntimeState } from "../../config/config.js";
import { withEnvAsync } from "../../test-utils/env.js";
import { nodeFilePath } from "../../test-utils/node-file-path.js";
import { ensureDevGatewayConfig } from "./dev.js";
describe("ensureDevGatewayConfig integration", () => {
const tempDirs: string[] = [];
afterEach(async () => {
resetConfigRuntimeState();
await Promise.all(
tempDirs.splice(0).map((dir) => fs.rm(dir, { recursive: true, force: true })),
);
});
it("writes the dedicated dev roster into a fresh state directory", async () => {
const root = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-dev-config-integration-"));
tempDirs.push(root);
const stateDir = path.join(root, "state");
const configPath = path.join(stateDir, "openclaw.json");
const workspace = path.join(root, "workspace");
await withEnvAsync(
{
OPENCLAW_CONFIG_PATH: configPath,
OPENCLAW_STATE_DIR: stateDir,
OPENCLAW_WORKSPACE_DIR: workspace,
},
async () => {
resetConfigRuntimeState();
await ensureDevGatewayConfig({});
},
);
const config = JSON.parse(await fs.readFile(configPath, "utf8")) as {
agents?: { entries?: Record<string, { default?: boolean; workspace?: string }> };
};
expect(config.agents?.entries).toEqual({
dev: { default: true, workspace: `${workspace}-dev`, identity: expect.any(Object) },
});
});
it("can retry after a partial dev workspace write fails", async () => {
const root = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-dev-config-integration-"));
tempDirs.push(root);
const stateDir = path.join(root, "state");
const configPath = path.join(stateDir, "openclaw.json");
const workspace = path.join(root, "workspace");
const devWorkspace = `${workspace}-dev`;
await withEnvAsync(
{
OPENCLAW_CONFIG_PATH: configPath,
OPENCLAW_STATE_DIR: stateDir,
OPENCLAW_WORKSPACE_DIR: workspace,
},
async () => {
resetConfigRuntimeState();
const realWriteFile = fs.writeFile.bind(fs);
const writeSpy = vi
.spyOn(fs, "writeFile")
.mockImplementation(async (filePath, data, options) => {
const rawPath = nodeFilePath(filePath);
if (!rawPath) {
return await realWriteFile(filePath, data, options);
}
const target = path.resolve(rawPath);
const parent = path.dirname(target);
const isStagedAgents =
path.dirname(parent) === devWorkspace &&
path.basename(parent).startsWith("openclaw-bootstrap-") &&
path.basename(target) === "AGENTS.md";
if (isStagedAgents) {
await realWriteFile(filePath, "# PARTIAL\n", options);
const error = new Error("ENOSPC") as NodeJS.ErrnoException;
error.code = "ENOSPC";
throw error;
}
return await realWriteFile(filePath, data, options);
});
try {
await expect(ensureDevGatewayConfig({})).rejects.toMatchObject({ code: "ENOSPC" });
await expect(fs.access(configPath)).rejects.toMatchObject({ code: "ENOENT" });
await expect(fs.access(path.join(devWorkspace, "AGENTS.md"))).rejects.toMatchObject({
code: "ENOENT",
});
} finally {
writeSpy.mockRestore();
}
await ensureDevGatewayConfig({});
const agents = await fs.readFile(path.join(devWorkspace, "AGENTS.md"), "utf8");
expect(agents).toContain("gateway --dev");
expect(agents).not.toBe("# PARTIAL\n");
await expect(fs.access(configPath)).resolves.toBeUndefined();
},
);
});
});
|