feat: improve operations diagnostics and channel management
This commit is contained in:
@@ -81,7 +81,7 @@ function createPrismaMock() {
|
||||
channelHealthMetric: { findMany: jest.fn() },
|
||||
smsChannelGroup: {
|
||||
findMany: jest.fn(),
|
||||
findUnique: jest.fn().mockResolvedValue({ id: 'group-1', code: 'G-MOBILE', name: '移动组', carrier: 'mobile', status: 'active', retryEnabled: true, retryTimeLimitHours: 72, retryTimeLimitMinutes: 4320 }),
|
||||
findUnique: jest.fn().mockResolvedValue({ id: 'group-1', code: 'G-MOBILE', name: '移动组', carrier: 'mobile', status: 'active', retryEnabled: true, retryTimeLimitHours: 72, retryTimeLimitMinutes: 4320, items: [] }),
|
||||
create: jest.fn().mockImplementation(({ data }) => Promise.resolve({ id: 'group-1', ...data })),
|
||||
delete: jest.fn().mockResolvedValue({ id: 'group-1', code: 'G-MOBILE', name: '移动组' }),
|
||||
},
|
||||
@@ -137,6 +137,7 @@ function createPrismaMock() {
|
||||
},
|
||||
smsApplication: {
|
||||
findUnique: jest.fn().mockResolvedValue({ id: 'app-1', tenantId: 'tenant-1' }),
|
||||
findMany: jest.fn().mockResolvedValue([]),
|
||||
},
|
||||
tenant: {
|
||||
findFirst: jest.fn().mockResolvedValue({ id: 'tenant-1', createdAt: new Date('2026-07-09T00:00:00.000Z') }),
|
||||
@@ -153,6 +154,7 @@ function createPrismaMock() {
|
||||
},
|
||||
smsSubmitRecord: {
|
||||
create: jest.fn().mockImplementation(({ data }) => Promise.resolve({ id: 'submit-record-1', ...data })),
|
||||
count: jest.fn().mockResolvedValue(0),
|
||||
},
|
||||
cmppConnectionState: {
|
||||
findMany: jest.fn(),
|
||||
@@ -866,16 +868,60 @@ describe('ChannelsService', () => {
|
||||
expect(prisma.channelRouteRule.create).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('deletes channel groups only when no active route rule is bound', async () => {
|
||||
it('counts distinct normal and deleted applications, channels, and queued supplier submits before deletion', async () => {
|
||||
const prisma = createPrismaMock();
|
||||
const service = new ChannelsService(prisma as never);
|
||||
prisma.smsChannelGroup.findUnique.mockResolvedValueOnce({ id: 'group-1', name: '移动主通道组', items: [{ id: 'item-1' }, { id: 'item-2' }] });
|
||||
prisma.channelRouteRule.findMany.mockResolvedValueOnce([
|
||||
{ applicationId: 'app-active' },
|
||||
{ applicationId: 'app-active' },
|
||||
{ applicationId: 'app-deleted' },
|
||||
{ applicationId: 'app-missing' },
|
||||
]);
|
||||
prisma.smsApplication.findMany.mockResolvedValueOnce([
|
||||
{ id: 'app-active', status: 'active' },
|
||||
{ id: 'app-deleted', status: 'deleted' },
|
||||
]);
|
||||
prisma.smsSubmitRecord.count.mockResolvedValueOnce(2);
|
||||
|
||||
await service.deleteGroup('group-1');
|
||||
expect(prisma.smsChannelGroupItem.deleteMany).toHaveBeenCalledWith({ where: { groupId: 'group-1' } });
|
||||
expect(prisma.smsChannelGroup.delete).toHaveBeenCalledWith({ where: { id: 'group-1' } });
|
||||
await expect(service.getGroupDeletionImpact('group-1')).resolves.toEqual({
|
||||
groupId: 'group-1',
|
||||
groupName: '移动主通道组',
|
||||
normalApplicationCount: 1,
|
||||
deletedApplicationCount: 2,
|
||||
channelCount: 2,
|
||||
pendingSupplierSubmitCount: 2,
|
||||
});
|
||||
expect(prisma.smsSubmitRecord.count).toHaveBeenCalledWith({
|
||||
where: { channelGroupId: 'group-1', submitStatus: 'queued' },
|
||||
});
|
||||
});
|
||||
|
||||
prisma.channelRouteRule.findFirst.mockResolvedValueOnce({ id: 'route-1' });
|
||||
await expect(service.deleteGroup('group-1')).rejects.toThrow('Channel group is used by application route rules');
|
||||
it('logically deletes channel groups without removing application bindings or group items', async () => {
|
||||
const prisma = createPrismaMock();
|
||||
const service = new ChannelsService(prisma as never);
|
||||
const groupUpdate = jest.fn().mockResolvedValue({ id: 'group-1', status: 'deleted' });
|
||||
const operationLogCreate = jest.fn();
|
||||
prisma.channelRouteRule.findMany.mockResolvedValue([{ applicationId: 'app-1' }]);
|
||||
prisma.smsApplication.findMany.mockResolvedValue([{ id: 'app-1', status: 'active' }]);
|
||||
prisma.$transaction.mockImplementationOnce((callback) => callback({
|
||||
smsChannelGroup: { update: groupUpdate },
|
||||
operationLog: { create: operationLogCreate },
|
||||
}));
|
||||
|
||||
await expect(service.deleteGroup('group-1')).resolves.toEqual({ id: 'group-1', status: 'deleted' });
|
||||
expect(groupUpdate).toHaveBeenCalledWith({ where: { id: 'group-1' }, data: { status: 'deleted' } });
|
||||
expect(prisma.smsChannelGroupItem.deleteMany).not.toHaveBeenCalled();
|
||||
expect(prisma.smsChannelGroup.delete).not.toHaveBeenCalled();
|
||||
expect(operationLogCreate).toHaveBeenCalledWith({
|
||||
data: expect.objectContaining({
|
||||
action: 'sms_channel_group.delete',
|
||||
detail: expect.objectContaining({
|
||||
deletionMode: 'soft_delete',
|
||||
impact: expect.objectContaining({ normalApplicationCount: 1 }),
|
||||
}),
|
||||
}),
|
||||
});
|
||||
});
|
||||
|
||||
it('upserts signature report material per channel field', async () => {
|
||||
|
||||
Reference in New Issue
Block a user