import { PrismaPg } from '../../api/node_modules/@prisma/adapter-pg/dist/index.js'; import { PrismaClient } from '../../api/node_modules/@prisma/client/index.js'; const databaseUrl = process.env.DATABASE_URL ?? 'postgresql://cmpp:cmpp_password@localhost:5432/cmpp_platform?schema=public'; const apiBaseUrl = process.env.API_BASE_URL ?? 'http://127.0.0.1:3102/api'; const databaseHost = new URL(databaseUrl).hostname; const apiHost = new URL(apiBaseUrl).hostname; if (!['localhost', '127.0.0.1', '::1'].includes(databaseHost) || !['localhost', '127.0.0.1', '::1'].includes(apiHost)) { throw new Error('This smoke test is restricted to a local API and PostgreSQL database'); } const prisma = new PrismaClient({ adapter: new PrismaPg(databaseUrl) }); const suffix = `${Date.now()}-${process.pid}`; const messageId = `SMOKE-RECEIPT-${suffix}`; const submitId = `SMOKE-SUBMIT-${suffix}`; const gatewayMessageId1 = `SMOKE-GW-1-${suffix}`; const gatewayMessageId2 = `SMOKE-GW-2-${suffix}`; let messageRecordId; let originalChannelId; let copyChannelId; async function postReceipt(body) { const response = await fetch(`${apiBaseUrl}/gateway/events/receipt`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body), }); const payload = await response.json().catch(() => ({})); if (!response.ok) { throw new Error(`receipt API returned ${response.status}: ${JSON.stringify(payload)}`); } return payload; } try { const supplier = { carrier: 'all', sendRegion: '全国', protocol: 'CMPP', gatewayHost: '127.0.0.1', gatewayPort: 27890, account: 'smoke-shared-supplier', passwordCipher: 'smoke-only', srcId: '10690000', cmppVersion: '2.0', status: 'disabled', }; const originalChannel = await prisma.smsChannel.create({ data: { ...supplier, code: `SMOKE-ORIG-${suffix}`, name: 'Smoke original supplier connection' }, }); const copyChannel = await prisma.smsChannel.create({ data: { ...supplier, code: `SMOKE-COPY-${suffix}`, name: 'Smoke copied supplier connection' }, }); originalChannelId = originalChannel.id; copyChannelId = copyChannel.id; const message = await prisma.smsMessageRecord.create({ data: { messageId, phoneNumber: '13127620092', content: '本地跨连接长短信回执聚合验证', billingUnits: 2, channelId: originalChannel.id, submitId, gatewayMessageId: gatewayMessageId1, status: 'submitted', submitStatus: 'accepted', submittedAt: new Date(), }, }); messageRecordId = message.id; const submit = await prisma.smsSubmitRecord.create({ data: { messageRecordId: message.id, channelId: originalChannel.id, submitId, gatewayMessageId: gatewayMessageId1, submitStatus: 'accepted', submittedAt: new Date(), }, }); await prisma.smsMessageSegmentAudit.createMany({ data: [ { messageRecordId: message.id, submitRecordId: submit.id, channelId: originalChannel.id, submitId, segmentTotal: 2, segmentIndex: 1, gatewayMessageId: gatewayMessageId1, submitStatus: 'accepted', }, { messageRecordId: message.id, submitRecordId: submit.id, channelId: originalChannel.id, submitId, segmentTotal: 2, segmentIndex: 2, gatewayMessageId: gatewayMessageId2, submitStatus: 'accepted', }, ], }); await postReceipt({ messageId: `receipt-${gatewayMessageId2}`, channelId: copyChannel.id, gatewayMessageId: gatewayMessageId2, phoneNumber: '13127620092', receiptStatus: 'delivered', rawStatus: 'DELIVRD', }); const partial = await prisma.smsMessageRecord.findUniqueOrThrow({ where: { id: message.id } }); if (partial.status !== 'submitted' || partial.receiptStatus !== null) { throw new Error(`first segment finalized the main message unexpectedly: ${partial.status}/${partial.receiptStatus}`); } const crossReceipt = await prisma.smsReceiptRecord.findFirstOrThrow({ where: { messageRecordId: message.id, gatewayMessageId: gatewayMessageId2 }, }); if (crossReceipt.channelId !== originalChannel.id) { throw new Error(`cross-connection receipt kept physical channel ${crossReceipt.channelId}`); } await postReceipt({ messageId, channelId: originalChannel.id, gatewayMessageId: gatewayMessageId1, phoneNumber: '13127620092', receiptStatus: 'delivered', rawStatus: 'DELIVRD', }); const completed = await prisma.smsMessageRecord.findUniqueOrThrow({ where: { id: message.id } }); const receipts = await prisma.smsReceiptRecord.count({ where: { messageRecordId: message.id } }); const deliveredSegments = await prisma.smsMessageSegmentAudit.count({ where: { messageRecordId: message.id, receiptStatus: 'delivered' }, }); if (completed.status !== 'delivered' || completed.receiptStatus !== 'delivered' || receipts !== 2 || deliveredSegments !== 2) { throw new Error(`aggregate result mismatch: ${completed.status}/${completed.receiptStatus}, receipts=${receipts}, segments=${deliveredSegments}`); } console.log(JSON.stringify({ passed: true, messageId, physicalReceiptChannelId: copyChannel.id, logicalReceiptChannelId: crossReceipt.channelId, statusAfterOneOfTwo: partial.status, finalStatus: completed.status, receipts, deliveredSegments, })); } finally { if (messageRecordId) { await prisma.cmppDownstreamDelivery.deleteMany({ where: { messageRecordId } }); await prisma.smsReceiptRecord.deleteMany({ where: { messageRecordId } }); await prisma.smsMessageSegmentAudit.deleteMany({ where: { messageRecordId } }); await prisma.smsSubmitRecord.deleteMany({ where: { messageRecordId } }); await prisma.smsMessageRecord.deleteMany({ where: { id: messageRecordId } }); } await prisma.protocolInteractionLog.deleteMany({ where: { messageId } }).catch(() => undefined); const channelIds = [originalChannelId, copyChannelId].filter(Boolean); if (channelIds.length > 0) { await prisma.smsChannel.deleteMany({ where: { id: { in: channelIds } } }); } await prisma.$disconnect(); }