mirror of
https://github.com/hansjone/dsh-im-ops.git
synced 2026-10-09 00:33:20 +08:00
131 lines
4.8 KiB
JavaScript
131 lines
4.8 KiB
JavaScript
import assert from 'node:assert/strict';
|
|
import test from 'node:test';
|
|
|
|
import {
|
|
DELIVERY_RPC_CHANNEL,
|
|
DELIVERY_TEST_MESSAGE,
|
|
createDeliveryRpcHandler,
|
|
installDeliveryRpc,
|
|
} from '../plugin-src/host/delivery-rpc.mjs';
|
|
|
|
function serviceFixture() {
|
|
const calls = [];
|
|
const service = {};
|
|
for (const method of [
|
|
'send',
|
|
'listTargets',
|
|
'listSuggestions',
|
|
'createTarget',
|
|
'updateTarget',
|
|
'deleteTarget',
|
|
]) {
|
|
service[method] = async (...args) => {
|
|
calls.push([method, ...args]);
|
|
return { method };
|
|
};
|
|
}
|
|
return { service, calls };
|
|
}
|
|
|
|
test('delivery RPC forwards all endpoints and both target.test payloads to the shared service', async () => {
|
|
const { service, calls } = serviceFixture();
|
|
const handle = createDeliveryRpcHandler(service);
|
|
const signal = new AbortController().signal;
|
|
const target = {
|
|
targetId: 'daily-report',
|
|
name: 'Daily report',
|
|
kind: 'group',
|
|
route: { chatId: 'chat-one' },
|
|
};
|
|
const replacement = { kind: 'group', route: { chatId: 'chat-two' } };
|
|
const draft = { kind: 'group', route: { chatId: 'chat-draft' } };
|
|
|
|
for (const [endpoint, payload] of [
|
|
['message.send', { botId: 'bot_one', targetId: 'daily-report', text: 'hello' }],
|
|
['target.list', { botId: 'bot_one' }],
|
|
['target.suggestion.list', { botId: 'bot_one' }],
|
|
['target.create', { botId: 'bot_one', target }],
|
|
['target.update', { botId: 'bot_one', targetId: 'daily-report', target: replacement }],
|
|
['target.delete', { botId: 'bot_one', targetId: 'daily-report' }],
|
|
['target.test', { botId: 'bot_one', targetId: 'daily-report' }],
|
|
['target.test', { botId: 'bot_one', target: draft }],
|
|
]) {
|
|
assert.equal((await handle(endpoint, payload, signal)).ok, true);
|
|
}
|
|
assert.deepEqual(calls, [
|
|
['send', 'bot_one', 'daily-report', 'hello', { signal }],
|
|
['listTargets', 'bot_one'],
|
|
['listSuggestions', 'bot_one'],
|
|
['createTarget', 'bot_one', target],
|
|
['updateTarget', 'bot_one', 'daily-report', replacement],
|
|
['deleteTarget', 'bot_one', 'daily-report'],
|
|
['send', 'bot_one', 'daily-report', DELIVERY_TEST_MESSAGE, { signal }],
|
|
['send', 'bot_one', draft, DELIVERY_TEST_MESSAGE, { signal }],
|
|
]);
|
|
});
|
|
|
|
test('delivery RPC rejects unknown, missing, and extra fields before calling the service', async () => {
|
|
const { service, calls } = serviceFixture();
|
|
const handle = createDeliveryRpcHandler(service);
|
|
for (const [endpoint, payload] of [
|
|
['unknown', {}],
|
|
['message.send', { botId: 'bot_one', targetId: 'target', text: 'hello', sessionId: 'no' }],
|
|
['message.send', { botId: 'bot_one', targetId: 'target', text: ' ' }],
|
|
['target.list', { botId: '../bot' }],
|
|
['target.suggestion.list', { botId: 'bot_one', sessionId: 'no' }],
|
|
['target.create', {
|
|
botId: 'bot_one',
|
|
target: { targetId: 'bad target', kind: 'group', route: { chatId: 'one' } },
|
|
}],
|
|
['target.update', {
|
|
botId: 'bot_one',
|
|
targetId: 'old',
|
|
target: { targetId: 'new', kind: 'group', route: { chatId: 'one' } },
|
|
}],
|
|
['target.delete', { botId: 'bot_one', targetId: 'target', confirm: true }],
|
|
['target.test', ['bot_one', 'target']],
|
|
['target.test', { botId: 'bot_one', targetId: 'target', target: {
|
|
kind: 'group', route: { chatId: 'one' },
|
|
} }],
|
|
['target.test', { botId: 'bot_one', target: {
|
|
targetId: 'target', kind: 'group', route: { chatId: 'one' },
|
|
} }],
|
|
['target.test', { botId: 'bot_one', target: {
|
|
name: 'Draft', kind: 'group', route: { chatId: 'one' },
|
|
} }],
|
|
['target.test', { botId: 'bot_one', target: { kind: 'group' } }],
|
|
]) {
|
|
assert.equal((await handle(endpoint, payload)).error.code, 'bad-request');
|
|
}
|
|
assert.deepEqual(calls, []);
|
|
});
|
|
|
|
test('delivery RPC returns only stable public errors and handles pre-cancelled calls', async () => {
|
|
const { service } = serviceFixture();
|
|
service.listTargets = async () => {
|
|
throw new Error('token=secret /Users/private/workspaces.json');
|
|
};
|
|
const handle = createDeliveryRpcHandler(service);
|
|
assert.deepEqual(await handle('target.list', { botId: 'bot_one' }), {
|
|
ok: false,
|
|
error: { code: 'delivery-failed', message: 'delivery-failed', details: {} },
|
|
});
|
|
|
|
const abort = new AbortController();
|
|
abort.abort();
|
|
assert.deepEqual(await handle('target.list', { botId: 'bot_one' }, abort.signal), {
|
|
ok: false,
|
|
error: { code: 'cancelled', message: 'cancelled', details: {} },
|
|
});
|
|
});
|
|
|
|
test('delivery RPC uses its own channel and the configured management authority', () => {
|
|
const { service } = serviceFixture();
|
|
const calls = [];
|
|
installDeliveryRpc({
|
|
connection: { rpc: { handle: (...args) => calls.push(args) } },
|
|
}, service, { authority: 'trusted-host' });
|
|
assert.equal(calls[0][0], DELIVERY_RPC_CHANNEL);
|
|
assert.equal(typeof calls[0][1], 'function');
|
|
assert.deepEqual(calls[0][2], { authority: 'trusted-host' });
|
|
});
|