Files
memind/server/portal-integration-services-bootstrap.test.mjs
2026-07-28 09:33:25 +08:00

596 lines
15 KiB
JavaScript

import assert from 'node:assert/strict';
import test from 'node:test';
import { bootstrapPortalIntegrationServices } from './portal-integration-services-bootstrap.mjs';
function createSetup(overrides = {}) {
const calls = [];
const pool = { id: 'pool' };
const userAuth = {
async getUserById(userId) {
calls.push(['get-user', userId]);
return { id: userId, username: 'John' };
},
setRechargeNotifier(notifier) {
calls.push(['set-recharge-notifier']);
this.rechargeNotifier = notifier;
},
};
const sessionAccess = { id: 'session-access' };
const tkmindProxy = {
apiFetch: { id: 'api-fetch' },
startSessionForUser(userId, options) {
calls.push(['start-session', userId, options]);
return { sessionId: 'session-1' };
},
async resolveTarget(sessionId) {
calls.push(['resolve-target', sessionId]);
return 'http://target';
},
apiFetchTo(target, pathname, init) {
calls.push([
'api-fetch-to',
target,
pathname,
init,
]);
return { ok: true };
},
submitSessionReplyForUser(...args) {
calls.push(['submit-reply', ...args]);
return { accepted: true };
},
applySessionLlmProvider(sessionId) {
calls.push(['apply-provider', sessionId]);
return { applied: true };
},
};
const wechatMpService = {
enabled: true,
sendTextToUser(userId, text) {
calls.push(['send-wechat-text', userId, text]);
return { sent: true };
},
};
const notificationDispatcher = {
async sendRechargeSuccess(options) {
calls.push(['recharge-success', options]);
},
};
const scheduleService = { id: 'schedule' };
const mindSpacePublicFinish = {
async prepareWechatHtmlDelivery() {
return { confirmedArtifacts: [] };
},
async ensureWechatFreshPageThumbnails() {
return { ok: true };
},
async prepareWechatPageDataDelivery() {
return { outcome: { action: 'skip' } };
},
};
const sessionSnapshotService = {
isEnabled() {
return true;
},
refresh(...args) {
calls.push(['snapshot-refresh', ...args]);
return { refreshed: true };
},
};
let wechatOptions;
let notificationOptions;
let reminderOptions;
let pageEditOptions;
let timerCallback;
let timerDelay;
let unrefCount = 0;
const subscriptionService = {
async processAutoRenewals() {
calls.push(['auto-renew']);
return { renewed: 2, failed: 1 };
},
async expireStaleSubscriptions() {
calls.push(['expire-subscriptions']);
return 3;
},
};
const options = {
pool,
h5Root: '/app',
codeRoot: '/runtime',
env: {
H5_SCHEDULE_ENABLED: '1',
H5_REMINDER_WORKER_ENABLED: '1',
},
usersRoot: '/users',
wechatMpConfig: { enabled: true },
mindSpacePublicFinish,
userAuth,
sessionAccess,
tkmindProxy,
scheduleService,
wechatScheduleLlmConfigService: {
id: 'schedule-llm',
},
llmProviderService: { id: 'llm' },
chatIntentRouter: {
classifySessionAction(options) {
calls.push(['classify-session', options]);
return { action: 'chat' };
},
},
systemDisclosurePolicyService: {
id: 'system-disclosure-policy',
},
sessionSnapshotService,
mindSpaceAnalyticsConfig: { enabled: true },
mindSpaceRybbitConfig: { enabled: true },
subscriptionService,
apiTarget: 'http://api',
apiSecret: 'secret',
mindSpacePages: { id: 'pages' },
mindSpacePageLiveEdit: { id: 'live-edit' },
logger: {
log(...args) {
calls.push(['log', ...args]);
},
warn(...args) {
calls.push(['warn', ...args]);
},
},
async loadWechatMpModuleFn(h5Root) {
calls.push(['load-wechat', h5Root]);
return {
createWechatMpService(receivedOptions) {
calls.push(['create-wechat']);
wechatOptions = receivedOptions;
return wechatMpService;
},
};
},
resolveAnalyticsOwnerSegmentFn(user) {
calls.push(['owner-segment', user]);
return 'segment';
},
resolveAnalyticsOwnerLabelFn(user) {
calls.push(['owner-label', user]);
return 'label';
},
resolveAnalyticsPlanFn(user) {
calls.push(['plan-type', user]);
return 'pro';
},
sendMindSpaceAnalyticsEventFn(event) {
calls.push(['analytics', event]);
return Promise.resolve();
},
sendMindSpaceRybbitEventFn(event) {
calls.push(['rybbit', event]);
return Promise.resolve();
},
createNotificationDispatcherFn(receivedOptions) {
calls.push(['notification-dispatcher']);
notificationOptions = receivedOptions;
return notificationDispatcher;
},
startScheduleReminderWorkerFn(receivedOptions) {
calls.push(['reminder-worker']);
reminderOptions = receivedOptions;
return { id: 'reminder-worker' };
},
createPageEditSessionServiceFn(receivedOptions) {
calls.push(['page-edit']);
pageEditOptions = receivedOptions;
return { id: 'page-edit' };
},
setIntervalFn(callback, delay) {
calls.push(['set-interval']);
timerCallback = callback;
timerDelay = delay;
return {
unref() {
unrefCount += 1;
calls.push(['timer-unref']);
},
};
},
...overrides,
};
return {
calls,
options,
pool,
userAuth,
sessionAccess,
tkmindProxy,
wechatMpService,
notificationDispatcher,
scheduleService,
sessionSnapshotService,
subscriptionService,
getCaptured() {
return {
wechatOptions,
notificationOptions,
reminderOptions,
pageEditOptions,
timerCallback,
timerDelay,
unrefCount,
};
},
};
}
test('requires Portal integration dependencies', async () => {
await assert.rejects(
bootstrapPortalIntegrationServices(),
/requires Portal integration dependencies/,
);
});
test('preserves WeChat service configuration and proxy callbacks', async () => {
const setup = createSetup();
await bootstrapPortalIntegrationServices(
setup.options,
);
const { wechatOptions } = setup.getCaptured();
assert.deepEqual(
setup.calls.find(([kind]) => kind === 'load-wechat'),
['load-wechat', '/runtime'],
);
assert.equal(
wechatOptions.pageDataFinishGuard,
setup.options.mindSpacePublicFinish,
);
assert.equal(
wechatOptions.pageDataDeliveryReviewer,
null,
);
assert.equal(
wechatOptions.htmlDeliveryAuthority,
setup.options.mindSpacePublicFinish,
);
assert.equal(
wechatOptions.apiFetch,
setup.tkmindProxy.apiFetch,
);
assert.equal(
wechatOptions.scheduleService,
setup.scheduleService,
);
assert.equal(
wechatOptions.systemDisclosurePolicyService,
setup.options.systemDisclosurePolicyService,
);
assert.deepEqual(
wechatOptions.startAgentSession({
userId: 'user-1',
workingDir: '/workspace',
sessionPolicy: { sandboxed: true },
}),
{ sessionId: 'session-1' },
);
assert.deepEqual(
setup.calls.find(([kind]) => kind === 'start-session'),
[
'start-session',
'user-1',
{
workingDir: '/workspace',
sessionPolicy: { sandboxed: true },
origin: 'wechat',
},
],
);
assert.deepEqual(
await wechatOptions.sessionApiFetch(
'session-1',
'/status',
{ method: 'GET' },
),
{ ok: true },
);
assert.deepEqual(
wechatOptions.submitSessionReply({
userId: 'user-1',
sessionId: 'session-1',
requestId: 'request-1',
userMessage: 'hello',
options: { deep: true },
}),
{ accepted: true },
);
assert.deepEqual(
wechatOptions.sessionIntentClassifier({
text: 'hello',
}),
{ action: 'chat' },
);
assert.deepEqual(
wechatOptions.applySessionLlmProvider('session-1'),
{ applied: true },
);
});
test('wires the isolated WeChat Page Data reviewer only when its channel flag is enabled', async () => {
const toolGateway = { id: 'wechat-review-tool-gateway' };
const reviewer = { reviewIfNeeded() {} };
let gatewayOptions;
let reviewerOptions;
const setup = createSetup({
wechatMpConfig: {
enabled: true,
pageDataAiderReviewEnabled: true,
},
createToolGatewayFn(options) {
gatewayOptions = options;
return toolGateway;
},
createPageDataDeliveryCodeReviewServiceFn(options) {
reviewerOptions = options;
return reviewer;
},
});
await bootstrapPortalIntegrationServices(setup.options);
const { wechatOptions } = setup.getCaptured();
assert.equal(gatewayOptions.llmProviderService, setup.options.llmProviderService);
assert.equal(reviewerOptions.toolGateway, toolGateway);
assert.equal(reviewerOptions.userAuth, setup.options.userAuth);
assert.equal(wechatOptions.pageDataDeliveryReviewer, reviewer);
});
test('preserves snapshot refresh through the resolved session target', async () => {
const setup = createSetup();
await bootstrapPortalIntegrationServices(
setup.options,
);
const { wechatOptions } = setup.getCaptured();
assert.equal(
typeof wechatOptions.refreshSessionSnapshot,
'function',
);
assert.deepEqual(
wechatOptions.refreshSessionSnapshot(
'session-1',
'user-1',
),
{ refreshed: true },
);
const refreshCall = setup.calls.find(
([name]) => name === 'snapshot-refresh',
);
const fetchSnapshot = refreshCall[3];
assert.deepEqual(
await fetchSnapshot('/snapshot', {
method: 'GET',
}),
{ ok: true },
);
assert.ok(
setup.calls.some(
([name, sessionId]) =>
name === 'resolve-target' &&
sessionId === 'session-1',
),
);
});
test('preserves generated-page analytics projection', async () => {
const setup = createSetup();
await bootstrapPortalIntegrationServices(
setup.options,
);
const { wechatOptions } = setup.getCaptured();
await wechatOptions.onPageGenerated({
userId: 'user-1',
sessionId: 'session-1',
artifacts: [
{
relativePath: 'public/page.html',
url: 'https://example/page',
},
],
});
assert.equal(
setup.calls.filter(([name]) => name === 'get-user')
.length,
1,
);
const analyticsCall = setup.calls.find(
([name]) => name === 'analytics',
);
assert.deepEqual(analyticsCall[1], {
config: { enabled: true },
eventName: 'page_generated',
ownerId: 'user-1',
ownerSegment: 'segment',
ownerLabel: 'label',
planType: 'pro',
generatedAt: analyticsCall[1].generatedAt,
pageId: 'public/page.html',
publicationId: 'session-1',
agentRunId: 'session-1',
channel: 'wechat_mp',
url: 'https://example/page',
});
assert.match(
analyticsCall[1].generatedAt,
/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/,
);
const rybbitCall = setup.calls.find(
([name]) => name === 'rybbit',
);
assert.deepEqual(rybbitCall[1], {
...analyticsCall[1],
config: { enabled: true },
});
});
test('preserves notification, recharge, reminder, and page-edit wiring', async () => {
const setup = createSetup();
const result =
await bootstrapPortalIntegrationServices(
setup.options,
);
const captured = setup.getCaptured();
assert.equal(
captured.notificationOptions.sendWechatTextToUser(
'user-1',
'hello',
).sent,
true,
);
await setup.userAuth.rechargeNotifier({
userId: 'user-1',
title: 'Recharge',
body: 'Success',
dedupeKey: 'dedupe-1',
});
assert.deepEqual(captured.reminderOptions, {
scheduleService: setup.scheduleService,
notificationDispatcher:
setup.notificationDispatcher,
});
assert.equal(result.scheduleReminderWorker.id, 'reminder-worker');
assert.deepEqual(captured.pageEditOptions, {
apiTarget: 'http://api',
apiSecret: 'secret',
userAuth: setup.userAuth,
sessionAccess: setup.sessionAccess,
pageService: setup.options.mindSpacePages,
pageLiveEdit: setup.options.mindSpacePageLiveEdit,
llmProviderService:
setup.options.llmProviderService,
});
});
test('preserves subscription timer work, logs, and unref', async () => {
const setup = createSetup();
await bootstrapPortalIntegrationServices(
setup.options,
);
const captured = setup.getCaptured();
assert.equal(captured.timerDelay, 60 * 60 * 1000);
assert.equal(captured.unrefCount, 1);
await captured.timerCallback();
assert.ok(
setup.calls.some(
([name, message]) =>
name === 'log' &&
message === 'Auto-renewed 2 subscription(s)',
),
);
assert.ok(
setup.calls.some(
([name, message]) =>
name === 'log' &&
message ===
'Auto-renew failed for 1 subscription(s) (balance insufficient)',
),
);
assert.ok(
setup.calls.some(
([name, message]) =>
name === 'log' &&
message === 'Expired 3 stale subscription(s)',
),
);
});
test('keeps optional integrations disabled and contains timer failures', async () => {
const setup = createSetup({
env: {},
mindSpacePublicFinish: null,
scheduleService: null,
subscriptionService: {
async processAutoRenewals() {
throw new Error('renew failed');
},
async expireStaleSubscriptions() {
return 0;
},
},
sessionSnapshotService: {
isEnabled: () => false,
},
async loadWechatMpModuleFn() {
return {
createWechatMpService(options) {
setup.disabledWechatOptions = options;
return { enabled: false };
},
};
},
});
const result =
await bootstrapPortalIntegrationServices(
setup.options,
);
const captured = setup.getCaptured();
await captured.timerCallback();
assert.equal(
setup.disabledWechatOptions.pageDataFinishGuard,
null,
);
assert.equal(
setup.disabledWechatOptions
.htmlDeliveryAuthority,
null,
);
assert.equal(
setup.disabledWechatOptions.scheduleService,
null,
);
assert.equal(
setup.disabledWechatOptions.refreshSessionSnapshot,
null,
);
assert.equal(result.scheduleReminderWorker, null);
assert.equal(
captured.notificationOptions.sendWechatTextToUser,
null,
);
assert.ok(
setup.calls.some(
([name, message, error]) =>
name === 'warn' &&
message ===
'Subscription expiry check failed:' &&
error?.message === 'renew failed',
),
);
});
test('passive candidate runtime disables singleton reminder and subscription timers', async () => {
const setup = createSetup({
env: {
H5_SCHEDULE_ENABLED: '1',
H5_REMINDER_WORKER_ENABLED: '1',
MEMIND_RUNTIME_ROLE: 'candidate',
MEMIND_CANARY_PASSIVE_RUNTIME: '1',
},
});
const result = await bootstrapPortalIntegrationServices(setup.options);
const captured = setup.getCaptured();
assert.equal(result.scheduleReminderWorker, null);
assert.equal(result.subscriptionExpiryTimer, null);
assert.equal(captured.reminderOptions, undefined);
assert.equal(captured.timerCallback, undefined);
assert.equal(setup.calls.some(([name]) => name === 'reminder-worker'), false);
assert.equal(setup.calls.some(([name]) => name === 'set-interval'), false);
});