fix: make downstream connection events idempotent

This commit is contained in:
hectorzhao
2026-08-25 17:53:05 +08:00
parent 394949f9f6
commit b5005f21d5
4 changed files with 35 additions and 4 deletions
+26 -2
View File
@@ -147,6 +147,7 @@ function createPrismaMock() {
findMany: jest.fn().mockResolvedValue([{ id: 'downstream-1', applicationId: 'app-1', tenantId: 'tenant-1', account: '100001', enterpriseCode: 'APP-EC', connectionId: 'gateway-1-1', status: 'connected', connectedAt: new Date(), lastHeartbeatAt: new Date() }]),
findUnique: jest.fn().mockResolvedValue(null),
create: jest.fn().mockImplementation(({ data }) => Promise.resolve({ id: 'downstream-1', ...data })),
upsert: jest.fn().mockImplementation(({ create, update }) => Promise.resolve({ id: 'downstream-1', ...(create ?? update) })),
update: jest.fn().mockImplementation(({ data }) => Promise.resolve({ id: 'downstream-1', ...data })),
delete: jest.fn().mockResolvedValue({ id: 'downstream-1' }),
deleteMany: jest.fn().mockResolvedValue({ count: 0 }),
@@ -646,8 +647,9 @@ describe('SmsConfigService', () => {
observedAt: '2026-07-11T11:00:00.000Z',
});
expect(prisma.cmppDownstreamConnection.create).toHaveBeenCalledWith({
data: expect.objectContaining({
expect(prisma.cmppDownstreamConnection.upsert).toHaveBeenCalledWith({
where: { connectionId: 'gateway-1-1' },
create: expect.objectContaining({
applicationId: 'app-1',
tenantId: 'tenant-1',
account: '100001',
@@ -656,6 +658,10 @@ describe('SmsConfigService', () => {
status: 'connected',
remoteIp: '127.0.0.1',
}),
update: expect.objectContaining({
applicationId: 'app-1',
status: 'connected',
}),
});
expect(prisma.cmppDownstreamConnection.deleteMany).toHaveBeenCalledWith({
where: {
@@ -1103,6 +1109,24 @@ describe('SmsConfigService', () => {
expect(prisma.smsSignature.update).not.toHaveBeenCalled();
});
it('accepts concurrent state callbacks for the same newly connected Gateway session', async () => {
const prisma = createPrismaMock();
prisma.smsApplication.findUnique.mockResolvedValue({
id: 'app-1', tenantId: 'tenant-1', cmppEnterpriseCode: 'APP-EC', cmppMaxConnections: 1,
interfaceEnabled: true, status: 'active', ipAllowlist: [],
});
prisma.cmppDownstreamConnection.findUnique.mockResolvedValue(null);
prisma.cmppDownstreamConnection.findMany.mockResolvedValue([{ connectionId: 'gateway-current' }]);
const service = new SmsConfigService(prisma as never);
await expect(service.recordDownstreamConnectionEvent({
account: '100001', connectionId: 'gateway-current', status: 'submit', remoteIp: '127.0.0.1',
})).resolves.toEqual(expect.objectContaining({ connectionId: 'gateway-current' }));
expect(prisma.cmppDownstreamConnection.upsert).toHaveBeenCalledWith(expect.objectContaining({
where: { connectionId: 'gateway-current' },
}));
});
it('applies the audit submission range to signatures, templates and drainage records', async () => {
const prisma = createPrismaMock();
const service = new SmsConfigService(prisma as never);