test: complete phase3 phase4 acceptance coverage

This commit is contained in:
2026-08-25 00:24:43 +08:00
parent 84ad5e779a
commit 73d206e3f3
21 changed files with 908 additions and 69 deletions
@@ -86,11 +86,30 @@ export async function run(context) {
locationVersion = Number(afterData?.location?.version)
}
// Public APIs do not expose a safe way to create a real occupied pallet/
// location association without an inbound allocation fixture. Keep this as
// an explicit automation gap instead of claiming a deletion-protection pass.
context.addCoverageGap(MODULE, 'resource-occupancy', '托盘/库位真实占用删除保护',
'当前公共验收 API 未提供可安全构造并释放占用关联的独立 fixture;未操作历史资源', 'no-public-fixture-api')
// phase3-loading has already created and rebound a marker-owned live
// occupancy. Reuse that exact location to prove deletion protection without
// touching historical resources or inventing a setup-only API.
const loading = context.createdResources?.phase3Loading
const occupiedLocationId = id(loading?.inventoryMutationCleanup?.targetLocationId)
const occupiedWarehouseId = id(loading?.warehouseId)
context.assert(MODULE, '取得本轮装柜链真实占用库位', null,
Boolean(occupiedLocationId && occupiedWarehouseId && loading?.marker === context.marker),
`locationId=${occupiedLocationId || 'missing'}, warehouseId=${occupiedWarehouseId || 'missing'}`, OPTIONS)
if (occupiedLocationId && occupiedWarehouseId && loading?.marker === context.marker) {
const occupiedPath = `/api/platform/v1/locations/${occupiedLocationId}?tenantId=0&warehouseId=${occupiedWarehouseId}`
const occupiedDetail = await context.request('GET', occupiedPath)
const occupied = context.apiSuccess(MODULE, '读取本轮真实占用库位版本', occupiedDetail, '', OPTIONS)
const occupiedVersion = Number(occupied?.location?.version)
const rejectedDelete = await context.request('DELETE', `${occupiedPath}&version=${occupiedVersion}`)
context.addStep(MODULE, '真实占用库位删除返回A0409且保留资源', rejectedDelete,
rejectedDelete.http === 200 && ['A0409', '409'].includes(codeOf(rejectedDelete)),
`HTTP=${rejectedDelete.http}, code=${codeOf(rejectedDelete)}, version=${occupiedVersion}`, OPTIONS)
const occupiedAfter = await context.request('GET', occupiedPath)
const after = context.apiSuccess(MODULE, '删除冲突后回查占用库位', occupiedAfter, '', OPTIONS)
context.assert(MODULE, '占用删除冲突未造成资源丢失', occupiedAfter,
id(after?.location?.id) === occupiedLocationId,
`expected=${occupiedLocationId}, actual=${id(after?.location?.id) || 'missing'}`, OPTIONS)
}
// Import boundary probes use only in-memory bytes and dry-run where supported.
const bogusXlsx = new Uint8Array([0x50, 0x4b, 0x03, 0x04, 0x00, 0x00])