Files
baiyue-firstleg/scripts/fleet-test-env-acceptance.test.mjs
T

714 lines
54 KiB
JavaScript

import test from 'node:test'
import assert from 'node:assert/strict'
import { mkdtempSync, mkdirSync, readFileSync, writeFileSync, existsSync, rmSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { join, dirname, resolve } from 'node:path'
import { AcceptanceRun } from './admin-test-env-acceptance.mjs'
import { run as runInboundMeasurement } from './admin-test-env-modules/inbound-measurement.mjs'
import { verifyPalletLabels } from './admin-test-env-modules/phase3-loading-finalize.mjs'
function departedRecoveryFixture() {
const snapshotTrip = { tripNo: 'TR-OWN', status: 'IN_TRANSIT', recordVersion: '27', vehicleId: 'V1', driverId: 'D1', warehouseId: 'W1', departedAt: '2026-10-03T11:00:00Z' }
const cargo = [{ dispatchNo: 'OWN', dispatchItemId: 'I1', warehousePalletId: 'P1', packages: 2 }, { dispatchNo: 'EXT', dispatchItemId: 'I2', warehousePalletId: 'P2', packages: 1 }]
const departure = { action: 'DEPART', recordVersion: '27', snapshot: { trip: snapshotTrip, confirmedLoad: { manifestHash: 'a'.repeat(64), cargo } } }
const proof = { marker: 'RUN', tripNo: 'TR-OWN', warehouseId: 'W1', customerId: 'C1', status: 'CHECKING', stage: 'TRIP_OPERATING_COSTS', checkpoints: [],
dispatchNos: ['OWN', 'EXT'], picker: { membershipId: 'OLD-PDA' }, departureRequest: { idempotencyKey: 'old-key' },
departure: { tripNo: 'TR-OWN', status: 'IN_TRANSIT', departedAt: snapshotTrip.departedAt, shippedPackages: 3 } }
const trip = { marker: 'RUN', tripNo: 'TR-OWN', costAcceptance: { marker: 'RUN', status: 'FAILED', costs: [], departure,
requests: [{ method: 'GET', status: 'RESPONDED', http: 200, code: '200', requestId: 'r', traceId: 't' }] },
externalReceipt: { status: 'VERIFIED', bookingNo: 'BK', warehousePalletId: 'P2' }, externalDispatch: { dispatchNo: 'EXT', deliveryNo: 'DL-EXT' } }
const report = { success: false, steps: [{ name: '独立预期覆盖全部实物且没有重叠托盘', passed: false }, { name: '模块执行', passed: false }],
createdResources: { fleetAcceptance: proof, fleetTrips: [trip], fleetCostActors: { status: 'DISABLED' }, fleetFeeCoverageCases: [{ mode: 'PARTIAL', proof: { deliveryNos: ['DL-OWN'] } }] } }
const base = '/api/platform/v1/last-leg/fleet/trips/TR-OWN'
const responses = new Map([[base, { trip: structuredClone(snapshotTrip), dispatches: [{ dispatchNo: 'OWN', customerId: 'C1' }, { dispatchNo: 'EXT', customerId: 'C1' }] }],
[base + '/history?page=1&size=100', { total: 1, records: [structuredClone(departure)] }],
[base + '/costs?page=1&size=100', { page: { records: [], total: 0 }, summary: { manifestHash: 'a'.repeat(64), departureVersion: '27', totals: [] } }],
[base + '/handovers', { records: [], total: 0 }]])
for (const row of cargo) {
responses.set('/api/platform/v1/last-leg/dispatches/' + row.dispatchNo, { dispatchNo: row.dispatchNo, status: 'DEPARTED', overseasWarehouseId: 'W1',
packageCount: row.packages, pickedPackageCount: row.packages, shippedPackageCount: row.packages,
items: [{ id: row.dispatchItemId, warehousePalletId: row.warehousePalletId, packageCount: row.packages }] })
responses.set('/api/platform/v1/last-leg/delivery-orders/DL-' + row.dispatchNo + '?customerId=C1', { order: { deliveryNo: 'DL-' + row.dispatchNo,
customerId: 'C1', dispatchNo: row.dispatchNo, status: 'WAIT_DELIVERY', version: '1', packageCount: row.packages,
documentSummary: { categories: [{ fileCount: 0 }] } } })
}
const calls = [], ctx = { marker: 'RUN', token: 'writer', context: {}, createdResources: report.createdResources, async checkpoint() { calls.push('checkpoint') },
async request(method, path) { assert.equal(method, 'GET', 'recovery verification must never write'); calls.push(path); assert.ok(responses.has(path), path)
return { http: 200, body: { code: '200', data: responses.get(path) }, requestId: 'r', traceId: 't' } } }
return { report, ctx, calls, responses, base, trip }
}
function createdVehicleRecoveryFixture() {
const f = afterCostsRecoveryFixture(), snapshot = { id: '2106360046045675522', plateNumber: 'HO-24255909-3BC', recordVersion: '0',
status: 'IN_SERVICE', ownership: 'OWNED', region: 'OVERSEAS', maxPalletSpaces: 30, maxLoadKg: 18000, maxVolumeCbm: 90 }
f.report.steps[0].name = '接替车辆返回真实身份及车牌'
const request = { method: 'POST', path: '/api/platform/v1/last-leg/master-data/vehicles', body: { plateNumber: 'HO-24255909-3bc' },
status: 'RESPONDED', http: 200, code: '200', requestId: 'created-r', traceId: 'created-t', result: snapshot }
f.trip.handover.requests.push(request)
f.responses.set('/api/platform/v1/last-leg/master-data/vehicles/' + snapshot.id, structuredClone(snapshot))
f.ctx.context.readReviewedVehicleOccupation = async vehicleId => ({ vehicleId, assignmentCount: 0 })
return { ...f, snapshot, request }
}
test('created-vehicle checkpoint requires exact successful uppercase response and no subsequent writes', () => {
const { report } = createdVehicleRecoveryFixture()
const accepted = reviewedFullCheckpoint(report, 'DEPARTED_VEHICLE_CREATED')
assert.equal(accepted.createdVehicle.snapshot.plateNumber, 'HO-24255909-3BC')
assert.equal(accepted.createdVehicle.creationRequest.body.plateNumber, 'HO-24255909-3bc')
for (const mutation of [f => f.request.http = 0, f => f.request.status = 'UNKNOWN_RESULT', f => f.request.code = 'A0409',
f => f.request.traceId = null, f => f.trip.handover.requests.push({ method: 'POST', path: '/drivers' })]) {
const f = createdVehicleRecoveryFixture(); mutation(f)
assert.throws(() => reviewedFullCheckpoint(f.report, 'DEPARTED_VEHICLE_CREATED'), /Created vehicle recovery/)
}
assert.throws(() => reviewedFullCheckpoint(report, 'DEPARTED_AFTER_COSTS_BEFORE_HANDOVER'), /checkpoint/)
})
for (const fault of ['none', 'changed', 'occupied', 'missing-reader']) test(`created vehicle exact snapshot and no occupation mandatory: ${fault}`, async () => {
const f = createdVehicleRecoveryFixture(), accepted = reviewedFullCheckpoint(f.report, 'DEPARTED_VEHICLE_CREATED')
if (fault === 'changed') f.responses.get('/api/platform/v1/last-leg/master-data/vehicles/' + f.snapshot.id).recordVersion = '1'
if (fault === 'occupied') f.ctx.context.readReviewedVehicleOccupation = async vehicleId => ({ vehicleId, assignmentCount: 1 })
if (fault === 'missing-reader') delete f.ctx.context.readReviewedVehicleOccupation
const options = { costsAlreadyVerified: true, createdVehicle: accepted.createdVehicle }
if (fault === 'none') { const r = await verifyDepartedRecovery(f.ctx, options); assert.equal(r.reviewedVehicle.snapshot.id, f.snapshot.id) }
else await assert.rejects(continueReviewedDeparture(f.ctx, { ...options, makePicker: () => assert.fail('no session before verification') }), /recovery refused/)
})
test('occupancy reader is scoped to exact numeric vehicle and readonly evidence transport', async () => {
const env = { JENKINS_URL: 'https://test.invalid/', JENKINS_USER: 'reader', JENKINS_API_TOKEN: 'secret', FBA_CORE_JENKINS_AGENT: 'java-test-agent' }
const result = await readReviewedVehicleOccupation(env, '123', async (url, init) => {
assert.equal(url.pathname, '/scriptText'); assert.equal(init.method, 'POST'); assert.ok(init.body.get('script').includes('executeGroovy'))
return new Response('FBA_CORE_JSON={"ok":true,"rows":[{"vehicleId":"123","assignmentCount":0}]}')
})
assert.deepEqual(result, { vehicleId: '123', assignmentCount: 0 })
await assert.rejects(readReviewedVehicleOccupation(env, '123; DELETE', () => assert.fail('invalid identity')), /numeric/)
})
function afterCostsRecoveryFixture() {
const fixture = departedRecoveryFixture(), { report, trip, responses, base } = fixture
report.createdResources.fleetAcceptance.stage = 'IN_TRANSIT_HANDOVER'
report.steps[0].name = '每张排车已发车且货量与客户起运仓一致'
trip.costAcceptance.status = 'VERIFIED'
trip.costAcceptance.costs = [{ costNo: 'CNY-COST' }, { costNo: 'USD-COST' }]
trip.costAcceptance.final = { page: { records: structuredClone(trip.costAcceptance.costs), total: 2 },
summary: { manifestHash: 'a'.repeat(64), departureVersion: '27', totals: [{ currency: 'CNY', directCost: '100.03' }, { currency: 'USD', directCost: '13.07' }], allocationBlockReason: 'MULTI_STOP' } }
trip.handover = { status: 'FAILED', requests: [{ method: 'GET', status: 'RESPONDED', http: 200, code: '200' }] }
responses.set(base + '/costs?page=1&size=100', structuredClone(trip.costAcceptance.final))
return fixture
}
test('after-cost recovery requires its exact known read-only handover failure and rejects any handover write', () => {
const { report } = afterCostsRecoveryFixture()
assert.equal(reviewedFullCheckpoint(report, 'DEPARTED_AFTER_COSTS_BEFORE_HANDOVER').costsAlreadyVerified, true)
report.createdResources.fleetTrips[0].handover.requests.push({ method: 'POST', status: 'RESPONDED', http: 200, code: '200' })
assert.throws(() => reviewedFullCheckpoint(report, 'DEPARTED_AFTER_COSTS_BEFORE_HANDOVER'), /checkpoint/)
})
test('after-cost recovery checks original cost contents and refuses a changed amount before any write', async () => {
const { ctx, responses, base } = afterCostsRecoveryFixture()
responses.get(base + '/costs?page=1&size=100').summary.totals[0].directCost = '100.04'
await assert.rejects(continueReviewedDeparture(ctx, { costsAlreadyVerified: true,
prepareActors: () => assert.fail('no new actors'), makePicker: () => assert.fail('no new PDA before verification') }), /costs already written or cargo basis changed/)
})
test('after-cost recovery retains verified costs and only enters handover, signatures and resource closure', async () => {
const { ctx, trip } = afterCostsRecoveryFixture(), costs = trip.costAcceptance, oldHandover = trip.handover, operations = []
await continueReviewedDeparture(ctx, { costsAlreadyVerified: true, prepareActors: () => assert.fail('verified costs need no new cost actors'),
resolveAccess: async () => ({}), makePicker: async () => ({ token: 'new-pda', membershipId: 'NEW-PDA' }), closePicker: async () => operations.push('close-pda'),
complete: (context, trip, picker, details, options) => completeDepartedFleetScenario(context, trip, picker, details, { ...options,
verifyCosts: () => assert.fail('costs must never be recreated'), handover: async () => operations.push('handover'),
completeDelivery: async (_ctx, order) => { operations.push('sign:' + order.deliveryNo); return { order: { status: 'DELIVERED', signedAt: 'signed' } } },
closeTrip: async () => { operations.push('release'); return { status: 'CARGO_COMPLETED_AND_RESOURCES_RELEASED' } }, cleanup: async () => operations.push('cleanup'),
}) })
assert.equal(trip.costAcceptance, costs); assert.equal(trip.previousReadOnlyHandoverAttempts[0], oldHandover)
assert.deepEqual(operations, ['handover', 'sign:DL-OWN', 'sign:DL-EXT', 'release', 'cleanup', 'close-pda'])
})
test('departed recovery requires reviewed SHA and exactly the original read-only cost failure', () => {
assert.throws(() => parseFleetArguments(['--resume-report', 'reports/r5/report.json', '--resume-stage', 'DEPARTED_BEFORE_COSTS']), /SHA256/)
const args = ['--resume-report', 'reports/r5/report.json', '--resume-stage', 'DEPARTED_BEFORE_COSTS', '--resume-sha256', 'a'.repeat(64)]
assert.equal(parseFleetArguments(args).resumeSha256, 'a'.repeat(64))
assert.throws(() => parseFleetArguments([...args, '--scenario', 'return-redispatch']), /fresh run/)
assert.equal(reviewedFullCheckpoint(departedRecoveryFixture().report, 'DEPARTED_BEFORE_COSTS').departed, true)
for (const change of [r => r.createdResources.fleetTrips[0].costAcceptance.requests.push({ method: 'POST' }),
r => r.createdResources.fleetTrips[0].handover = {}, r => r.createdResources.fleetAcceptance.receipts = [],
r => r.createdResources.fleetCostActors.status = 'READY', r => r.steps[0].name = 'unknown write']) {
const { report } = departedRecoveryFixture(); change(report)
assert.throws(() => reviewedFullCheckpoint(report, 'DEPARTED_BEFORE_COSTS'), /checkpoint/)
}
})
for (const mutation of ['none', 'version', 'history', 'cost', 'handover', 'cargo', 'signature', 'document'])
test(`recovery rechecks actual state before any session/business write: ${mutation}`, async () => {
const { ctx, responses, base } = departedRecoveryFixture()
if (mutation === 'version') responses.get(base).trip.recordVersion = '28'
if (mutation === 'history') responses.get(base + '/history?page=1&size=100').records[0].snapshot.confirmedLoad.manifestHash = 'changed'
if (mutation === 'cost') responses.get(base + '/costs?page=1&size=100').page.records.push({ costNo: 'COST' })
if (mutation === 'handover') responses.get(base + '/handovers').records.push({ handoverNo: 'H' })
if (mutation === 'cargo') responses.get('/api/platform/v1/last-leg/dispatches/OWN').items[0].packageCount = 3
const delivery = responses.get('/api/platform/v1/last-leg/delivery-orders/DL-OWN?customerId=C1').order
if (mutation === 'signature') delivery.signedAt = 'now'
if (mutation === 'document') delivery.documentSummary.categories[0].fileCount = 1
if (mutation === 'none') { await verifyDepartedRecovery(ctx); assert.equal(ctx.createdResources.fleetDepartureRecoveryVerification.status, 'VERIFIED') }
else await assert.rejects(continueReviewedDeparture(ctx, { prepareActors: () => assert.fail('no new actors before validation') }), /recovery refused/)
})
test('reviewed recovery archives old evidence and creates fresh sessions before shared post-departure flow only', async () => {
const { ctx, trip, calls } = departedRecoveryFixture(); const oldCost = trip.costAcceptance
await continueReviewedDeparture(ctx, {
prepareActors: async () => { assert.equal(ctx.createdResources.fleetDepartureRecoveryVerification.status, 'VERIFIED'); calls.push('new-actors'); return { marker: 'RUN', listOnlyToken: 'reader', deniedToken: 'denied', async close() { calls.push('close-actors') } } },
resolveAccess: async () => ({}), makePicker: async child => { assert.match(child.marker, /RECOVERY-PDA/); calls.push('new-picker'); return { membershipId: 'NEW', token: 'new-pda' } },
closePicker: async () => calls.push('close-picker'),
complete: async (context, actualTrip, picker, dispatches) => {
assert.equal(actualTrip, trip); assert.equal(trip.costAcceptance, undefined); assert.equal(picker.membershipId, 'NEW'); assert.equal(dispatches.length, 2)
assert.equal(trip.previousReadOnlyCostAttempts[0], oldCost); assert.equal(context.createdResources.fleetAcceptance.previousPicker.membershipId, 'OLD-PDA')
calls.push('continue-from-costs')
},
})
assert.deepEqual(calls.filter(x => !x.startsWith('/') && x !== 'checkpoint'), ['new-actors', 'new-picker', 'continue-from-costs', 'close-picker', 'close-actors'])
})
test('shared continuation starts at costs, retains unavailable allocation and never enters picking or DEPART', async () => {
const { ctx, trip, calls } = departedRecoveryFixture()
const verified = await verifyDepartedRecovery(ctx), operations = []
await completeDepartedFleetScenario(ctx, trip, { token: 'pda' }, verified.dispatchDetails, {
costActors: { marker: 'RUN' },
verifyCosts: async () => { operations.push('costs'); trip.costAcceptance = { status: 'VERIFIED', expected: { allocationStatus: 'UNAVAILABLE' } } },
handover: async () => { assert.equal(trip.costAcceptance.expected.allocationStatus, 'UNAVAILABLE'); operations.push('handover') },
completeDelivery: async (context, order) => { operations.push('signature:' + order.deliveryNo); return { order: { status: 'DELIVERED', signedAt: 'signed' } } },
closeTrip: async () => { operations.push('close-trip'); return { status: 'CARGO_COMPLETED_AND_RESOURCES_RELEASED' } },
cleanup: async () => operations.push('cleanup'),
})
assert.deepEqual(operations, ['costs', 'handover', 'signature:DL-OWN', 'signature:DL-EXT', 'close-trip', 'cleanup'])
assert.equal(ctx.createdResources.fleetAcceptance.stage, 'FINISHED')
assert.ok(!calls.some(x => /\/depart$|\/pick|\/loading/.test(x)))
})
test('changed source report SHA blocks recovery before creating context or logging in', async () => {
const temporary = mkdtempSync(join(tmpdir(), 'fleet-recovery-sha-'))
const root = join(temporary, 'chongchong-global', 'baiyue-firstleg'); mkdirSync(join(root, 'reports', 'original'), { recursive: true })
writeFileSync(join(root, 'reports', 'original', 'report.json'), JSON.stringify(departedRecoveryFixture().report))
try {
const result = await runFleetAcceptance({ execute: true, environment: 'TEST', runId: 'reviewed', resumeStage: 'DEPARTED_BEFORE_COSTS',
resumeReport: 'reports/original/report.json', resumeSha256: 'b'.repeat(64) }, { root,
env: { CHONGCHONG_ENV: 'test', CHONGCHONG_ADMIN_API_BASE_URL: 'https://test.invalid', CHONGCHONG_ADMIN_USERNAME: 'admin',
CHONGCHONG_ADMIN_PASSWORD: 'secret', ADMIN_PDA_USERNAME: 'pda', ADMIN_PDA_PASSWORD: 'secret' },
createContext: () => assert.fail('SHA mismatch must precede context/network'),
})
assert.equal(result.success, false); assert.match(result.fatal, /SHA256 mismatch/)
} finally {
assert.equal(dirname(resolve(temporary)), resolve(tmpdir()))
assert.ok(resolve(temporary).startsWith(join(resolve(tmpdir()), 'fleet-recovery-sha-')))
rmSync(temporary, { recursive: true, force: true })
}
})
import { parseFleetArguments, fleetExecutionPlan, runFleetAcceptance, reviewedFullCheckpoint, verifyFleetTerminalState, runFleetHandoverStage, fleetCostShares, prepareFleetCostActors, findFleetActorPhone, guardFleetWrites, redactFleetWrite, verifyDepartedRecovery, continueReviewedDeparture, completeDepartedFleetScenario, readReviewedVehicleOccupation } from './fleet-test-env-acceptance.mjs'
for (const response of [
{ http: 0 }, { http: 503, body: { code: 'A0500' }, requestId: 'r', traceId: 't' },
{ http: 200, body: null }, { http: 200, body: { code: '200' } },
{ http: 302, body: { code: '200' }, requestId: 'r', traceId: 't' },
]) test(`unknown prerequisite write stops every subsequent request: ${JSON.stringify(response)}`, async () => {
const saved = [], calls = []
const ctx = { async request(method, path, body) {
assert.equal(saved.at(-1).status, 'SENDING')
assert.deepEqual(saved.at(-1).body, body)
calls.push(path); return response
} }
guardFleetWrites(ctx, entry => saved.push(structuredClone(entry)))
const body = { expectedVersion: 6, idempotencyKey: 'original-key', internalNotes: ['test remark'] }
await assert.rejects(ctx.request('PUT', '/orders/1/remarks?tenantId=2', body), /Unknown write outcome/)
body.expectedVersion = 99
assert.equal(saved[0].body.expectedVersion, 6)
assert.equal(saved[1].status, 'UNKNOWN_RESULT')
for (const method of ['POST', 'GET', 'DELETE']) await assert.rejects(ctx.request(method, '/must-not-run'), /Unknown write outcome/)
assert.deepEqual(calls, ['/orders/1/remarks?tenantId=2'])
})
test('formal correlated rejection is recorded and remains available for expected negative assertions', async () => {
const saved = [], response = { http: 200, body: { code: 'A0409' }, requestId: 'r', traceId: 't' }
const ctx = { async request() { return response } }
guardFleetWrites(ctx, entry => saved.push(structuredClone(entry)))
assert.equal(await ctx.request('POST', '/negative', { recordVersion: 7 }), response)
assert.equal(saved[1].status, 'RESPONDED')
await ctx.request('GET', '/readback'); assert.equal(saved.length, 2)
})
test('response evidence preserves business messages and returned resource IDs with explicit session provenance and no tokens', async () => {
const saved = [], ctx = { token: 'admin-session', pdaToken: 'pda-session', options: { username: 'test-admin' },
async request() { return { http: 200, body: { code: '200', message: 'created', data: {
id: '123', businessNo: 'FIXTURE-123', accessToken: 'new-secret', refreshToken: 'refresh-secret' } }, requestId: 'r', traceId: 't' } } }
guardFleetWrites(ctx, entry => saved.push(redactFleetWrite(structuredClone(entry))))
await ctx.request('POST', '/create', { expectedVersion: 3 })
assert.deepEqual(saved[0].actor, { kind: 'PLATFORM', source: 'CONTEXT_ADMIN_SESSION' })
assert.equal(saved[1].responseBody.message, 'created'); assert.equal(saved[1].responseBody.data.id, '123')
await ctx.request('POST', '/pda', {}, 'pda-session'); assert.equal(saved[2].actor.kind, 'PDA')
await ctx.request('POST', '/other', {}, 'unresolved-session'); assert.equal(saved[4].actor.kind, 'UNKNOWN')
await ctx.request('POST', '/login', {}, ''); assert.equal(saved[6].actor.source, 'NO_SESSION')
for (const secret of ['admin-session', 'pda-session', 'new-secret', 'refresh-secret', 'unresolved-session'])
assert.ok(!JSON.stringify(saved).includes(secret))
})
test('POST carton-label PDF is a definite binary response with durable hash and permits same-fixture readback', async () => {
const saved = [], calls = [], response = { http: 200, body: null, bytes: Buffer.from('%PDF-1.7\nfixture'),
contentType: 'application/pdf', requestId: 'r', traceId: 't' }
const ctx = { async requestBinary(method, path) {
assert.equal(saved.at(-1).status, 'SENDING'); calls.push(path); return response
}, async request() { calls.push('readback') } }
guardFleetWrites(ctx, entry => saved.push(structuredClone(entry)))
const path = '/api/platform/inbounds/1/carton-label-pdf?tenantId=2&cartonIndex=1'
assert.equal(await ctx.requestBinary('POST', path), response)
assert.equal(saved[0].path, path); assert.equal(saved[1].status, 'RESPONDED')
assert.equal(saved[1].binary.bytes, response.bytes.length); assert.match(saved[1].binary.sha256, /^[a-f0-9]{64}$/)
assert.equal(saved[1].binary.validPdf, true)
await ctx.request('GET', '/api/platform/inbounds/1'); assert.deepEqual(calls, [path, 'readback'])
})
test('real inbound prerequisite and AcceptanceRun binary transport accept three PDF writes then stop raw multipart retries', async t => {
const calls = [], saved = [], summary = { id: '1', tenantId: '2', processStatus: 'WAIT_MEASURE', inboundCode: 'FIXTURE-INBOUND', totalPackageCount: 2 }
const native = t.mock.method(globalThis, 'fetch', async (input, init) => {
const req = new Request(input, init), path = new URL(req.url).pathname
calls.push({ method: req.method, path })
const headers = { 'x-request-id': 'r', 'x-trace-id': 't' }
if (req.method === 'GET') return new Response(JSON.stringify({ code: '200', data: { summary } }), { headers: { ...headers, 'content-type': 'application/json' } })
assert.equal(saved.at(-1).status, 'SENDING')
if (path.endsWith('/carton-label-pdf')) return new Response('%PDF-1.7\nfixture', { headers: { ...headers, 'content-type': 'application/pdf' } })
assert.ok(path.endsWith('/measurement/carton-scans'))
throw Error('transport failure Bearer sensitive-session https://example.invalid/private')
})
const context = new AcceptanceRun({ gateway: 'https://test.invalid' })
context.createdResources.orders = { marker: context.marker, inboundId: '1', tenantId: '2' }
const restore = guardFleetWrites(context, entry => saved.push(redactFleetWrite(structuredClone(entry))), { guardFetch: true })
try {
await runInboundMeasurement(context)
assert.equal(calls.filter(row => row.path.endsWith('/carton-label-pdf')).length, 3)
assert.equal(calls.filter(row => row.path.endsWith('/measurement/carton-scans')).length, 1, 'raw helper retries must not reach transport')
const pdfs = saved.filter(row => row.binary?.validPdf)
assert.equal(pdfs.length, 3); assert.ok(pdfs.every(row => row.status === 'RESPONDED'))
assert.equal(context.steps.find(row => row.name === '生成箱唛 PDF 并冻结稳定箱码').passed, true)
const last = saved.at(-1); assert.equal(last.status, 'UNKNOWN_RESULT')
assert.ok(last.body.multipart.some(row => row.field === 'data' && row.base64))
assert.ok(last.raw.includes('transport failure')); assert.ok(!last.raw.includes('sensitive-session')); assert.ok(!last.raw.includes('example.invalid'))
await assert.rejects(context.request('POST', '/subsequent'), /transport failure/)
} finally { restore(); assert.equal(globalThis.fetch, native); t.mock.restoreAll() }
})
test('raw JSON prerequisite writes retain headers, original version and bounded diagnostics without duplicate journaling', async t => {
let calls = 0
t.mock.method(globalThis, 'fetch', async () => { calls++; return new Response('x'.repeat(600), { status: 502 }) })
const saved = [], context = new AcceptanceRun({ gateway: 'https://test.invalid' })
const restore = guardFleetWrites(context, entry => saved.push(redactFleetWrite(structuredClone(entry))), { guardFetch: true })
try {
await assert.rejects(fetch('https://test.invalid/approve', { method: 'PUT', headers: { 'content-type': 'application/json',
Authorization: 'Bearer secret', 'Idempotency-Key': 'same-key' }, body: JSON.stringify({ expectedVersion: 6 }) }), /Unknown write outcome/)
assert.equal(saved.length, 2); assert.equal(saved[0].body.expectedVersion, 6)
assert.equal(saved[0].headers['idempotency-key'], 'same-key'); assert.equal(saved[0].headers.authorization, '[REDACTED]')
assert.equal(saved[1].raw.length, 500)
await assert.rejects(fetch('https://test.invalid/retry', { method: 'POST' }), /Unknown write outcome/)
assert.equal(calls, 1)
} finally { restore(); t.mock.restoreAll() }
})
for (const invalidPdf of [false, true, 'zip']) test(`real loading finalize prints both PDFs through guarded direct fetch; invalid=${invalidPdf}`, async t => {
const saved = [], calls = [], fixture = { destinationType: 'FBA', warehouseId: '1', containerNo: 'CONTAINER', cabinetNo: 'CABINET' }
const manifest = { containerNo: fixture.containerNo, totalCount: 1, groups: [{ destinationWarehouseCode: 'FBA', labels: [{
containerNo: fixture.containerNo, destinationWarehouseInternalCode: 'F01', palletIndex: 1, palletCode: 'CABINET-F01-001' }] }] }
t.mock.method(globalThis, 'fetch', async (input, init) => {
const req = new Request(input, init); calls.push(req.url)
assert.equal(saved.at(-1).status, 'SENDING')
const headers = { 'x-request-id': 'r', 'x-trace-id': 't' }
return req.url.includes('/prepare?')
? new Response(JSON.stringify({ code: '200', data: manifest }), { headers: { ...headers, 'content-type': 'application/json' } })
: new Response(invalidPdf === true ? '<html>proxy failure</html>' : '%PDF-1.6\nfixture',
{ headers: { ...headers, 'content-type': invalidPdf === 'zip' ? 'application/zip' : 'application/pdf' } })
})
const ctx = new AcceptanceRun({ gateway: 'https://test.invalid' })
const restore = guardFleetWrites(ctx, entry => saved.push(redactFleetWrite(structuredClone(entry))), { guardFetch: true })
try {
await verifyPalletLabels(ctx, fixture, '2')
const prints = saved.filter(row => row.path.includes('/print?'))
assert.equal(calls.filter(url => url.includes('/print?')).length, invalidPdf ? 1 : 2)
assert.equal(prints.at(-1).status, invalidPdf ? 'UNKNOWN_RESULT' : 'RESPONDED')
assert.equal(prints.at(-1).binary.validPdf, !invalidPdf)
assert.equal(prints.at(-1).raw, null, 'binary response bytes must not enter text evidence')
assert.equal(prints[0].body.destinationWarehouseCode, null)
if (!invalidPdf) { assert.equal(prints[2].body.destinationWarehouseCode, 'FBA'); assert.ok(ctx.steps.every(row => row.passed)) }
else await assert.rejects(ctx.request('POST', '/no-retry'), /Unknown write outcome/)
} finally { restore(); t.mock.restoreAll() }
})
for (const override of [{ http: 0 }, { http: 503 }, { bytes: Buffer.from('<html>proxy</html>') },
{ bytes: new Uint8Array() }, { contentType: 'text/html' }, { traceId: null },
{ contentType: 'application/json', bytes: Buffer.from('{"code":"200"}'), body: { code: '200' } }])
test(`binary write still stops on unknown or invalid response: ${JSON.stringify(override)}`, async () => {
const saved = [], ctx = { async requestBinary() { return { http: 200, body: null, bytes: Buffer.from('%PDF-1.7'),
contentType: 'application/pdf', requestId: 'r', traceId: 't', ...override } }, async request() { assert.fail('must stop') } }
guardFleetWrites(ctx, entry => saved.push(structuredClone(entry)))
await assert.rejects(ctx.requestBinary('POST', '/carton-label-pdf'), /Unknown write outcome/)
assert.equal(saved[1].status, 'UNKNOWN_RESULT')
await assert.rejects(ctx.request('GET', '/readback'), /Unknown write outcome/)
})
test('checkpoint failure stops before dispatch; transport throw stops even after caller catches', async () => {
let calls = 0
const ctx = { async request() { calls++; throw Error('transport failure') } }
guardFleetWrites(ctx, () => { throw Error('disk full') })
await assert.rejects(ctx.request('POST', '/write'), /disk full/)
await assert.rejects(ctx.request('GET', '/later'), /disk full/); assert.equal(calls, 0)
const saved = [], other = { async request() { calls++; throw Error('transport failure') } }
guardFleetWrites(other, entry => saved.push(structuredClone(entry)))
await assert.rejects(other.request('PUT', '/write'), /transport failure/)
await assert.rejects(other.request('POST', '/cleanup'), /transport failure/)
assert.equal(calls, 1); assert.equal(saved[1].status, 'UNKNOWN_RESULT')
})
test('multipart delegates once and retains recoverable fixture bytes, business keys and versions without credentials', async () => {
const saved = [], ctx = {
async requestMultipart(method, path, form) { return this.requestWithBody(method, path, form) },
async requestWithBody() { return { http: 200, body: { code: '200' }, requestId: 'r', traceId: 't' } },
}
guardFleetWrites(ctx, entry => saved.push(redactFleetWrite(structuredClone(entry))))
const form = new FormData(); form.append('file', new Blob(['fixture']), 'proof.txt'); form.append('password', 'hidden')
await ctx.requestMultipart('POST', '/upload', form)
assert.equal(saved.length, 2); assert.equal(Buffer.from(saved[0].body.multipart[0].base64, 'base64').toString(), 'fixture')
assert.ok(!JSON.stringify(saved).includes('hidden'))
const clean = redactFleetWrite({ draftToken: 'business-draft', idempotencyKey: 'command-key', expectedVersion: 6,
headers: { Authorization: 'Bearer hidden', 'X-Access-Token': 'hidden' }, body: { password: 'hidden', accessToken: 'hidden' } })
assert.equal(clean.draftToken, 'business-draft'); assert.equal(clean.idempotencyKey, 'command-key')
assert.equal(clean.expectedVersion, 6); assert.ok(!JSON.stringify(clean).includes('hidden'))
})
test('fleet entry defaults to a no-side-effect plan and requires explicit TEST and unique run ID', () => {
const p = parseFleetArguments([])
assert.equal(p.execute, false); assert.equal(fleetExecutionPlan(p).execution, 'PLAN')
for (const args of [['--execute'], ['--execute', '--run-id', 'new'], ['--execute', '--environment', 'prod', '--run-id', 'new'],
['--execute', '--environment', 'TEST', '--run-id', '../old'], ['--plan', '--execute'], ['--force'], ['--run-id', 'a', '--run-id', 'b']]) {
assert.throws(() => parseFleetArguments(args))
}
assert.equal(parseFleetArguments(['--execute', '--environment', 'TEST', '--run-id', 'new']).execute, true)
const handover = parseFleetArguments(['--plan', '--environment', 'TEST', '--run-id', 'fleet-handover-20261003', '--output', 'reports/fleet-handover-live-20261003'])
assert.equal(fleetExecutionPlan(handover).outputDir, 'reports/fleet-handover-live-20261003')
for (const output of ['reports/../outside', 'C:/temp/output', 'reports', 'reports/nested/path']) assert.throws(() => parseFleetArguments(['--output', output]))
})
test('return redispatch is explicit, fresh-only and declares source-event proof separately', () => {
const config = parseFleetArguments(['--plan', '--environment', 'TEST', '--run-id', 'return-new', '--scenario', 'return-redispatch'])
const plan = fleetExecutionPlan(config)
assert.equal(plan.scenario, 'return-redispatch'); assert.ok(plan.returnRedispatch.required.includes('Two current-run domestic sources'))
assert.throws(() => parseFleetArguments(['--scenario', 'return-redispatch', '--resume-report', 'reports/old/report.json', '--resume-stage', 'FULL_COVERAGE']), /fresh run/)
assert.throws(() => parseFleetArguments(['--scenario', 'unknown']))
})
test('handover stage exports only a verified same-run departure fixture before the optional UI checkpoint', async () => {
const order = [], departure = { tripNo: 'TR-NEW', status: 'IN_TRANSIT' }
const context = { marker: 'CURRENT', context: { saveFleetHandoverFixture(value) { order.push('save'); assert.equal(value.marker, 'CURRENT') } },
createdResources: { fleetAcceptance: { departure } } }
const trip = { tripNo: 'TR-NEW', warehouseId: '92', costAcceptance: { status: 'VERIFIED', marker: 'CURRENT', expected: { finalCny: '100.03', usd: '13.07' } } }, details = [{ dispatchNo: 'PC-NEW' }]
const verified = { status: 'VERIFIED', marker: 'CURRENT', originalDeparture: { snapshot: { confirmedLoad: { pallets: [] } } },
browser: { tripNo: 'TR-NEW' }, handoverNo: 'HO-NEW' }
const result = await runFleetHandoverStage(context, trip, 'secret-picker-token', details, {
verify: async (ctx, module, proof, token, dispatches) => { order.push('verify'); assert.equal(ctx, context); assert.equal(proof, trip); assert.equal(token, 'secret-picker-token'); assert.equal(dispatches, details); return verified },
onReady: async fixture => { order.push('ui'); assert.equal(fixture.status, 'DEPART_AND_HANDOVER_VERIFIED'); assert.equal(fixture.departure, departure) },
})
assert.deepEqual(order, ['verify', 'save', 'ui']); assert.ok(!JSON.stringify(result).includes('secret-picker-token'))
assert.deepEqual(result.costs, trip.costAcceptance)
for (const invalid of [{ ...verified, status: 'FAILED' }, { ...verified, marker: 'OLD' }, { ...verified, originalDeparture: null }]) {
await assert.rejects(runFleetHandoverStage(context, trip, 'token', details, { verify: async () => invalid,
onReady: async () => assert.fail('invalid evidence must not reach the browser checkpoint') }), /current verified/)
}
})
test('cost shares use controlled physical pallets and the original external booking, never statistical totals', () => {
const trip = { externalReceipt: { status: 'VERIFIED', bookingNo: 'BK-ONE', warehousePalletId: '3' }, externalDispatch: { dispatchNo: 'EXT' } }
const details = [{ dispatchNo: 'OWN', items: [{ warehousePalletId: '1' }, { warehousePalletId: '1' }, { warehousePalletId: '2' }] },
{ dispatchNo: 'EXT', items: [{ warehousePalletId: '3' }] }]
assert.deepEqual(fleetCostShares(trip, details), [
{ businessNo: 'OWN', sourceType: 'OWN', dispatchNo: 'OWN', warehousePalletIds: ['1', '2'], palletSpaces: 2 },
{ businessNo: 'BK-ONE', sourceType: 'EXTERNAL', dispatchNo: 'EXT', warehousePalletIds: ['3'], palletSpaces: 1 },
])
assert.throws(() => fleetCostShares(trip, [{ ...details[0], items: [{ warehousePalletId: '3' }] }, details[1]]), /distinct/)
assert.throws(() => fleetCostShares(trip, [details[0], { ...details[1], items: [{ warehousePalletId: '4' }] }]), /receipt/)
})
test('missing isolated cost actor preparation rejects before readers or fixture creation', async () => {
let touched = false
await assert.rejects(runFleetAcceptance({ execute: true, environment: 'TEST' }, {
env: { CHONGCHONG_ENV: 'test' }, prepareCostActors: null, readers: { preflight() { touched = true } },
}), /actor preparation/)
assert.equal(touched, false)
})
for (const failLogin of [false, true]) test(`cost actors create exact isolated roles and disable only owned accounts; login failure=${failLogin}`, async () => {
const calls = [], saved = [], roles = [], users = []
const context = { marker: 'RUN', token: 'admin-secret', createdResources: {}, async findAvailablePhone() { return '19900000000' },
async checkpoint() { saved.push(structuredClone(context.createdResources)) },
async request(method, path, body, token) {
if (method === 'GET' && (path.startsWith('/api/platform/v1/iam/users?') || path.includes('/administrator-phone-availability?')))
return { http: 200, body: { code: '200', data: path.includes('/administrator-phone-availability?') ? true : { records: [], total: 0 } }, requestId: 'r', traceId: 't' }
const pending = saved.at(-1).fleetCostActors.requests.at(-1)
assert.equal(pending.status, 'SENDING'); assert.equal(pending.path, path)
calls.push({ method, path, body, token })
let data
if (path.endsWith('/authorization/permissions')) data = token === 'session-1' ? ['platform:fleet:trip:list'] : []
else if (path.endsWith('/permissions') && method === 'GET') data = [{ id: '7', permissionCode: 'platform:fleet:trip:list', status: 'ACTIVE' }]
else if (path.endsWith('/roles') && method === 'POST') { data = { ...body, id: String(roles.length + 1), roleType: 'CUSTOM' }; roles.push(data) }
else if (path.endsWith('/roles/permissions')) data = body
else if (path.endsWith('/users') && method === 'POST') { data = { ...body, membershipId: String(users.length + 10) }; users.push(data) }
else if (path === '/api/auth/login') { if (failLogin) throw Error('login unavailable'); data = { accessToken: `session-${users.length}` } }
else if (path.endsWith('/status')) data = body
else assert.fail(path)
return { http: 200, body: { code: '200', data }, requestId: 'request', traceId: 'trace' }
} }
if (failLogin) await assert.rejects(prepareFleetCostActors(context), /login unavailable/)
else {
const actors = await prepareFleetCostActors(context)
assert.equal(actors.listOnlyToken, 'session-1'); assert.equal(actors.deniedToken, 'session-2')
assert.equal(calls.filter(row => row.path.endsWith('/roles/permissions'))[1].body.permissionIds.length, 0)
await actors.close()
const count = calls.length; await actors.close(); assert.equal(calls.length, count)
}
assert.equal(context.createdResources.fleetCostActors.status, 'DISABLED')
assert.equal(calls.filter(row => /\/users\/\d+\/status$/.test(row.path)).length, users.length)
assert.equal(calls.filter(row => /\/roles\/\d+\/status$/.test(row.path)).length, roles.length)
const evidence = JSON.stringify(saved)
assert.ok(!evidence.includes('session-1')); assert.ok(!evidence.includes('admin-secret'))
for (const user of users) assert.ok(!evidence.includes(user.password))
assert.ok(!calls.some(row => row.method === 'DELETE'))
})
test('fresh cost actor phones avoid existing platform users and use an independent namespace under the same original marker', async () => {
const phones = [], ctx = { marker: 'ORIGINAL-RUN', async request(method, path) {
assert.equal(method, 'GET')
let data
if (path.includes('/users?')) {
const phone = new URL('https://test.invalid' + path).searchParams.get('keyword'); phones.push(phone)
data = { records: phones.length === 1 ? [{ phone }] : [], total: phones.length === 1 ? 1 : 0 }
} else data = true
return { http: 200, body: { code: '200', data }, requestId: 'r', traceId: 't' }
} }
const first = await findFleetActorPhone(ctx, 'a'.repeat(16))
assert.notEqual(first, phones[0]); assert.match(first, /^18\d{9}$/)
const second = await findFleetActorPhone(ctx, 'b'.repeat(16))
assert.notEqual(first, second)
})
test('phone lookup failure stops without any user creation or guessing', async () => {
let calls = 0
await assert.rejects(findFleetActorPhone({ marker: 'RUN', async request(method) {
assert.equal(method, 'GET'); calls++; return { http: 0 }
} }, 'a'.repeat(16)), /Cannot verify/)
assert.equal(calls, 1)
})
test('main chain performs handover after actual DEPART and before receipts, and cleanup follows current-resource closure', async () => {
const source = readFileSync(new URL('./fleet-test-env-acceptance.mjs', import.meta.url), 'utf8')
const savedDeparture = source.indexOf('proof.departure = departed'), handover = source.indexOf("stage('IN_TRANSIT_HANDOVER')")
const receipt = source.indexOf("stage('RECEIPTS_AND_RESOURCE_RELEASE')"), closure = source.indexOf('proof.closure = await closeTrip')
const cleanup = source.indexOf('await cleanup(context, MODULE, trip)')
assert.ok(savedDeparture > 0 && savedDeparture < handover && handover < receipt && receipt < closure && closure < cleanup)
assert.match(source, /finally \{ await disablePicker\(context, picker, 71\) \}/)
})
async function executeFixture(failProducer = false) {
const temporary = mkdtempSync(join(tmpdir(), 'fleet-entry-contract-'))
const root = join(temporary, 'chongchong-global', 'baiyue-firstleg'); mkdirSync(root, { recursive: true })
const calls = [], secrets = 'never-print-this-secret'
const env = { CHONGCHONG_ENV: 'test', CHONGCHONG_ADMIN_API_BASE_URL: 'https://test.invalid', CHONGCHONG_ADMIN_USERNAME: 'fixture-admin',
CHONGCHONG_ADMIN_PASSWORD: secrets, ADMIN_PDA_USERNAME: 'fixture-pda', ADMIN_PDA_PASSWORD: secrets }
const config = parseFleetArguments(['--execute', '--environment', 'TEST', '--run-id', 'fixture'])
const createContext = options => ({ options, context: {}, createdResources: {}, steps: [], modules: [], coverageGaps: [], token: secrets,
async request(method, path, body) {
const pending = JSON.parse(readFileSync(join(root, 'reports/fleet-fixture/evidence/write-000001.json'), 'utf8'))
assert.equal(pending.request.status, 'SENDING'); assert.deepEqual(pending.request.body, body)
assert.equal(pending.request.path, path); calls.push('unknown-write'); return { http: 0 }
},
async executeModule(name, handler) {
try { await handler(); this.modules.push({ name, success: true }) }
catch { this.modules.push({ name, success: false }); this.steps.push({ name: 'producer failed', passed: false }) }
},
async run() {
await this.executeModule('producer', async () => {
calls.push('producer')
if (failProducer === 'unknown') {
try { await this.request('PUT', '/orders/1/remarks?tenantId=2', { expectedVersion: 6, idempotencyKey: 'original-key', internalNotes: ['fixture'] }) } catch { /* Simulate a prerequisite swallowing an error. */ }
await this.request('POST', '/loading/must-not-run', {})
}
if (failProducer) throw Error('fixture failure')
})
await this.executeModule('phase4-overseas-dispatch', async () => { calls.push('dispatch'); this.createdResources.current = { accessToken: secrets } })
return { success: true, steps: this.steps, modules: this.modules, createdResources: this.createdResources, summary: { failed: 0 } }
},
})
try {
const options = { root, env, createContext, readers: { async preflight() { calls.push('preflight') }, async readReceiving() { throw Error('not used') } },
scenario: async context => {
calls.push('fleet'); context.createdResources.fleetAcceptance = { status: 'HTTP_CHAIN_VERIFIED_WITH_ACK_GAP' }
const command = { requests: [{ method: 'POST', status: 'SENDING', body: { idempotencyKey: 'original-key' }, accessToken: secrets }] }
await context.context.checkpointFleetHandover(command)
const firstPath = join(root, 'reports/fleet-fixture/evidence/handover-000001.json')
const before = readFileSync(firstPath, 'utf8'), saved = JSON.parse(before)
assert.equal(saved.proof.requests[0].body.idempotencyKey, 'original-key')
assert.equal(saved.proof.requests[0].status, 'SENDING'); assert.ok(!before.includes(secrets))
command.requests[0].status = 'RESPONDED'
await context.context.checkpointFleetHandover(command)
assert.equal(readFileSync(firstPath, 'utf8'), before)
assert.equal(JSON.parse(readFileSync(join(root, 'reports/fleet-fixture/evidence/handover-000002.json'), 'utf8')).proof.requests[0].status, 'RESPONDED')
} }
const result = await runFleetAcceptance(config, options)
const report = JSON.parse(readFileSync(result.report, 'utf8'))
if (failProducer === 'unknown') {
const unknown = JSON.parse(readFileSync(join(root, 'reports/fleet-fixture/evidence/write-000002.json'), 'utf8'))
assert.equal(unknown.request.status, 'UNKNOWN_RESULT'); assert.equal(unknown.request.body.expectedVersion, 6)
assert.equal(unknown.request.body.idempotencyKey, 'original-key')
}
assert.ok(!readFileSync(result.report, 'utf8').includes(secrets))
assert.equal(existsSync(join(root, 'reports/.fleet-acceptance.lock')), false)
const oldReport = readFileSync(result.report, 'utf8')
const repeated = await runFleetAcceptance(config, options)
assert.equal(repeated.success, false)
assert.equal(readFileSync(result.report, 'utf8'), oldReport, 'existing run is never overwritten or resumed')
return { result, report, calls }
} finally {
assert.equal(dirname(resolve(temporary)), resolve(tmpdir()))
assert.ok(resolve(temporary).startsWith(join(resolve(tmpdir()), 'fleet-entry-contract-')))
rmSync(temporary, { recursive: true, force: true })
}
}
test('fresh entry runs dedicated fleet scenario after prerequisites without altering the default F40 chain', async () => {
const { result, report, calls } = await executeFixture()
assert.equal(result.success, true)
assert.deepEqual(calls, ['preflight', 'producer', 'dispatch', 'fleet'])
assert.equal(report.fleetGoalComplete, false)
assert.equal(report.createdResources.current.accessToken, '[REDACTED]')
})
test('failed prerequisite stops before further fixture creation and retains the failed report', async () => {
const { result, report, calls } = await executeFixture(true)
assert.equal(result.success, false)
assert.deepEqual(calls, ['preflight', 'producer'])
assert.equal(report.fatal, 'Producer stopped: producer')
})
test('real fleet entry journals prerequisite writes before sending and stops loading even if producer catches unknown outcome', async () => {
const { result, report, calls } = await executeFixture('unknown')
assert.equal(result.success, false)
assert.deepEqual(calls, ['preflight', 'producer', 'unknown-write'])
assert.equal(report.fatal, 'Producer stopped: producer')
})
test('environment mismatch rejects before invoking any readers or contexts', async () => {
let touched = false
await assert.rejects(() => runFleetAcceptance({ execute: true, environment: 'TEST', runId: 'new' }, {
env: { CHONGCHONG_ENV: 'production' }, readers: { preflight() { touched = true } },
}), /TEST/)
assert.equal(touched, false)
})
test('reviewed resume requires explicit paired checkpoint options', () => {
assert.throws(() => parseFleetArguments(['--resume-report', 'reports/old/report.json']))
assert.throws(() => parseFleetArguments(['--resume-report', 'reports/old/report.json', '--resume-stage', 'PICK_EACH_DISPATCH']))
const c = parseFleetArguments(['--execute', '--environment', 'TEST', '--run-id', 'reviewed', '--resume-report', 'reports/old/report.json', '--resume-stage', 'FULL_COVERAGE'])
assert.equal(c.resumeStage, 'FULL_COVERAGE')
})
test('checkpoint guard forbids repeating commands whose write outcome may be unknown', () => {
const report = { success: false, createdResources: {
fleetAcceptance: { marker: 'M', stage: 'FULL_COVERAGE', status: 'CHECKING', tripNo: 'T', originalDispatch: { dispatchNo: 'D' } },
fleetTrips: [{ tripNo: 'T', dispatchNo: 'D' }],
fleetFeeCoverageCases: [{ mode: 'FULL', marker: 'M', dispatchNo: 'D', proof: { status: 'CHECKING', requests: [{ method: 'GET' }] } }],
} }
assert.equal(reviewedFullCheckpoint(report).marker, 'M')
const mutated = structuredClone(report)
mutated.createdResources.fleetFeeCoverageCases[0].proof.requests.push({ method: 'POST' })
assert.throws(() => reviewedFullCheckpoint(mutated), /unknown outcomes/)
mutated.createdResources.fleetFeeCoverageCases[0].proof.requests.pop()
mutated.createdResources.fleetFeeCoverageCases[0].proof.outboundNo = 'OUT-1'
assert.throws(() => reviewedFullCheckpoint(mutated), /unknown outcomes/)
assert.throws(() => reviewedFullCheckpoint(mutated, 'FULL_COVERAGE_PERSISTED'), /exact successful command/)
Object.assign(mutated.createdResources.fleetFeeCoverageCases[0].proof, { deliveryNos: ['DEL-1'], confirmationRequest: { idempotencyKey: 'original-key' } })
mutated.createdResources.fleetFeeCoverageCases[0].proof.requests.push({ label: '正式保存本次原费用服务覆盖并转派送', method: 'POST', http: 200, code: '200' })
assert.equal(reviewedFullCheckpoint(mutated, 'FULL_COVERAGE_PERSISTED').persisted, true)
})
test('receipt-ready reconciliation cannot repeat a receipt that has already started', () => {
const report = { success: false, steps: [{ name: '创建海外PDA仓库操作员71', code: 'A0409', message: '手机号已存在' }], createdResources: {
fleetAcceptance: { marker: 'M', stage: 'RESERVATIONS', status: 'CHECKING', tripNo: 'T' },
fleetTrips: [{ tripNo: 'T', dispatchNo: 'D2', reservation: { status: 'VERIFIED' } }],
fleetFeeCoverageCases: [{ mode: 'FULL', proof: { status: 'VERIFIED' } }, { mode: 'PARTIAL', dispatchNo: 'D2', proof: { status: 'VERIFIED' } }],
} }
assert.equal(reviewedFullCheckpoint(report, 'EXTERNAL_RECEIPT_READY').receiptReady, true)
report.createdResources.fleetTrips[0].externalReceipt = { status: 'CHECKING' }
assert.throws(() => reviewedFullCheckpoint(report, 'EXTERNAL_RECEIPT_READY'), /no receipt writes/)
})
test('palletized checkpoint requires a saved successful command, owned operator, and no later confirmation', () => {
const report = { success: false, createdResources: {
fleetAcceptance: { marker: 'M', stage: 'EXTERNAL_RECEIPT', status: 'CHECKING', tripNo: 'T', picker: { membershipId: '71' }, pickerMarker: 'M-PDA' },
fleetTrips: [{ tripNo: 'T', dispatchNo: 'D2', reservation: { status: 'VERIFIED' }, externalReceipt: { status: 'CHECKING',
warehousePalletId: 'P1', palletizeRequest: { idempotencyKey: 'original' }, requests: [
{ label: 'PDA正式完成外接收货及库存入账', method: 'POST', http: 200, code: '200' },
] } }],
fleetFeeCoverageCases: [{ mode: 'FULL', proof: { status: 'VERIFIED' } }, { mode: 'PARTIAL', dispatchNo: 'D2', proof: { status: 'VERIFIED' } }],
} }
assert.equal(reviewedFullCheckpoint(report, 'EXTERNAL_PALLETIZED').palletized, true)
assert.throws(() => reviewedFullCheckpoint(report, 'EXTERNAL_RECEIPT_CONFIRMED'), /exact successful PDA command/)
const confirmed = structuredClone(report)
confirmed.createdResources.fleetTrips[0].externalReceipt.receiptRequest = { idempotencyKey: 'confirm-original' }
assert.throws(() => reviewedFullCheckpoint(confirmed, 'EXTERNAL_RECEIPT_CONFIRMED'), /exact successful PDA command/)
confirmed.createdResources.fleetTrips[0].externalReceipt.requests.push({ label: '运营按实际1托位和新单价30确认实收', method: 'POST', http: 200, code: '200' })
assert.equal(reviewedFullCheckpoint(confirmed, 'EXTERNAL_RECEIPT_CONFIRMED').receiptConfirmed, true)
assert.throws(() => reviewedFullCheckpoint(confirmed, 'EXTERNAL_PALLETIZED'), /exact successful PDA command/)
for (const mutate of [
r => { r.fleetTrips[0].externalReceipt.requests[0].code = 'A0409' },
r => { delete r.fleetTrips[0].externalReceipt.palletizeRequest.idempotencyKey },
r => { delete r.fleetAcceptance.picker },
r => { r.fleetTrips[0].externalReceipt.receiptRequest = { idempotencyKey: 'later' } },
r => { r.fleetTrips[0].externalDispatch = { status: 'CHECKING' } },
]) {
const invalid = structuredClone(report); mutate(invalid.createdResources)
assert.throws(() => reviewedFullCheckpoint(invalid, 'EXTERNAL_PALLETIZED'), /exact successful PDA command/)
}
})
function terminalFixture(fault = '') {
const finalTrip = { status: 'COMPLETED', completedAt: '2026-10-02T22:01:00Z', recordVersion: '30', vehicleRelease: { endLocation: 'ONT8' }, driverRelease: { endLocation: 'ONT8' } }
const closure = { status: 'CARGO_COMPLETED_AND_RESOURCES_RELEASED', finalTrip, probes: [{ tripNo: 'PROBE' }] }
const trip = { tripNo: 'T', closure, externalReceipt: { status: 'VERIFIED' }, reassignment: { status: 'VERIFIED' }, externalDispatch: { status: 'VERIFIED', dispatchNo: 'EXT', deliveryNo: 'DEL-EXT' } }
const proof = { marker: 'M', tripNo: 'T', customerId: '92', stage: 'RECEIPTS_AND_RESOURCE_RELEASE', closure,
receipts: ['DEL-OWN', 'DEL-EXT'].map(deliveryNo => ({ deliveryNo, signedAt: '2026-10-02T22:00:00' })),
departure: { shippedPackages: 6 }, finance: { status: 'CONSUMER_PERSISTED', source: { sourceFeeId: 'F1', sourceVersion: 1 } } }
const resources = { fleetAcceptance: proof, fleetTrips: [trip], fleetFeeCoverageCases: [{ mode: 'PARTIAL', dispatchNo: 'OWN', proof: { deliveryNos: ['DEL-OWN'] } }] }
const calls = []
const context = { createdResources: resources, assert() {}, async request(method, path) {
calls.push({ method, path }); assert.equal(method, 'GET')
let data
if (path.endsWith('/trips/T')) data = { trip: finalTrip, dispatches: ['OWN', 'EXT'].map(dispatchNo => ({ dispatchNo })) }
else if (path.endsWith('/trips/PROBE')) data = { trip: { status: 'CANCELLED' } }
else if (path.includes('/dispatches/')) { const number = path.split('/').at(-1), count = number === 'OWN' ? 5 : 1
data = { dispatchNo: number, status: 'DEPARTED', packageCount: count, pickedPackageCount: count, shippedPackageCount: fault === 'quantity' ? 0 : count } }
else if (path.includes('/delivery-orders/')) data = { order: { deliveryNo: path.split('/').at(-1).split('?')[0], status: fault === 'unsigned' ? 'WAIT_DELIVERY' : 'DELIVERED', signedAt: '2026-10-02T22:00:00' } }
else if (path.includes('/fee-pool?')) data = [{ customerId: '92', sourceId: 'F1', sourceVersion: fault === 'wrong-fee-version' ? 2 : 1, amount: 30, currency: 'CNY', sourceType: 'OVERSEAS_DELIVERY_FEE' }]
else throw Error('unexpected path')
return { http: 200, body: { code: '200', data: structuredClone(data) }, requestId: 'r', traceId: 't' }
} }
return { context, calls, report: { success: false, createdResources: resources, steps: [{ name: '本次车次货物结案及车辆司机释放完成', passed: false }] } }
}
test('terminal reconciliation reads actual completion, every dispatch/delivery and exact fee without replaying writes', async () => {
const f = terminalFixture()
assert.equal(reviewedFullCheckpoint(f.report, 'TERMINAL_READONLY').terminal, true)
const result = await verifyFleetTerminalState(f.context)
assert.equal(result.terminalReadback.status, 'VERIFIED')
assert.equal(f.calls.length, 7)
assert.ok(f.calls.every(row => row.method === 'GET'))
const invalid = terminalFixture().report
invalid.steps.push({ name: '真实业务失败', passed: false })
assert.throws(() => reviewedFullCheckpoint(invalid, 'TERMINAL_READONLY'), /known aggregate assertion/)
})
for (const fault of ['quantity', 'unsigned', 'wrong-fee-version']) test(`terminal readback rejects ${fault}`, async () => {
const f = terminalFixture(fault)
await assert.rejects(() => verifyFleetTerminalState(f.context))
assert.equal(f.context.createdResources.fleetAcceptance.terminalReadback.status, 'CHECKING')
})