98 lines
3.2 KiB
TypeScript
98 lines
3.2 KiB
TypeScript
import { NextRequest } from 'next/server';
|
||
import { POST } from '../route';
|
||
import { updatePremiumModuleRuntimeStatus } from '@/lib/license/premium-module-service';
|
||
|
||
jest.mock('@/lib/license/premium-module-service', () => ({
|
||
PREMIUM_MODULE_IDS: {
|
||
PAID_CORE: 'paid-core',
|
||
},
|
||
updatePremiumModuleRuntimeStatus: jest.fn(),
|
||
}));
|
||
|
||
const mockUpdatePremiumModuleRuntimeStatus =
|
||
updatePremiumModuleRuntimeStatus as jest.MockedFunction<typeof updatePremiumModuleRuntimeStatus>;
|
||
|
||
function createRequest(body: Record<string, unknown>, token = 'a'.repeat(32)) {
|
||
return new NextRequest('http://localhost/api/license/premium-modules/runtime-status', {
|
||
method: 'POST',
|
||
headers: {
|
||
authorization: `Bearer ${token}`,
|
||
},
|
||
body: JSON.stringify(body),
|
||
});
|
||
}
|
||
|
||
describe('POST /api/license/premium-modules/runtime-status', () => {
|
||
beforeEach(() => {
|
||
jest.clearAllMocks();
|
||
process.env.MODULE_RUNTIME_STATUS_TOKEN = 'a'.repeat(32);
|
||
delete process.env.FLNXI_MODULE_STATUS_CALLBACK_TOKEN;
|
||
});
|
||
|
||
afterEach(() => {
|
||
delete process.env.MODULE_RUNTIME_STATUS_TOKEN;
|
||
delete process.env.FLNXI_MODULE_STATUS_CALLBACK_TOKEN;
|
||
});
|
||
|
||
it('需要回写 token,避免公开接口被任意写入模块运行态', async () => {
|
||
const response = await POST(createRequest({
|
||
moduleId: 'paid-core',
|
||
image: 'registry.test/flnxi/premium/paid-core:1.0.0',
|
||
status: 'running',
|
||
lastSyncAt: new Date().toISOString(),
|
||
}, 'wrong-token'));
|
||
|
||
expect(response.status).toBe(401);
|
||
expect(mockUpdatePremiumModuleRuntimeStatus).not.toHaveBeenCalled();
|
||
});
|
||
|
||
it('token 未配置时默认关闭回写入口', async () => {
|
||
delete process.env.MODULE_RUNTIME_STATUS_TOKEN;
|
||
|
||
const response = await POST(createRequest({
|
||
moduleId: 'paid-core',
|
||
image: 'registry.test/flnxi/premium/paid-core:1.0.0',
|
||
status: 'running',
|
||
lastSyncAt: new Date().toISOString(),
|
||
}));
|
||
|
||
expect(response.status).toBe(503);
|
||
expect(mockUpdatePremiumModuleRuntimeStatus).not.toHaveBeenCalled();
|
||
});
|
||
|
||
it('接受 Agent 上报的合法模块运行状态并持久化', async () => {
|
||
const lastSyncAt = new Date().toISOString();
|
||
const response = await POST(createRequest({
|
||
moduleId: 'paid-core',
|
||
image: 'registry.test/flnxi/premium/paid-core:1.0.0',
|
||
digest: 'sha256:' + 'a'.repeat(64),
|
||
status: 'running',
|
||
lastSyncAt,
|
||
}));
|
||
const data = await response.json();
|
||
|
||
expect(response.status).toBe(200);
|
||
expect(data).toEqual({ success: true, updated: 1 });
|
||
expect(mockUpdatePremiumModuleRuntimeStatus).toHaveBeenCalledWith({
|
||
moduleId: 'paid-core',
|
||
image: 'registry.test/flnxi/premium/paid-core:1.0.0',
|
||
digest: 'sha256:' + 'a'.repeat(64),
|
||
status: 'running',
|
||
lastSyncAt,
|
||
lastError: undefined,
|
||
});
|
||
});
|
||
|
||
it('拒绝未知模块或非法状态', async () => {
|
||
const response = await POST(createRequest({
|
||
moduleId: 'unknown-module',
|
||
image: 'registry.test/flnxi/premium/unknown:1.0.0',
|
||
status: 'running',
|
||
lastSyncAt: new Date().toISOString(),
|
||
}));
|
||
|
||
expect(response.status).toBe(400);
|
||
expect(mockUpdatePremiumModuleRuntimeStatus).not.toHaveBeenCalled();
|
||
});
|
||
});
|