test(perf): dedupe fixtures and reduce flaky waits

This commit is contained in:
Peter Steinberger
2026-02-22 22:05:49 +00:00
parent b534dfa3e0
commit 7b229decdd
13 changed files with 249 additions and 239 deletions

View File

@@ -2,16 +2,15 @@ import fs from "node:fs/promises";
import path from "node:path";
import { describe, expect, it } from "vitest";
import type { OpenClawConfig } from "../config/config.js";
import { resolveOpenClawAgentDir } from "./agent-paths.js";
import { installModelsConfigTestHooks, withModelsTempHome } from "./models-config.e2e-harness.js";
import { ensureOpenClawModelsJson } from "./models-config.js";
describe("models-config", () => {
installModelsConfigTestHooks();
it("normalizes gemini 3 ids to preview for google providers", async () => {
await withModelsTempHome(async () => {
const { ensureOpenClawModelsJson } = await import("./models-config.js");
const { resolveOpenClawAgentDir } = await import("./agent-paths.js");
const cfg: OpenClawConfig = {
models: {
providers: {

View File

@@ -317,23 +317,12 @@ async function runTurnWithCooldownSeed(params: {
describe("runEmbeddedPiAgent auth profile rotation", () => {
it("rotates for auto-pinned profiles across retryable stream failures", async () => {
const cases = [
{
errorMessage: "rate limit",
sessionKey: "agent:test:auto",
runId: "run:auto",
},
{
errorMessage: "request ended without sending any chunks",
sessionKey: "agent:test:empty-chunk-stream",
runId: "run:empty-chunk-stream",
},
] as const;
for (const testCase of cases) {
const { usageStats } = await runAutoPinnedRotationCase(testCase);
expect(typeof usageStats["openai:p2"]?.lastUsed).toBe("number");
}
const { usageStats } = await runAutoPinnedRotationCase({
errorMessage: "rate limit",
sessionKey: "agent:test:auto",
runId: "run:auto",
});
expect(typeof usageStats["openai:p2"]?.lastUsed).toBe("number");
});
it("rotates on timeout without cooling down the timed-out profile", async () => {

View File

@@ -233,7 +233,7 @@ const runDefaultEmbeddedTurn = async (sessionFile: string, prompt: string, sessi
});
};
describe.concurrent("runEmbeddedPiAgent", () => {
describe("runEmbeddedPiAgent", () => {
it("handles prompt error paths without dropping user state", async () => {
for (const testCase of [
{

View File

@@ -166,10 +166,11 @@ afterAll(async () => {
}
});
beforeEach(() => {
runCommandWithTimeoutMock.mockClear();
scanDirectoryWithSummaryMock.mockClear();
fetchWithSsrFGuardMock.mockClear();
beforeEach(async () => {
runCommandWithTimeoutMock.mockReset();
runCommandWithTimeoutMock.mockResolvedValue(runCommandResult());
scanDirectoryWithSummaryMock.mockReset();
fetchWithSsrFGuardMock.mockReset();
scanDirectoryWithSummaryMock.mockResolvedValue({
scannedFiles: 0,
critical: 0,
@@ -242,10 +243,7 @@ describe("installSkill download extraction safety", () => {
});
it("rejects targetDir escapes outside the per-skill tools root", async () => {
for (const testCase of [
{ name: "targetdir-escape", targetDir: path.join(workspaceDir, "outside") },
{ name: "relative-traversal", targetDir: "../outside" },
]) {
for (const testCase of [{ name: "relative-traversal", targetDir: "../outside" }]) {
mockArchiveResponse(new Uint8Array(SAFE_ZIP_BUFFER));
await writeDownloadSkill({
workspaceDir,
@@ -288,16 +286,6 @@ describe("installSkill download extraction safety", () => {
describe("installSkill download extraction safety (tar.bz2)", () => {
it("handles tar.bz2 extraction safety edge-cases", async () => {
for (const testCase of [
{
label: "rejects traversal before extraction",
name: "tbz2-slip",
url: "https://example.invalid/evil.tbz2",
listOutput: "../outside.txt\n",
verboseListOutput: "-rw-r--r-- 0 0 0 0 Jan 1 00:00 ../outside.txt\n",
extract: "reject" as const,
expectedOk: false,
expectedExtract: false,
},
{
label: "rejects archives containing symlinks",
name: "tbz2-symlink",

View File

@@ -1,14 +1,31 @@
import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { describe, expect, it } from "vitest";
import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { withEnv } from "../test-utils/env.js";
import { writeSkill } from "./skills.e2e-test-helpers.js";
import { buildWorkspaceSkillsPrompt } from "./skills.js";
let fixtureRoot = "";
let fixtureCount = 0;
async function createCaseDir(prefix: string): Promise<string> {
const dir = path.join(fixtureRoot, `${prefix}-${fixtureCount++}`);
await fs.mkdir(dir, { recursive: true });
return dir;
}
beforeAll(async () => {
fixtureRoot = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-skills-prompt-suite-"));
});
afterAll(async () => {
await fs.rm(fixtureRoot, { recursive: true, force: true });
});
describe("buildWorkspaceSkillsPrompt", () => {
it("prefers workspace skills over managed skills", async () => {
const workspaceDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-"));
const workspaceDir = await createCaseDir("workspace");
const managedDir = path.join(workspaceDir, ".managed");
const bundledDir = path.join(workspaceDir, ".bundled");
const managedSkillDir = path.join(managedDir, "demo-skill");
@@ -45,7 +62,7 @@ describe("buildWorkspaceSkillsPrompt", () => {
expect(prompt).not.toContain(path.join(bundledSkillDir, "SKILL.md"));
});
it("gates by bins, config, and always", async () => {
const workspaceDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-"));
const workspaceDir = await createCaseDir("workspace");
const skillsDir = path.join(workspaceDir, "skills");
const binDir = path.join(workspaceDir, "bin");
@@ -80,9 +97,12 @@ describe("buildWorkspaceSkillsPrompt", () => {
metadata: '{"openclaw":{"requires":{"env":["ENV_KEY"]},"primaryEnv":"ENV_KEY"}}',
});
const defaultPrompt = buildWorkspaceSkillsPrompt(workspaceDir, {
managedSkillsDir: path.join(workspaceDir, ".managed"),
});
const managedSkillsDir = path.join(workspaceDir, ".managed");
const defaultPrompt = withEnv({ PATH: "" }, () =>
buildWorkspaceSkillsPrompt(workspaceDir, {
managedSkillsDir,
}),
);
expect(defaultPrompt).toContain("always-skill");
expect(defaultPrompt).toContain("config-skill");
expect(defaultPrompt).not.toContain("bin-skill");
@@ -94,23 +114,23 @@ describe("buildWorkspaceSkillsPrompt", () => {
await fs.writeFile(fakebinPath, "#!/bin/sh\nexit 0\n", "utf-8");
await fs.chmod(fakebinPath, 0o755);
withEnv({ PATH: `${binDir}${path.delimiter}${process.env.PATH ?? ""}` }, () => {
const gatedPrompt = buildWorkspaceSkillsPrompt(workspaceDir, {
managedSkillsDir: path.join(workspaceDir, ".managed"),
const gatedPrompt = withEnv({ PATH: binDir }, () =>
buildWorkspaceSkillsPrompt(workspaceDir, {
managedSkillsDir,
config: {
browser: { enabled: false },
skills: { entries: { "env-skill": { apiKey: "ok" } } },
},
});
expect(gatedPrompt).toContain("bin-skill");
expect(gatedPrompt).toContain("anybin-skill");
expect(gatedPrompt).toContain("env-skill");
expect(gatedPrompt).toContain("always-skill");
expect(gatedPrompt).not.toContain("config-skill");
});
}),
);
expect(gatedPrompt).toContain("bin-skill");
expect(gatedPrompt).toContain("anybin-skill");
expect(gatedPrompt).toContain("env-skill");
expect(gatedPrompt).toContain("always-skill");
expect(gatedPrompt).not.toContain("config-skill");
});
it("uses skillKey for config lookups", async () => {
const workspaceDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-"));
const workspaceDir = await createCaseDir("workspace");
const skillDir = path.join(workspaceDir, "skills", "alias-skill");
await writeSkill({
dir: skillDir,

View File

@@ -1,7 +1,7 @@
import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { describe, expect, it } from "vitest";
import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { withEnv } from "../test-utils/env.js";
import { writeSkill } from "./skills.e2e-test-helpers.js";
import { buildWorkspaceSkillsPrompt, syncSkillsToWorkspace } from "./skills.js";
@@ -15,10 +15,27 @@ async function pathExists(filePath: string): Promise<boolean> {
}
}
let fixtureRoot = "";
let fixtureCount = 0;
async function createCaseDir(prefix: string): Promise<string> {
const dir = path.join(fixtureRoot, `${prefix}-${fixtureCount++}`);
await fs.mkdir(dir, { recursive: true });
return dir;
}
beforeAll(async () => {
fixtureRoot = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-skills-sync-suite-"));
});
afterAll(async () => {
await fs.rm(fixtureRoot, { recursive: true, force: true });
});
describe("buildWorkspaceSkillsPrompt", () => {
it("syncs merged skills into a target workspace", async () => {
const sourceWorkspace = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-"));
const targetWorkspace = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-"));
const sourceWorkspace = await createCaseDir("source");
const targetWorkspace = await createCaseDir("target");
const extraDir = path.join(sourceWorkspace, ".extra");
const bundledDir = path.join(sourceWorkspace, ".bundled");
const managedDir = path.join(sourceWorkspace, ".managed");
@@ -64,9 +81,9 @@ describe("buildWorkspaceSkillsPrompt", () => {
expect(prompt).toContain(path.join(targetWorkspace, "skills", "demo-skill", "SKILL.md"));
});
it("keeps synced skills confined under target workspace when frontmatter name uses traversal", async () => {
const sourceWorkspace = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-"));
const targetWorkspace = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-"));
const escapeId = `${Date.now()}-${process.pid}-${Math.random().toString(16).slice(2)}`;
const sourceWorkspace = await createCaseDir("source");
const targetWorkspace = await createCaseDir("target");
const escapeId = fixtureCount;
const traversalName = `../../../skill-sync-escape-${escapeId}`;
const escapedDest = path.resolve(targetWorkspace, "skills", traversalName);
@@ -94,9 +111,9 @@ describe("buildWorkspaceSkillsPrompt", () => {
expect(await pathExists(escapedDest)).toBe(false);
});
it("keeps synced skills confined under target workspace when frontmatter name is absolute", async () => {
const sourceWorkspace = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-"));
const targetWorkspace = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-"));
const escapeId = `${Date.now()}-${process.pid}-${Math.random().toString(16).slice(2)}`;
const sourceWorkspace = await createCaseDir("source");
const targetWorkspace = await createCaseDir("target");
const escapeId = fixtureCount;
const absoluteDest = path.join(os.tmpdir(), `skill-sync-abs-escape-${escapeId}`);
await fs.rm(absoluteDest, { recursive: true, force: true });
@@ -121,7 +138,7 @@ describe("buildWorkspaceSkillsPrompt", () => {
expect(await pathExists(absoluteDest)).toBe(false);
});
it("filters skills based on env/config gates", async () => {
const workspaceDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-"));
const workspaceDir = await createCaseDir("workspace");
const skillDir = path.join(workspaceDir, "skills", "nano-banana-pro");
await writeSkill({
dir: skillDir,
@@ -149,7 +166,7 @@ describe("buildWorkspaceSkillsPrompt", () => {
});
});
it("applies skill filters, including empty lists", async () => {
const workspaceDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-"));
const workspaceDir = await createCaseDir("workspace");
await writeSkill({
dir: path.join(workspaceDir, "skills", "alpha"),
name: "alpha",