test(hub): stabilize lifecycle coverage on Windows

This commit is contained in:
Mohamed Boudra
2026-07-13 16:32:27 +02:00
parent 3c5921f143
commit 9c30982e6b
2 changed files with 20 additions and 11 deletions
@@ -60,7 +60,7 @@ test("failed Hub auto-archive creates release their lifecycle subscriptions", as
const hub = await launchRelationship();
const subscriptionBaseline = hub.agentSubscriptionCount();
hub.failNextProviderPromptStart();
hub.failProviderPromptStart();
hub.beginOwnedCreate("failed-prompt-create-1", "failed-prompt-execution-1", {
autoArchive: true,
worktree: { mode: "branch-off", newBranch: "failed-prompt-1" },
@@ -76,7 +76,7 @@ test("failed Hub auto-archive creates release their lifecycle subscriptions", as
expect(await hub.listedWorktrees()).toHaveLength(1);
expect(hub.agentSubscriptionCount()).toBe(subscriptionBaseline);
hub.failNextProviderPromptStart();
hub.failProviderPromptStart();
hub.beginOwnedCreate("failed-prompt-create-2", "failed-prompt-execution-2", {
autoArchive: true,
worktree: { mode: "branch-off", newBranch: "failed-prompt-2" },
@@ -95,7 +95,7 @@ test("failed Hub auto-archive creates release their lifecycle subscriptions", as
test("failed Hub create cleans durable state when provider close rejects", async () => {
const hub = await launchRelationship();
hub.failNextProviderPromptStart();
hub.failProviderPromptStart();
hub.failNextProviderSessionClose();
hub.beginOwnedCreate("failed-close-create", "failed-close-execution", {
worktree: { mode: "branch-off", newBranch: "failed-close-worktree" },
@@ -138,9 +138,11 @@ test("failed create never archives a reused worktree", async () => {
expect(worktreeCwd).toEqual(expect.any(String));
await hub.ownedTurnCompletion(original.payload.agentId!);
hub.failNextProviderPromptStart();
const failedPrompt = "Fail the reused worktree create";
hub.failProviderPromptStart(failedPrompt);
hub.beginOwnedCreate("reused-create", "reused-execution", {
autoArchive: true,
prompt: failedPrompt,
worktree: { mode: "branch-off", newBranch: "shared-hub-worktree" },
});
const reused = await hub.ownedCreateResult("reused-create");
@@ -1,7 +1,7 @@
import { execFile } from "node:child_process";
import { execFileSync } from "node:child_process";
import { EventEmitter } from "node:events";
import { existsSync, readFileSync, statSync, watch } from "node:fs";
import { existsSync, readFileSync, realpathSync, statSync, watch } from "node:fs";
import { mkdir, mkdtemp, readdir, rm, writeFile } from "node:fs/promises";
import { networkInterfaces, platform, tmpdir } from "node:os";
import path from "node:path";
@@ -446,7 +446,7 @@ export class HubRelationshipHarness {
private readonly providerPrompts: AgentPromptInput[] = [];
private readonly cliProcesses = new Set<Promise<unknown>>();
private readonly claimedCliSockets = new Set<WebSocket>();
private failNextPromptStart = false;
private readonly promptsToFail = new Set<string>();
private failNextSessionClose = false;
private observedEnrollments = 0;
private observedSockets = 0;
@@ -459,8 +459,8 @@ export class HubRelationshipHarness {
throw new Error("Requested provider session close failure");
},
onStartTurn: (prompt) => {
if (this.failNextPromptStart) {
this.failNextPromptStart = false;
const promptText = typeof prompt === "string" ? prompt : JSON.stringify(prompt);
if (this.promptsToFail.delete(promptText)) {
throw new Error("Requested provider prompt startup failure");
}
this.providerPrompts.push(prompt);
@@ -594,8 +594,8 @@ export class HubRelationshipHarness {
this.remote.failRevocations(count);
}
failNextProviderPromptStart(): void {
this.failNextPromptStart = true;
failProviderPromptStart(prompt = "Create through the Hub"): void {
this.promptsToFail.add(prompt);
}
failNextProviderSessionClose(): void {
@@ -1305,7 +1305,14 @@ export class HubRelationshipHarness {
}
private comparablePath(value: string): string {
const normalized = path.normalize(path.resolve(value));
const resolved = path.resolve(value);
let canonical = resolved;
try {
canonical = realpathSync.native(resolved);
} catch {
// An archived worktree no longer exists, so compare its normalized target path.
}
const normalized = path.normalize(canonical);
return platform() === "win32" ? normalized.toLowerCase() : normalized;
}