Files
baiyue-firstleg/scripts/admin-test-env-modules/completed-command-replay-contract.test.mjs
T

67 lines
3.6 KiB
JavaScript

import test from 'node:test'
import assert from 'node:assert/strict'
import { replayCompletedCommand, completedPlanAssignmentProbe } from './phase3-loading-finalize.mjs'
test('completed-command replay retries one connection failure and keeps its diagnostic', async () => {
const failure = { http: 0, raw: 'fetch failed' }
const success = { http: 200, body: { code: '200' } }
const responses = [failure, success]
const diagnostics = []
let calls = 0
assert.equal(await replayCompletedCommand(async () => { calls++; return responses.shift() }, r => diagnostics.push(r)), success)
assert.equal(calls, 2)
assert.deepEqual(diagnostics, [failure])
})
test('business failures are never retried; a second connection failure remains failure', async () => {
for (const response of [{ http: 200, body: { code: 'A0409' } }, { http: 503 }, { http: 0 }]) {
let calls = 0
const result = await replayCompletedCommand(async () => { calls++; return response }, () => {})
assert.equal(result, response)
assert.equal(calls, response.http === 0 ? 2 : 1)
}
})
function assignmentFixture(change = false) {
const baseline = { status: 'COMPLETED', version: 7, items: [{ id: '11', packageCount: 2 }] }
const reads = [], writes = []
const context = { marker: 'batch', createdResources: {}, async request(method, path) {
reads.push({ method, path }); return { http: 200, body: { code: '200', data: change ? { ...baseline, version: 8 } : structuredClone(baseline) } }
} }
const input = { planPath: '/plans/1', baseline,
body: { inboundId: '10', inboundDetailId: '11', packageCount: 1, expectedVersion: 7, operationId: 'batch-negative' } }
const send = async (_context, method, path, body) => {
writes.push({ method, path, body: structuredClone(body) })
return writes.length === 1 ? { http: 0, raw: 'fetch failed', transportError: { code: 'ECONNRESET' } }
: { http: 200, body: { code: 'A0409' } }
}
return { baseline, context, input, reads, writes, send }
}
test('completed plan rejection probe checks unchanged authoritative state before exact original replay and retains first transport evidence', async () => {
const f = assignmentFixture()
const result = await completedPlanAssignmentProbe(f.context, f.input, f.send)
assert.equal(result.body.code, 'A0409'); assert.equal(f.writes.length, 2)
assert.deepEqual(f.writes[0], f.writes[1]); assert.equal(f.reads.length, 2)
const proof = f.context.createdResources.completedPlanAssignmentProbes[0]
assert.equal(proof.attempts[0].transportError.code, 'ECONNRESET')
assert.equal(proof.status, 'VERIFIED_REJECTION_AFTER_TRANSPORT_RECOVERY')
})
test('changed completed plan after lost response stops without any second write', async () => {
const f = assignmentFixture(true)
await assert.rejects(completedPlanAssignmentProbe(f.context, f.input, f.send), /禁止重放/)
assert.equal(f.writes.length, 1)
assert.equal(f.context.createdResources.completedPlanAssignmentProbes[0].status, 'UNKNOWN_RESULT_STATE_CHANGED')
})
test('completed plan rejection recovery never retries business rejection, server error or permits an ordinary active plan', async () => {
for (const response of [{ http: 200, body: { code: 'A0409' } }, { http: 503 }, { http: 0 }]) {
const f = assignmentFixture(); let count = 0
await completedPlanAssignmentProbe(f.context, f.input, async () => { count++; return response })
assert.equal(count, response.http === 0 ? 2 : 1)
}
const f = assignmentFixture(); f.input.baseline.status = 'ACTIVE'
await assert.rejects(completedPlanAssignmentProbe(f.context, f.input, f.send), /不可变命令/)
assert.equal(f.writes.length, 0)
})