Files
baiyue-firstleg/scripts/admin-test-env-modules/phase3-loading-model-bridge.mjs
T

47 lines
3.8 KiB
JavaScript

const MODULE = 'phase3-loading-model-bridge'
const OPTIONS = { scenario: 'parallel-loading-models', deploymentBlocker: true }
function id(value) { return value == null ? '' : String(value) }
function codeOf(response) { return response?.body?.code == null ? 'missing' : String(response.body.code) }
function failure(response) { return [400, 401, 403, 404, 409, 503].includes(response?.http) || (response?.http === 200 && codeOf(response) !== '200') }
async function request(context, method, path, body, headers = {}) {
try {
const response = await fetch(`${context.options.gateway}${path}`, { method,
headers: { Accept: 'application/json', Authorization: `Bearer ${context.token}`,
...(body === undefined ? {} : { 'Content-Type': 'application/json; charset=utf-8' }), ...headers },
body: body === undefined ? undefined : JSON.stringify(body), signal: AbortSignal.timeout(60_000) })
const raw = await response.text(); let payload = null
try { payload = raw ? JSON.parse(raw) : null } catch { /* bounded raw evidence */ }
return { method, path, http: response.status, body: payload, raw: payload === null ? raw.slice(0, 500) : null,
requestId: payload?.requestId || response.headers.get('x-request-id'), traceId: payload?.traceId || response.headers.get('x-trace-id') }
} catch (error) { return { method, path, http: 0, body: null, raw: String(error), requestId: null, traceId: null } }
}
export async function run(context) {
const fixture = context.createdResources?.phase3Loading
const tenantId = id(fixture?.tenantId); const inboundId = id(fixture?.inboundId)
const loadingPlanId = id(fixture?.loadingPlanId)
if (!tenantId || !inboundId || !loadingPlanId || fixture?.marker !== context.marker) {
context.addCoverageGap(MODULE, OPTIONS.scenario, '入库单级预装与柜次级智能装柜串联',
'本轮未取得同一 marker 的预装/柜次计划关联 fixture,未使用历史资源', 'fixture',
{ activation: { state: 'pending-fixture', assertions: ['双向关联可查', '双版本冲突原子回滚', '终态门禁一致'] } })
return
}
const inboundPath = `/api/platform/v1/inbounds/${inboundId}/preload/loading-plans?tenantId=${encodeURIComponent(tenantId)}`
const inboundResponse = await request(context, 'GET', inboundPath)
const inboundLinks = context.apiSuccess(MODULE, '从入库侧查询预装与柜次关联', inboundResponse, '', OPTIONS)
const link = Array.isArray(inboundLinks) ? inboundLinks.find((item) => id(item.loadingPlanId) === loadingPlanId) : null
context.assert(MODULE, '入库侧关联只返回本轮柜次和客户隔离键', inboundResponse,
Boolean(link) && id(link.inboundId) === inboundId && id(link.tenantId) === tenantId
&& Number(link.allocatedPackageCount) > 0, `links=${inboundLinks?.length ?? 'n/a'}`, OPTIONS)
const planResponse = await request(context, 'GET', `/api/platform/v1/first-leg/smart-loading/plans/${loadingPlanId}/preloads`)
const planLinks = context.apiSuccess(MODULE, '从柜次侧查询反向预装关联', planResponse, '', OPTIONS)
context.assert(MODULE, '柜次侧反查到同一预装计划', planResponse,
Array.isArray(planLinks) && planLinks.some((item) => id(item.inboundId) === inboundId
&& id(item.preloadPlanId) === id(fixture.preloadPlanId)), `links=${planLinks?.length ?? 'n/a'}`, OPTIONS)
const forged = await request(context, 'POST',
`/api/platform/v1/inbounds/${inboundId}/preload/loading-plans/${loadingPlanId}?tenantId=${encodeURIComponent(tenantId)}`,
{ expectedPreloadVersion: 0, expectedLoadingPlanVersion: 0 },
{ 'Idempotency-Key': `${context.marker}-bridge-bind`.slice(0, 128) })
context.addStep(MODULE, '桥接同幂等键不同版本请求拒绝且不产生部分更新', forged, failure(forged),
`HTTP=${forged.http}, code=${codeOf(forged)}`, OPTIONS)
}