157 lines
4.5 KiB
TypeScript
157 lines
4.5 KiB
TypeScript
import { readFileSync } from 'fs';
|
|
import { join } from 'path';
|
|
import { INestApplication } from '@nestjs/common';
|
|
import { Test } from '@nestjs/testing';
|
|
import { getRepositoryToken } from '@nestjs/typeorm';
|
|
import * as request from 'supertest';
|
|
import { JwtAuthGuard } from '../../../../src/admin/auth/jwt-auth.guard';
|
|
import { QqbotPluginPlatformController } from '../../../../src/modules/qqbot/plugin-platform/plugin-platform.controller';
|
|
import { QqbotPluginPlatformModule } from '../../../../src/modules/qqbot/plugin-platform/plugin-platform.module';
|
|
import { QqbotPluginPlatformService } from '../../../../src/modules/qqbot/plugin-platform/plugin-platform.service';
|
|
import {
|
|
QQBOT_PLUGIN_PLATFORM_ENTITIES,
|
|
QqbotPlugin,
|
|
QqbotPluginAccountBinding,
|
|
QqbotPluginAsset,
|
|
QqbotPluginConfig,
|
|
QqbotPluginEventHandler,
|
|
QqbotPluginInstallation,
|
|
QqbotPluginOperation,
|
|
QqbotPluginRuntimeEvent,
|
|
QqbotPluginVersion,
|
|
} from '../../../../src/modules/qqbot/plugin-platform/persistence';
|
|
import {
|
|
collectControllerRoutes,
|
|
routeKey,
|
|
} from '../../../helpers/controller-route.helper';
|
|
|
|
const createRepositoryMock = () => ({
|
|
find: jest.fn(async () => []),
|
|
save: jest.fn(async (value) => value),
|
|
update: jest.fn(async () => ({ affected: 1 })),
|
|
});
|
|
|
|
const createManifest = () => ({
|
|
assets: [],
|
|
configSchema: {
|
|
type: 'object',
|
|
},
|
|
entry: 'src/index.ts',
|
|
events: [],
|
|
minApiSdkVersion: '1.0.0',
|
|
name: 'Demo Plugin',
|
|
operations: [
|
|
{
|
|
handlerName: 'echo',
|
|
key: 'demo-plugin.echo',
|
|
name: 'Echo',
|
|
permissions: ['qqbot.send'],
|
|
timeoutMs: 3000,
|
|
},
|
|
],
|
|
permissions: ['qqbot.send'],
|
|
pluginKey: 'demo-plugin',
|
|
runtime: {
|
|
maxConcurrency: 1,
|
|
memoryMb: 128,
|
|
timeoutMs: 5000,
|
|
workerType: 'node-worker',
|
|
},
|
|
version: '0.1.0',
|
|
});
|
|
|
|
describe('QQBot plugin platform API contract', () => {
|
|
let app: INestApplication;
|
|
|
|
beforeEach(async () => {
|
|
const moduleRef = await Test.createTestingModule({
|
|
controllers: [QqbotPluginPlatformController],
|
|
providers: [
|
|
QqbotPluginPlatformService,
|
|
...[
|
|
QqbotPlugin,
|
|
QqbotPluginVersion,
|
|
QqbotPluginInstallation,
|
|
QqbotPluginOperation,
|
|
QqbotPluginEventHandler,
|
|
QqbotPluginAccountBinding,
|
|
QqbotPluginConfig,
|
|
QqbotPluginAsset,
|
|
QqbotPluginRuntimeEvent,
|
|
].map((entity) => ({
|
|
provide: getRepositoryToken(entity),
|
|
useFactory: createRepositoryMock,
|
|
})),
|
|
],
|
|
})
|
|
.overrideGuard(JwtAuthGuard)
|
|
.useValue({ canActivate: () => true })
|
|
.compile();
|
|
|
|
app = moduleRef.createNestApplication();
|
|
await app.init();
|
|
});
|
|
|
|
afterEach(async () => {
|
|
await app.close();
|
|
});
|
|
|
|
it('registers plugin-platform as a first-class AppModule import', () => {
|
|
const source = readFileSync(
|
|
join(__dirname, '../../../../src/app.module.ts'),
|
|
'utf8',
|
|
);
|
|
|
|
expect(source).toContain('QqbotPluginPlatformModule');
|
|
});
|
|
|
|
it('exposes plugin-platform management routes', () => {
|
|
expect(routeKey).toBeDefined();
|
|
expect(
|
|
collectControllerRoutes([QqbotPluginPlatformController]).map(routeKey),
|
|
).toEqual(
|
|
expect.arrayContaining([
|
|
'GET /qqbot/plugin-platform/installations',
|
|
'POST /qqbot/plugin-platform/upload',
|
|
'POST /qqbot/plugin-platform/validate',
|
|
'POST /qqbot/plugin-platform/install',
|
|
'POST /qqbot/plugin-platform/install-local',
|
|
'POST /qqbot/plugin-platform/enable',
|
|
'POST /qqbot/plugin-platform/disable',
|
|
'POST /qqbot/plugin-platform/upgrade',
|
|
'POST /qqbot/plugin-platform/uninstall',
|
|
'POST /qqbot/plugin-platform/config',
|
|
'GET /qqbot/plugin-platform/runtime-events',
|
|
'GET /qqbot/plugin-platform/account-bindings',
|
|
]),
|
|
);
|
|
});
|
|
|
|
it('validates manifests through the real HTTP wrapper', async () => {
|
|
const response = await request(app.getHttpServer())
|
|
.post('/qqbot/plugin-platform/validate')
|
|
.send({
|
|
manifest: createManifest(),
|
|
})
|
|
.expect(200);
|
|
|
|
expect(response.body).toMatchObject({
|
|
code: 200,
|
|
data: {
|
|
manifest: {
|
|
pluginKey: 'demo-plugin',
|
|
runtime: {
|
|
timeoutMs: 5000,
|
|
},
|
|
},
|
|
valid: true,
|
|
},
|
|
});
|
|
});
|
|
|
|
it('keeps TypeORM entity registration aligned with the persistence contract', () => {
|
|
expect(QqbotPluginPlatformModule).toBeDefined();
|
|
expect(QQBOT_PLUGIN_PLATFORM_ENTITIES).toHaveLength(9);
|
|
});
|
|
});
|