mirror of https://github.com/openclaw/openclaw.git
test: add update global and migration fs coverage
This commit is contained in:
parent
0386dcb63f
commit
413c8d189c
|
|
@ -0,0 +1,71 @@
|
|||
import fs from "node:fs";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
ensureDir,
|
||||
existsDir,
|
||||
fileExists,
|
||||
isLegacyWhatsAppAuthFile,
|
||||
readSessionStoreJson5,
|
||||
safeReadDir,
|
||||
} from "./state-migrations.fs.js";
|
||||
|
||||
describe("state migration fs helpers", () => {
|
||||
it("reads directories safely and creates missing directories", () => {
|
||||
const base = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-state-migrations-fs-"));
|
||||
const nested = path.join(base, "nested");
|
||||
|
||||
expect(safeReadDir(nested)).toEqual([]);
|
||||
ensureDir(nested);
|
||||
fs.writeFileSync(path.join(nested, "file.txt"), "ok", "utf8");
|
||||
|
||||
expect(safeReadDir(nested).map((entry) => entry.name)).toEqual(["file.txt"]);
|
||||
expect(existsDir(nested)).toBe(true);
|
||||
expect(existsDir(path.join(nested, "file.txt"))).toBe(false);
|
||||
});
|
||||
|
||||
it("distinguishes files from directories", () => {
|
||||
const base = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-state-migrations-fs-"));
|
||||
const filePath = path.join(base, "store.json");
|
||||
const dirPath = path.join(base, "dir");
|
||||
fs.writeFileSync(filePath, "{}", "utf8");
|
||||
fs.mkdirSync(dirPath);
|
||||
|
||||
expect(fileExists(filePath)).toBe(true);
|
||||
expect(fileExists(dirPath)).toBe(false);
|
||||
expect(fileExists(path.join(base, "missing.json"))).toBe(false);
|
||||
});
|
||||
|
||||
it("recognizes legacy whatsapp auth file names", () => {
|
||||
expect(isLegacyWhatsAppAuthFile("creds.json")).toBe(true);
|
||||
expect(isLegacyWhatsAppAuthFile("creds.json.bak")).toBe(true);
|
||||
expect(isLegacyWhatsAppAuthFile("session-123.json")).toBe(true);
|
||||
expect(isLegacyWhatsAppAuthFile("pre-key-1.json")).toBe(true);
|
||||
expect(isLegacyWhatsAppAuthFile("sender-key-1.txt")).toBe(false);
|
||||
expect(isLegacyWhatsAppAuthFile("other.json")).toBe(false);
|
||||
});
|
||||
|
||||
it("parses json5 session stores and rejects invalid shapes", () => {
|
||||
const base = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-state-migrations-fs-"));
|
||||
const okPath = path.join(base, "store.json");
|
||||
const badPath = path.join(base, "bad.json");
|
||||
const listPath = path.join(base, "list.json");
|
||||
|
||||
fs.writeFileSync(okPath, "{session: {sessionId: 'abc', updatedAt: 1}}", "utf8");
|
||||
fs.writeFileSync(badPath, "{not valid", "utf8");
|
||||
fs.writeFileSync(listPath, "[]", "utf8");
|
||||
|
||||
expect(readSessionStoreJson5(okPath)).toEqual({
|
||||
ok: true,
|
||||
store: {
|
||||
session: {
|
||||
sessionId: "abc",
|
||||
updatedAt: 1,
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(readSessionStoreJson5(badPath)).toEqual({ ok: false, store: {} });
|
||||
expect(readSessionStoreJson5(listPath)).toEqual({ ok: false, store: {} });
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,150 @@
|
|||
import fs from "node:fs/promises";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import { captureEnv } from "../test-utils/env.js";
|
||||
import {
|
||||
cleanupGlobalRenameDirs,
|
||||
detectGlobalInstallManagerByPresence,
|
||||
detectGlobalInstallManagerForRoot,
|
||||
globalInstallArgs,
|
||||
globalInstallFallbackArgs,
|
||||
resolveGlobalPackageRoot,
|
||||
resolveGlobalInstallSpec,
|
||||
resolveGlobalRoot,
|
||||
type CommandRunner,
|
||||
} from "./update-global.js";
|
||||
|
||||
describe("update global helpers", () => {
|
||||
let envSnapshot: ReturnType<typeof captureEnv> | undefined;
|
||||
|
||||
afterEach(() => {
|
||||
envSnapshot?.restore();
|
||||
envSnapshot = undefined;
|
||||
});
|
||||
|
||||
it("prefers explicit package spec overrides", () => {
|
||||
envSnapshot = captureEnv(["OPENCLAW_UPDATE_PACKAGE_SPEC"]);
|
||||
process.env.OPENCLAW_UPDATE_PACKAGE_SPEC = "file:/tmp/openclaw.tgz";
|
||||
|
||||
expect(resolveGlobalInstallSpec({ packageName: "openclaw", tag: "latest" })).toBe(
|
||||
"file:/tmp/openclaw.tgz",
|
||||
);
|
||||
expect(
|
||||
resolveGlobalInstallSpec({
|
||||
packageName: "openclaw",
|
||||
tag: "beta",
|
||||
env: { OPENCLAW_UPDATE_PACKAGE_SPEC: "openclaw@next" },
|
||||
}),
|
||||
).toBe("openclaw@next");
|
||||
});
|
||||
|
||||
it("resolves global roots and package roots from runner output", async () => {
|
||||
const runCommand: CommandRunner = async (argv) => {
|
||||
if (argv[0] === "npm") {
|
||||
return { stdout: "/tmp/npm-root\n", stderr: "", code: 0 };
|
||||
}
|
||||
if (argv[0] === "pnpm") {
|
||||
return { stdout: "", stderr: "", code: 1 };
|
||||
}
|
||||
throw new Error(`unexpected command: ${argv.join(" ")}`);
|
||||
};
|
||||
|
||||
await expect(resolveGlobalRoot("npm", runCommand, 1000)).resolves.toBe("/tmp/npm-root");
|
||||
await expect(resolveGlobalRoot("pnpm", runCommand, 1000)).resolves.toBeNull();
|
||||
await expect(resolveGlobalRoot("bun", runCommand, 1000)).resolves.toContain(
|
||||
path.join(".bun", "install", "global", "node_modules"),
|
||||
);
|
||||
await expect(resolveGlobalPackageRoot("npm", runCommand, 1000)).resolves.toBe(
|
||||
"/tmp/npm-root/openclaw",
|
||||
);
|
||||
});
|
||||
|
||||
it("detects install managers from resolved roots and on-disk presence", async () => {
|
||||
const base = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-update-global-"));
|
||||
const npmRoot = path.join(base, "npm-root");
|
||||
const pnpmRoot = path.join(base, "pnpm-root");
|
||||
const bunRoot = path.join(base, ".bun", "install", "global", "node_modules");
|
||||
const pkgRoot = path.join(pnpmRoot, "openclaw");
|
||||
await fs.mkdir(pkgRoot, { recursive: true });
|
||||
await fs.mkdir(path.join(npmRoot, "openclaw"), { recursive: true });
|
||||
await fs.mkdir(path.join(bunRoot, "openclaw"), { recursive: true });
|
||||
|
||||
envSnapshot = captureEnv(["BUN_INSTALL"]);
|
||||
process.env.BUN_INSTALL = path.join(base, ".bun");
|
||||
|
||||
const runCommand: CommandRunner = async (argv) => {
|
||||
if (argv[0] === "npm") {
|
||||
return { stdout: `${npmRoot}\n`, stderr: "", code: 0 };
|
||||
}
|
||||
if (argv[0] === "pnpm") {
|
||||
return { stdout: `${pnpmRoot}\n`, stderr: "", code: 0 };
|
||||
}
|
||||
throw new Error(`unexpected command: ${argv.join(" ")}`);
|
||||
};
|
||||
|
||||
await expect(detectGlobalInstallManagerForRoot(runCommand, pkgRoot, 1000)).resolves.toBe(
|
||||
"pnpm",
|
||||
);
|
||||
await expect(detectGlobalInstallManagerByPresence(runCommand, 1000)).resolves.toBe("npm");
|
||||
|
||||
await fs.rm(path.join(npmRoot, "openclaw"), { recursive: true, force: true });
|
||||
await fs.rm(path.join(pnpmRoot, "openclaw"), { recursive: true, force: true });
|
||||
await expect(detectGlobalInstallManagerByPresence(runCommand, 1000)).resolves.toBe("bun");
|
||||
});
|
||||
|
||||
it("builds install argv and npm fallback argv", () => {
|
||||
expect(globalInstallArgs("npm", "openclaw@latest")).toEqual([
|
||||
"npm",
|
||||
"i",
|
||||
"-g",
|
||||
"openclaw@latest",
|
||||
"--no-fund",
|
||||
"--no-audit",
|
||||
"--loglevel=error",
|
||||
]);
|
||||
expect(globalInstallArgs("pnpm", "openclaw@latest")).toEqual([
|
||||
"pnpm",
|
||||
"add",
|
||||
"-g",
|
||||
"openclaw@latest",
|
||||
]);
|
||||
expect(globalInstallArgs("bun", "openclaw@latest")).toEqual([
|
||||
"bun",
|
||||
"add",
|
||||
"-g",
|
||||
"openclaw@latest",
|
||||
]);
|
||||
|
||||
expect(globalInstallFallbackArgs("npm", "openclaw@latest")).toEqual([
|
||||
"npm",
|
||||
"i",
|
||||
"-g",
|
||||
"openclaw@latest",
|
||||
"--omit=optional",
|
||||
"--no-fund",
|
||||
"--no-audit",
|
||||
"--loglevel=error",
|
||||
]);
|
||||
expect(globalInstallFallbackArgs("pnpm", "openclaw@latest")).toBeNull();
|
||||
});
|
||||
|
||||
it("cleans only renamed package directories", async () => {
|
||||
const root = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-update-cleanup-"));
|
||||
await fs.mkdir(path.join(root, ".openclaw-123"), { recursive: true });
|
||||
await fs.mkdir(path.join(root, ".openclaw-456"), { recursive: true });
|
||||
await fs.writeFile(path.join(root, ".openclaw-file"), "nope", "utf8");
|
||||
await fs.mkdir(path.join(root, "openclaw"), { recursive: true });
|
||||
|
||||
await expect(
|
||||
cleanupGlobalRenameDirs({
|
||||
globalRoot: root,
|
||||
packageName: "openclaw",
|
||||
}),
|
||||
).resolves.toEqual({
|
||||
removed: [".openclaw-123", ".openclaw-456"],
|
||||
});
|
||||
await expect(fs.stat(path.join(root, "openclaw"))).resolves.toBeDefined();
|
||||
await expect(fs.stat(path.join(root, ".openclaw-file"))).resolves.toBeDefined();
|
||||
});
|
||||
});
|
||||
Loading…
Reference in New Issue