243 lines
8.1 KiB
TypeScript
243 lines
8.1 KiB
TypeScript
|
|
import { Test, TestingModule } from '@nestjs/testing';
|
||
|
|
import { getRepositoryToken } from '@nestjs/typeorm';
|
||
|
|
import { Repository, DataSource } from 'typeorm';
|
||
|
|
import { AssetsService } from './assets.service';
|
||
|
|
import { Asset } from '../../entities/asset.entity';
|
||
|
|
import { AssetLog } from '../../entities/asset-log.entity';
|
||
|
|
import { Group } from '../../entities/group.entity';
|
||
|
|
import { GroupMember } from '../../entities/group-member.entity';
|
||
|
|
import { AssetType, AssetStatus, GroupMemberRole, AssetLogAction } from '../../common/enums';
|
||
|
|
import { NotFoundException, ForbiddenException, BadRequestException } from '@nestjs/common';
|
||
|
|
|
||
|
|
describe('AssetsService', () => {
|
||
|
|
let service: AssetsService;
|
||
|
|
let assetRepository: Repository<Asset>;
|
||
|
|
let assetLogRepository: Repository<AssetLog>;
|
||
|
|
let groupRepository: Repository<Group>;
|
||
|
|
let groupMemberRepository: Repository<GroupMember>;
|
||
|
|
|
||
|
|
const mockAsset = {
|
||
|
|
id: 'asset-1',
|
||
|
|
groupId: 'group-1',
|
||
|
|
type: AssetType.ACCOUNT,
|
||
|
|
name: '测试账号',
|
||
|
|
description: '测试描述',
|
||
|
|
accountCredentials: 'encrypted-data',
|
||
|
|
quantity: 1,
|
||
|
|
status: AssetStatus.AVAILABLE,
|
||
|
|
currentBorrowerId: null,
|
||
|
|
createdAt: new Date(),
|
||
|
|
updatedAt: new Date(),
|
||
|
|
};
|
||
|
|
|
||
|
|
const mockGroup = {
|
||
|
|
id: 'group-1',
|
||
|
|
name: '测试小组',
|
||
|
|
};
|
||
|
|
|
||
|
|
const mockGroupMember = {
|
||
|
|
id: 'member-1',
|
||
|
|
userId: 'user-1',
|
||
|
|
groupId: 'group-1',
|
||
|
|
role: GroupMemberRole.ADMIN,
|
||
|
|
};
|
||
|
|
|
||
|
|
const mockDataSource = {
|
||
|
|
createQueryRunner: jest.fn().mockReturnValue({
|
||
|
|
connect: jest.fn(),
|
||
|
|
startTransaction: jest.fn(),
|
||
|
|
commitTransaction: jest.fn(),
|
||
|
|
rollbackTransaction: jest.fn(),
|
||
|
|
release: jest.fn(),
|
||
|
|
manager: {
|
||
|
|
findOne: jest.fn(),
|
||
|
|
find: jest.fn(),
|
||
|
|
create: jest.fn(),
|
||
|
|
save: jest.fn(),
|
||
|
|
},
|
||
|
|
}),
|
||
|
|
};
|
||
|
|
|
||
|
|
beforeEach(async () => {
|
||
|
|
const module: TestingModule = await Test.createTestingModule({
|
||
|
|
providers: [
|
||
|
|
AssetsService,
|
||
|
|
{
|
||
|
|
provide: getRepositoryToken(Asset),
|
||
|
|
useValue: {
|
||
|
|
create: jest.fn(),
|
||
|
|
save: jest.fn(),
|
||
|
|
find: jest.fn(),
|
||
|
|
findOne: jest.fn(),
|
||
|
|
remove: jest.fn(),
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{
|
||
|
|
provide: getRepositoryToken(AssetLog),
|
||
|
|
useValue: {
|
||
|
|
create: jest.fn(),
|
||
|
|
save: jest.fn(),
|
||
|
|
find: jest.fn(),
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{
|
||
|
|
provide: getRepositoryToken(Group),
|
||
|
|
useValue: {
|
||
|
|
findOne: jest.fn(),
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{
|
||
|
|
provide: getRepositoryToken(GroupMember),
|
||
|
|
useValue: {
|
||
|
|
findOne: jest.fn(),
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{
|
||
|
|
provide: DataSource,
|
||
|
|
useValue: mockDataSource,
|
||
|
|
},
|
||
|
|
],
|
||
|
|
}).compile();
|
||
|
|
|
||
|
|
service = module.get<AssetsService>(AssetsService);
|
||
|
|
assetRepository = module.get<Repository<Asset>>(getRepositoryToken(Asset));
|
||
|
|
assetLogRepository = module.get<Repository<AssetLog>>(getRepositoryToken(AssetLog));
|
||
|
|
groupRepository = module.get<Repository<Group>>(getRepositoryToken(Group));
|
||
|
|
groupMemberRepository = module.get<Repository<GroupMember>>(getRepositoryToken(GroupMember));
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should be defined', () => {
|
||
|
|
expect(service).toBeDefined();
|
||
|
|
});
|
||
|
|
|
||
|
|
describe('create', () => {
|
||
|
|
it('应该成功创建资产', async () => {
|
||
|
|
const createDto = {
|
||
|
|
groupId: 'group-1',
|
||
|
|
type: AssetType.ACCOUNT,
|
||
|
|
name: '测试账号',
|
||
|
|
description: '测试描述',
|
||
|
|
};
|
||
|
|
|
||
|
|
jest.spyOn(groupRepository, 'findOne').mockResolvedValue(mockGroup as any);
|
||
|
|
jest.spyOn(groupMemberRepository, 'findOne').mockResolvedValue(mockGroupMember as any);
|
||
|
|
jest.spyOn(assetRepository, 'create').mockReturnValue(mockAsset as any);
|
||
|
|
jest.spyOn(assetRepository, 'save').mockResolvedValue(mockAsset as any);
|
||
|
|
jest.spyOn(assetRepository, 'findOne').mockResolvedValue(mockAsset as any);
|
||
|
|
|
||
|
|
const result = await service.create('user-1', createDto);
|
||
|
|
|
||
|
|
expect(result).toBeDefined();
|
||
|
|
expect(groupRepository.findOne).toHaveBeenCalledWith({ where: { id: 'group-1' } });
|
||
|
|
expect(groupMemberRepository.findOne).toHaveBeenCalled();
|
||
|
|
});
|
||
|
|
|
||
|
|
it('小组不存在时应该抛出异常', async () => {
|
||
|
|
const createDto = {
|
||
|
|
groupId: 'group-1',
|
||
|
|
type: AssetType.ACCOUNT,
|
||
|
|
name: '测试账号',
|
||
|
|
};
|
||
|
|
|
||
|
|
jest.spyOn(groupRepository, 'findOne').mockResolvedValue(null);
|
||
|
|
|
||
|
|
await expect(service.create('user-1', createDto)).rejects.toThrow(NotFoundException);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('无权限时应该抛出异常', async () => {
|
||
|
|
const createDto = {
|
||
|
|
groupId: 'group-1',
|
||
|
|
type: AssetType.ACCOUNT,
|
||
|
|
name: '测试账号',
|
||
|
|
};
|
||
|
|
|
||
|
|
jest.spyOn(groupRepository, 'findOne').mockResolvedValue(mockGroup as any);
|
||
|
|
jest.spyOn(groupMemberRepository, 'findOne').mockResolvedValue({
|
||
|
|
...mockGroupMember,
|
||
|
|
role: GroupMemberRole.MEMBER,
|
||
|
|
} as any);
|
||
|
|
|
||
|
|
await expect(service.create('user-1', createDto)).rejects.toThrow(ForbiddenException);
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
describe('findAll', () => {
|
||
|
|
it('应该返回资产列表', async () => {
|
||
|
|
jest.spyOn(assetRepository, 'find').mockResolvedValue([mockAsset] as any);
|
||
|
|
|
||
|
|
const result = await service.findAll('group-1');
|
||
|
|
|
||
|
|
expect(result).toHaveLength(1);
|
||
|
|
expect(result[0].accountCredentials).toBeUndefined();
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
describe('borrow', () => {
|
||
|
|
it('应该成功借用资产', async () => {
|
||
|
|
const borrowDto = { reason: '需要使用' };
|
||
|
|
|
||
|
|
jest.spyOn(assetRepository, 'findOne').mockResolvedValue(mockAsset as any);
|
||
|
|
jest.spyOn(groupMemberRepository, 'findOne').mockResolvedValue(mockGroupMember as any);
|
||
|
|
jest.spyOn(assetRepository, 'save').mockResolvedValue({ ...mockAsset, status: AssetStatus.IN_USE } as any);
|
||
|
|
jest.spyOn(assetLogRepository, 'create').mockReturnValue({} as any);
|
||
|
|
jest.spyOn(assetLogRepository, 'save').mockResolvedValue({} as any);
|
||
|
|
|
||
|
|
const result = await service.borrow('user-1', 'asset-1', borrowDto);
|
||
|
|
|
||
|
|
expect(result.message).toBe('借用成功');
|
||
|
|
expect(assetRepository.save).toHaveBeenCalled();
|
||
|
|
expect(assetLogRepository.save).toHaveBeenCalled();
|
||
|
|
});
|
||
|
|
|
||
|
|
it('资产不可用时应该抛出异常', async () => {
|
||
|
|
const borrowDto = { reason: '需要使用' };
|
||
|
|
|
||
|
|
jest.spyOn(assetRepository, 'findOne').mockResolvedValue({
|
||
|
|
...mockAsset,
|
||
|
|
status: AssetStatus.IN_USE,
|
||
|
|
} as any);
|
||
|
|
|
||
|
|
await expect(service.borrow('user-1', 'asset-1', borrowDto)).rejects.toThrow(BadRequestException);
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
describe('return', () => {
|
||
|
|
it('应该成功归还资产', async () => {
|
||
|
|
jest.spyOn(assetRepository, 'findOne').mockResolvedValue({
|
||
|
|
...mockAsset,
|
||
|
|
currentBorrowerId: 'user-1',
|
||
|
|
} as any);
|
||
|
|
jest.spyOn(assetRepository, 'save').mockResolvedValue(mockAsset as any);
|
||
|
|
jest.spyOn(assetLogRepository, 'create').mockReturnValue({} as any);
|
||
|
|
jest.spyOn(assetLogRepository, 'save').mockResolvedValue({} as any);
|
||
|
|
|
||
|
|
const result = await service.return('user-1', 'asset-1', '已归还');
|
||
|
|
|
||
|
|
expect(result.message).toBe('归还成功');
|
||
|
|
expect(assetRepository.save).toHaveBeenCalled();
|
||
|
|
});
|
||
|
|
|
||
|
|
it('非借用人归还时应该抛出异常', async () => {
|
||
|
|
jest.spyOn(assetRepository, 'findOne').mockResolvedValue({
|
||
|
|
...mockAsset,
|
||
|
|
currentBorrowerId: 'user-2',
|
||
|
|
} as any);
|
||
|
|
|
||
|
|
await expect(service.return('user-1', 'asset-1')).rejects.toThrow(ForbiddenException);
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
describe('remove', () => {
|
||
|
|
it('应该成功删除资产', async () => {
|
||
|
|
jest.spyOn(assetRepository, 'findOne').mockResolvedValue(mockAsset as any);
|
||
|
|
jest.spyOn(groupMemberRepository, 'findOne').mockResolvedValue(mockGroupMember as any);
|
||
|
|
jest.spyOn(assetRepository, 'remove').mockResolvedValue(mockAsset as any);
|
||
|
|
|
||
|
|
const result = await service.remove('user-1', 'asset-1');
|
||
|
|
|
||
|
|
expect(result.message).toBe('删除成功');
|
||
|
|
expect(assetRepository.remove).toHaveBeenCalled();
|
||
|
|
});
|
||
|
|
});
|
||
|
|
});
|