feat(FN-4410): complete Step 1 — dispatch reclaim telemetry wiring
Fusion-Task-Id: FN-4410 Fusion-Task-Lineage: 306d4fe0-d024-49dd-86b4-fb98d4ceff59
This commit is contained in:
@@ -1859,6 +1859,46 @@ describe("TaskExecutor dependency-based worktree creation", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("records branch:auto-reclaim run-audit event when pooled prepare returns reclaimed worktree", async () => {
|
||||
const pool = new WorktreePool();
|
||||
pool.release("/tmp/test/.worktrees/idle-wt");
|
||||
mockedExistsSync.mockImplementation((p) => p === "/tmp/test/.worktrees/idle-wt" || p === "/tmp/test/.worktrees/live-wt");
|
||||
|
||||
vi.spyOn(pool, "prepareForTask").mockResolvedValue({
|
||||
branch: "fusion/fn-066",
|
||||
worktreePath: "/tmp/test/.worktrees/live-wt",
|
||||
reclaimed: true,
|
||||
existingTipSha: "abc123def456",
|
||||
strandedCommitCount: 2,
|
||||
});
|
||||
|
||||
const store = createMockStore();
|
||||
store.recordRunAuditEvent = vi.fn().mockResolvedValue(undefined);
|
||||
store.getSettings.mockResolvedValue({
|
||||
maxConcurrent: 2,
|
||||
maxWorktrees: 4,
|
||||
pollIntervalMs: 15000,
|
||||
groupOverlappingFiles: false,
|
||||
autoMerge: false,
|
||||
recycleWorktrees: true,
|
||||
});
|
||||
|
||||
const executor = new TaskExecutor(store, "/tmp/test", { pool });
|
||||
await executor.execute(makeTask({ id: "FN-066", worktree: null, branch: null }));
|
||||
|
||||
expect(store.recordRunAuditEvent).toHaveBeenCalledWith(expect.objectContaining({
|
||||
mutationType: "branch:auto-reclaim",
|
||||
target: "fusion/fn-066",
|
||||
metadata: expect.objectContaining({
|
||||
taskId: "FN-066",
|
||||
trigger: "dispatch-preflight",
|
||||
worktreePath: "/tmp/test/.worktrees/live-wt",
|
||||
existingTipSha: "abc123def456",
|
||||
strandedCommitCount: 2,
|
||||
}),
|
||||
}));
|
||||
});
|
||||
|
||||
it("stores suffixed branch name when pool returns a different name", async () => {
|
||||
const pool = new WorktreePool();
|
||||
pool.release("/tmp/test/.worktrees/idle-wt");
|
||||
|
||||
@@ -41,6 +41,7 @@ describe("acquireTaskWorktree", () => {
|
||||
|
||||
it("acquires from pool when enabled", async () => {
|
||||
const prepareForTask = vi.fn().mockResolvedValue({ branch: "fusion/fn-1", worktreePath: "/tmp/pooled", reclaimed: false });
|
||||
const release = vi.fn();
|
||||
const result = await acquireTaskWorktree({
|
||||
task,
|
||||
rootDir: process.cwd(),
|
||||
@@ -49,10 +50,11 @@ describe("acquireTaskWorktree", () => {
|
||||
pool: {
|
||||
acquire: () => "/tmp/pooled",
|
||||
prepareForTask,
|
||||
release: vi.fn(),
|
||||
release,
|
||||
} as any,
|
||||
createWorktree: vi.fn(),
|
||||
});
|
||||
expect(release).not.toHaveBeenCalled();
|
||||
expect(result.source).toBe("pool");
|
||||
expect(prepareForTask).toHaveBeenCalledWith(
|
||||
"/tmp/pooled",
|
||||
@@ -63,6 +65,30 @@ describe("acquireTaskWorktree", () => {
|
||||
expect(store.updateTask).toHaveBeenCalledWith("FN-1", { worktree: "/tmp/pooled", branch: "fusion/fn-1" });
|
||||
});
|
||||
|
||||
it("releases acquired pooled worktree when prepareForTask returns reclaimed path", async () => {
|
||||
const release = vi.fn();
|
||||
await acquireTaskWorktree({
|
||||
task,
|
||||
rootDir: process.cwd(),
|
||||
store,
|
||||
settings: { recycleWorktrees: true } as any,
|
||||
pool: {
|
||||
acquire: () => "/tmp/pooled",
|
||||
prepareForTask: vi.fn().mockResolvedValue({
|
||||
branch: "fusion/fn-1",
|
||||
worktreePath: "/tmp/live-existing",
|
||||
reclaimed: true,
|
||||
existingTipSha: "abc123",
|
||||
strandedCommitCount: 2,
|
||||
}),
|
||||
release,
|
||||
} as any,
|
||||
createWorktree: vi.fn(),
|
||||
});
|
||||
|
||||
expect(release).toHaveBeenCalledWith("/tmp/pooled");
|
||||
});
|
||||
|
||||
it("creates fresh when pool disabled", async () => {
|
||||
const createWorktree = vi.fn().mockResolvedValue({ path: "/tmp/new", branch: "fusion/fn-1" });
|
||||
const result = await acquireTaskWorktree({
|
||||
|
||||
@@ -154,6 +154,9 @@ export async function acquireTaskWorktree(opts: AcquireTaskWorktreeOptions): Pro
|
||||
const prepared = typeof preparedRaw === "string"
|
||||
? { branch: preparedRaw, worktreePath: pooled, reclaimed: false as const }
|
||||
: preparedRaw;
|
||||
if (prepared.reclaimed && prepared.worktreePath !== pooled) {
|
||||
pool.release(pooled);
|
||||
}
|
||||
worktreePath = prepared.worktreePath;
|
||||
branch = prepared.branch;
|
||||
acquiredFromPool = true;
|
||||
|
||||
Reference in New Issue
Block a user