308 lines
10 KiB
TypeScript
308 lines
10 KiB
TypeScript
/**
|
||
* 许可证限制检查工具测试
|
||
* 测试 lib/license/check-limits.ts 中的限制检查函数
|
||
*/
|
||
|
||
import {
|
||
canCreateUser,
|
||
canUploadMaterial,
|
||
canUseCustomTemplates,
|
||
canUseDepartmentIsolation,
|
||
canUseIntranetPenetration,
|
||
canUseSystemSettings,
|
||
canUseApiAccess,
|
||
} from '../license/check-limits';
|
||
|
||
// Mock license-service 模块
|
||
jest.mock('../license/license-service', () => ({
|
||
isFeatureEnabled: jest.fn(),
|
||
getLicenseType: jest.fn(),
|
||
}));
|
||
|
||
jest.mock('../license/premium-module-service', () => ({
|
||
authorizePremiumModuleAction: jest.fn(),
|
||
getAuthorizedUsageLimits: jest.fn(),
|
||
PREMIUM_MODULE_IDS: {
|
||
LICENSE_LIMITS_CORE: 'license-limits-core',
|
||
CUSTOM_TEMPLATES_CORE: 'custom-templates-core',
|
||
INTRANET_PENETRATION_CORE: 'intranet-penetration-core',
|
||
},
|
||
}));
|
||
|
||
jest.mock('@/lib/prisma', () => ({
|
||
prisma: {
|
||
user: { count: jest.fn() },
|
||
material: { count: jest.fn() },
|
||
},
|
||
}));
|
||
|
||
import { prisma } from '@/lib/prisma';
|
||
import { isFeatureEnabled, getLicenseType } from '../license/license-service';
|
||
import {
|
||
authorizePremiumModuleAction,
|
||
getAuthorizedUsageLimits,
|
||
} from '../license/premium-module-service';
|
||
|
||
const mockIsFeatureEnabled = isFeatureEnabled as jest.MockedFunction<typeof isFeatureEnabled>;
|
||
const mockGetLicenseType = getLicenseType as jest.MockedFunction<typeof getLicenseType>;
|
||
const mockGetAuthorizedUsageLimits = getAuthorizedUsageLimits as jest.MockedFunction<typeof getAuthorizedUsageLimits>;
|
||
const mockAuthorizePremiumModuleAction =
|
||
authorizePremiumModuleAction as jest.MockedFunction<typeof authorizePremiumModuleAction>;
|
||
const mockUserCount = prisma.user.count as jest.MockedFunction<typeof prisma.user.count>;
|
||
const mockMaterialCount = prisma.material.count as jest.MockedFunction<typeof prisma.material.count>;
|
||
|
||
describe('canCreateUser', () => {
|
||
beforeEach(() => {
|
||
jest.clearAllMocks();
|
||
mockAuthorizePremiumModuleAction.mockResolvedValue({
|
||
available: true,
|
||
moduleId: 'license-limits-core',
|
||
action: 'licenseLimits:enforce',
|
||
status: 'running',
|
||
});
|
||
});
|
||
|
||
it('当未达到限制时应该返回 allowed: true', async () => {
|
||
mockGetAuthorizedUsageLimits.mockResolvedValue({ maxUsers: 10, maxMaterials: 100 });
|
||
mockUserCount.mockResolvedValue(5);
|
||
|
||
const result = await canCreateUser();
|
||
|
||
expect(result.allowed).toBe(true);
|
||
expect(result.current).toBe(5);
|
||
expect(result.max).toBe(10);
|
||
expect(result.message).toBeUndefined();
|
||
expect(mockGetAuthorizedUsageLimits).toHaveBeenCalled();
|
||
expect(mockUserCount).toHaveBeenCalled();
|
||
});
|
||
|
||
it('当达到限制时(FREE 版本)应该返回授权处理提示', async () => {
|
||
mockGetAuthorizedUsageLimits.mockResolvedValue({ maxUsers: 10, maxMaterials: 100 });
|
||
mockUserCount.mockResolvedValue(10);
|
||
mockGetLicenseType.mockResolvedValue('FREE');
|
||
|
||
const result = await canCreateUser();
|
||
|
||
expect(result.allowed).toBe(false);
|
||
expect(result.message).toContain('当前许可证');
|
||
expect(result.message).toContain('10');
|
||
expect(result.message).toContain('联系管理员');
|
||
});
|
||
|
||
it('当达到限制时(非 FREE 版本)应该返回联系管理员提示', async () => {
|
||
mockGetAuthorizedUsageLimits.mockResolvedValue({ maxUsers: 100, maxMaterials: 1000 });
|
||
mockUserCount.mockResolvedValue(100);
|
||
mockGetLicenseType.mockResolvedValue('STANDARD');
|
||
|
||
const result = await canCreateUser();
|
||
|
||
expect(result.allowed).toBe(false);
|
||
expect(result.message).toContain('联系管理员');
|
||
expect(result.message).toContain('100');
|
||
});
|
||
|
||
it('缺少限额授权模块时应该拒绝创建用户', async () => {
|
||
mockGetAuthorizedUsageLimits.mockResolvedValue(null);
|
||
|
||
const result = await canCreateUser();
|
||
|
||
expect(result).toEqual({
|
||
allowed: false,
|
||
current: 0,
|
||
max: 0,
|
||
message: '授权限额模块不可用,请重新验证许可证或联系管理员。',
|
||
});
|
||
expect(mockUserCount).not.toHaveBeenCalled();
|
||
});
|
||
});
|
||
|
||
describe('canUploadMaterial', () => {
|
||
beforeEach(() => {
|
||
jest.clearAllMocks();
|
||
mockAuthorizePremiumModuleAction.mockResolvedValue({
|
||
available: true,
|
||
moduleId: 'license-limits-core',
|
||
action: 'licenseLimits:enforce',
|
||
status: 'running',
|
||
});
|
||
});
|
||
|
||
it('当未达到限制时应该返回 allowed: true', async () => {
|
||
mockGetAuthorizedUsageLimits.mockResolvedValue({ maxUsers: 10, maxMaterials: 100 });
|
||
mockMaterialCount.mockResolvedValue(50);
|
||
|
||
const result = await canUploadMaterial();
|
||
|
||
expect(result.allowed).toBe(true);
|
||
expect(result.current).toBe(50);
|
||
expect(result.max).toBe(100);
|
||
expect(mockGetAuthorizedUsageLimits).toHaveBeenCalled();
|
||
expect(mockMaterialCount).toHaveBeenCalled();
|
||
});
|
||
|
||
it('当达到限制时(FREE 版本)应该返回授权处理提示', async () => {
|
||
mockGetAuthorizedUsageLimits.mockResolvedValue({ maxUsers: 10, maxMaterials: 100 });
|
||
mockMaterialCount.mockResolvedValue(100);
|
||
mockGetLicenseType.mockResolvedValue('FREE');
|
||
|
||
const result = await canUploadMaterial();
|
||
|
||
expect(result.allowed).toBe(false);
|
||
expect(result.message).toContain('当前许可证');
|
||
expect(result.message).toContain('素材');
|
||
expect(result.message).toContain('联系管理员');
|
||
});
|
||
|
||
it('当达到限制时(非 FREE 版本)应该返回联系管理员提示', async () => {
|
||
mockGetAuthorizedUsageLimits.mockResolvedValue({ maxUsers: -1, maxMaterials: 1000 });
|
||
mockMaterialCount.mockResolvedValue(1000);
|
||
mockGetLicenseType.mockResolvedValue('PRO');
|
||
|
||
const result = await canUploadMaterial();
|
||
|
||
expect(result.allowed).toBe(false);
|
||
expect(result.message).toContain('联系管理员');
|
||
});
|
||
|
||
it('缺少限额授权模块时应该拒绝上传素材', async () => {
|
||
mockGetAuthorizedUsageLimits.mockResolvedValue(null);
|
||
|
||
const result = await canUploadMaterial();
|
||
|
||
expect(result).toEqual({
|
||
allowed: false,
|
||
current: 0,
|
||
max: 0,
|
||
message: '授权限额模块不可用,请重新验证许可证或联系管理员。',
|
||
});
|
||
expect(mockMaterialCount).not.toHaveBeenCalled();
|
||
});
|
||
});
|
||
|
||
describe('功能开关检查', () => {
|
||
beforeEach(() => {
|
||
jest.clearAllMocks();
|
||
});
|
||
|
||
describe('canUseCustomTemplates', () => {
|
||
it('当功能启用时应该返回 true', async () => {
|
||
mockIsFeatureEnabled.mockResolvedValue(true);
|
||
mockAuthorizePremiumModuleAction.mockResolvedValue({
|
||
available: true,
|
||
moduleId: 'custom-templates-core',
|
||
action: 'customTemplates:use',
|
||
status: 'running',
|
||
});
|
||
expect(await canUseCustomTemplates()).toBe(true);
|
||
expect(mockIsFeatureEnabled).toHaveBeenCalledWith('customTemplates');
|
||
expect(mockAuthorizePremiumModuleAction).toHaveBeenCalledWith(
|
||
'custom-templates-core',
|
||
'customTemplates:use'
|
||
);
|
||
});
|
||
|
||
it('当功能禁用时应该返回 false', async () => {
|
||
mockIsFeatureEnabled.mockResolvedValue(false);
|
||
expect(await canUseCustomTemplates()).toBe(false);
|
||
expect(mockAuthorizePremiumModuleAction).not.toHaveBeenCalled();
|
||
});
|
||
|
||
it('当付费能力模块未运行或拒绝授权时应该返回 false', async () => {
|
||
mockIsFeatureEnabled.mockResolvedValue(true);
|
||
mockAuthorizePremiumModuleAction.mockResolvedValue({
|
||
available: false,
|
||
moduleId: 'custom-templates-core',
|
||
action: 'customTemplates:use',
|
||
status: 'missing',
|
||
});
|
||
expect(await canUseCustomTemplates()).toBe(false);
|
||
});
|
||
});
|
||
|
||
describe('canUseDepartmentIsolation', () => {
|
||
it('当功能启用时应该返回 true', async () => {
|
||
mockIsFeatureEnabled.mockResolvedValue(true);
|
||
expect(await canUseDepartmentIsolation()).toBe(true);
|
||
expect(mockIsFeatureEnabled).toHaveBeenCalledWith('departmentIsolation');
|
||
});
|
||
|
||
it('当功能禁用时应该返回 false', async () => {
|
||
mockIsFeatureEnabled.mockResolvedValue(false);
|
||
expect(await canUseDepartmentIsolation()).toBe(false);
|
||
});
|
||
});
|
||
|
||
describe('canUseIntranetPenetration', () => {
|
||
it('当功能启用时应该返回 true', async () => {
|
||
mockIsFeatureEnabled.mockResolvedValue(true);
|
||
mockAuthorizePremiumModuleAction.mockResolvedValue({
|
||
available: true,
|
||
moduleId: 'intranet-penetration-core',
|
||
action: 'intranetPenetration:use',
|
||
status: 'running',
|
||
});
|
||
expect(await canUseIntranetPenetration()).toBe(true);
|
||
expect(mockIsFeatureEnabled).toHaveBeenCalledWith('intranetPenetration');
|
||
expect(mockAuthorizePremiumModuleAction).toHaveBeenCalledWith(
|
||
'intranet-penetration-core',
|
||
'intranetPenetration:use'
|
||
);
|
||
});
|
||
|
||
it('当功能禁用时应该返回 false', async () => {
|
||
mockIsFeatureEnabled.mockResolvedValue(false);
|
||
expect(await canUseIntranetPenetration()).toBe(false);
|
||
expect(mockAuthorizePremiumModuleAction).not.toHaveBeenCalled();
|
||
});
|
||
|
||
it('当付费能力模块未运行或拒绝授权时应该返回 false', async () => {
|
||
mockIsFeatureEnabled.mockResolvedValue(true);
|
||
mockAuthorizePremiumModuleAction.mockResolvedValue({
|
||
available: false,
|
||
moduleId: 'intranet-penetration-core',
|
||
action: 'intranetPenetration:use',
|
||
status: 'unhealthy',
|
||
});
|
||
expect(await canUseIntranetPenetration()).toBe(false);
|
||
});
|
||
});
|
||
|
||
describe('canUseSystemSettings', () => {
|
||
it('当功能启用时应该返回 true', async () => {
|
||
mockIsFeatureEnabled.mockResolvedValue(true);
|
||
expect(await canUseSystemSettings()).toBe(true);
|
||
expect(mockIsFeatureEnabled).toHaveBeenCalledWith('systemSettings');
|
||
});
|
||
|
||
it('当功能禁用时应该返回 false', async () => {
|
||
mockIsFeatureEnabled.mockResolvedValue(false);
|
||
expect(await canUseSystemSettings()).toBe(false);
|
||
});
|
||
});
|
||
|
||
describe('canUseApiAccess', () => {
|
||
it('当功能启用时应该返回 true', async () => {
|
||
mockIsFeatureEnabled.mockResolvedValue(true);
|
||
expect(await canUseApiAccess()).toBe(true);
|
||
expect(mockIsFeatureEnabled).toHaveBeenCalledWith('apiAccess');
|
||
});
|
||
|
||
it('当功能禁用时应该返回 false', async () => {
|
||
mockIsFeatureEnabled.mockResolvedValue(false);
|
||
expect(await canUseApiAccess()).toBe(false);
|
||
});
|
||
});
|
||
});
|
||
|
||
describe('LimitCheckResult 接口', () => {
|
||
it('应该正确处理无限制情况 (max = -1)', async () => {
|
||
mockGetAuthorizedUsageLimits.mockResolvedValue({ maxUsers: -1, maxMaterials: -1 });
|
||
|
||
const result = await canCreateUser();
|
||
|
||
expect(result.allowed).toBe(true);
|
||
expect(result.max).toBe(-1);
|
||
expect(mockUserCount).not.toHaveBeenCalled();
|
||
});
|
||
});
|