63 lines
3.6 KiB
JavaScript
63 lines
3.6 KiB
JavaScript
import assert from 'node:assert/strict'
|
|
import { readFileSync } from 'node:fs'
|
|
import { dirname, resolve } from 'node:path'
|
|
import test from 'node:test'
|
|
import { fileURLToPath } from 'node:url'
|
|
|
|
const here = dirname(fileURLToPath(import.meta.url))
|
|
const read = (name) => readFileSync(resolve(here, name), 'utf8')
|
|
|
|
test('phase3 downstream modules turn missing current-marker prerequisites into deployment blockers', () => {
|
|
const expectations = new Map([
|
|
['phase3-loading-model-bridge.mjs', '取得同 marker 的预装与柜次桥接前置'],
|
|
['phase3-pda-convergence.mjs', '取得同 marker 的 PDA 收敛前置'],
|
|
['phase3-evidence-gate.mjs', '取得同 marker 的五证据门禁前置'],
|
|
['phase3-outbound-dispatch.mjs', '取得同 marker 的 LOADED 国内出仓前置'],
|
|
['phase3-outbound-aggregate.mjs', '取得同 marker 的出仓主聚合前置'],
|
|
['phase3-dispatch-gate.mjs', '取得同 marker 的国内出仓门禁前置'],
|
|
['phase3-waiting-for-loading.mjs', '取得同 marker 的 WAITING_FOR_LOADING 前置'],
|
|
])
|
|
for (const [file, step] of expectations) {
|
|
const source = read(file)
|
|
assert.match(source, /deploymentBlocker: true/, file)
|
|
assert.match(source, new RegExp(`addStep\\(MODULE, '${step}'[\\s\\S]{0,500}false`), file)
|
|
assert.match(source, /fixtureMarker=.*runMarker=/, file)
|
|
}
|
|
})
|
|
|
|
test('phase3 inventory mutation and downstream gates cannot pass as coverage gaps', () => {
|
|
const loading = read('phase3-loading.mjs')
|
|
const convergence = read('phase3-pda-convergence.mjs')
|
|
const dispatch = read('phase3-outbound-dispatch.mjs')
|
|
const aggregate = read('phase3-outbound-aggregate.mjs')
|
|
assert.match(loading, /自动制造库存变化并验证旧 snapshot token A0409[\s\S]{0,300}false/)
|
|
assert.match(convergence, /PDA 真实库存变化后旧 token A0409 与刷新重试[\s\S]{0,300}false/)
|
|
assert.match(dispatch, /国内出仓八项门禁必须在同轮全部通过[\s\S]{0,300}false/)
|
|
assert.match(aggregate, /'CUSTOMS', 'SAILING_SCHEDULE'/)
|
|
assert.doesNotMatch(aggregate, /报关与船期历史并入统一时间线|当前服务端聚合未公开/)
|
|
})
|
|
|
|
test('outbound lifecycle checks confirm replay, immutable departure reverse boundary and final reread', () => {
|
|
const source = read('phase3-outbound-dispatch.mjs')
|
|
for (const step of [
|
|
'confirm-dispatch 幂等重放',
|
|
'相同 Idempotency-Key 不同请求拒绝',
|
|
'实际DEPARTED_WAREHOUSE节点产生后撤销精确返回A0409',
|
|
'禁止撤销边界重复请求仍精确返回A0409',
|
|
'负向与幂等验证后回查出仓聚合',
|
|
'出仓聚合保持 WAITING_FOR_LOADING、LOADED 且无成功撤销历史',
|
|
]) assert.match(source, new RegExp(step))
|
|
assert.match(source, /if \(!confirmed\?\.aggregate\) return/)
|
|
assert.match(source, /hashConflict\.http === 200 && codeOf\(hashConflict\) === 'A0409'/)
|
|
const confirm = source.indexOf('确认国内出仓进入等待装船')
|
|
const reverse = source.indexOf('实际DEPARTED_WAREHOUSE节点产生后撤销精确返回A0409')
|
|
const finalRead = source.indexOf('负向与幂等验证后回查出仓聚合')
|
|
assert.ok(confirm >= 0 && reverse > confirm && finalRead > reverse)
|
|
assert.match(source, /confirmedStatus: confirmed\.aggregate\.dispatchStatus/)
|
|
assert.doesNotMatch(source, /outbound-confirm-final|finalConfirmed|reversedVersion/)
|
|
const waiting = read('phase3-waiting-for-loading.mjs')
|
|
assert.match(waiting, /confirmations\.length === 1 && reversed\.length === 0/)
|
|
assert.match(waiting, /实际离仓节点冻结后保持一次确认且零次成功撤销/)
|
|
assert.match(waiting, /detail\?\.aggregate\?\.dispatchStatus === 'WAITING_FOR_LOADING'/)
|
|
})
|