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
3296 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
child.stdin.write('Hello MCP!');
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', () => process.exit(0));
63
});
64
`);
65
66
const before = Date.now();
67
handler.stop();
68
const result = await output;
69
const delay = Date.now() - before;
70
assert.strictEqual(result.trim(), 'stdin ended\nSIGTERM received');
71
assert.ok(delay >= GRACE_TIME, `Expected at least ${GRACE_TIME}ms delay, got ${delay}ms`);
72
});
73
}
74
75
test('sigkill after grace', async () => {
76
const { handler, output } = run(`
77
setInterval(() => {}, 1000);
78
process.stdin.on('end', () => process.stdout.write('stdin ended\\n'));
79
process.stdin.resume();
80
process.on('SIGTERM', () => {
81
process.stdout.write('SIGTERM received');
82
});
83
`);
84
85
const before = Date.now();
86
handler.stop();
87
const result = await output;
88
const delay = Date.now() - before;
89
if (!isWindows) {
90
assert.strictEqual(result.trim(), 'stdin ended\nSIGTERM received');
91
} else {
92
assert.strictEqual(result.trim(), 'stdin ended');
93
}
94
assert.ok(delay >= GRACE_TIME * 2, `Expected at least ${GRACE_TIME * 2}ms delay, got ${delay}ms`);
95
});
96
});
97
98