Batch 12 of the ad hoc timeout literal migration (epic #4445). Replaces every bare numeric timeout/timeoutMs object-literal property in tests/check-env.test.cjs, tests/config-get-default.test.cjs, tests/federated-config.test.cjs, tests/gsd-check-update-worker-platform-gate.test.cjs, tests/gsd-mcp-server-bin.test.cjs, tests/health-validation.test.cjs, tests/locking-bugs-1909-1916-1925-1927.test.cjs, tests/perf-316-state-lock-buffer-alloc.test.cjs, tests/perf-317-context-monitor-fs.test.cjs, and tests/pi-config-dir-env-override.test.cjs with a named constant, per eslint-rules/no-adhoc-timeout-literal.cjs. Removes these 10 files from the rule's allowlist. Ground truth via eslint matched the issue's stated 26 sites across 10 files exactly. Reuses PROBE_TIMEOUT_MS, GENERATOR_SCRIPT_TIMEOUT_MS, GSD_TOOLS_CLI_MODERATE_TIMEOUT_MS, and INSTALL_TIMEOUT_MS across 4 files. No new shared constants needed -- every recurring value across files was independently verified to be a genuinely different operation class, per this migration's standing rule that numeric coincidence is never identity. Adds 11 new file-local constants, three of which are not real subprocess timeouts at all (a config-merge fixture value, and two node:test per-test timeout options bounding ReDoS/lock-retry regression backstops). Per the issue's explicit mandate, gsd-check-update-worker-platform-gate.test.cjs now imports (read-only) NPM_VIEW_TIMEOUT_MS from gsd-core/bin/check-latest-version.cjs for disclosure -- this file and that production module once independently guessed the same 15000ms value, causing the PR #4428 Windows double-SIGKILL collision. No site in this file's current bare literals actually wraps a live npm-view call needing margin arithmetic, so the import documents the historical relationship honestly rather than fabricating a computation. No src/bin file edited (only a read-only import added), no numeric value changed anywhere. Co-authored-by: sim <sim@local> Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
58 lines
2.5 KiB
JavaScript
58 lines
2.5 KiB
JavaScript
'use strict';
|
|
/**
|
|
* Process-lifecycle test for the gsd-mcp-server bin entry (ADR-1239 Phase C-2,
|
|
* #1681 slice 3b / AC4). Spawns the shim, feeds line-delimited JSON-RPC over
|
|
* stdin, asserts stdout responses + clean exit on stdin EOF. Synchronous +
|
|
* bounded (the server exits when stdin closes — no orphan process).
|
|
*/
|
|
|
|
const { test } = require('node:test');
|
|
const assert = require('node:assert/strict');
|
|
const { spawnSync } = require('node:child_process');
|
|
const path = require('node:path');
|
|
const { PROTOCOL_VERSION } = require('../gsd-core/bin/lib/mcp-server.cjs');
|
|
const { PROBE_TIMEOUT_MS } = require('./helpers/timeouts.cjs');
|
|
|
|
const SHIM = path.join(__dirname, '..', 'bin', 'gsd-mcp-server.js');
|
|
|
|
function run(stdin) {
|
|
return spawnSync(process.execPath, [SHIM], {
|
|
input: stdin,
|
|
encoding: 'utf-8',
|
|
timeout: PROBE_TIMEOUT_MS,
|
|
env: { ...process.env, GSD_TEST_MODE: '1' },
|
|
});
|
|
}
|
|
|
|
test('gsd-mcp-server bin: initialize handshake + tools/list over stdio, then clean exit', () => {
|
|
const stdin = [
|
|
JSON.stringify({ jsonrpc: '2.0', id: 1, method: 'initialize' }),
|
|
JSON.stringify({ jsonrpc: '2.0', id: 2, method: 'tools/list' }),
|
|
].join('\n') + '\n';
|
|
const res = run(stdin);
|
|
assert.strictEqual(res.status, 0, `clean exit; stderr: ${res.stderr}`);
|
|
const lines = res.stdout.trim().split('\n').map((l) => JSON.parse(l));
|
|
assert.strictEqual(lines.length, 2, 'one response per request');
|
|
assert.strictEqual(lines[0].id, 1);
|
|
assert.strictEqual(lines[0].result.protocolVersion, PROTOCOL_VERSION, 'initialize returns the protocol version');
|
|
assert.ok(Array.isArray(lines[1].result.tools) && lines[1].result.tools.length === 3, 'tools/list advertises the 3 tools');
|
|
});
|
|
|
|
test('gsd-mcp-server bin: a malformed line surfaces a JSON-RPC parse error; the server keeps running', () => {
|
|
const stdin = [
|
|
'this is not json',
|
|
JSON.stringify({ jsonrpc: '2.0', id: 9, method: 'initialize' }),
|
|
].join('\n') + '\n';
|
|
const res = run(stdin);
|
|
assert.strictEqual(res.status, 0, `server survives the bad line; stderr: ${res.stderr}`);
|
|
const lines = res.stdout.trim().split('\n').map((l) => JSON.parse(l));
|
|
assert.strictEqual(lines[0].error.code, -32700, 'bad line → JSON-RPC parse error');
|
|
assert.strictEqual(lines[1].result.protocolVersion, PROTOCOL_VERSION, 'subsequent valid request still handled');
|
|
});
|
|
|
|
test('gsd-mcp-server bin: empty/whitespace-only stdin → clean exit, no output', () => {
|
|
const res = run('\n \n');
|
|
assert.strictEqual(res.status, 0);
|
|
assert.strictEqual(res.stdout.trim(), '', 'no requests → no responses');
|
|
});
|