142 lines
5.4 KiB
TypeScript
142 lines
5.4 KiB
TypeScript
import fs from "node:fs/promises";
|
|
import os from "node:os";
|
|
import path from "node:path";
|
|
import { describe, expect, it } from "vitest";
|
|
import {
|
|
resolveDefaultConfigCandidates,
|
|
resolveConfigPathCandidate,
|
|
resolveConfigPath,
|
|
resolveOAuthDir,
|
|
resolveOAuthPath,
|
|
resolveStateDir,
|
|
} from "./paths.js";
|
|
|
|
describe("oauth paths", () => {
|
|
it("prefers OPENCLAW_OAUTH_DIR over OPENCLAW_STATE_DIR", () => {
|
|
const env = {
|
|
OPENCLAW_OAUTH_DIR: "/custom/oauth",
|
|
OPENCLAW_STATE_DIR: "/custom/state",
|
|
} as NodeJS.ProcessEnv;
|
|
|
|
expect(resolveOAuthDir(env, "/custom/state")).toBe(path.resolve("/custom/oauth"));
|
|
expect(resolveOAuthPath(env, "/custom/state")).toBe(
|
|
path.join(path.resolve("/custom/oauth"), "oauth.json"),
|
|
);
|
|
});
|
|
|
|
it("derives oauth path from OPENCLAW_STATE_DIR when unset", () => {
|
|
const env = {
|
|
OPENCLAW_STATE_DIR: "/custom/state",
|
|
} as NodeJS.ProcessEnv;
|
|
|
|
expect(resolveOAuthDir(env, "/custom/state")).toBe(path.join("/custom/state", "credentials"));
|
|
expect(resolveOAuthPath(env, "/custom/state")).toBe(
|
|
path.join("/custom/state", "credentials", "oauth.json"),
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("state + config path candidates", () => {
|
|
it("uses OPENCLAW_STATE_DIR when set", () => {
|
|
const env = {
|
|
OPENCLAW_STATE_DIR: "/new/state",
|
|
} as NodeJS.ProcessEnv;
|
|
|
|
expect(resolveStateDir(env, () => "/home/test")).toBe(path.resolve("/new/state"));
|
|
});
|
|
|
|
it("uses OPENCLAW_HOME for default state/config locations", () => {
|
|
const env = {
|
|
OPENCLAW_HOME: "/srv/openclaw-home",
|
|
} as NodeJS.ProcessEnv;
|
|
|
|
const resolvedHome = path.resolve("/srv/openclaw-home");
|
|
expect(resolveStateDir(env)).toBe(path.join(resolvedHome, ".openclaw"));
|
|
|
|
const candidates = resolveDefaultConfigCandidates(env);
|
|
expect(candidates[0]).toBe(path.join(resolvedHome, ".openclaw", "openclaw.json"));
|
|
});
|
|
|
|
it("prefers OPENCLAW_HOME over HOME for default state/config locations", () => {
|
|
const env = {
|
|
OPENCLAW_HOME: "/srv/openclaw-home",
|
|
HOME: "/home/other",
|
|
} as NodeJS.ProcessEnv;
|
|
|
|
const resolvedHome = path.resolve("/srv/openclaw-home");
|
|
expect(resolveStateDir(env)).toBe(path.join(resolvedHome, ".openclaw"));
|
|
|
|
const candidates = resolveDefaultConfigCandidates(env);
|
|
expect(candidates[0]).toBe(path.join(resolvedHome, ".openclaw", "openclaw.json"));
|
|
});
|
|
|
|
it("orders default config candidates in a stable order", () => {
|
|
const home = "/home/test";
|
|
const resolvedHome = path.resolve(home);
|
|
const candidates = resolveDefaultConfigCandidates({} as NodeJS.ProcessEnv, () => home);
|
|
const expected = [
|
|
path.join(resolvedHome, ".openclaw", "openclaw.json"),
|
|
path.join(resolvedHome, ".openclaw", "clawdbot.json"),
|
|
path.join(resolvedHome, ".openclaw", "moldbot.json"),
|
|
path.join(resolvedHome, ".openclaw", "moltbot.json"),
|
|
path.join(resolvedHome, ".clawdbot", "openclaw.json"),
|
|
path.join(resolvedHome, ".clawdbot", "clawdbot.json"),
|
|
path.join(resolvedHome, ".clawdbot", "moldbot.json"),
|
|
path.join(resolvedHome, ".clawdbot", "moltbot.json"),
|
|
path.join(resolvedHome, ".moldbot", "openclaw.json"),
|
|
path.join(resolvedHome, ".moldbot", "clawdbot.json"),
|
|
path.join(resolvedHome, ".moldbot", "moldbot.json"),
|
|
path.join(resolvedHome, ".moldbot", "moltbot.json"),
|
|
path.join(resolvedHome, ".moltbot", "openclaw.json"),
|
|
path.join(resolvedHome, ".moltbot", "clawdbot.json"),
|
|
path.join(resolvedHome, ".moltbot", "moldbot.json"),
|
|
path.join(resolvedHome, ".moltbot", "moltbot.json"),
|
|
];
|
|
expect(candidates).toEqual(expected);
|
|
});
|
|
|
|
it("prefers ~/.openclaw when it exists and legacy dir is missing", async () => {
|
|
const root = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-state-"));
|
|
try {
|
|
const newDir = path.join(root, ".openclaw");
|
|
await fs.mkdir(newDir, { recursive: true });
|
|
const resolved = resolveStateDir({} as NodeJS.ProcessEnv, () => root);
|
|
expect(resolved).toBe(newDir);
|
|
} finally {
|
|
await fs.rm(root, { recursive: true, force: true });
|
|
}
|
|
});
|
|
|
|
it("CONFIG_PATH prefers existing config when present", async () => {
|
|
const root = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-config-"));
|
|
try {
|
|
const legacyDir = path.join(root, ".openclaw");
|
|
await fs.mkdir(legacyDir, { recursive: true });
|
|
const legacyPath = path.join(legacyDir, "openclaw.json");
|
|
await fs.writeFile(legacyPath, "{}", "utf-8");
|
|
|
|
const resolved = resolveConfigPathCandidate({} as NodeJS.ProcessEnv, () => root);
|
|
expect(resolved).toBe(legacyPath);
|
|
} finally {
|
|
await fs.rm(root, { recursive: true, force: true });
|
|
}
|
|
});
|
|
|
|
it("respects state dir overrides when config is missing", async () => {
|
|
const root = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-config-override-"));
|
|
try {
|
|
const legacyDir = path.join(root, ".openclaw");
|
|
await fs.mkdir(legacyDir, { recursive: true });
|
|
const legacyConfig = path.join(legacyDir, "openclaw.json");
|
|
await fs.writeFile(legacyConfig, "{}", "utf-8");
|
|
|
|
const overrideDir = path.join(root, "override");
|
|
const env = { OPENCLAW_STATE_DIR: overrideDir } as NodeJS.ProcessEnv;
|
|
const resolved = resolveConfigPath(env, overrideDir, () => root);
|
|
expect(resolved).toBe(path.join(overrideDir, "openclaw.json"));
|
|
} finally {
|
|
await fs.rm(root, { recursive: true, force: true });
|
|
}
|
|
});
|
|
});
|