diff --git a/packages/producer/src/regression-harness-parse.test.ts b/packages/producer/src/regression-harness-parse.test.ts index ae7ba39337..a27505a451 100644 --- a/packages/producer/src/regression-harness-parse.test.ts +++ b/packages/producer/src/regression-harness-parse.test.ts @@ -6,7 +6,10 @@ // must move together. import { describe, expect, it } from "bun:test"; -import { parseArgs } from "./regression-harness.js"; +import { mkdtempSync, mkdirSync, readFileSync, rmSync, statSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { createRegressionTempRoot, parseArgs } from "./regression-harness.js"; // parseArgs reads from index 2 onwards (node + script name are argv[0..1]). const withProgram = (rest: string[]): string[] => ["node", "regression-harness.ts", ...rest]; @@ -52,3 +55,29 @@ describe("parseArgs() — --exclude-tags", () => { expect(opts.excludeTags).toEqual([]); }); }); + +describe("regression temporary roots", () => { + it("isolates repeated suite runs and preserves the old predictable directory", () => { + const parent = mkdtempSync(join(tmpdir(), "hf-root-test-")); + try { + const legacy = join(parent, "hyperframes-tests", "same-suite"); + mkdirSync(legacy, { recursive: true }); + const sentinel = join(legacy, "keep.txt"); + writeFileSync(sentinel, "unrelated data"); + const first = createRegressionTempRoot("same-suite", parent); + const second = createRegressionTempRoot("same-suite", parent); + expect(first).not.toBe(second); + expect(first).not.toBe(legacy); + if (process.platform !== "win32") { + expect(statSync(first).mode & 0o777).toBe(0o700); + expect(statSync(second).mode & 0o777).toBe(0o700); + } + expect(readFileSync(sentinel, "utf8")).toBe("unrelated data"); + rmSync(first, { recursive: true, force: true }); + expect(statSync(second).isDirectory()).toBe(true); + expect(readFileSync(sentinel, "utf8")).toBe("unrelated data"); + } finally { + rmSync(parent, { recursive: true, force: true }); + } + }); +}); diff --git a/packages/producer/src/regression-harness.ts b/packages/producer/src/regression-harness.ts index f18fc16ec5..57eee5c9da 100644 --- a/packages/producer/src/regression-harness.ts +++ b/packages/producer/src/regression-harness.ts @@ -963,6 +963,10 @@ export async function checkStreamDurationParity( // ── Test Execution ─────────────────────────────────────────────────────────── +export function createRegressionTempRoot(suiteId: string, parent: string = tmpdir()): string { + return mkdtempSync(join(parent, `hyperframes-test-${suiteId}-`)); +} + async function runTestSuite( suite: TestSuite, options: { @@ -971,17 +975,7 @@ async function runTestSuite( mode: HarnessMode; }, ): Promise { - // Use predictable temp location: /tmp/hyperframes-tests/{test-id}/ - const testsRoot = join(tmpdir(), "hyperframes-tests"); - if (!existsSync(testsRoot)) { - mkdirSync(testsRoot, { recursive: true }); - } - - const tempRoot = join(testsRoot, suite.id); - if (existsSync(tempRoot)) { - rmSync(tempRoot, { recursive: true, force: true }); - } - mkdirSync(tempRoot, { recursive: true }); + const tempRoot = createRegressionTempRoot(suite.id); const tempDownloadDir = join(tempRoot, "downloads"); const outputFormat = suite.meta.renderConfig.format ?? "mp4"; diff --git a/packages/producer/src/services/render/stages/captureStreamingStage.test.ts b/packages/producer/src/services/render/stages/captureStreamingStage.test.ts index 80ed36203b..66dca5fbc3 100644 --- a/packages/producer/src/services/render/stages/captureStreamingStage.test.ts +++ b/packages/producer/src/services/render/stages/captureStreamingStage.test.ts @@ -1,5 +1,12 @@ // fallow-ignore-file code-duplication -import { describe, expect, it, mock } from "bun:test"; +import { afterAll, describe, expect, it, mock } from "bun:test"; +import { mkdtempSync, rmSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; + +const fixtureRoot = mkdtempSync(join(tmpdir(), "hf-stage-test-")); +const framesDir = join(fixtureRoot, "frames"); +afterAll(() => rmSync(fixtureRoot, { recursive: true, force: true })); import { getCaptureStageBrowserConsole } from "../captureStageError.js"; import { createCapturePlan } from "../capturePlan.js"; @@ -191,7 +198,7 @@ function createInput(cfg: MinimalEngineConfig) { addPreHeadScript: () => {}, }, workDir: "/tmp/hf-test-work", - framesDir: "/tmp/hf-test-frames", + framesDir: framesDir, videoOnlyPath: "/tmp/hf-test-video-only.mp4", job: { id: "streaming-config-test", @@ -487,7 +494,7 @@ describe("runCaptureStage", () => { const cfg = { forceScreenshot: false, ffmpegStreamingTimeout: 3_600_000 }; const probeSession = await createCaptureSession( "http://127.0.0.1:4173", - "/tmp/hf-test-frames", + framesDir, {}, null, cfg, @@ -599,7 +606,7 @@ describe("runCaptureHdrStage", () => { }, projectDir: "/tmp/hf-test-project", compiledDir: "/tmp/hf-test-compiled", - framesDir: "/tmp/hf-test-frames", + framesDir: framesDir, videoOnlyPath: "/tmp/hf-test-video-only.mp4", width: 1920, height: 1080, diff --git a/packages/producer/src/services/render/stages/probeStage.test.ts b/packages/producer/src/services/render/stages/probeStage.test.ts index 79721a7d91..b6ee9e5ed3 100644 --- a/packages/producer/src/services/render/stages/probeStage.test.ts +++ b/packages/producer/src/services/render/stages/probeStage.test.ts @@ -1,4 +1,10 @@ -import { describe, expect, it, mock } from "bun:test"; +import { afterAll, describe, expect, it, mock } from "bun:test"; +import { mkdtempSync, rmSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; + +const workDir = mkdtempSync(join(tmpdir(), "hf-stage-test-")); +afterAll(() => rmSync(workDir, { recursive: true, force: true })); import { createHash } from "node:crypto"; import { hasAutoStartVideos, @@ -239,7 +245,7 @@ function makeProbeInput(overrides: { return { projectDir: "/tmp/hf-probe-test-project", - workDir: "/tmp/hf-probe-test-work", + workDir: workDir, job: { id: "probe-test", config: { fps: { num: 30, den: 1 }, quality: "standard" },