fix(#2163): round-2 review fixes — deterministic fail-soft injection tests
- readGitStatus calls execFileSync via the child_process namespace so tests can inject spawn failures through the shared module object - two deterministic tests: ERR_CHILD_PROCESS_STDOUT_MAXBUFFER-shaped and ETIMEDOUT-shaped throws both degrade to null (segment absent), proving the fail-soft paths the PR previously only asserted Claude-Session: https://claude.ai/code/session_01Hme55Pvq6BhpgwBcyC5HAg
This commit is contained in:
@@ -6,7 +6,9 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const os = require('os');
|
||||
const { execFileSync } = require('child_process');
|
||||
// Namespace (not destructured) so tests can inject spawn failures by
|
||||
// monkeypatching childProcess.execFileSync.
|
||||
const childProcess = require('child_process');
|
||||
const { isSemverNewer } = require('../gsd-core/bin/lib/semver-compare.cjs');
|
||||
const { PACKAGE_NAME, updateCacheFileName } = require('../gsd-core/bin/lib/package-identity.cjs');
|
||||
|
||||
@@ -339,7 +341,7 @@ function readGitStatus(dir) {
|
||||
// 8 MiB maxBuffer (default 1 MiB) headroom for repos with very many changed
|
||||
// or untracked files; overflow still degrades safely to segment-absent via
|
||||
// the catch below.
|
||||
return execFileSync('git', ['-C', dir, 'status', '--porcelain=v2', '--branch'],
|
||||
return childProcess.execFileSync('git', ['-C', dir, 'status', '--porcelain=v2', '--branch'],
|
||||
{ encoding: 'utf8', timeout: GIT_STATUS_TIMEOUT_MS, maxBuffer: 8 * 1024 * 1024, stdio: ['ignore', 'pipe', 'ignore'] });
|
||||
} catch (e) {
|
||||
return null;
|
||||
|
||||
@@ -1500,6 +1500,41 @@ test('config-set statusline.show_context_tokens yes → rejected', () => {
|
||||
}
|
||||
});
|
||||
|
||||
// Deterministic IO-failure injection (repo convention, cf. the fs
|
||||
// monkeypatch in ensure-runtime-build.test.cjs): readGitStatus shares the
|
||||
// one cached child_process module object, so replacing execFileSync here
|
||||
// injects the failure without a real hang or oversized repo.
|
||||
test('maxBuffer overflow degrades to null (segment absent)', () => {
|
||||
const childProcess = require('node:child_process');
|
||||
const original = childProcess.execFileSync;
|
||||
childProcess.execFileSync = () => {
|
||||
const err = new RangeError('stdout maxBuffer length exceeded');
|
||||
err.code = 'ERR_CHILD_PROCESS_STDOUT_MAXBUFFER';
|
||||
throw err;
|
||||
};
|
||||
try {
|
||||
assert.equal(readGitStatus('/tmp'), null);
|
||||
} finally {
|
||||
childProcess.execFileSync = original;
|
||||
}
|
||||
});
|
||||
|
||||
test('spawn timeout degrades to null (segment absent)', () => {
|
||||
const childProcess = require('node:child_process');
|
||||
const original = childProcess.execFileSync;
|
||||
childProcess.execFileSync = () => {
|
||||
const err = new Error('spawnSync git ETIMEDOUT');
|
||||
err.code = 'ETIMEDOUT';
|
||||
err.errno = -110;
|
||||
throw err;
|
||||
};
|
||||
try {
|
||||
assert.equal(readGitStatus('/tmp'), null);
|
||||
} finally {
|
||||
childProcess.execFileSync = original;
|
||||
}
|
||||
});
|
||||
|
||||
test('fresh repo with an untracked file is counted', () => {
|
||||
const { dir } = makeGitRepo();
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user