import fs from "node:fs"; import path from "node:path"; import { describe, expect, it } from "vitest"; import { createExecutionArtifacts, resolvePnpmCommandInvocation, } from "../../scripts/test-planner/executor.mjs"; import { buildCIExecutionManifest, buildExecutionPlan, explainExecutionTarget, } from "../../scripts/test-planner/planner.mjs"; describe("test planner", () => { it("builds a capability-aware plan for mid-memory local runs", () => { const artifacts = createExecutionArtifacts({ RUNNER_OS: "macOS", OPENCLAW_TEST_HOST_CPU_COUNT: "10", OPENCLAW_TEST_HOST_MEMORY_GIB: "64", OPENCLAW_TEST_LOAD_AWARE: "0", }); const plan = buildExecutionPlan( { profile: null, mode: "local", surfaces: ["unit", "extensions"], passthroughArgs: [], }, { env: { RUNNER_OS: "macOS", OPENCLAW_TEST_HOST_CPU_COUNT: "10", OPENCLAW_TEST_HOST_MEMORY_GIB: "64", OPENCLAW_TEST_LOAD_AWARE: "0", }, platform: "darwin", writeTempJsonArtifact: artifacts.writeTempJsonArtifact, }, ); expect(plan.runtimeCapabilities.runtimeProfileName).toBe("local-darwin"); expect(plan.runtimeCapabilities.memoryBand).toBe("mid"); expect(plan.executionBudget.unitSharedWorkers).toBe(4); expect(plan.executionBudget.topLevelParallelLimitNoIsolate).toBe(8); expect(plan.executionBudget.topLevelParallelLimitIsolated).toBe(3); expect(plan.selectedUnits.some((unit) => unit.id.startsWith("unit-fast"))).toBe(true); expect(plan.selectedUnits.some((unit) => unit.id.startsWith("extensions"))).toBe(true); expect(plan.topLevelParallelLimit).toBe(8); artifacts.cleanupTempArtifacts(); }); it("scales down mid-tier local concurrency under saturated load", () => { const artifacts = createExecutionArtifacts({ RUNNER_OS: "Linux", OPENCLAW_TEST_HOST_CPU_COUNT: "10", OPENCLAW_TEST_HOST_MEMORY_GIB: "64", }); const plan = buildExecutionPlan( { profile: null, mode: "local", surfaces: ["unit", "extensions"], passthroughArgs: [], }, { env: { RUNNER_OS: "Linux", OPENCLAW_TEST_HOST_CPU_COUNT: "10", OPENCLAW_TEST_HOST_MEMORY_GIB: "64", }, platform: "linux", loadAverage: [11.5, 11.5, 11.5], writeTempJsonArtifact: artifacts.writeTempJsonArtifact, }, ); expect(plan.runtimeCapabilities.memoryBand).toBe("mid"); expect(plan.runtimeCapabilities.loadBand).toBe("saturated"); expect(plan.executionBudget.unitSharedWorkers).toBe(2); expect(plan.executionBudget.topLevelParallelLimitNoIsolate).toBe(4); expect(plan.executionBudget.topLevelParallelLimitIsolated).toBe(1); expect(plan.topLevelParallelLimit).toBe(4); expect(plan.deferredRunConcurrency).toBe(1); artifacts.cleanupTempArtifacts(); }); it("honors the max-profile top-level no-isolate cap without adding extra lanes", () => { const artifacts = createExecutionArtifacts({ RUNNER_OS: "Linux", OPENCLAW_TEST_HOST_CPU_COUNT: "16", OPENCLAW_TEST_HOST_MEMORY_GIB: "128", OPENCLAW_TEST_LOAD_AWARE: "0", OPENCLAW_TEST_PROFILE: "max", }); const plan = buildExecutionPlan( { profile: "max", mode: "local", surfaces: ["unit", "extensions"], passthroughArgs: [], }, { env: { RUNNER_OS: "Linux", OPENCLAW_TEST_HOST_CPU_COUNT: "16", OPENCLAW_TEST_HOST_MEMORY_GIB: "128", OPENCLAW_TEST_LOAD_AWARE: "0", OPENCLAW_TEST_PROFILE: "max", }, platform: "linux", writeTempJsonArtifact: artifacts.writeTempJsonArtifact, }, ); expect(plan.runtimeCapabilities.intentProfile).toBe("max"); expect(plan.executionBudget.topLevelParallelLimitNoIsolate).toBe(8); expect(plan.topLevelParallelLimit).toBe(8); artifacts.cleanupTempArtifacts(); }); it("splits mixed targeted file selections across surfaces", () => { const artifacts = createExecutionArtifacts({}); const plan = buildExecutionPlan( { mode: "local", surfaces: [], passthroughArgs: [ "src/auto-reply/reply/followup-runner.test.ts", "extensions/discord/src/monitor/message-handler.preflight.acp-bindings.test.ts", ], }, { env: {}, writeTempJsonArtifact: artifacts.writeTempJsonArtifact, }, ); expect(plan.targetedUnits).toHaveLength(2); expect( plan.targetedUnits .map((unit) => unit.surface) .toSorted((left, right) => left.localeCompare(right)), ).toEqual(["base", "channels"]); artifacts.cleanupTempArtifacts(); }); it("explains runtime truth using the same catalog and worker policy", () => { const explanation = explainExecutionTarget( { mode: "local", fileFilters: ["src/auto-reply/reply/followup-runner.test.ts"], }, { env: {}, }, ); expect(explanation.surface).toBe("base"); expect(explanation.pool).toBe("forks"); expect(explanation.reasons).toContain("base-pinned-manifest"); expect(explanation.intentProfile).toBe("normal"); }); it("uses hotspot-backed memory isolation when explaining unit tests", () => { const explanation = explainExecutionTarget( { mode: "local", fileFilters: ["src/infra/outbound/targets.channel-resolution.test.ts"], }, { env: { OPENCLAW_TEST_LOAD_AWARE: "0", }, }, ); expect(explanation.isolate).toBe(true); expect(explanation.reasons).toContain("unit-memory-isolated"); }); it("normalizes absolute explain targets before classification", () => { const relativeExplanation = explainExecutionTarget( { mode: "local", fileFilters: ["src/infra/outbound/targets.channel-resolution.test.ts"], }, { env: { OPENCLAW_TEST_LOAD_AWARE: "0", }, }, ); const absoluteExplanation = explainExecutionTarget( { mode: "local", fileFilters: [ path.join(process.cwd(), "src/infra/outbound/targets.channel-resolution.test.ts"), ], }, { env: { OPENCLAW_TEST_LOAD_AWARE: "0", }, }, ); expect(absoluteExplanation.file).toBe(relativeExplanation.file); expect(absoluteExplanation.surface).toBe(relativeExplanation.surface); expect(absoluteExplanation.pool).toBe(relativeExplanation.pool); expect(absoluteExplanation.isolate).toBe(relativeExplanation.isolate); expect(absoluteExplanation.reasons).toEqual(relativeExplanation.reasons); }); it("does not leak default-plan shard assignments into targeted units with the same id", () => { const artifacts = createExecutionArtifacts({}); const plan = buildExecutionPlan( { mode: "local", fileFilters: ["src/cli/qr-dashboard.integration.test.ts"], passthroughArgs: [], }, { env: { OPENCLAW_TEST_SHARDS: "4", OPENCLAW_TEST_SHARD_INDEX: "2", OPENCLAW_TEST_LOAD_AWARE: "0", }, writeTempJsonArtifact: artifacts.writeTempJsonArtifact, }, ); const targetedUnit = plan.targetedUnits.at(0); const defaultUnitWithSameId = plan.allUnits.find((unit) => unit.id === targetedUnit?.id); expect(targetedUnit).toBeTruthy(); expect(defaultUnitWithSameId).toBeTruthy(); expect(defaultUnitWithSameId).not.toBe(targetedUnit); expect(plan.topLevelSingleShardAssignments.get(targetedUnit)).toBeUndefined(); expect(plan.topLevelSingleShardAssignments.get(defaultUnitWithSameId)).toBeDefined(); artifacts.cleanupTempArtifacts(); }); it("removes planner temp artifacts when cleanup runs after planning", () => { const artifacts = createExecutionArtifacts({}); buildExecutionPlan( { mode: "local", surfaces: ["unit"], passthroughArgs: [], }, { env: {}, writeTempJsonArtifact: artifacts.writeTempJsonArtifact, }, ); const artifactDir = artifacts.ensureTempArtifactDir(); expect(fs.existsSync(artifactDir)).toBe(true); artifacts.cleanupTempArtifacts(); expect(fs.existsSync(artifactDir)).toBe(false); }); it("builds a CI manifest with planner-owned shard counts and matrices", () => { const manifest = buildCIExecutionManifest( { eventName: "pull_request", docsOnly: false, docsChanged: false, runNode: true, runMacos: true, runAndroid: true, runWindows: true, runSkillsPython: false, hasChangedExtensions: true, changedExtensionsMatrix: { include: [{ extension: "discord" }] }, }, { env: {}, }, ); expect(manifest.jobs.buildArtifacts.enabled).toBe(true); expect(manifest.shardCounts.unit).toBe(4); expect(manifest.shardCounts.channels).toBe(3); expect(manifest.shardCounts.windows).toBe(6); expect(manifest.shardCounts.macosNode).toBe(9); expect(manifest.jobs.checks.matrix.include).toHaveLength(7); expect(manifest.jobs.checksWindows.matrix.include).toHaveLength(6); expect(manifest.jobs.macosNode.matrix.include).toHaveLength(9); expect(manifest.jobs.macosSwift.enabled).toBe(true); expect(manifest.requiredCheckNames).toContain("macos-swift"); expect(manifest.requiredCheckNames).not.toContain("macos-swift-lint"); expect(manifest.requiredCheckNames).not.toContain("macos-swift-build"); expect(manifest.requiredCheckNames).not.toContain("macos-swift-test"); expect(manifest.jobs.extensionFast.matrix.include).toEqual([ { check_name: "extension-fast-discord", extension: "discord" }, ]); }); it("suppresses heavy CI jobs in docs-only manifests", () => { const manifest = buildCIExecutionManifest( { eventName: "pull_request", docsOnly: true, docsChanged: true, runNode: false, runMacos: false, runAndroid: false, runWindows: false, runSkillsPython: false, hasChangedExtensions: false, }, { env: {}, }, ); expect(manifest.jobs.buildArtifacts.enabled).toBe(false); expect(manifest.jobs.checks.enabled).toBe(false); expect(manifest.jobs.checksWindows.enabled).toBe(false); expect(manifest.jobs.macosNode.enabled).toBe(false); expect(manifest.jobs.checkDocs.enabled).toBe(true); }); it("adds push-only compat and release lanes to push manifests", () => { const manifest = buildCIExecutionManifest( { eventName: "push", docsOnly: false, docsChanged: false, runNode: true, runMacos: false, runAndroid: false, runWindows: false, runSkillsPython: false, hasChangedExtensions: false, }, { env: {}, }, ); expect(manifest.jobs.releaseCheck.enabled).toBe(true); expect( manifest.jobs.checks.matrix.include.some((entry) => entry.task === "compat-node22"), ).toBe(true); }); }); describe("resolvePnpmCommandInvocation", () => { it("prefers the parent pnpm CLI path when npm_execpath points to pnpm", () => { expect( resolvePnpmCommandInvocation({ npmExecPath: "/opt/homebrew/lib/node_modules/corepack/dist/pnpm.cjs", nodeExecPath: "/usr/local/bin/node", platform: "linux", }), ).toEqual({ command: "/usr/local/bin/node", args: ["/opt/homebrew/lib/node_modules/corepack/dist/pnpm.cjs"], }); }); it("falls back to cmd.exe mediation on Windows when npm_execpath is unavailable", () => { expect( resolvePnpmCommandInvocation({ npmExecPath: "", platform: "win32", comSpec: "C:\\Windows\\System32\\cmd.exe", }), ).toEqual({ command: "C:\\Windows\\System32\\cmd.exe", args: ["/d", "/s", "/c", "pnpm.cmd"], }); }); });