61 lines
2.4 KiB
TypeScript
61 lines
2.4 KiB
TypeScript
import { SendGatewaySubmitService } from './send-gateway-submit.service';
|
|
|
|
describe('shared dispatch night gate', () => {
|
|
function setup() {
|
|
const message = {
|
|
id: 'm1',
|
|
status: 'queued',
|
|
tenantId: 't1',
|
|
applicationId: 'a1',
|
|
batchTaskId: 'b1',
|
|
content: '任意内容',
|
|
};
|
|
const prisma = {
|
|
smsMessageRecord: {
|
|
findUnique: jest.fn().mockResolvedValue(message),
|
|
findMany: jest.fn().mockResolvedValue([message, { ...message, id: 'm2' }]),
|
|
update: jest.fn(),
|
|
},
|
|
};
|
|
const risk = { guardNightSending: jest.fn().mockResolvedValue(new Set(['m1'])) };
|
|
const facade = {
|
|
refreshTaskProgress: jest.fn(),
|
|
selectChannelForMessage: jest.fn(),
|
|
submitMessageToGateway: jest.fn(),
|
|
};
|
|
const sut = new SendGatewaySubmitService(
|
|
prisma as never,
|
|
{} as never,
|
|
risk as never,
|
|
{} as never,
|
|
{} as never,
|
|
facade as never,
|
|
{} as never,
|
|
);
|
|
return { sut, prisma, risk, facade };
|
|
}
|
|
it('holds single-message jobs before any channel or Submit operation', async () => {
|
|
const { sut, facade } = setup();
|
|
expect(await sut.processSendJob({ messageRecordId: 'm1' })).toMatchObject({
|
|
status: 'pending_review',
|
|
submitted: false,
|
|
});
|
|
expect(facade.selectChannelForMessage).not.toHaveBeenCalled();
|
|
expect(facade.submitMessageToGateway).not.toHaveBeenCalled();
|
|
});
|
|
it('partitions the fast worker batch by persistent gate decisions', async () => {
|
|
const { sut } = setup();
|
|
const route = jest.spyOn(sut as never, 'planRoutesBatch').mockResolvedValue({ planned: [], failed: [] } as never);
|
|
const result = await sut['processSendJobBatch']([{ messageRecordId: 'm1' }, { messageRecordId: 'm2' }]);
|
|
expect(result.get('m1')).toMatchObject({ status: 'pending_review' });
|
|
expect(route).toHaveBeenCalledWith([expect.objectContaining({ id: 'm2' })]);
|
|
});
|
|
it('propagates database failures without submitting or misclassifying them as routing failures', async () => {
|
|
const { sut, risk, facade, prisma } = setup();
|
|
risk.guardNightSending.mockRejectedValue(new Error('database unavailable'));
|
|
await expect(sut.processSendJob({ messageRecordId: 'm1' })).rejects.toThrow('database unavailable');
|
|
expect(prisma.smsMessageRecord.update).not.toHaveBeenCalled();
|
|
expect(facade.submitMessageToGateway).not.toHaveBeenCalled();
|
|
});
|
|
});
|