qwen_2.5_model / src /core /plugins /plugin-loader-activation.spec.ts
Muhammad Noman
Deploy OpenWA to Hugging Face Spaces
46252cd
Raw
History Blame Contribute Delete
5.8 kB
import { ConfigService } from '@nestjs/config';
import { ModuleRef } from '@nestjs/core';
import { PluginLoaderService } from './plugin-loader.service';
import { PluginStorageService } from './plugin-storage.service';
import { HookManager, HookHandler } from '../hooks';
import { PluginContext, PluginInstance, PluginManifest, PluginStatus, PluginType } from './plugin.interfaces';
function makePlugin(opts: { sessionScoped?: boolean; activeSessions?: string[] }): PluginInstance {
const manifest: PluginManifest = {
id: 'act-ext',
name: 'Activation Ext',
version: '1.0.0',
type: PluginType.EXTENSION,
main: 'index.js',
sessionScoped: opts.sessionScoped,
};
return { manifest, status: PluginStatus.ENABLED, config: {}, instance: null, activeSessions: opts.activeSessions };
}
describe('PluginLoaderService — per-session activation gate (hook delivery)', () => {
let loader: PluginLoaderService;
let hookManager: HookManager;
let setSessions: jest.Mock;
beforeEach(() => {
hookManager = new HookManager();
const configService = { get: jest.fn().mockReturnValue(undefined) } as unknown as ConfigService;
setSessions = jest.fn();
const pluginStorage = {
createPluginStorage: jest.fn().mockReturnValue({}),
setPluginSessions: setSessions,
} as unknown as PluginStorageService;
loader = new PluginLoaderService(configService, hookManager, pluginStorage, {
get: jest.fn(),
} as unknown as ModuleRef);
});
const seed = (plugin: PluginInstance): void => {
(loader as unknown as { plugins: Map<string, PluginInstance> }).plugins.set(plugin.manifest.id, plugin);
};
function register(plugin: PluginInstance, handler: HookHandler): void {
const ctx = (
loader as unknown as { createPluginContext: (p: PluginInstance) => PluginContext }
).createPluginContext(plugin);
ctx.registerHook('message:received', handler);
}
const fire = (sessionId: string): Promise<unknown> =>
hookManager.execute('message:received', {}, { sessionId, source: 'Engine' });
it('delivers a hook only for the sessions a session-scoped plugin is activated for', async () => {
const handler = jest.fn().mockResolvedValue({ continue: true });
register(makePlugin({ activeSessions: ['sess-1'] }), handler);
await fire('sess-1');
expect(handler).toHaveBeenCalledTimes(1);
await fire('sess-2');
expect(handler).toHaveBeenCalledTimes(1); // not delivered for the inactive session
});
it("delivers for every session when activeSessions is ['*']", async () => {
const handler = jest.fn().mockResolvedValue({ continue: true });
register(makePlugin({ activeSessions: ['*'] }), handler);
await fire('a');
await fire('b');
expect(handler).toHaveBeenCalledTimes(2);
});
it('defaults to all sessions when activeSessions is unset', async () => {
const handler = jest.fn().mockResolvedValue({ continue: true });
register(makePlugin({}), handler); // no activeSessions
await fire('anything');
expect(handler).toHaveBeenCalledTimes(1);
});
it('a global plugin (sessionScoped:false) always receives the hook, even with no active sessions', async () => {
const handler = jest.fn().mockResolvedValue({ continue: true });
register(makePlugin({ sessionScoped: false, activeSessions: [] }), handler);
await fire('x');
expect(handler).toHaveBeenCalledTimes(1);
});
describe('setPluginSessions', () => {
it('updates a session-scoped plugin and persists the new active set', () => {
const plugin = makePlugin({ activeSessions: ['*'] });
seed(plugin);
loader.setPluginSessions('act-ext', ['sess-1', 'sess-2']);
expect(plugin.activeSessions).toEqual(['sess-1', 'sess-2']);
expect(setSessions).toHaveBeenCalledWith('act-ext', ['sess-1', 'sess-2']);
});
it('rejects activating a global (non-session-scoped) plugin per session', () => {
seed(makePlugin({ sessionScoped: false }));
expect(() => loader.setPluginSessions('act-ext', ['sess-1'])).toThrow(/global/i);
expect(setSessions).not.toHaveBeenCalled();
});
});
});
// A built-in/bundled plugin must read its persisted per-session activation + config back into the
// runtime on boot, exactly like a directory plugin (loadPlugin) — otherwise the gate falls back to
// all-sessions/base-config after every restart, silently widening delivery for a plugin the operator
// had restricted.
describe('PluginLoaderService — registerBuiltInPlugin restart read-back', () => {
it('seeds activeSessions and sessionConfig from persisted storage', () => {
const hookManager = new HookManager();
const configService = { get: jest.fn().mockReturnValue(undefined) } as unknown as ConfigService;
const pluginStorage = {
getPluginConfig: jest.fn().mockReturnValue({}),
getPluginSessions: jest.fn().mockReturnValue(['sess-1']),
getPluginSessionConfig: jest.fn().mockReturnValue({ 'sess-1': { lang: 'id' } }),
getPluginEntry: jest.fn().mockReturnValue(undefined),
setPluginEntry: jest.fn(),
} as unknown as PluginStorageService;
const loader = new PluginLoaderService(configService, hookManager, pluginStorage, {
get: jest.fn(),
} as unknown as ModuleRef);
const manifest: PluginManifest = {
id: 'builtin-ext',
name: 'Built-in Ext',
version: '1.0.0',
type: PluginType.EXTENSION,
main: 'index.js',
sessionScoped: true,
};
loader.registerBuiltInPlugin(manifest, {});
const plugin = (loader as unknown as { plugins: Map<string, PluginInstance> }).plugins.get('builtin-ext');
expect(plugin?.activeSessions).toEqual(['sess-1']);
expect(plugin?.sessionConfig).toEqual({ 'sess-1': { lang: 'id' } });
});
});