2026-10-30 12:28:48 +01:00
|
|
|
// Generated, do not edit. sha256:d705db22a94bcceb849648fab7596bd5a84e34d8b58a472ec9dc677c8db0cc0a
|
2026-10-29 11:57:29 +01:00
|
|
|
import { describe, it, before, after } from 'node:test';
|
|
|
|
|
import assert from 'node:assert/strict';
|
|
|
|
|
import { spawn } from 'node:child_process';
|
|
|
|
|
import { DatabaseSync } from 'node:sqlite';
|
|
|
|
|
import { mkdtemp, rm } from 'node:fs/promises';
|
|
|
|
|
import { tmpdir } from 'node:os';
|
|
|
|
|
import { join } from 'node:path';
|
|
|
|
|
import { fileURLToPath } from 'node:url';
|
|
|
|
|
|
|
|
|
|
const WORTEL = join(fileURLToPath(import.meta.url), '..', '..', '..');
|
|
|
|
|
const STDIO = join(WORTEL, 'server', 'mcp', 'stdio.mjs');
|
|
|
|
|
|
2026-10-30 12:28:48 +01:00
|
|
|
let dir, dbPad, proc, buffer = '', wachtenden = [];
|
2026-10-29 11:57:29 +01:00
|
|
|
|
|
|
|
|
function stuur(bericht) {
|
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
|
wachtenden.push(resolve);
|
|
|
|
|
const klaar = setTimeout(() => reject(new Error('geen antwoord binnen 10s')), 10_000);
|
|
|
|
|
wachtenden[wachtenden.length - 1] = (a) => { clearTimeout(klaar); resolve(a); };
|
|
|
|
|
proc.stdin.write(`${JSON.stringify(bericht)}\n`);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
before(async () => {
|
|
|
|
|
dir = await mkdtemp(join(tmpdir(), 'assetapp-mcp-stdio-'));
|
2026-10-30 12:28:48 +01:00
|
|
|
dbPad = join(dir, 'MyAssets', 'db.sqlite');
|
|
|
|
|
const env = { ...process.env, ASSETAPP_DATA_DIR: dir, ASSETAPP_DB_FILE: dbPad };
|
|
|
|
|
const eerste = spawn(process.execPath, [STDIO], { env, stdio: 'ignore' });
|
|
|
|
|
assert.equal(await new Promise((klaar) => eerste.once('exit', klaar)), 0, 'een verse installatie stopt met de koppeling uit');
|
|
|
|
|
const db = new DatabaseSync(dbPad);
|
|
|
|
|
db.exec(`UPDATE Preference SET value = '1' WHERE scope = 'ai' AND key = 'enabled'`);
|
|
|
|
|
db.close();
|
|
|
|
|
proc = spawn(process.execPath, [STDIO], { env, stdio: ['pipe', 'pipe', 'pipe'] });
|
2026-10-29 11:57:29 +01:00
|
|
|
proc.stdout.on('data', (brok) => {
|
|
|
|
|
buffer += brok.toString();
|
|
|
|
|
let n;
|
|
|
|
|
while ((n = buffer.indexOf('\n')) >= 0) {
|
|
|
|
|
const regel = buffer.slice(0, n).trim();
|
|
|
|
|
buffer = buffer.slice(n + 1);
|
|
|
|
|
if (regel) (wachtenden.shift() || (() => {}))(JSON.parse(regel));
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
await new Promise((resolve) => proc.stderr.once('data', resolve));
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
after(async () => {
|
|
|
|
|
proc.stdin.end();
|
|
|
|
|
await new Promise((resolve) => proc.once('exit', resolve));
|
|
|
|
|
await rm(dir, { recursive: true, force: true });
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
describe('mcp-stdio: het proces beantwoordt bericht na bericht', () => {
|
|
|
|
|
it('antwoordt op initialize', async () => {
|
|
|
|
|
const a = await stuur({ jsonrpc: '2.0', id: 1, method: 'initialize', params: {} });
|
|
|
|
|
assert.equal(a.id, 1);
|
|
|
|
|
assert.ok(a.result.serverInfo.name, 'er hoort een servernaam in te staan');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('geeft de toollijst, en doet dat twee keer achter elkaar', async () => {
|
|
|
|
|
const een = await stuur({ jsonrpc: '2.0', id: 2, method: 'tools/list', params: {} });
|
|
|
|
|
assert.ok(een.result.tools.length > 0, 'er hoort minstens één tool te zijn');
|
|
|
|
|
|
|
|
|
|
const twee = await stuur({ jsonrpc: '2.0', id: 3, method: 'tools/list', params: {} });
|
|
|
|
|
assert.deepEqual(twee.result.tools.map(t => t.name), een.result.tools.map(t => t.name));
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('voert een tool uit en legt hem vast in het auditlog', async () => {
|
|
|
|
|
const a = await stuur({
|
|
|
|
|
jsonrpc: '2.0', id: 4, method: 'tools/call',
|
|
|
|
|
params: { name: 'connection_test', arguments: {} },
|
|
|
|
|
});
|
|
|
|
|
assert.equal(a.id, 4);
|
|
|
|
|
assert.equal(a.error, undefined, `geen fout verwacht: ${JSON.stringify(a.error)}`);
|
|
|
|
|
assert.ok(a.result.content[0].text, 'er hoort een antwoord in te staan');
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
describe('mcp-stdio: de schuif "Actief" zet dit proces uit', () => {
|
|
|
|
|
it('stopt bij het eerstvolgende bericht zodra de schuif uit gaat', async () => {
|
2026-10-30 12:28:48 +01:00
|
|
|
const db = new DatabaseSync(dbPad);
|
2026-10-29 11:57:29 +01:00
|
|
|
db.exec(`PRAGMA busy_timeout = 5000`);
|
|
|
|
|
db.exec(`INSERT INTO Preference (scope, key, value) VALUES ('ai', 'enabled', '0')
|
|
|
|
|
ON CONFLICT (scope, key) DO UPDATE SET value = '0'`);
|
|
|
|
|
db.close();
|
|
|
|
|
|
|
|
|
|
const antwoord = await stuur({ jsonrpc: '2.0', id: 99, method: 'tools/list', params: {} });
|
|
|
|
|
|
|
|
|
|
assert.ok(antwoord.error, 'het laatste bericht hoort nog een antwoord te krijgen');
|
|
|
|
|
assert.match(antwoord.error.message, /Actief/, 'en dat antwoord wijst de juiste schuif aan');
|
|
|
|
|
|
|
|
|
|
const code = await new Promise((klaar) => proc.once('exit', klaar));
|
|
|
|
|
assert.equal(code, 0, 'een uitgezette koppeling is een keuze en geen storing');
|
|
|
|
|
});
|
|
|
|
|
});
|