Skip to content

Commit 6917936

Browse files
committed
feat: refactor runDoctorReport tests to use withWorkspacePath and add seedDoctorTooling function
1 parent 5acf7c5 commit 6917936

1 file changed

Lines changed: 118 additions & 69 deletions

File tree

tests/doctorHarnessIntegration.test.ts

Lines changed: 118 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import path from "node:path";
22
import os from "node:os";
33
import { mkdtempSync, rmSync } from "node:fs";
4-
import { mkdir, writeFile } from "node:fs/promises";
4+
import { chmod, mkdir, writeFile } from "node:fs/promises";
55

66
import { afterEach, describe, expect, it } from "vitest";
77

@@ -22,15 +22,18 @@ afterEach(() => {
2222
describe("runDoctorReport", () => {
2323
it("includes harness diagnostics for current workspace runs", async () => {
2424
const workspace = createTempWorkspace("autolabos-doctor-harness-");
25+
await seedDoctorTooling(workspace);
2526
await writeFile(path.join(workspace, "ISSUES.md"), VALID_ISSUE_MARKDOWN, "utf8");
2627
await writeJson(path.join(workspace, ".autolabos", "runs", "runs.json"), { runs: [] });
2728

28-
const report = await runDoctorReport(createCodexStub(), {
29-
workspaceRoot: workspace,
30-
includeHarnessValidation: true,
31-
includeHarnessTestRecords: false,
32-
maxHarnessFindings: 10
33-
});
29+
const report = await withWorkspacePath(workspace, () =>
30+
runDoctorReport(createCodexStub(), {
31+
workspaceRoot: workspace,
32+
includeHarnessValidation: true,
33+
includeHarnessTestRecords: false,
34+
maxHarnessFindings: 10
35+
})
36+
);
3437

3538
expect(report.checks.length).toBeGreaterThan(0);
3639
expect(report.harness).toBeDefined();
@@ -44,6 +47,7 @@ describe("runDoctorReport", () => {
4447

4548
it("includes the latest compiled paper page-budget check when available", async () => {
4649
const workspace = createTempWorkspace("autolabos-doctor-page-budget-");
50+
await seedDoctorTooling(workspace);
4751
await writeFile(path.join(workspace, "ISSUES.md"), VALID_ISSUE_MARKDOWN, "utf8");
4852
await writeJson(path.join(workspace, ".autolabos", "runs", "runs.json"), {
4953
runs: [{ id: "run-1", updatedAt: "2026-03-19T12:00:00.000Z" }]
@@ -57,10 +61,12 @@ describe("runDoctorReport", () => {
5761
message: "Compiled PDF is only 3 pages, below the configured minimum_main_pages of 8."
5862
});
5963

60-
const report = await runDoctorReport(createCodexStub(), {
61-
workspaceRoot: workspace,
62-
includeHarnessValidation: false
63-
});
64+
const report = await withWorkspacePath(workspace, () =>
65+
runDoctorReport(createCodexStub(), {
66+
workspaceRoot: workspace,
67+
includeHarnessValidation: false
68+
})
69+
);
6470

6571
expect(report.checks).toContainEqual(
6672
expect.objectContaining({
@@ -77,19 +83,22 @@ describe("runDoctorReport", () => {
7783

7884
it("captures readiness snapshot fields for approval mode and workspace write probing", async () => {
7985
const workspace = createTempWorkspace("autolabos-doctor-readiness-");
86+
await seedDoctorTooling(workspace);
8087
await writeFile(path.join(workspace, "ISSUES.md"), VALID_ISSUE_MARKDOWN, "utf8");
8188
await writeJson(path.join(workspace, ".autolabos", "runs", "runs.json"), { runs: [] });
8289

83-
const report = await runDoctorReport(createCodexStub(), {
84-
workspaceRoot: workspace,
85-
includeHarnessValidation: false,
86-
approvalMode: "manual",
87-
executionApprovalMode: "risk_ack",
88-
dependencyMode: "docker",
89-
sessionMode: "existing",
90-
codeExecutionExpected: true,
91-
candidateIsolation: "attempt_worktree"
92-
});
90+
const report = await withWorkspacePath(workspace, () =>
91+
runDoctorReport(createCodexStub(), {
92+
workspaceRoot: workspace,
93+
includeHarnessValidation: false,
94+
approvalMode: "manual",
95+
executionApprovalMode: "risk_ack",
96+
dependencyMode: "docker",
97+
sessionMode: "existing",
98+
codeExecutionExpected: true,
99+
candidateIsolation: "attempt_worktree"
100+
})
101+
);
93102

94103
expect(report.readiness.approvalMode).toBe("manual");
95104
expect(report.readiness.executionApprovalMode).toBe("risk_ack");
@@ -107,20 +116,23 @@ describe("runDoctorReport", () => {
107116

108117
it("treats local snapshot isolation plus disabled network as ready for code execution", async () => {
109118
const workspace = createTempWorkspace("autolabos-doctor-local-isolation-");
119+
await seedDoctorTooling(workspace);
110120
await writeFile(path.join(workspace, "ISSUES.md"), VALID_ISSUE_MARKDOWN, "utf8");
111121
await writeJson(path.join(workspace, ".autolabos", "runs", "runs.json"), { runs: [] });
112122

113-
const report = await runDoctorReport(createCodexStub(), {
114-
workspaceRoot: workspace,
115-
includeHarnessValidation: false,
116-
approvalMode: "manual",
117-
executionApprovalMode: "manual",
118-
dependencyMode: "local",
119-
sessionMode: "existing",
120-
codeExecutionExpected: true,
121-
candidateIsolation: "attempt_snapshot_restore",
122-
allowNetwork: false
123-
});
123+
const report = await withWorkspacePath(workspace, () =>
124+
runDoctorReport(createCodexStub(), {
125+
workspaceRoot: workspace,
126+
includeHarnessValidation: false,
127+
approvalMode: "manual",
128+
executionApprovalMode: "manual",
129+
dependencyMode: "local",
130+
sessionMode: "existing",
131+
codeExecutionExpected: true,
132+
candidateIsolation: "attempt_snapshot_restore",
133+
allowNetwork: false
134+
})
135+
);
124136

125137
expect(report.readiness.blocked).toBe(false);
126138
expect(report.checks).toContainEqual(
@@ -142,22 +154,25 @@ describe("runDoctorReport", () => {
142154

143155
it("downgrades declared networked execution to a warning instead of a hard failure", async () => {
144156
const workspace = createTempWorkspace("autolabos-doctor-network-declared-");
157+
await seedDoctorTooling(workspace);
145158
await writeFile(path.join(workspace, "ISSUES.md"), VALID_ISSUE_MARKDOWN, "utf8");
146159
await writeJson(path.join(workspace, ".autolabos", "runs", "runs.json"), { runs: [] });
147160

148-
const report = await runDoctorReport(createCodexStub(), {
149-
workspaceRoot: workspace,
150-
includeHarnessValidation: false,
151-
approvalMode: "manual",
152-
executionApprovalMode: "risk_ack",
153-
dependencyMode: "local",
154-
sessionMode: "fresh",
155-
codeExecutionExpected: true,
156-
candidateIsolation: "attempt_snapshot_restore",
157-
allowNetwork: true,
158-
networkPolicy: "declared",
159-
networkPurpose: "logging"
160-
});
161+
const report = await withWorkspacePath(workspace, () =>
162+
runDoctorReport(createCodexStub(), {
163+
workspaceRoot: workspace,
164+
includeHarnessValidation: false,
165+
approvalMode: "manual",
166+
executionApprovalMode: "risk_ack",
167+
dependencyMode: "local",
168+
sessionMode: "fresh",
169+
codeExecutionExpected: true,
170+
candidateIsolation: "attempt_snapshot_restore",
171+
allowNetwork: true,
172+
networkPolicy: "declared",
173+
networkPurpose: "logging"
174+
})
175+
);
161176

162177
expect(report.readiness.blocked).toBe(false);
163178
expect(report.readiness.networkPolicy).toBe("declared");
@@ -179,22 +194,25 @@ describe("runDoctorReport", () => {
179194

180195
it("surfaces required networked execution as a stronger warning with explicit highlight guidance", async () => {
181196
const workspace = createTempWorkspace("autolabos-doctor-network-required-");
197+
await seedDoctorTooling(workspace);
182198
await writeFile(path.join(workspace, "ISSUES.md"), VALID_ISSUE_MARKDOWN, "utf8");
183199
await writeJson(path.join(workspace, ".autolabos", "runs", "runs.json"), { runs: [] });
184200

185-
const report = await runDoctorReport(createCodexStub(), {
186-
workspaceRoot: workspace,
187-
includeHarnessValidation: false,
188-
approvalMode: "manual",
189-
executionApprovalMode: "risk_ack",
190-
dependencyMode: "remote_gpu",
191-
sessionMode: "fresh",
192-
codeExecutionExpected: true,
193-
candidateIsolation: "attempt_snapshot_restore",
194-
allowNetwork: true,
195-
networkPolicy: "required",
196-
networkPurpose: "remote_inference"
197-
});
201+
const report = await withWorkspacePath(workspace, () =>
202+
runDoctorReport(createCodexStub(), {
203+
workspaceRoot: workspace,
204+
includeHarnessValidation: false,
205+
approvalMode: "manual",
206+
executionApprovalMode: "risk_ack",
207+
dependencyMode: "remote_gpu",
208+
sessionMode: "fresh",
209+
codeExecutionExpected: true,
210+
candidateIsolation: "attempt_snapshot_restore",
211+
allowNetwork: true,
212+
networkPolicy: "required",
213+
networkPurpose: "remote_inference"
214+
})
215+
);
198216

199217
expect(report.readiness.blocked).toBe(false);
200218
expect(report.readiness.networkPolicy).toBe("required");
@@ -215,20 +233,23 @@ describe("runDoctorReport", () => {
215233

216234
it("fails doctor readiness when network access is enabled without a declared policy", async () => {
217235
const workspace = createTempWorkspace("autolabos-doctor-network-undeclared-");
236+
await seedDoctorTooling(workspace);
218237
await writeFile(path.join(workspace, "ISSUES.md"), VALID_ISSUE_MARKDOWN, "utf8");
219238
await writeJson(path.join(workspace, ".autolabos", "runs", "runs.json"), { runs: [] });
220239

221-
const report = await runDoctorReport(createCodexStub(), {
222-
workspaceRoot: workspace,
223-
includeHarnessValidation: false,
224-
approvalMode: "manual",
225-
executionApprovalMode: "manual",
226-
dependencyMode: "local",
227-
sessionMode: "fresh",
228-
codeExecutionExpected: true,
229-
candidateIsolation: "attempt_snapshot_restore",
230-
allowNetwork: true
231-
});
240+
const report = await withWorkspacePath(workspace, () =>
241+
runDoctorReport(createCodexStub(), {
242+
workspaceRoot: workspace,
243+
includeHarnessValidation: false,
244+
approvalMode: "manual",
245+
executionApprovalMode: "manual",
246+
dependencyMode: "local",
247+
sessionMode: "fresh",
248+
codeExecutionExpected: true,
249+
candidateIsolation: "attempt_snapshot_restore",
250+
allowNetwork: true
251+
})
252+
);
232253

233254
expect(report.readiness.blocked).toBe(true);
234255
expect(report.readiness.networkDeclarationPresent).toBe(false);
@@ -258,6 +279,34 @@ function createTempWorkspace(prefix: string): string {
258279
return dir;
259280
}
260281

282+
async function seedDoctorTooling(workspace: string): Promise<void> {
283+
const binDir = path.join(workspace, "bin");
284+
await mkdir(binDir, { recursive: true });
285+
await writeExecutable(path.join(binDir, "python3"), "#!/bin/sh\nexit 0\n");
286+
await writeExecutable(path.join(binDir, "pip3"), "#!/bin/sh\nexit 0\n");
287+
await writeExecutable(path.join(binDir, "pdflatex"), "#!/bin/sh\nexit 0\n");
288+
}
289+
290+
async function writeExecutable(filePath: string, content: string): Promise<void> {
291+
await writeFile(filePath, content, "utf8");
292+
await chmod(filePath, 0o755);
293+
}
294+
295+
async function withWorkspacePath<T>(workspace: string, fn: () => Promise<T>): Promise<T> {
296+
const originalPath = process.env.PATH;
297+
const binDir = path.join(workspace, "bin");
298+
process.env.PATH = `${binDir}${path.delimiter}${originalPath || ""}`;
299+
try {
300+
return await fn();
301+
} finally {
302+
if (originalPath === undefined) {
303+
delete process.env.PATH;
304+
} else {
305+
process.env.PATH = originalPath;
306+
}
307+
}
308+
}
309+
261310
async function writeJson(filePath: string, value: unknown): Promise<void> {
262311
await mkdir(path.dirname(filePath), { recursive: true });
263312
await writeFile(filePath, `${JSON.stringify(value, null, 2)}\n`, "utf8");

0 commit comments

Comments
 (0)