135 lines
4.3 KiB
TypeScript
135 lines
4.3 KiB
TypeScript
type GrantRecord = {
|
|
licenseId: string;
|
|
moduleId: string;
|
|
status: 'active' | 'disabled' | 'revoked';
|
|
image?: string | null;
|
|
version?: string | null;
|
|
digest?: string | null;
|
|
expiresAt?: Date | null;
|
|
revokedAt?: Date | null;
|
|
};
|
|
|
|
function createFakePrisma(initial: GrantRecord[] = []) {
|
|
const grants = new Map<string, GrantRecord>();
|
|
for (const grant of initial) {
|
|
grants.set(`${grant.licenseId}:${grant.moduleId}`, grant);
|
|
}
|
|
|
|
return {
|
|
grants,
|
|
licenseModuleGrant: {
|
|
findUnique: jest.fn(async ({ where }) => {
|
|
const key = `${where.licenseId_moduleId.licenseId}:${where.licenseId_moduleId.moduleId}`;
|
|
return grants.get(key) || null;
|
|
}),
|
|
findMany: jest.fn(async ({ where, orderBy }) => {
|
|
const now = where.OR?.[1]?.expiresAt?.gt;
|
|
const result = Array.from(grants.values()).filter((grant) => {
|
|
if (grant.licenseId !== where.licenseId) return false;
|
|
if (grant.status !== where.status) return false;
|
|
if (where.revokedAt === null && grant.revokedAt) return false;
|
|
if (!grant.expiresAt) return true;
|
|
return now ? grant.expiresAt > now : true;
|
|
});
|
|
|
|
if (orderBy?.moduleId === 'asc') {
|
|
result.sort((left, right) => left.moduleId.localeCompare(right.moduleId));
|
|
}
|
|
|
|
return result;
|
|
}),
|
|
create: jest.fn(async ({ data }) => {
|
|
const record = { ...data, revokedAt: null } as GrantRecord;
|
|
grants.set(`${record.licenseId}:${record.moduleId}`, record);
|
|
return record;
|
|
}),
|
|
},
|
|
};
|
|
}
|
|
|
|
describe('module-grants', () => {
|
|
beforeEach(() => {
|
|
process.env.PREMIUM_MODULE_REGISTRY_BASE = 'registry.test/flnxi/premium';
|
|
process.env.PREMIUM_MODULE_VERSION = '1.0.0';
|
|
});
|
|
|
|
afterEach(() => {
|
|
delete process.env.PREMIUM_MODULE_REGISTRY_BASE;
|
|
delete process.env.PREMIUM_MODULE_VERSION;
|
|
});
|
|
|
|
it('应按许可证版本初始化默认模块授权台账', async () => {
|
|
const { ensureDefaultModuleGrants } = await import('../module-grants');
|
|
const prisma = createFakePrisma();
|
|
|
|
await ensureDefaultModuleGrants(prisma, {
|
|
id: 'license-1',
|
|
licenseType: 'STANDARD',
|
|
expiresAt: null,
|
|
});
|
|
|
|
expect(prisma.licenseModuleGrant.create).toHaveBeenCalledTimes(2);
|
|
expect(Array.from(prisma.grants.keys()).sort()).toEqual([
|
|
'license-1:custom-templates-core',
|
|
'license-1:license-limits-core',
|
|
]);
|
|
});
|
|
|
|
it('已禁用的模块授权不应被默认初始化重新启用', async () => {
|
|
const { ensureDefaultModuleGrants, getAuthorizedModuleGrant } = await import('../module-grants');
|
|
const prisma = createFakePrisma([
|
|
{
|
|
licenseId: 'license-1',
|
|
moduleId: 'custom-templates-core',
|
|
status: 'disabled',
|
|
image: 'registry.test/flnxi/premium/custom-templates-core:1.0.0',
|
|
version: '1.0.0',
|
|
digest: null,
|
|
expiresAt: null,
|
|
revokedAt: null,
|
|
},
|
|
]);
|
|
|
|
const license = { id: 'license-1', licenseType: 'STANDARD' as const, expiresAt: null };
|
|
await ensureDefaultModuleGrants(prisma, license);
|
|
|
|
expect(prisma.grants.get('license-1:custom-templates-core')?.status).toBe('disabled');
|
|
await expect(getAuthorizedModuleGrant(prisma, license, 'custom-templates-core')).resolves.toBeNull();
|
|
});
|
|
|
|
it('被吊销或过期的模块不应出现在授权清单里', async () => {
|
|
const { listAuthorizedModuleGrants } = await import('../module-grants');
|
|
const prisma = createFakePrisma([
|
|
{
|
|
licenseId: 'license-1',
|
|
moduleId: 'license-limits-core',
|
|
status: 'active',
|
|
expiresAt: null,
|
|
revokedAt: null,
|
|
},
|
|
{
|
|
licenseId: 'license-1',
|
|
moduleId: 'custom-templates-core',
|
|
status: 'active',
|
|
expiresAt: null,
|
|
revokedAt: new Date('2026-05-01T00:00:00.000Z'),
|
|
},
|
|
{
|
|
licenseId: 'license-1',
|
|
moduleId: 'intranet-penetration-core',
|
|
status: 'active',
|
|
expiresAt: new Date('2026-05-30T00:00:00.000Z'),
|
|
revokedAt: null,
|
|
},
|
|
]);
|
|
|
|
const grants = await listAuthorizedModuleGrants(
|
|
prisma,
|
|
{ id: 'license-1', licenseType: 'PRO', expiresAt: null },
|
|
new Date('2026-06-02T00:00:00.000Z')
|
|
);
|
|
|
|
expect(grants.map((grant) => grant.moduleId)).toEqual(['license-limits-core']);
|
|
});
|
|
});
|