mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-12 07:20:45 +00:00
test(perf): trim fixture churn in install and cron suites
This commit is contained in:
@@ -36,6 +36,7 @@ vi.mock("../infra/net/fetch-guard.js", () => ({
|
||||
installGatewayTestHooks({ scope: "suite" });
|
||||
const CRON_WAIT_INTERVAL_MS = 5;
|
||||
const CRON_WAIT_TIMEOUT_MS = 3_000;
|
||||
const EMPTY_CRON_STORE_CONTENT = JSON.stringify({ version: 1, jobs: [] });
|
||||
let cronSuiteTempRootPromise: Promise<string> | null = null;
|
||||
let cronSuiteCaseId = 0;
|
||||
|
||||
@@ -79,10 +80,20 @@ async function waitForCondition(check: () => boolean | Promise<boolean>, timeout
|
||||
);
|
||||
}
|
||||
|
||||
async function createCronCasePaths(tempPrefix: string): Promise<{
|
||||
dir: string;
|
||||
storePath: string;
|
||||
}> {
|
||||
const suiteRoot = await getCronSuiteTempRoot();
|
||||
const dir = path.join(suiteRoot, `${tempPrefix}${cronSuiteCaseId++}`);
|
||||
const storePath = path.join(dir, "cron", "jobs.json");
|
||||
await fs.mkdir(path.dirname(storePath), { recursive: true });
|
||||
return { dir, storePath };
|
||||
}
|
||||
|
||||
async function cleanupCronTestRun(params: {
|
||||
ws: { close: () => void };
|
||||
server: { close: () => Promise<void> };
|
||||
dir: string;
|
||||
prevSkipCron: string | undefined;
|
||||
clearSessionConfig?: boolean;
|
||||
}) {
|
||||
@@ -108,16 +119,13 @@ async function setupCronTestRun(params: {
|
||||
}): Promise<{ prevSkipCron: string | undefined; dir: string }> {
|
||||
const prevSkipCron = process.env.OPENCLAW_SKIP_CRON;
|
||||
process.env.OPENCLAW_SKIP_CRON = "0";
|
||||
const suiteRoot = await getCronSuiteTempRoot();
|
||||
const dir = path.join(suiteRoot, `${params.tempPrefix}${cronSuiteCaseId++}`);
|
||||
await fs.mkdir(dir, { recursive: true });
|
||||
testState.cronStorePath = path.join(dir, "cron", "jobs.json");
|
||||
const { dir, storePath } = await createCronCasePaths(params.tempPrefix);
|
||||
testState.cronStorePath = storePath;
|
||||
testState.sessionConfig = params.sessionConfig;
|
||||
testState.cronEnabled = params.cronEnabled;
|
||||
await fs.mkdir(path.dirname(testState.cronStorePath), { recursive: true });
|
||||
await fs.writeFile(
|
||||
testState.cronStorePath,
|
||||
JSON.stringify({ version: 1, jobs: params.jobs ?? [] }),
|
||||
params.jobs ? JSON.stringify({ version: 1, jobs: params.jobs }) : EMPTY_CRON_STORE_CONTENT,
|
||||
);
|
||||
return { prevSkipCron, dir };
|
||||
}
|
||||
@@ -138,7 +146,7 @@ describe("gateway server cron", () => {
|
||||
});
|
||||
|
||||
test("handles cron CRUD, normalization, and patch semantics", { timeout: 20_000 }, async () => {
|
||||
const { prevSkipCron, dir } = await setupCronTestRun({
|
||||
const { prevSkipCron } = await setupCronTestRun({
|
||||
tempPrefix: "openclaw-gw-cron-",
|
||||
sessionConfig: { mainKey: "primary" },
|
||||
cronEnabled: false,
|
||||
@@ -403,7 +411,6 @@ describe("gateway server cron", () => {
|
||||
await cleanupCronTestRun({
|
||||
ws,
|
||||
server,
|
||||
dir,
|
||||
prevSkipCron,
|
||||
clearSessionConfig: true,
|
||||
});
|
||||
@@ -514,7 +521,7 @@ describe("gateway server cron", () => {
|
||||
const runs = autoEntries?.entries ?? [];
|
||||
expect(runs.at(-1)?.jobId).toBe(autoJobId);
|
||||
} finally {
|
||||
await cleanupCronTestRun({ ws, server, dir, prevSkipCron });
|
||||
await cleanupCronTestRun({ ws, server, prevSkipCron });
|
||||
}
|
||||
}, 45_000);
|
||||
|
||||
@@ -532,7 +539,7 @@ describe("gateway server cron", () => {
|
||||
payload: { kind: "systemEvent", text: "legacy webhook" },
|
||||
state: {},
|
||||
};
|
||||
const { prevSkipCron, dir } = await setupCronTestRun({
|
||||
const { prevSkipCron } = await setupCronTestRun({
|
||||
tempPrefix: "openclaw-gw-cron-webhook-",
|
||||
cronEnabled: false,
|
||||
jobs: [legacyNotifyJob],
|
||||
@@ -741,7 +748,7 @@ describe("gateway server cron", () => {
|
||||
await yieldToEventLoop();
|
||||
expect(fetchWithSsrFGuardMock).toHaveBeenCalledTimes(1);
|
||||
} finally {
|
||||
await cleanupCronTestRun({ ws, server, dir, prevSkipCron });
|
||||
await cleanupCronTestRun({ ws, server, prevSkipCron });
|
||||
}
|
||||
}, 60_000);
|
||||
});
|
||||
|
||||
@@ -29,6 +29,34 @@ const archiveFixturePathCache = new Map<string, string>();
|
||||
const dynamicArchiveTemplatePathCache = new Map<string, string>();
|
||||
let installPluginFromDirTemplateDir = "";
|
||||
let manifestInstallTemplateDir = "";
|
||||
const DYNAMIC_ARCHIVE_TEMPLATE_PRESETS = [
|
||||
{
|
||||
outName: "traversal.tgz",
|
||||
withDistIndex: true,
|
||||
packageJson: {
|
||||
name: "@evil/..",
|
||||
version: "0.0.1",
|
||||
openclaw: { extensions: ["./dist/index.js"] },
|
||||
} as Record<string, unknown>,
|
||||
},
|
||||
{
|
||||
outName: "reserved.tgz",
|
||||
withDistIndex: true,
|
||||
packageJson: {
|
||||
name: "@evil/.",
|
||||
version: "0.0.1",
|
||||
openclaw: { extensions: ["./dist/index.js"] },
|
||||
} as Record<string, unknown>,
|
||||
},
|
||||
{
|
||||
outName: "bad.tgz",
|
||||
withDistIndex: false,
|
||||
packageJson: {
|
||||
name: "@openclaw/nope",
|
||||
version: "0.0.1",
|
||||
} as Record<string, unknown>,
|
||||
},
|
||||
];
|
||||
|
||||
function ensureSuiteTempRoot() {
|
||||
if (suiteTempRoot) {
|
||||
@@ -41,7 +69,7 @@ function ensureSuiteTempRoot() {
|
||||
function makeTempDir() {
|
||||
const dir = path.join(ensureSuiteTempRoot(), `case-${String(tempDirCounter)}`);
|
||||
tempDirCounter += 1;
|
||||
fs.mkdirSync(dir, { recursive: true });
|
||||
fs.mkdirSync(dir);
|
||||
return dir;
|
||||
}
|
||||
|
||||
@@ -157,8 +185,10 @@ function setupPluginInstallDirs() {
|
||||
}
|
||||
|
||||
function setupInstallPluginFromDirFixture(params?: { devDependencies?: Record<string, string> }) {
|
||||
const stateDir = makeTempDir();
|
||||
const pluginDir = path.join(makeTempDir(), "plugin");
|
||||
const caseDir = makeTempDir();
|
||||
const stateDir = path.join(caseDir, "state");
|
||||
const pluginDir = path.join(caseDir, "plugin");
|
||||
fs.mkdirSync(stateDir, { recursive: true });
|
||||
fs.cpSync(installPluginFromDirTemplateDir, pluginDir, { recursive: true });
|
||||
if (params?.devDependencies) {
|
||||
const packageJsonPath = path.join(pluginDir, "package.json");
|
||||
@@ -185,8 +215,10 @@ async function installFromDirWithWarnings(params: { pluginDir: string; extension
|
||||
}
|
||||
|
||||
function setupManifestInstallFixture(params: { manifestId: string }) {
|
||||
const stateDir = makeTempDir();
|
||||
const pluginDir = path.join(makeTempDir(), "plugin-src");
|
||||
const caseDir = makeTempDir();
|
||||
const stateDir = path.join(caseDir, "state");
|
||||
const pluginDir = path.join(caseDir, "plugin-src");
|
||||
fs.mkdirSync(stateDir, { recursive: true });
|
||||
fs.cpSync(manifestInstallTemplateDir, pluginDir, { recursive: true });
|
||||
fs.writeFileSync(
|
||||
path.join(pluginDir, "openclaw.plugin.json"),
|
||||
@@ -226,31 +258,11 @@ async function installArchivePackageAndReturnResult(params: {
|
||||
withDistIndex?: boolean;
|
||||
}) {
|
||||
const stateDir = makeTempDir();
|
||||
const templateKey = JSON.stringify({
|
||||
const archivePath = await ensureDynamicArchiveTemplate({
|
||||
outName: params.outName,
|
||||
packageJson: params.packageJson,
|
||||
withDistIndex: params.withDistIndex === true,
|
||||
});
|
||||
let archivePath = dynamicArchiveTemplatePathCache.get(templateKey);
|
||||
if (!archivePath) {
|
||||
const templateDir = makeTempDir();
|
||||
const pkgDir = path.join(templateDir, "package");
|
||||
fs.mkdirSync(pkgDir, { recursive: true });
|
||||
if (params.withDistIndex) {
|
||||
fs.mkdirSync(path.join(pkgDir, "dist"), { recursive: true });
|
||||
fs.writeFileSync(path.join(pkgDir, "dist", "index.js"), "export {};", "utf-8");
|
||||
}
|
||||
fs.writeFileSync(
|
||||
path.join(pkgDir, "package.json"),
|
||||
JSON.stringify(params.packageJson),
|
||||
"utf-8",
|
||||
);
|
||||
archivePath = await packToArchive({
|
||||
pkgDir,
|
||||
outDir: ensureSuiteFixtureRoot(),
|
||||
outName: params.outName,
|
||||
});
|
||||
dynamicArchiveTemplatePathCache.set(templateKey, archivePath);
|
||||
}
|
||||
|
||||
const extensionsDir = path.join(stateDir, "extensions");
|
||||
const result = await installPluginFromArchive({
|
||||
@@ -260,6 +272,46 @@ async function installArchivePackageAndReturnResult(params: {
|
||||
return result;
|
||||
}
|
||||
|
||||
function buildDynamicArchiveTemplateKey(params: {
|
||||
packageJson: Record<string, unknown>;
|
||||
withDistIndex: boolean;
|
||||
}): string {
|
||||
return JSON.stringify({
|
||||
packageJson: params.packageJson,
|
||||
withDistIndex: params.withDistIndex,
|
||||
});
|
||||
}
|
||||
|
||||
async function ensureDynamicArchiveTemplate(params: {
|
||||
packageJson: Record<string, unknown>;
|
||||
outName: string;
|
||||
withDistIndex: boolean;
|
||||
}): Promise<string> {
|
||||
const templateKey = buildDynamicArchiveTemplateKey({
|
||||
packageJson: params.packageJson,
|
||||
withDistIndex: params.withDistIndex,
|
||||
});
|
||||
const cachedPath = dynamicArchiveTemplatePathCache.get(templateKey);
|
||||
if (cachedPath) {
|
||||
return cachedPath;
|
||||
}
|
||||
const templateDir = makeTempDir();
|
||||
const pkgDir = path.join(templateDir, "package");
|
||||
fs.mkdirSync(pkgDir, { recursive: true });
|
||||
if (params.withDistIndex) {
|
||||
fs.mkdirSync(path.join(pkgDir, "dist"), { recursive: true });
|
||||
fs.writeFileSync(path.join(pkgDir, "dist", "index.js"), "export {};", "utf-8");
|
||||
}
|
||||
fs.writeFileSync(path.join(pkgDir, "package.json"), JSON.stringify(params.packageJson), "utf-8");
|
||||
const archivePath = await packToArchive({
|
||||
pkgDir,
|
||||
outDir: ensureSuiteFixtureRoot(),
|
||||
outName: params.outName,
|
||||
});
|
||||
dynamicArchiveTemplatePathCache.set(templateKey, archivePath);
|
||||
return archivePath;
|
||||
}
|
||||
|
||||
afterAll(() => {
|
||||
if (!suiteTempRoot) {
|
||||
return;
|
||||
@@ -327,6 +379,14 @@ beforeAll(async () => {
|
||||
}),
|
||||
"utf-8",
|
||||
);
|
||||
|
||||
for (const preset of DYNAMIC_ARCHIVE_TEMPLATE_PRESETS) {
|
||||
await ensureDynamicArchiveTemplate({
|
||||
packageJson: preset.packageJson,
|
||||
outName: preset.outName,
|
||||
withDistIndex: preset.withDistIndex,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
|
||||
Reference in New Issue
Block a user