test(release): inject read failures at the bounded descriptor boundary

This commit is contained in:
Forge
2026-09-23 20:50:24 +00:00
parent bf81c39c23
commit 307a39957c
3 changed files with 13 additions and 10 deletions
+7 -7
View File
@@ -1,6 +1,6 @@
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import * as cp from 'child_process';
import * as fs from 'fs';
import * as fs from 'node:fs';
import * as os from 'os';
import * as path from 'path';
import { CodeGraph } from '../src';
@@ -11,9 +11,9 @@ vi.mock('child_process', async importOriginal => {
const actual = await importOriginal<typeof import('child_process')>();
return { ...actual, execFileSync: vi.fn(actual.execFileSync) };
});
vi.mock('fs', async importOriginal => {
const actual = await importOriginal<typeof import('fs')>();
return { ...actual, readFileSync: vi.fn(actual.readFileSync) };
vi.mock('node:fs', async importOriginal => {
const actual = await importOriginal<typeof import('node:fs')>();
return { ...actual, readFileSync: vi.fn(actual.readFileSync), openSync: vi.fn(actual.openSync) };
});
describe('git index currency across commits and restores (#1829)', () => {
@@ -132,12 +132,12 @@ describe('git index currency across commits and restores (#1829)', () => {
it('keeps a committed path pending when sync cannot read it', async () => {
write('new.ts', 'newSymbol'); commit();
const real = fs.readFileSync;
const real = fs.openSync;
let injected = 0;
vi.spyOn(fs, 'readFileSync').mockImplementation(((file: any, ...args: any[]) => {
vi.spyOn(fs, 'openSync').mockImplementation(((file: any, ...args: any[]) => {
if (String(file) === path.join(root, 'new.ts')) { injected++; throw new Error('Injected transient read error'); }
return (real as any)(file, ...args);
}) as typeof fs.readFileSync);
}) as typeof fs.openSync);
await cg.sync();
expect(injected).toBeGreaterThan(0);
expect(symbols('newSymbol')).not.toContain('newSymbol');
+5 -2
View File
@@ -6,6 +6,7 @@ out=root/'.qa/release-full';out.mkdir(parents=True,exist_ok=True)
files=sorted(str(p.relative_to(root)) for p in (root/'__tests__').rglob('*.test.ts'))
manifest={'revision':expected,'files':files,'commands':[]}
(out/'manifest.json').write_text(json.dumps(manifest,indent=2)+'\n')
failures=[]
for shard in range(1,5):
name=f'release-final-shard-{shard}'
if (root/'.qa/recovery'/f'{name}.json').exists():
@@ -15,7 +16,7 @@ for shard in range(1,5):
assert subprocess.check_output(['git','rev-parse','HEAD'],cwd=root,text=True).strip()==expected
command=['node','node_modules/vitest/vitest.mjs','run',f'--shard={shard}/4','--maxWorkers=1','--minWorkers=1','--reporter=default','--reporter=json',f'--outputFile.json=.qa/release-full/shard-{shard}.json']
result=subprocess.run(['python3','docs/validation/release-command.py',name,*command],cwd=root)
if result.returncode:sys.exit(result.returncode)
if result.returncode:failures.append(shard)
seen=[];counts={'passed':0,'failed':0,'pending':0}
for shard in range(1,5):
report=json.loads((out/f'shard-{shard}.json').read_text())
@@ -23,5 +24,7 @@ for shard in range(1,5):
seen.append(str(pathlib.Path(suite['name']).relative_to(root)))
for k in counts:counts[k]+=report[{'passed':'numPassedTests','failed':'numFailedTests','pending':'numPendingTests'}[k]]
assert len(seen)==len(set(seen)) and set(seen)==set(files),(len(seen),len(files),set(files)-set(seen))
summary={'revision':expected,'counts':counts,'testFiles':len(files),'exactlyOnce':True,'finished':datetime.datetime.now(datetime.timezone.utc).isoformat()}
summary={'revision':expected,'counts':counts,'testFiles':len(files),'exactlyOnce':True,'success':not failures and counts['failed']==0,'failedShards':failures,'finished':datetime.datetime.now(datetime.timezone.utc).isoformat()}
(out/'summary.json').write_text(json.dumps(summary,indent=2)+'\n');print(json.dumps(summary),flush=True)
sys.exit(0 if summary['success'] else 1)
+1 -1
View File
@@ -39,7 +39,7 @@ async function run(name, command, args, timeout = 360000, overrides = {}) {
const built = await run('build', ...npmCommand(['run', 'build']));
if (built && metadata.scope === 'repairs') {
metadata.notRun = ['unchanged core/worker/lifecycle paths: reuse successful steps at 90516f8, run 35880834124'];
await run('focused', process.execPath, ['node_modules/vitest/vitest.mjs', 'run', '__tests__/db-reopen-on-replace.test.ts', '__tests__/upgrade.test.ts', '__tests__/update-check.test.ts', '__tests__/cli-ui-command.test.ts', '--maxWorkers=1', '--minWorkers=1', '--reporter=default', '--reporter=json', `--outputFile.json=${path.join(out, 'focused.json')}`], 300000);
await run('focused', process.execPath, ['node_modules/vitest/vitest.mjs', 'run', '__tests__/db-reopen-on-replace.test.ts', '__tests__/upgrade.test.ts', '__tests__/update-check.test.ts', '__tests__/git-index-currency.test.ts', '__tests__/cli-ui-command.test.ts', '--maxWorkers=1', '--minWorkers=1', '--reporter=default', '--reporter=json', `--outputFile.json=${path.join(out, 'focused.json')}`], 300000);
await run('file-growth-race', process.execPath, ['scripts/validation/release-size-race.cjs','dist']);
await run('installer-archives', process.execPath, ['scripts/validation/release-installers.cjs']);
await run('security-negative', process.execPath, ['scripts/validation/release-security.cjs','.','dist']);