import test from 'node:test' import assert from 'node:assert/strict' import { mkdtempSync, readFileSync, mkdirSync, writeFileSync, existsSync } from 'node:fs' import { tmpdir } from 'node:os' import { join } from 'node:path' import { F40_MODES, parseCoreArguments, executionPlan, validateCoreEnvironment, redactEvidence, runFbaCore } from './fba-core-regression-test-env.mjs' const env=()=>({CHONGCHONG_ADMIN_API_BASE_URL:'https://test.example.invalid/api',FBA_CORE_TEST_GATEWAY_ORIGIN:'https://test.example.invalid', CHONGCHONG_ADMIN_USERNAME:'offline-admin',CHONGCHONG_ADMIN_PASSWORD:'offline-password',ADMIN_PDA_USERNAME:'offline-pda', ADMIN_PDA_PASSWORD:'offline-pda-password',JENKINS_URL:'https://ci.example.invalid/',JENKINS_USER:'offline-ci', JENKINS_API_TOKEN:'offline-api-secret',FBA_CORE_JENKINS_AGENT:'java-test-agent'}) const config=()=>parseCoreArguments(['--execute','--environment','TEST','--run-id','offline-check']) const scope=()=>({customerId:'2105209721220861954',warehouseId:'193000000000200003',bookingId:'2105220190013755394', stage:'BEFORE_COMPLETE',containerNo:'TEST-ONE',inboundCodes:['IN-1'],sourceInboundIds:['2105220155339444226'], expectedPackagesByInbound:{'IN-1':1}}) const completion=()=>({customerId:'90',rootOrderId:'100',sourceOrderIds:['100','101'],eventType:'FIRST_LEG_ORDER_FULFILLMENT_COMPLETED'}) const root=()=>mkdtempSync(join(tmpdir(),'fba-core-contract-')) const readers=()=>({preflight:async()=>{},readReceiving:async()=>({balances:[]}),readCompletion:async()=>({orders:[]})}) const pass=()=>({success:true,summary:{failed:0},steps:[],deploymentBlockers:[],createdResources:{phase5RootFulfillment:{finalStatus:'VERIFIED'}}}) test('default plan is offline and exposes exact serial modes, required keys and retained reports',()=>{ const plan=executionPlan(parseCoreArguments([])) assert.equal(plan.execution,'PLAN');assert.deepEqual(plan.modes,F40_MODES) assert.equal(plan.taxMode,'BUY_DECLARATION');assert.match(plan.scope,/BUY_DECLARATION/) assert.ok(plan.requiredEnvironmentKeys.includes('ADMIN_PDA_PASSWORD')) for(const args of [['--execute'],['--execute','--environment','PROD','--run-id','x'],['--plan','--execute'],['--mode','ROOT_FIRST']])assert.throws(()=>parseCoreArguments(args)) }) test('tax mode is explicit, defaults to BUY and rejects aliases, duplicate and unsupported values',()=>{ const tax=parseCoreArguments(['--plan','--tax-mode','TAX_REFUND']) assert.equal(tax.taxMode,'TAX_REFUND') const plan=executionPlan(tax) assert.deepEqual(plan.modes,F40_MODES);assert.match(plan.scope,/post-COMPLETED customer document reads\/downloads/) for(const args of [['--tax-mode','REFUND'],['--tax-mode','tax_refund'],['--tax-mode',''],['--taxMode','TAX_REFUND'], ['--tax-mode','TAX_REFUND','--tax-mode','BUY_DECLARATION']])assert.throws(()=>parseCoreArguments(args)) }) test('explicit single signature mode runs only that mode and reports the narrowed scope', async()=>{ const cfg=parseCoreArguments(['--execute','--environment','TEST','--run-id','single-mode','--signature-mode','ROOT_FIRST']) assert.deepEqual(executionPlan(cfg).modes,['ROOT_FIRST']) assert.doesNotMatch(executionPlan(cfg).reports.join(','),/child_first/) const seen=[] const summary=await runFbaCore(cfg,{env:env(),readers:readers(),outputRoot:root(),createContext:mode=>({context:{},async run(){seen.push(mode);return pass()}})}) assert.equal(summary.success,true);assert.deepEqual(seen,['ROOT_FIRST']);assert.equal(summary.modes.length,1) for(const args of [['--signature-mode','ALL'],['--signature-mode','root_first'],['--signature-mode','ROOT_FIRST','--signature-mode','CHILD_FIRST']])assert.throws(()=>parseCoreArguments(args)) }) test('both tax modes pass unchanged to all three existing contexts and persist on all report surfaces',async()=>{ for(const taxMode of ['BUY_DECLARATION','TAX_REFUND']){ const outputRoot=root(),cfg={...config(),taxMode},seen=[] const result=await runFbaCore(cfg,{env:env(),outputRoot,readers:readers(),createContext:mode=>({context:{},async run(){ seen.push({mode,taxMode:this.context.f40TaxMode}) await this.context.phase4ReceivingEvidenceReader(scope()) return pass() }})}) assert.equal(result.success,true);assert.equal(result.taxMode,taxMode) assert.deepEqual(seen,F40_MODES.map(mode=>({mode,taxMode}))) const read=name=>JSON.parse(readFileSync(join(outputRoot,cfg.outputDir,name),'utf8')) assert.equal(read('manifest.json').taxMode,taxMode) assert.equal(read('summary.json').taxMode,taxMode) assert.ok(read('summary.json').modes.every(mode=>mode.taxMode===taxMode)) for(const mode of F40_MODES){ const report=read(mode.toLowerCase()+'.json') assert.equal(report.regressionScope.taxMode,taxMode) assert.equal(report.regressionScope.signatureOrder,mode) assert.match(report.regressionScope.description,new RegExp(taxMode)) assert.equal(read(`evidence/${mode.toLowerCase()}-0001-receiving.json`).taxMode,taxMode) } } }) test('tax mode exception is retained with exact scope and does not start later fixtures',async()=>{ const outputRoot=root(),cfg={...config(),taxMode:'TAX_REFUND'},seen=[] const result=await runFbaCore(cfg,{env:env(),outputRoot,readers:readers(),createContext:mode=>({context:{},createdResources:{},async run(){ seen.push(mode);throw Error('private failure') }})}) assert.deepEqual(seen,['ROOT_FIRST']);assert.equal(result.success,false);assert.equal(result.taxMode,'TAX_REFUND') const report=JSON.parse(readFileSync(join(outputRoot,cfg.outputDir,'root_first.json'),'utf8')) assert.equal(report.regressionScope.taxMode,'TAX_REFUND');assert.equal(report.fatal,'FBA_CORE_MODE_EXCEPTION') }) test('TEST configuration rejects cross environment origins, embedded credentials and wrong workspace',()=>{ assert.equal(validateCoreEnvironment(env()),'https://test.example.invalid') for(const changed of [{FBA_CORE_TEST_GATEWAY_ORIGIN:'https://other.example.invalid'}, {CHONGCHONG_ADMIN_API_BASE_URL:'https://user:secret@test.example.invalid'}, {CHONGCHONG_ADMIN_API_BASE_URL:'https://prod.example.invalid',FBA_CORE_TEST_GATEWAY_ORIGIN:'https://prod.example.invalid'}, {ADMIN_PDA_PASSWORD:''},{FBA_CORE_JENKINS_AGENT:"test');println('bad"}])assert.throws(()=>validateCoreEnvironment({...env(),...changed})) assert.throws(()=>validateCoreEnvironment(env(),'C:/wrong/chongchong-global-dev/baiyue-firstleg')) }) test('serial runner injects both readers and emits all modes without overlap',async()=>{ const outputRoot=root(),order=[];let active=0 const summary=await runFbaCore(config(),{env:env(),outputRoot,readers:readers(),createContext:mode=>({context:{},async run(){ assert.equal(active++,0);order.push(mode) assert.equal(this.context.f40SignatureOrder,mode) await this.context.phase4ReceivingEvidenceReader(scope());await this.context.f40ReadOnlyOutboxEvidence(completion()) active--;return pass() }})}) assert.equal(summary.success,true);assert.deepEqual(order,F40_MODES) const saved=JSON.parse(readFileSync(join(outputRoot,config().outputDir,'summary.json'),'utf8')) assert.equal(saved.modes.length,3);assert.equal(saved.modes[0].evidenceFiles,2) }) test('first failed mode stops later fixtures and keeps report plus evidence',async()=>{ const outputRoot=root(),calls=[] const result=await runFbaCore(config(),{env:env(),outputRoot,readers:readers(),createContext:mode=>({context:{},async run(){ calls.push(mode);await this.context.phase4ReceivingEvidenceReader(scope());return {...pass(),success:false} }})}) assert.equal(result.success,false);assert.deepEqual(calls,['ROOT_FIRST']) assert.ok(existsSync(join(outputRoot,config().outputDir,'root_first.json'))) assert.ok(existsSync(join(outputRoot,config().outputDir,'evidence/root_first-0001-receiving.json'))) }) test('reader exception journals failure, hides secret and prevents next mode',async()=>{ const outputRoot=root(),r=readers();r.readReceiving=async()=>{throw Error('offline-api-secret')} const result=await runFbaCore(config(),{env:env(),outputRoot,readers:r,createContext:()=>({context:{},createdResources:{},async run(){ await this.context.phase4ReceivingEvidenceReader(scope());return pass() }})}) assert.equal(result.modes.length,1);assert.equal(result.success,false) const text=readFileSync(join(outputRoot,config().outputDir,'evidence/root_first-0001-receiving.json'),'utf8') assert.match(text,/READ_ONLY_EVIDENCE_FAILED/);assert.doesNotMatch(text,/offline-api-secret/) }) test('preflight failure creates summary but no HTTP fixture; existing run or active lock cannot overwrite',async()=>{ const outputRoot=root(),r=readers();let created=0;r.preflight=async()=>{throw Error('private')} await runFbaCore(config(),{env:env(),outputRoot,readers:r,createContext:()=>{created++}}) assert.equal(created,0) const summaryPath=join(outputRoot,config().outputDir,'summary.json'),before=readFileSync(summaryPath,'utf8') await runFbaCore(config(),{env:env(),outputRoot,readers:readers(),createContext:()=>{created++}}) assert.equal(readFileSync(summaryPath,'utf8'),before);assert.equal(created,0) const lock=join(outputRoot,'reports/.fba-core-regression.lock');writeFileSync(lock,'occupied') await assert.rejects(runFbaCore({...config(),runId:'next',outputDir:'reports/next'},{env:env(),outputRoot,readers:readers()})) assert.equal(readFileSync(lock,'utf8'),'occupied') }) test('reports redact dynamically created account secrets and environment/token values',()=>{ const value=redactEvidence({password:'x',pdaToken:'y',message:'failure private-secret',nested:{gateway:'url',value:'safe'}},['private-secret']) assert.equal(value.password,'[REDACTED]');assert.equal(value.pdaToken,'[REDACTED]') assert.equal(value.message,'failure [REDACTED]');assert.equal(value.nested.value,'safe') }) test('delivery fault requires one explicit mode and verified proof plus restoration, even after caught run failures', async()=>{ assert.throws(()=>parseCoreArguments(['--plan','--verify-delivery-event-recovery'])) const cfg=parseCoreArguments(['--execute','--environment','TEST','--run-id','fault-one','--signature-mode','ROOT_FIRST','--verify-delivery-event-recovery']) assert.equal(executionPlan(cfg).verifyDeliveryEventRecovery,true) for(const failure of ['none','context','proof','restore']) { const outputRoot=root();let cleanups=0,prepares=0 const r={...readers(),readFleetInventory:async scope=>({scope,balances:[],positions:[],ledger:[]})} const summary=await runFbaCore(cfg,{env:{...env(),CHONGCHONG_ENV:'test'},readers:r,outputRoot, faultFactory:()=>({prepare:async()=>{prepares++},cleanup:async()=>{ cleanups++;if(failure==='restore')throw Error('private failure') return {restored:true,healthy:true,proxyStopped:true} }}),createContext:()=>({context:{},createdResources:{},async run(){ await this.context.f40DeliveryEventFaultExecutor.prepare({marker:'F40',customerId:'90',deliveryId:'91'}) await this.context.f40ReadOnlyInventoryEvidence({marker:'F40',customerId:'90',warehouseId:'92'}) if(failure==='context')throw Error('private failure') const report=pass() if(failure!=='proof')report.createdResources.phase5RootFulfillment.deliveryEventRecovery={status:'VERIFIED'} return report }})}) assert.equal(summary.success,failure==='none') assert.equal(cleanups,1);assert.equal(prepares,1) const evidencePath=join(outputRoot,cfg.outputDir,'evidence') assert.ok(existsSync(join(evidencePath,'root_first-delivery-scope.json'))) assert.ok(existsSync(join(evidencePath,'root_first-0001-inventory.json'))) const report=JSON.parse(readFileSync(join(outputRoot,cfg.outputDir,'root_first.json'),'utf8')) if(failure==='restore')assert.equal(report.deliveryRestorationFailed,true) } })