test: align acceptance contracts with current initialization and service clients

This commit is contained in:
2026-09-29 15:06:42 +08:00
parent 60f61d7e0a
commit 41d8387cd5
6 changed files with 32 additions and 25 deletions
@@ -123,7 +123,7 @@ test('字段断言接入正式生产模块和默认全量入口', () => {
})
test('矩阵登记 LANDED 与 UNKNOWN 且禁止 fixture 伪造未知字段', () => {
const matrix = read(workspace, 'docs', '国内货柜履约', '货柜履约原型字段验收矩阵-2026-08-17.md')
const matrix = read(workspace, 'docs', '国内货柜履约', '归档', '货柜履约原型字段验收矩阵-2026-08-17.md')
assert.match(matrix, /LANDED/)
assert.match(matrix, /UNKNOWN/)
assert.match(matrix, /不得由 fixture 伪造|不生成假值/)
@@ -28,7 +28,7 @@ test('transfer review integration covers both source types and known blank-reaso
const source = await read('warehouse-transfer-review.mjs')
const caller = await read('phase4-overseas-client-services.mjs')
assert.match(caller, /return verifyWarehouseTransferReview\(context, token, order.row.customerId, body, transferNo\)/)
for (const value of ['WAIT_PDA_RECEIVING', 'PENDING_ASSIGNMENT', 'WAIT_DELIVERY', 'CANCELLED',
for (const value of ['WAIT_PDA_RECEIVING', 'INBOUND_MEASURING', 'CANCELLED',
'REJECTED', 'APPROVED', 'customerId=', 'rejected(denied, 403)', 'rejected(missingScope, 400)',
'rejected(reverse, 409)', 'rejected(emptyReason, 400)', "sourceLastlegOrderIds: []"])
assert.ok(source.includes(value), value)
@@ -22,7 +22,7 @@ const containerOverviewPanel = read(`${adminRoot}container-loading/components/Co
const containerLoadingAcceptance = read('phase3-container-loading.mjs')
const phase3LoadingAcceptance = read('phase3-loading.mjs')
const truckAcceptance = read('truck-appointments.mjs')
const matrix = read('../../../docs/国内货柜履约/货柜管理全链验收矩阵-2026-08-13.md')
const matrix = read('../../../docs/国内货柜履约/归档/货柜管理全链验收矩阵-2026-08-13.md')
test('container acceptance reads the canonical domestic workbench route', () => {
assert.match(containerLoadingAcceptance, /const DOMESTIC_CONTAINERS = `\$\{CONTAINERS\}\/domestic`/)
+16 -18
View File
@@ -152,16 +152,17 @@ test('domestic Auth receives the overseas JWT signing configuration', async () =
]) assert.match(compose, new RegExp(`${key}: \\$\\{${key}`))
})
test('domestic event bridge SQL converges legacy tenant columns to the customer entity contract', async () => {
test('domestic event bridge initialization defines customer columns without legacy migration', async () => {
const baseline = await read('event-bridge-service/src/main/resources/db/event-bridge.sql')
const incremental = await read('deploy/sql/头程数据库统一增量-MySQL8.sql')
assert.equal((baseline.match(/customer_id VARCHAR\(128\) NOT NULL/g) || []).length, 2)
assert.equal((incremental.slice(0, incremental.indexOf('CREATE TABLE IF NOT EXISTS bridge_delivery_attempt'))
.match(/customer_id VARCHAR\(128\) NOT NULL/g) || []).length, 2)
assert.match(incremental, /ALTER TABLE bridge_inbox RENAME COLUMN tenant_id TO customer_id/)
assert.match(incremental, /ALTER TABLE bridge_outbox RENAME COLUMN tenant_id TO customer_id/)
assert.match(incremental, /bridge_inbox_customer_column = 0 AND @bridge_inbox_tenant_column = 1/)
assert.match(incremental, /bridge_outbox_customer_column = 0 AND @bridge_outbox_tenant_column = 1/)
for (const table of ['bridge_inbox', 'bridge_outbox']) {
const definition = incremental.match(new RegExp(`CREATE TABLE ${table} \\(([\\s\\S]*?)\\) ENGINE`))?.[1]
assert.ok(definition, `${table} must be defined by the empty-database baseline`)
assert.match(definition, /customer_id varchar\(128\)[^\n]*NOT NULL/i)
assert.doesNotMatch(definition, /\btenant_id\b/)
}
assert.doesNotMatch(incremental, /RENAME COLUMN tenant_id TO customer_id/)
})
test('both overseas PDF consumers explicitly connect to the existing CN Print service', async () => {
@@ -176,15 +177,12 @@ test('both overseas PDF consumers explicitly connect to the existing CN Print se
}
})
test('domestic unified SQL creates the overseas hold version before queuing its comment', async () => {
test('domestic initialization defines the overseas hold version and comment in the table', async () => {
const incremental = await read('deploy/sql/头程数据库统一增量-MySQL8.sql')
const addColumn = incremental.indexOf('CALL add_inbound_overseas_hold_version();')
const queueComment = incremental.indexOf("CALL queue_column_comment('baiyue_firstleg', 'fl_inbound_order', 'last_overseas_hold_version'")
assert.notEqual(addColumn, -1)
assert.notEqual(queueComment, -1)
assert.ok(addColumn < queueComment,
'existing databases must add last_overseas_hold_version before the strict comment queue reads it')
const definition = incremental.match(/CREATE TABLE fl_inbound_order \(([\s\S]*?)\) ENGINE/)?.[1]
assert.ok(definition)
assert.match(definition, /last_overseas_hold_version bigint unsigned DEFAULT NULL COMMENT '[^']+'/i)
assert.doesNotMatch(incremental, /CALL (?:add_inbound_overseas_hold_version|queue_column_comment)\(/)
})
test('overseas unified SQL initializes the isolated Event Bridge database before services start', async () => {
@@ -192,15 +190,15 @@ test('overseas unified SQL initializes the isolated Event Bridge database before
assert.match(overseas, /CREATE DATABASE IF NOT EXISTS baiyue_event_bridge_overseas/)
assert.match(overseas, /USE baiyue_event_bridge_overseas;/)
for (const table of ['bridge_outbox', 'bridge_inbox', 'bridge_delivery_attempt']) {
assert.match(overseas, new RegExp(`CREATE TABLE IF NOT EXISTS ${table}`))
assert.match(overseas, new RegExp(`CREATE TABLE ${table} \\(`))
}
for (const index of [
'uk_bridge_outbox_idempotency', 'idx_bridge_outbox_schedule',
'uk_bridge_inbox_idempotency', 'idx_bridge_inbox_consume',
'uk_bridge_attempt', 'idx_bridge_attempt_event'
]) assert.match(overseas, new RegExp(index))
assert.match(overseas, /COUNT\(DISTINCT CONCAT\(table_name, ':', index_name\)\)/)
assert.match(overseas, /CALL assert_overseas_event_bridge_schema\(\);/)
assert.doesNotMatch(overseas, /CREATE TABLE IF NOT EXISTS/)
assert.match(overseas, /initialization_status/)
assert.ok(overseas.indexOf('USE baiyue_event_bridge_overseas;') < overseas.indexOf('USE baiyue_lastleg;'),
'overseas Event Bridge schema must be initialized before Lastleg tables')
})
@@ -15,6 +15,14 @@ const http = (path, source, target, contexts, access, idempotency, note) => ({
})
export const SYNCHRONOUS_CLIENTS = Object.freeze([
feign('firstleg/src/main/java/com/baiyue/firstleg/client/DomesticPdaOperatorClient.java',
'firstleg-service', 'iam-service', ['REQUEST'], 'READ', 'SAFE_READ', '按作业仓与账号查询有效国内 PDA 操作人,内部服务令牌保护'),
feign('order/src/main/java/com/baiyue/order/client/LegacyImportPricingClient.java',
'order-service', 'firstleg-service', ['REQUEST'], 'READ', 'SAFE_READ', '历史订单导入按客户与始发仓只读匹配渠道'),
feign('order/src/main/java/com/baiyue/order/client/LegacyImportWarehouseClient.java',
'order-service', 'warehouse-service', ['REQUEST'], 'READ', 'SAFE_READ', '历史订单导入只读匹配仓库目录'),
http('lastleg-service/src/main/java/com/baiyue/lastleg/transfer/gateway/HttpTransferMeasurementPhotoFileGateway.java',
'lastleg-service', 'file-service', ['REQUEST'], 'READ_WRITE', 'MIXED', '转仓测量照片上传无幂等键,元数据与下载按客户、业务类型和转仓单校验归属'),
feign('lastleg-service/src/main/java/com/baiyue/lastleg/client/PrintPdfClient.java',
'lastleg-service', 'print-service', ['REQUEST'], 'READ', 'SAFE_READ', '根据已授权排车快照生成 BOL PDF,内部令牌保护,无业务状态写入'),
feign('auth/src/main/java/com/baiyue/auth/client/IamAuthorizationClient.java',
@@ -101,15 +101,15 @@ async function discoverFeignEdges() {
return clients.sort((left, right) => left.path.localeCompare(right.path))
}
test('all 60 Feign clients have reviewed context, access and idempotency metadata', async () => {
test('all Feign clients have reviewed context, access and idempotency metadata', async () => {
const reviewed = SYNCHRONOUS_CLIENTS.filter(client => client.transport === 'FEIGN')
.map(({ path, source, target }) => ({ path, source, target }))
.sort((left, right) => left.path.localeCompare(right.path))
assert.equal(reviewed.length, 60)
assert.equal(reviewed.length, 63)
assert.deepEqual(await discoverFeignEdges(), reviewed)
})
test('all 23 raw HTTP transports have reviewed context, access and idempotency metadata', async () => {
test('all raw HTTP transports have reviewed context, access and idempotency metadata', async () => {
const discovered = []
for (const module of ['common-audit', 'event-bridge-service', 'gateway-overseas', 'lastleg-service', 'integration-service']) {
for (const file of await javaFiles(path.join(root, module, 'src', 'main', 'java'))) {
@@ -121,7 +121,7 @@ test('all 23 raw HTTP transports have reviewed context, access and idempotency m
}
const reviewed = SYNCHRONOUS_CLIENTS.filter(client => client.transport === 'HTTP')
.map(client => client.path).sort()
assert.equal(reviewed.length, 23)
assert.equal(reviewed.length, 24)
assert.deepEqual(discovered.sort(), reviewed)
})
@@ -224,6 +224,7 @@ test('Order, Firstleg and Finance form the reviewed REQUEST SCC', () => {
'order/src/main/java/com/baiyue/order/client/FirstlegInboundClient.java',
'order/src/main/java/com/baiyue/order/client/FirstlegPricingClient.java',
'order/src/main/java/com/baiyue/order/client/FirstlegUnifiedOrderClient.java',
'order/src/main/java/com/baiyue/order/client/LegacyImportPricingClient.java',
'order/src/main/java/com/baiyue/order/client/MerchantPricingCatalogClient.java'
])
assert.deepEqual(firstlegToOrder.map(client => client.path).sort(), [