170 lines
6.1 KiB
JavaScript
170 lines
6.1 KiB
JavaScript
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();
|
|
}
|