Files
memind/server/portal-integration-services-bootstrap.test.mjs
T
john 286069449b
Memind CI / Test, build, and release guards (push) Failing after 2m14s
feat: add guarded portal canary release
2026-07-26 19:51:44 +08:00

531 lines
13 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 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',
env: {
H5_SCHEDULE_ENABLED: '1',
H5_REMINDER_WORKER_ENABLED: '1',
},
usersRoot: '/users',
wechatMpConfig: { enabled: true },
authPool: pool,
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;
},
};
},
resolveMindSpaceRuntimeConfigFn(h5Root, env) {
calls.push(['runtime-config', h5Root, env]);
return { storageRoot: '/storage' };
},
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(wechatOptions.pageDataFinishGuard, {
pool: setup.pool,
h5Root: '/app',
storageRoot: '/storage',
});
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(
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('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: {},
authPool: 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.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);
});