import test from 'node:test' import assert from 'node:assert/strict' import { mkdtempSync, mkdirSync, readFileSync, existsSync, rmSync } from 'node:fs' import { tmpdir } from 'node:os' import { join, dirname, resolve } from 'node:path' import { parseFleetArguments, fleetExecutionPlan, runFleetAcceptance, reviewedFullCheckpoint, verifyFleetTerminalState, runFleetHandoverStage, fleetCostShares, prepareFleetCostActors } from './fleet-test-env-acceptance.mjs' 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) { 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('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 finishFleetTrip') const cleanup = source.indexOf('await cleanupFleetHandoverResources(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 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) 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')) 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('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') })