mirror of https://github.com/garrytan/gstack.git
test(windows): curate skill-census + browser-manager-unit; surface unhandled errors in the epilogue
Round-2 Windows census (zero failing TESTS — the first curation wave held): shard 1 failed on an unhandled module-load throw in skill-census (the skills-tree symlink layout needs Developer Mode CI runners lack) and shard 2 wedged to its wall deadline inside browser-manager-unit — both get receipted exclusions; macOS + Linux lanes keep covering the files. The unhandled-error class also exposed an epilogue gap: it fails the shard via the strict classifier but produces no (fail) lines, so the epilogue read 'FAIL — 0 failing test(s)' with no culprit. The reporter now attributes each '# Unhandled error between tests' marker to its chunk and the FAIL line carries the count.
This commit is contained in:
parent
f7f402106d
commit
e3cb0416ee
|
|
@ -197,6 +197,15 @@ export const KNOWN_WINDOWS_INCOMPATIBLE: Array<{ file: string; reason: string }>
|
||||||
file: 'design/test/variants-retry-after.test.ts',
|
file: 'design/test/variants-retry-after.test.ts',
|
||||||
reason: 'wall-clock retry-timing assertions — flaky on the slow windows-latest runner even with widened bounds',
|
reason: 'wall-clock retry-timing assertions — flaky on the slow windows-latest runner even with widened bounds',
|
||||||
},
|
},
|
||||||
|
// Round-2 census (PR #2593 run 31919227507) after the first seven:
|
||||||
|
{
|
||||||
|
file: 'test/skill-census.test.ts',
|
||||||
|
reason: 'census walk throws at module load on Windows (skill-census.ts:63) — the skills-tree symlink layout needs Developer Mode that CI runners lack',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
file: 'browse/test/browser-manager-unit.test.ts',
|
||||||
|
reason: 'wedges the shard to its wall deadline on windows-latest (in-flight at kill); needs a Windows repro to diagnose — macOS + Linux lanes cover the file',
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
// Force-include overrides: files a WINDOWS_FRAGILE_PATTERNS regex excludes for
|
// Force-include overrides: files a WINDOWS_FRAGILE_PATTERNS regex excludes for
|
||||||
|
|
@ -574,6 +583,14 @@ export interface FreeRunReport {
|
||||||
failures: FreeRunFailure[];
|
failures: FreeRunFailure[];
|
||||||
/** Files that crashed a worker (bun retries once; a second crash is final). Deduped. */
|
/** Files that crashed a worker (bun retries once; a second crash is final). Deduped. */
|
||||||
crashedFiles: string[];
|
crashedFiles: string[];
|
||||||
|
/**
|
||||||
|
* "# Unhandled error between tests" markers, attributed to the chunk they
|
||||||
|
* appeared in. These fail the shard via the strict classifier but produce
|
||||||
|
* NO (fail) lines — without surfacing them here, the epilogue reads
|
||||||
|
* "FAIL — 0 failing test(s)" and the culprit is undiscoverable from CI
|
||||||
|
* output (first Windows lane run: a module-load throw in skill-census).
|
||||||
|
*/
|
||||||
|
unhandledErrors: Array<{ file: string | null }>;
|
||||||
/**
|
/**
|
||||||
* Wedge-suspect heuristic for a wall-timeout kill: files whose header was
|
* Wedge-suspect heuristic for a wall-timeout kill: files whose header was
|
||||||
* seen but whose chunk never ENDED (chunk end = the next file's header, or
|
* seen but whose chunk never ENDED (chunk end = the next file's header, or
|
||||||
|
|
@ -620,6 +637,7 @@ export class FreeRunReporter {
|
||||||
private readonly crashed = new Set<string>();
|
private readonly crashed = new Set<string>();
|
||||||
private currentFile: string | null = null;
|
private currentFile: string | null = null;
|
||||||
private inRecap = false;
|
private inRecap = false;
|
||||||
|
private readonly unhandled: Array<{ file: string | null }> = [];
|
||||||
private testsRan: number | null = null;
|
private testsRan: number | null = null;
|
||||||
private filesRan: number | null = null;
|
private filesRan: number | null = null;
|
||||||
private sawSummary = false;
|
private sawSummary = false;
|
||||||
|
|
@ -665,6 +683,7 @@ export class FreeRunReporter {
|
||||||
sawTerminalSummary: this.sawSummary,
|
sawTerminalSummary: this.sawSummary,
|
||||||
failures: [...this.failures],
|
failures: [...this.failures],
|
||||||
crashedFiles: [...this.crashed].sort(),
|
crashedFiles: [...this.crashed].sort(),
|
||||||
|
unhandledErrors: [...this.unhandled],
|
||||||
inFlight,
|
inFlight,
|
||||||
filesWithNoOutput: this.plannedFiles.filter((f) => !this.progress.has(normalizeRelativePath(f))).length,
|
filesWithNoOutput: this.plannedFiles.filter((f) => !this.progress.has(normalizeRelativePath(f))).length,
|
||||||
};
|
};
|
||||||
|
|
@ -689,6 +708,10 @@ export class FreeRunReporter {
|
||||||
this.currentFile = null;
|
this.currentFile = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (line === '# Unhandled error between tests') {
|
||||||
|
this.unhandled.push({ file: this.currentFile });
|
||||||
|
}
|
||||||
|
|
||||||
const header = FILE_HEADER_RE.exec(line);
|
const header = FILE_HEADER_RE.exec(line);
|
||||||
if (header) {
|
if (header) {
|
||||||
const file = this.canonicalize(header[1]);
|
const file = this.canonicalize(header[1]);
|
||||||
|
|
@ -788,7 +811,7 @@ export function buildRunEpilogue(
|
||||||
const failingFiles = new Set(report.failures.map((f) => f.file ?? '(unattributed)'));
|
const failingFiles = new Set(report.failures.map((f) => f.file ?? '(unattributed)'));
|
||||||
const lines = [
|
const lines = [
|
||||||
`[test:free] FAIL — ${report.failures.length} failing test(s) in ${failingFiles.size} file(s), `
|
`[test:free] FAIL — ${report.failures.length} failing test(s) in ${failingFiles.size} file(s), `
|
||||||
+ `${report.crashedFiles.length} crashed worker(s). Full log: ${logPath}`,
|
+ `${report.crashedFiles.length} crashed worker(s)${report.unhandledErrors.length > 0 ? `, ${report.unhandledErrors.length} unhandled error(s) between tests` : ''}. Full log: ${logPath}`,
|
||||||
];
|
];
|
||||||
for (const failure of report.failures) {
|
for (const failure of report.failures) {
|
||||||
lines.push(` ✗ ${failure.file ?? '(unattributed)'} — ${failure.testName}`);
|
lines.push(` ✗ ${failure.file ?? '(unattributed)'} — ${failure.testName}`);
|
||||||
|
|
@ -796,6 +819,9 @@ export function buildRunEpilogue(
|
||||||
for (const file of report.crashedFiles) {
|
for (const file of report.crashedFiles) {
|
||||||
lines.push(` ⚠ crashed+retried: ${file}`);
|
lines.push(` ⚠ crashed+retried: ${file}`);
|
||||||
}
|
}
|
||||||
|
for (const u of report.unhandledErrors) {
|
||||||
|
lines.push(` ⚠ unhandled error between tests (around ${u.file ?? 'unknown file'})`);
|
||||||
|
}
|
||||||
if (status === 'timed-out') {
|
if (status === 'timed-out') {
|
||||||
if (report.inFlight.length > 0) {
|
if (report.inFlight.length > 0) {
|
||||||
lines.push(` ⏱ in flight at kill: ${report.inFlight.join(', ')}`);
|
lines.push(` ⏱ in flight at kill: ${report.inFlight.join(', ')}`);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue