dsh-im-ops/test/host-harness-connection.test.mjs
2026-08-29 20:22:07 +08:00

131 lines
4.7 KiB
JavaScript

import assert from 'node:assert/strict';
import test from 'node:test';
import { harnessConnection } from '../plugin-src/host/harness-connection.mjs';
import { inject as hostInject } from '../plugin-src/host/index.mjs';
const IM_CHANNELS = [
'weixin', 'feishu', 'dingtalk', 'wecom', 'qq',
'slack', 'telegram', 'discord', 'whatsapp',
];
test('Host connections share the current Cordis root without depending on a webServer', () => {
const root = {};
const apiProxy = {};
const first = harnessConnection({ root, apiProxy });
const second = harnessConnection({ root, apiProxy });
assert.deepEqual(first, { apiProxy, interactionScope: root });
assert.equal(first.interactionScope, second.interactionScope);
assert.notEqual(first.interactionScope, harnessConnection({ root: {}, apiProxy }).interactionScope);
const fixtureContext = { apiProxy };
assert.equal(harnessConnection(fixtureContext).interactionScope, fixtureContext);
});
test('an explicit Harness URL preserves HTTP transport and never reads the Host apiProxy', () => {
const ctx = { get apiProxy() { throw new Error('must not read local apiProxy'); } };
const connection = harnessConnection(ctx, { harnessBaseUrl: 'https://harness.example/base/' });
assert.equal(connection.baseUrl.href, 'https://harness.example/base/');
assert.deepEqual(Object.keys(connection), ['baseUrl']);
assert.throws(() => harnessConnection(ctx, { harnessBaseUrl: 'not a URL' }), TypeError);
});
test('a Host with neither legacy apiProxy nor a modern gateway fails clearly', () => {
assert.throws(
() => harnessConnection({ webServer: { port: 3080 } }),
/requires the modern Host Typert gateway/,
);
});
test('Host and all IM channel plugins require only services shared by old and new Harness', async () => {
assert.equal(hostInject.includes('apiProxy'), false);
assert.equal(hostInject.includes('webServer'), false);
assert.ok(hostInject.includes('typertGateway'));
for (const channel of IM_CHANNELS) {
const { inject } = await import(`../plugin-src/host/channels/${channel}/index.mjs`);
assert.equal(inject.includes('apiProxy'), false, channel);
assert.equal(inject.includes('webServer'), false, channel);
assert.ok(inject.includes('typertGateway'), channel);
}
});
async function assembledHarness(channel, ctx, config = {}) {
const { createProductionController } = await import(
`../plugin-src/host/channels/${channel}/production.mjs`
);
const constructed = {};
class ConfigStore {
async load() { return this; }
list() { return []; }
}
class Harness {
constructor(options) { constructed.harness = options; }
stopManagedProcess() {}
}
class Controller {
constructor(options) { constructed.controller = options; }
async initialize() {}
async close() {}
}
class Runtime {
constructor(options) { constructed.runtime = options; }
}
const production = await createProductionController(ctx, {
workspace: '/test/workspace',
...config,
}, {
ConfigStore,
HarnessClient: Harness,
Controller,
Runtime,
FeishuRuntime: Runtime,
api: {},
deviceAuth: {},
qrAuth: {},
lark: {},
proxyEnv: {},
workspaces: {
async reconcile() {},
async ensure() {},
decorateStatus(value) { return value; },
},
createConnectionSupervisor: () => ({
ready: Promise.resolve(),
start() { return this; },
async close() {},
}),
});
try {
if (channel === 'office') {
constructed.controller.createRuntime({});
constructed.runtime.createHarness({ workspace: '/test/workspace' });
}
return constructed.harness;
} finally {
await production.close();
}
}
for (const channel of [...IM_CHANNELS, 'office']) {
test(`${channel} production uses its Host apiProxy with no webServer or listening port`, async () => {
const apiProxy = {};
const root = {};
const options = await assembledHarness(channel, { credentials: {}, apiProxy, root });
assert.equal(options.apiProxy, apiProxy);
assert.equal(options.interactionScope, root);
assert.equal(Object.hasOwn(options, 'baseUrl'), false);
assert.equal(options.workspace, '/test/workspace');
assert.equal(options.autostart, false);
});
test(`${channel} production preserves an explicitly configured Harness URL`, async () => {
const options = await assembledHarness(channel, {
credentials: {},
get apiProxy() { throw new Error('explicit URL must not use local apiProxy'); },
}, { harnessBaseUrl: 'http://127.0.0.1:43210/custom/' });
assert.equal(options.baseUrl.href, 'http://127.0.0.1:43210/custom/');
assert.equal(Object.hasOwn(options, 'apiProxy'), false);
assert.equal(Object.hasOwn(options, 'interactionScope'), false);
assert.equal(options.autostart, false);
});
}