102 lines
6.6 KiB
JavaScript
102 lines
6.6 KiB
JavaScript
import test from 'node:test'
|
|
import assert from 'node:assert/strict'
|
|
import { mkdtempSync, readFileSync, existsSync, readdirSync, rmSync } from 'node:fs'
|
|
import { tmpdir } from 'node:os'
|
|
import { join, dirname, basename, resolve } from 'node:path'
|
|
import { parseCrossCustomerArguments, runCrossCustomer } from './fleet-cross-customer-test-env.mjs'
|
|
|
|
const config = () => parseCrossCustomerArguments(['--execute', '--environment', 'TEST', '--run-id', 'offline-one', '--warehouse-id', '900', '--destination-warehouse-id', '901'])
|
|
const env = { CHONGCHONG_ENV: 'test', CHONGCHONG_ADMIN_API_BASE_URL: 'https://test.example.invalid/api', CHONGCHONG_ADMIN_USERNAME: 'fixture-admin', CHONGCHONG_ADMIN_PASSWORD: 'private-admin-password' }
|
|
function harness(root, fail = false) {
|
|
const calls = [], cleanup = []
|
|
const context = { marker: 'CROSS-OFFLINE', steps: [], modules: [], coverageGaps: [], context: {}, createdResources: {},
|
|
async request(method, path) {
|
|
calls.push({ method, path })
|
|
const data = path === '/api/auth/login' ? { accessToken: 'private-access', refreshToken: 'private-refresh' }
|
|
: path.includes('warehouse-options') ? [{ id: '900' }] : {}
|
|
return { http: 200, body: { code: '200', data } }
|
|
}, async requestWithBody() { throw Error('Unexpected multipart') } }
|
|
return { calls, cleanup, context, options: { env, outputRoot: root, contextFactory: () => context,
|
|
readers: { preflight: async () => {}, readFleetInventory: async scope => ({ scope, balances: [], positions: [], ledger: [] }) },
|
|
pickerAccess: async () => ({}), pickerCreate: async () => ({ membershipId: '81', token: 'private-pda', password: 'private-pda-password' }),
|
|
pickerDisable: async (_context, picker) => { cleanup.push(picker.membershipId) },
|
|
prepare: async (_context, options) => {
|
|
assert.equal(options.pdaToken, 'private-pda')
|
|
await context.request('POST', '/api/test-owned-command', { idempotencyKey: 'stable-command', password: 'private-pda-password' })
|
|
if (fail) throw Error('FIXTURE_FAILED')
|
|
return { pdaToken: options.pdaToken, marker: context.marker, tripNo: 'TR-OFFLINE', members: [{ customerId: '42' }, { customerId: '43' }] }
|
|
}, verify: async (_context, _fixture, options) => {
|
|
await options.readInventory({ marker: context.marker, customerId: '42', warehouseId: '900' })
|
|
context.createdResources.fleetCrossCustomer = { status: 'VERIFIED', tripNo: 'TR-OFFLINE' }
|
|
context.createdResources.fleetTrips = [{ tripNo: 'TR-OFFLINE' }]
|
|
return context.createdResources.fleetCrossCustomer
|
|
},
|
|
finish: async (_context, _module, trip) => { trip.closure = { status: 'CARGO_COMPLETED_AND_RESOURCES_RELEASED' } },
|
|
} }
|
|
}
|
|
test('plan is network-free and execution requires explicit TEST, unique run and warehouse', async () => {
|
|
const plan = await runCrossCustomer(parseCrossCustomerArguments([]), { env: {}, prepare: () => { throw Error('must not execute') } })
|
|
assert.equal(plan.execute, false)
|
|
for (const args of [['--execute'], ['--execute', '--environment', 'PROD', '--run-id', 'one', '--warehouse-id', '900'], ['--run-id', '../outside'], ['--plan', '--execute'], ['--warehouse-id', '1 OR 1=1']]) assert.throws(() => parseCrossCustomerArguments(args))
|
|
await assert.rejects(runCrossCustomer(config(), { env: { ...env, CHONGCHONG_ENV: 'prod' } }), /TEST/)
|
|
})
|
|
|
|
for (const result of [undefined,{status:'FAILED',tripNo:'TR-OFFLINE'},{status:'VERIFIED',tripNo:'TR-OTHER'}]) test('unverified or foreign result cannot close fixture resources',async()=>{
|
|
const root=mkdtempSync(join(tmpdir(),'fleet-cross-contract-'))
|
|
try {
|
|
const h=harness(root);let finished=false
|
|
h.options.verify=async()=>result;h.options.finish=async()=>{finished=true}
|
|
const report=await runCrossCustomer(config(),h.options)
|
|
assert.equal(report.success,false);assert.equal(finished,false);assert.deepEqual(h.cleanup,['81'])
|
|
}finally{assert.equal(dirname(resolve(root)),resolve(tmpdir()));assert.ok(basename(root).startsWith('fleet-cross-contract-'));rmSync(root,{recursive:true,force:true})}
|
|
})
|
|
for (const fail of [false, true]) test(`execution ${fail ? 'failure' : 'success'} preserves evidence, closes session and disables only its operator`, async () => {
|
|
const root = mkdtempSync(join(tmpdir(), 'fleet-cross-contract-'))
|
|
try {
|
|
const h = harness(root, fail), report = await runCrossCustomer(config(), h.options)
|
|
assert.equal(report.success, !fail)
|
|
assert.deepEqual(h.cleanup, ['81'])
|
|
assert.equal(h.calls.filter(c => c.path === '/api/test-owned-command').length, 1)
|
|
assert.equal(h.calls.filter(c => c.path === '/api/auth/logout').length, 1)
|
|
assert.equal(report.sessionsClosed, true)
|
|
assert.equal(existsSync(join(root, 'reports/.fleet-acceptance.lock')), false)
|
|
const folder = join(root, 'reports/fleet-cross-offline-one')
|
|
for (const file of readdirSync(join(folder, 'requests'))) {
|
|
const saved = readFileSync(join(folder, 'requests', file), 'utf8')
|
|
assert.doesNotMatch(saved, /private-admin-password|private-access|private-refresh|private-pda/)
|
|
}
|
|
const originalReport = readFileSync(join(folder, 'report.json'), 'utf8')
|
|
const replay = await runCrossCustomer(config(), h.options)
|
|
assert.equal(replay.success, false)
|
|
assert.equal(readFileSync(join(folder, 'report.json'), 'utf8'), originalReport)
|
|
assert.equal(h.calls.filter(c => c.path === '/api/test-owned-command').length, 1)
|
|
} finally {
|
|
assert.equal(dirname(resolve(root)), resolve(tmpdir()))
|
|
assert.ok(basename(root).startsWith('fleet-cross-contract-'))
|
|
rmSync(root, { recursive: true, force: true })
|
|
}
|
|
})
|
|
|
|
test('operator creation followed by login failure still disables the newly created membership', async () => {
|
|
const root = mkdtempSync(join(tmpdir(), 'fleet-cross-contract-'))
|
|
try {
|
|
const h = harness(root), original = h.context.request
|
|
h.context.request = async function (...args) {
|
|
if (args[1] === '/api/platform/v1/iam/users') return { http: 200, body: { code: '200', data: { membershipId: '82' } } }
|
|
return original.apply(this, args)
|
|
}
|
|
h.options.pickerCreate = async context => {
|
|
await context.request('POST', '/api/platform/v1/iam/users', { username: 'pda_overseas_current_81', overseasWarehouseId: '900', password: 'private-pda-password' })
|
|
throw Error('PDA_LOGIN_FAILED')
|
|
}
|
|
const report = await runCrossCustomer(config(), h.options)
|
|
assert.equal(report.success, false)
|
|
assert.deepEqual(h.cleanup, ['82'])
|
|
assert.equal(h.calls.some(row => row.path === '/api/test-owned-command'), false)
|
|
} finally {
|
|
assert.equal(dirname(resolve(root)), resolve(tmpdir()))
|
|
assert.ok(basename(root).startsWith('fleet-cross-contract-'))
|
|
rmSync(root, { recursive: true, force: true })
|
|
}
|
|
})
|