mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-03 12:54:29 +00:00
test(producer): extract frameDirMaxIndexCache to its own module and pin cross-job isolation (#381)
## Summary Extract the `frameDirMaxIndexCache` from a private module-scoped Map inside `renderOrchestrator.ts` into its own `frameDirCache.ts` module, then add a 11-test bun:test suite that pins the cross-job isolation contract added in Chunk 5B. ## Why `Chunk 9E` of `plans/hdr-followups.md`. The cache lived as a private Map inside `renderOrchestrator.ts`, which made the cross-job isolation contract from Chunk 5B impossible to unit-test directly. Extracting it both makes the contract testable and reduces orchestrator complexity slightly. ## What changed - New `packages/producer/src/services/frameDirCache.ts` exposes `getMaxFrameIndex` / `clearMaxFrameIndex` / `getMaxFrameIndexCacheSize` (plus a test-only `__resetMaxFrameIndexCacheForTests` helper). Behavior is unchanged: callers still get the same module-scoped sharing inside a job, and `renderOrchestrator`'s outer `finally` still clears every entry it registered so the cache cannot grow monotonically across renders. - `renderOrchestrator.ts`: imports the new helpers, drops the unused `readdirSync` import, updates inline comments, and replaces two `frameDirMaxIndexCache.delete` sites with `clearMaxFrameIndex`. - New `frameDirCache.test.ts` (bun:test, 11 tests) covering: - Reading the max index from a populated directory. - Ignoring filenames that don't match `frame_NNNN.png` (wrong ext, wrong prefix, wrong case, double extension, empty index group, same-named subdirectory). - Empty- and missing-directory paths returning `0` and being cached. - Intra-job invariant: subsequent readdir mutations not observed once cached. - `clearMaxFrameIndex` forcing a re-read; returns `false` for paths that were never cached. - Per-directory isolation when multiple directories are registered. - The cross-job contract from Chunk 5B: cache empty between well-behaved jobs, doesn't grow monotonically across 20 simulated renders with 3 HDR videos each (steady-state cache size stays at 3), and a buggy job that forgets to clear leaks exactly its own entries rather than affecting unrelated jobs. ## Test plan - [x] `frameDirCache.test.ts` 11/11 pass. - [x] Existing producer tests unchanged. - [x] Behavior preserved: same module-scoped sharing inside a job, same outer-`finally` eviction. ## Stack Chunk 9E of `plans/hdr-followups.md`. Test-driven extraction; complements Chunk 5B.
This commit is contained in:
@@ -2,13 +2,17 @@ import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import { createServer, type Server } from "node:net";
|
||||
import { PORT_PROBE_HOSTS, testPortOnAllHosts } from "./portUtils.js";
|
||||
|
||||
// High-ephemeral range with runway so parallel test shards don't collide.
|
||||
const BASE = 45_000;
|
||||
|
||||
const openServers: Server[] = [];
|
||||
|
||||
function allocFreePort(): number {
|
||||
return BASE + Math.floor(Math.random() * 1_000);
|
||||
async function allocFreePort(): Promise<number> {
|
||||
const srv = createServer();
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
srv.once("error", reject);
|
||||
srv.listen(0, "127.0.0.1", () => resolve());
|
||||
});
|
||||
const port = (srv.address() as import("node:net").AddressInfo).port;
|
||||
await new Promise<void>((resolve) => srv.close(() => resolve()));
|
||||
return port;
|
||||
}
|
||||
|
||||
afterEach(async () => {
|
||||
@@ -31,13 +35,13 @@ describe("testPortOnAllHosts — real-socket behaviour (OS-dependent)", () => {
|
||||
// regression gate.
|
||||
|
||||
it("returns true for a genuinely free port (regression: #309)", async () => {
|
||||
const port = allocFreePort();
|
||||
const port = await allocFreePort();
|
||||
const result = await testPortOnAllHosts(port);
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it("returns false when the port is occupied on 0.0.0.0", async () => {
|
||||
const port = allocFreePort();
|
||||
const port = await allocFreePort();
|
||||
const blocker = createServer();
|
||||
openServers.push(blocker);
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
|
||||
Reference in New Issue
Block a user