117 lines
8.4 KiB
JavaScript
117 lines
8.4 KiB
JavaScript
import assert from 'node:assert/strict'
|
|||
|
|
import test from 'node:test'
|
||
|
|
import { mkdtemp, readFile, readdir, rm } from 'node:fs/promises'
|
||
|
|
import { tmpdir } from 'node:os'
|
||
|
|
import { join } from 'node:path'
|
||
|
|
import { installQuoteJournal, requireTestProfile, READY_COMMIT } from './fleet-quotes-test-env.mjs'
|
||
|
|
import { AcceptanceRun } from './admin-test-env-acceptance.mjs'
|
||
|
|
import { run, runQuoteSession } from './admin-test-env-modules/fleet-quotes-operations.mjs'
|
||
|
|
|
||
|
|
const ok = data => ({ http: 200, body: { code: '200', data }, requestId: 'offline-request', traceId: 'offline-trace' })
|
||
|
|
function harness(respond = () => ok({})) {
|
||
|
|
const context = new AcceptanceRun({ environment: 'test', username: 'synthetic-user', password: 'synthetic-password', quiet: true })
|
||
|
|
const events = [], calls = []
|
||
|
|
const persist = async (name, value) => events.push({ name, value: structuredClone(value) })
|
||
|
|
for (const name of ['request', 'requestWithBody', 'requestBinary']) context[name] = async (...args) => {
|
||
|
|
const before = events.at(-1)
|
||
|
|
assert.match(before.name, /-before.json$/)
|
||
|
|
assert.equal(before.value.method, args[0]); assert.equal(before.value.path, args[1])
|
||
|
|
calls.push({ name, args })
|
||
|
|
return respond(...args)
|
||
|
|
}
|
||
|
|
return { context, events, calls, persist }
|
||
|
|
}
|
||
|
|
test('requires exactly one explicit authorized TEST profile and the deployed commit acknowledgement', () => {
|
||
|
|
const file = 'C:/Users/BY-OY/.codex/env/chongchong-global/test-acceptance.env'
|
||
|
|
assert.ok(requireTestProfile([`--ready-commit=${READY_COMMIT}`], [`--env-file=${file}`]))
|
||
|
|
for (const [args, runtime] of [
|
||
|
|
[[], [`--env-file=${file}`]], [['--ready-commit=old'], [`--env-file=${file}`]],
|
||
|
|
[[`--ready-commit=${READY_COMMIT}`], []], [[`--ready-commit=${READY_COMMIT}`], [`--env-file=${file.replace('test-', 'prod-')}`]],
|
||
|
|
[[`--ready-commit=${READY_COMMIT}`], [`--env-file=${file}`, `--env-file=${file}`]],
|
||
|
|
[[`--ready-commit=${READY_COMMIT}`, '--resume'], [`--env-file=${file}`]],
|
||
|
|
]) assert.throws(() => requireTestProfile(args, runtime))
|
||
|
|
})
|
||
|
|
test('writes immutable exact business body and key before sending and pairs response diagnostics', async () => {
|
||
|
|
const h = harness(); await installQuoteJournal(h.context, '', { persist: h.persist })
|
||
|
|
const body = { idempotencyKey: 'same-original-key', details: { looseDeliveryPrice: 0, selfPickupPrice: null } }
|
||
|
|
await h.context.request('POST', '/api/platform/v1/last-leg/fleet/quotes', body)
|
||
|
|
body.details.looseDeliveryPrice = 20
|
||
|
|
assert.equal(h.events[1].value.body.value.details.looseDeliveryPrice, 0)
|
||
|
|
assert.equal(h.events[1].value.idempotencyKey, 'same-original-key')
|
||
|
|
assert.equal(h.events[2].value.sample, h.events[1].name)
|
||
|
|
assert.equal(h.events[2].value.requestId, 'offline-request')
|
||
|
|
})
|
||
|
|
for (const response of [{ http: 0 }, { http: 408 }, { http: 503 }, { http: 200, body: { code: 'S0500' } }, { http: 200, body: null }]) {
|
||
|
|
test(`unknown write ${JSON.stringify(response)} halts without retry while allowing journaled logout`, async () => {
|
||
|
|
const h = harness((method, path) => path === '/api/auth/logout' ? ok(null) : response)
|
||
|
|
const journal = await installQuoteJournal(h.context, '', { persist: h.persist })
|
||
|
|
await assert.rejects(h.context.request('POST', '/api/platform/v1/suppliers', { name: 'isolated' }), /Unknown write/)
|
||
|
|
await assert.rejects(h.context.request('POST', '/api/platform/v1/suppliers', { name: 'isolated' }), /halted/)
|
||
|
|
await assert.rejects(h.context.request('PATCH', '/api/platform/v1/suppliers/1/status', { status: 'INACTIVE' }), /halted/)
|
||
|
|
assert.equal(h.calls.length, 1); assert.equal(journal.unknown(), true)
|
||
|
|
await h.context.request('POST', '/api/auth/logout', { refreshToken: 'synthetic-refresh' })
|
||
|
|
assert.equal(h.calls.length, 2); assert.equal(h.events[2].value.outcome, 'UNKNOWN_STOP')
|
||
|
|
})
|
||
|
|
}
|
||
|
|
test('failure to persist before sending blocks all HTTP', async () => {
|
||
|
|
const h = harness(); let writes = 0
|
||
|
|
await installQuoteJournal(h.context, '', { persist: async () => { if (++writes > 1) throw new Error('disk full') } })
|
||
|
|
await assert.rejects(h.context.request('POST', '/api/platform/v1/suppliers', {}), /disk full/)
|
||
|
|
assert.equal(h.calls.length, 0)
|
||
|
|
})
|
||
|
|
test('an uncertain quote command skips all resource deactivation and retains the original supplier', async () => {
|
||
|
|
const h = harness((method, path) => path.includes('/suppliers') ? ok({ id: '321' }) : { http: 0 })
|
||
|
|
h.context.marker = 'FLEET-QUOTE-20261003'
|
||
|
|
h.context.createdResources.merchantQualificationFixture = { marker: h.context.marker, tenantId: '123' }
|
||
|
|
await installQuoteJournal(h.context, '', { persist: h.persist })
|
||
|
|
await assert.rejects(run(h.context), /Unknown write/)
|
||
|
|
assert.equal(h.context.createdResources.fleetQuoteAcceptance.cleanup, 'NOT_ATTEMPTED_UNKNOWN_OUTCOME')
|
||
|
|
assert.equal(h.context.createdResources.fleetQuoteAcceptance.supplierId, '321')
|
||
|
|
assert.equal(h.calls.length, 2)
|
||
|
|
assert.ok(h.calls.every(call => call.args[0] === 'POST'))
|
||
|
|
})
|
||
|
|
test('failure to persist a response retains the before sample and forbids replay', async () => {
|
||
|
|
const h = harness()
|
||
|
|
await installQuoteJournal(h.context, '', { persist: async (name, value) => { if (name.includes('-after')) throw new Error('disk full'); await h.persist(name, value) } })
|
||
|
|
await assert.rejects(h.context.request('POST', '/api/platform/v1/suppliers', { name: 'isolated' }), /disk full/)
|
||
|
|
await assert.rejects(h.context.request('POST', '/api/platform/v1/suppliers', { name: 'isolated' }), /halted/)
|
||
|
|
assert.equal(h.calls.length, 1); assert.match(h.events.at(-1).name, /before/)
|
||
|
|
})
|
||
|
|
test('multipart checkpoint preserves upload bytes, filenames, digest and scalar fields', async () => {
|
||
|
|
const h = harness(); await installQuoteJournal(h.context, '', { persist: h.persist })
|
||
|
|
const body = new FormData(); body.append('businessLicense', new Blob(['fixture-png'], { type: 'image/png' }), 'fixture.png'); body.append('kind', 'BUSINESS_LICENSE')
|
||
|
|
await h.context.requestWithBody('POST', '/api/platform/v1/files/qualifications/1/required-package', body)
|
||
|
|
const parts = h.events[1].value.body.parts
|
||
|
|
assert.equal(Buffer.from(parts[0].base64, 'base64').toString(), 'fixture-png')
|
||
|
|
assert.equal(parts[0].filename, 'fixture.png'); assert.equal(parts[0].sha256.length, 64)
|
||
|
|
assert.equal(parts[1].value, 'BUSINESS_LICENSE')
|
||
|
|
})
|
||
|
|
test('login, fresh fixture and logout have durable checkpoints without credentials even when fixture outcome is unknown', async () => {
|
||
|
|
const h = harness((method, path) => path === '/api/auth/login' ? ok({ accessToken: 'synthetic-access', refreshToken: 'synthetic-refresh' }) : path === '/api/auth/logout' ? ok(null) : { http: 0 })
|
||
|
|
await installQuoteJournal(h.context, '', { persist: h.persist, secrets: ['synthetic-password', 'synthetic-user'] })
|
||
|
|
const report = await runQuoteSession(h.context, { prepareCustomer: async current => { await current.request('POST', '/api/platform/v1/iam/tenants', { tenantName: current.marker }) } })
|
||
|
|
assert.equal(report.success, false); assert.equal(report.loggedOut, true)
|
||
|
|
assert.deepEqual(h.calls.map(call => call.args[1]), ['/api/auth/login', '/api/platform/v1/iam/tenants', '/api/auth/logout'])
|
||
|
|
assert.ok(h.events.some(event => event.name.includes('module-end')))
|
||
|
|
assert.doesNotMatch(JSON.stringify(h.events), /synthetic-password|synthetic-user|synthetic-access|synthetic-refresh/)
|
||
|
|
})
|
||
|
|
test('redacts newly issued customer credentials including echoes in diagnostic strings', async () => {
|
||
|
|
const h = harness(() => ok({ temporaryPassword: 'generated-secret', administratorUsername: 'generated-user', message: 'generated-secret generated-user' }))
|
||
|
|
await installQuoteJournal(h.context, '', { persist: h.persist })
|
||
|
|
await h.context.request('POST', '/api/platform/v1/iam/tenants', { tenantName: 'current-run' })
|
||
|
|
assert.doesNotMatch(JSON.stringify(h.events), /generated-secret|generated-user/)
|
||
|
|
})
|
||
|
|
test('exclusive on-disk claim prevents a second run from replacing original evidence', async () => {
|
||
|
|
const directory = await mkdtemp(join(tmpdir(), 'fleet-quote-journal-'))
|
||
|
|
try {
|
||
|
|
const h = harness(); const original = async () => ok(null)
|
||
|
|
h.context.request = original
|
||
|
|
await installQuoteJournal(h.context, directory)
|
||
|
|
await h.context.request('POST', '/api/platform/v1/suppliers', { name: 'original-sample' })
|
||
|
|
const files = await readdir(directory)
|
||
|
|
assert.equal(files.length, 3)
|
||
|
|
await assert.rejects(installQuoteJournal(harness().context, directory), { code: 'EEXIST' })
|
||
|
|
assert.match(await readFile(join(directory, '00002-before.json'), 'utf8'), /original-sample/)
|
||
|
|
} finally { await rm(directory, { recursive: true, force: true }) }
|
||
|
|
})
|