Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/contrib/mcp/test/node/mcpStdioStateHandler.test.ts
5260 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { spawn } from 'child_process';
7
import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js';
8
import * as assert from 'assert';
9
import { McpStdioStateHandler } from '../../node/mcpStdioStateHandler.js';
10
import { isWindows } from '../../../../../base/common/platform.js';
11
12
const GRACE_TIME = 100;
13
14
suite('McpStdioStateHandler', () => {
15
const store = ensureNoDisposablesAreLeakedInTestSuite();
16
17
function run(code: string) {
18
const child = spawn('node', ['-e', code], {
19
stdio: 'pipe',
20
env: { ...process.env, ELECTRON_RUN_AS_NODE: '1' },
21
});
22
23
return {
24
child,
25
handler: store.add(new McpStdioStateHandler(child, GRACE_TIME)),
26
processId: new Promise<number>((resolve) => {
27
child.on('spawn', () => resolve(child.pid!));
28
}),
29
output: new Promise<string>((resolve) => {
30
let output = '';
31
child.stderr.setEncoding('utf-8').on('data', (data) => {
32
output += data.toString();
33
});
34
child.stdout.setEncoding('utf-8').on('data', (data) => {
35
output += data.toString();
36
});
37
child.on('close', () => resolve(output));
38
}),
39
};
40
}
41
42
test('stdin ends process', async () => {
43
const { child, handler, output } = run(`
44
const data = require('fs').readFileSync(0, 'utf-8');
45
process.stdout.write('Data received: ' + data);
46
process.on('SIGTERM', () => process.stdout.write('SIGTERM received'));
47
`);
48
49
await new Promise<void>(r => child.stdin.write('Hello MCP!', () => r()));
50
handler.stop();
51
const result = await output;
52
assert.strictEqual(result.trim(), 'Data received: Hello MCP!');
53
});
54
55
if (!isWindows) {
56
test('sigterm after grace', async () => {
57
const { handler, output } = run(`
58
setInterval(() => {}, 1000);
59
process.stdin.on('end', () => process.stdout.write('stdin ended\\n'));
60
process.stdin.resume();
61
process.on('SIGTERM', () => {
62
process.stdout.write('SIGTERM received', () => {
63
process.stdout.end(() => process.exit(0));
64
});
65
});
66
`);
67
68
const before = Date.now();
69
handler.stop();
70
const result = await output;
71
const delay = Date.now() - before;
72
assert.strictEqual(result.trim(), 'stdin ended\nSIGTERM received');
73
assert.ok(delay >= GRACE_TIME, `Expected at least ${GRACE_TIME}ms delay, got ${delay}ms`);
74
});
75
}
76
77
test('sigkill after grace', async () => {
78
const { handler, output } = run(`
79
setInterval(() => {}, 1000);
80
process.stdin.on('end', () => process.stdout.write('stdin ended\\n'));
81
process.stdin.resume();
82
process.on('SIGTERM', () => {
83
process.stdout.write('SIGTERM received');
84
});
85
`);
86
87
const before = Date.now();
88
handler.stop();
89
const result = await output;
90
const delay = Date.now() - before;
91
if (!isWindows) {
92
assert.strictEqual(result.trim(), 'stdin ended\nSIGTERM received');
93
} else {
94
assert.strictEqual(result.trim(), 'stdin ended');
95
}
96
assert.ok(delay >= GRACE_TIME * 2, `Expected at least ${GRACE_TIME * 2}ms delay, got ${delay}ms`);
97
});
98
});
99
100