61 lines
2.0 KiB
TypeScript
61 lines
2.0 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { createConfigIO } from "./io.js";
|
|
|
|
function makeEaccesFs(configPath: string) {
|
|
const eaccesErr = Object.assign(new Error(`EACCES: permission denied, open '${configPath}'`), {
|
|
code: "EACCES",
|
|
});
|
|
return {
|
|
existsSync: (p: string) => p === configPath,
|
|
readFileSync: (p: string): string => {
|
|
if (p === configPath) {
|
|
throw eaccesErr;
|
|
}
|
|
throw new Error(`unexpected readFileSync: ${p}`);
|
|
},
|
|
promises: {
|
|
readFile: () => Promise.reject(eaccesErr),
|
|
mkdir: () => Promise.resolve(),
|
|
writeFile: () => Promise.resolve(),
|
|
appendFile: () => Promise.resolve(),
|
|
},
|
|
} as unknown as typeof import("node:fs");
|
|
}
|
|
|
|
describe("config io EACCES handling", () => {
|
|
it("returns a helpful error message when config file is not readable (EACCES)", async () => {
|
|
const configPath = "/data/.openclaw/openclaw.json";
|
|
const errors: string[] = [];
|
|
const io = createConfigIO({
|
|
configPath,
|
|
fs: makeEaccesFs(configPath),
|
|
logger: {
|
|
error: (msg: unknown) => errors.push(String(msg)),
|
|
warn: () => {},
|
|
},
|
|
});
|
|
|
|
const snapshot = await io.readConfigFileSnapshot();
|
|
expect(snapshot.valid).toBe(false);
|
|
expect(snapshot.issues).toHaveLength(1);
|
|
expect(snapshot.issues[0].message).toContain("EACCES");
|
|
expect(snapshot.issues[0].message).toContain("chown");
|
|
expect(snapshot.issues[0].message).toContain(configPath);
|
|
// Should also emit to the logger
|
|
expect(errors.some((e) => e.includes("chown"))).toBe(true);
|
|
});
|
|
|
|
it("includes configPath in the chown hint for the correct remediation command", async () => {
|
|
const configPath = "/home/myuser/.openclaw/openclaw.json";
|
|
const io = createConfigIO({
|
|
configPath,
|
|
fs: makeEaccesFs(configPath),
|
|
logger: { error: () => {}, warn: () => {} },
|
|
});
|
|
|
|
const snapshot = await io.readConfigFileSnapshot();
|
|
expect(snapshot.issues[0].message).toContain(configPath);
|
|
expect(snapshot.issues[0].message).toContain("container");
|
|
});
|
|
});
|