test(FN-4954): cover pool double-lease throw and fresh fallback

Fusion-Task-Id: FN-4954
Fusion-Task-Lineage: b3dd2d2f-3aa3-48f1-8a56-56e66518d139
This commit is contained in:
Fusion (runfusion.ai)
2026-05-17 21:10:56 -07:00
committed by gsxdsm
parent c6453ca956
commit b8514b658e
2 changed files with 50 additions and 2 deletions

View File

@@ -1,7 +1,7 @@
import { describe, it, expect, vi, beforeEach } from "vitest";
import { promisify } from "node:util";
import { acquireTaskWorktree } from "../worktree-acquisition.js";
import { classifyTaskWorktree } from "../worktree-pool.js";
import { classifyTaskWorktree, PoolDoubleLeaseError } from "../worktree-pool.js";
vi.mock("../worktree-pool.js", async () => {
const actual = await vi.importActual<any>("../worktree-pool.js");
@@ -146,6 +146,29 @@ describe("acquireTaskWorktree", () => {
expect(store.updateTask).toHaveBeenCalledWith("FN-1", { worktree: null, branch: null, sessionFile: null });
});
it("falls through to fresh creation when pool acquire throws PoolDoubleLeaseError", async () => {
const createWorktree = vi.fn().mockResolvedValue({ path: "/tmp/new", branch: "fusion/fn-1" });
const result = await acquireTaskWorktree({
task,
rootDir: process.cwd(),
store,
settings: { recycleWorktrees: true } as any,
pool: {
acquire: () => {
throw new PoolDoubleLeaseError("/tmp/pooled", "FN-OTHER", "FN-1", "acquire");
},
prepareForTask: vi.fn(),
release: vi.fn(),
} as any,
createWorktree,
logger: { log: vi.fn(), warn: vi.fn(), error: vi.fn() },
});
expect(result.source).toBe("fresh");
expect(createWorktree).toHaveBeenCalled();
expect(store.logEntry).toHaveBeenCalledWith("FN-1", expect.stringContaining("Pool double-lease guard triggered"), undefined, undefined);
});
it("creates fresh when pool disabled", async () => {
const createWorktree = vi.fn().mockResolvedValue({ path: "/tmp/new", branch: "fusion/fn-1" });
const result = await acquireTaskWorktree({

View File

@@ -8,7 +8,7 @@ vi.mock("node:fs", () => ({
realpathSync: vi.fn((path: string) => path),
}));
import { WorktreePool } from "../worktree-pool.js";
import { PoolDoubleLeaseError, WorktreePool } from "../worktree-pool.js";
// FN-4954 deterministic race backstop.
describe("WorktreePool double-lease guard", () => {
@@ -36,6 +36,31 @@ describe("WorktreePool double-lease guard", () => {
expect(violations).toEqual([{ phase: "rehydrate", existingHolder: "FN-A" }]);
});
it("throws PoolDoubleLeaseError when corrupted idle state tries to re-lease a leased path", () => {
const violations: Array<{ phase: string; requestingTaskId: string; existingHolder: string }> = [];
pool.setInvariantViolationHandler((violation) => {
violations.push({
phase: violation.phase,
requestingTaskId: violation.requestingTaskId,
existingHolder: violation.existingHolder,
});
});
pool.release("/tmp/wt-race");
expect(pool.acquire("FN-A")).toBe("/tmp/wt-race");
(pool as any).idle.add("/tmp/wt-race");
expect(() => pool.acquire("FN-B")).toThrow(PoolDoubleLeaseError);
expect(violations).toEqual([{ phase: "acquire", requestingTaskId: "FN-B", existingHolder: "FN-A" }]);
});
it("does not throw for same-task re-entry when no idle path exists", () => {
pool.release("/tmp/wt-race");
expect(pool.acquire("FN-A")).toBe("/tmp/wt-race");
expect(() => pool.acquire("FN-A")).not.toThrow();
expect(pool.acquire("FN-A")).toBeNull();
});
it("keeps release best-effort when releasing task differs", () => {
const violations: Array<{ phase: string; requestingTaskId: string }> = [];
pool.setInvariantViolationHandler((violation) => violations.push({ phase: violation.phase, requestingTaskId: violation.requestingTaskId }));