import test from 'node:test'; import assert from 'node:assert/strict'; import {parseArguments,validateEnvironment,runAcceptance,businessRejected,offRejected,evidence,pin,fixtureDate,validateSyntheticNotes,syntheticCases} from './selfoperated-test-env-acceptance.mjs'; const env={CHONGCHONG_ENV:'TEST',CHONGCHONG_ADMIN_API_BASE_URL:'https://test.example.invalid/api', CHONGCHONG_ADMIN_USERNAME:'admin-secret',CHONGCHONG_ADMIN_PASSWORD:'password-secret', CHONGCHONG_MERCHANT_USERNAME:'merchant-secret',CHONGCHONG_MERCHANT_PASSWORD:'merchant-password-secret', SELFOP_READONLY_USERNAME:'readonly-secret',SELFOP_READONLY_PASSWORD:'readonly-password-secret', SELFOP_DENIED_USERNAME:'denied-secret',SELFOP_DENIED_PASSWORD:'denied-password-secret'}; const options={execute:true,environment:'TEST',probeOff:true,account:'fixture-account',warehouse:'W1',otherWarehouse:'W2',report:'unused.json'}; const READ='platform:self-operated-analytics:list',SYNC='platform:self-operated-analytics:sync'; function fixture({mode='OFF',offCode='B0001',offMessage='采集功能未启用,当前环境不允许执行采集或重试',acceptCommand=false,changeMode=false}={}){ const requests=[]; const context={salesRunId:'11',inventoryRunId:'22',salesScopeHash:'sales-hash',inventoryScopeHash:'stock-hash',queryAsOf:new Date().toISOString()}; const sales=[{sourceAccount:options.account,warehouseCode:'W1',customerCode:'owner-secret-A',sku:'sku-secret',observedQuantity:4}, {sourceAccount:options.account,warehouseCode:'W1',customerCode:'owner-secret-B',sku:'sku-secret',observedQuantity:8}]; const response=(code='200',data=null,http=200,message='do-not-report-sensitive-message')=>({status:http,headers:new Headers({'x-request-id':'request-1','x-trace-id':'trace-1'}), json:async()=>({code,data,requestId:'request-1',traceId:'trace-1',message})}); const fetchImpl=async(url,init)=>{ const u=new URL(url),path=u.pathname.substring(4),params=u.searchParams,body=init.body?JSON.parse(init.body):null; requests.push({url,method:init.method,body,headers:init.headers}); if(path==='/auth/login'){ const label=body.loginId.split('-')[0];const authorities=label==='admin'?[READ,SYNC]:label==='readonly'?[READ]:[]; return response('200',{accessToken:'token-secret-'+label,refreshToken:'refresh-secret-'+label,authorities}); } if(path==='/auth/logout')return response(); const bearer=init.headers.Authorization??''; if(!bearer)return response('A0401',null,401); if(bearer.endsWith('denied')||bearer.endsWith('merchant'))return response('A0403'); if(init.method==='POST'){ if(bearer.endsWith('readonly'))return response('A0403'); return response(acceptCommand?'200':offCode,acceptCommand?{taskNo:'unexpected'}:null,200,offMessage); } const route=path.split('/').at(-1),warehouse=params.get('warehouseCode'); if(params.get('sourceAccount')?.startsWith('SELFOP-UNCONFIGURED')||warehouse?.startsWith('SELFOP-UNCONFIGURED'))return response('B0001'); if(route==='sync-overview'){ const count=requests.filter(r=>new URL(r.url).pathname.endsWith('/sync-overview')).length; return response('200',{collectionMode:changeMode&&count>6?'BUSINESS':mode,warehouses:[{warehouseCode:warehouse,executionEnabled:false,publicationEnabled:false}]}); } if(params.has('queryAsOf')&&(params.get('queryAsOf')!==context.queryAsOf||warehouse==='W2'))return response('B0001'); if(route==='sku-sales-summary')return response('200',{context,records:params.get('current')==='2'?[]:sales.filter(r=> !params.has('customerCode')||r.customerCode===params.get('customerCode')),total:2}); if(route==='sku-daily-sales')return response('200',{context,summary:{customerCode:params.get('customerCode'),sku:params.get('sku')},points:[ {businessDate:'2026-10-10',dataStatus:'COMPLETE',outboundQuantity:4,observedQuantity:4}, {businessDate:'2026-10-11',dataStatus:'UNKNOWN',outboundQuantity:null,observedQuantity:null}, {businessDate:'2026-10-12',dataStatus:'PARTIAL',outboundQuantity:null,observedQuantity:1}]}); if(route==='owner-overview')return params.has('current')||params.has('size')?response('B0001'):response('200',{context,customerCode:params.get('customerCode')}); if(path.includes('/sync-tasks/'))return warehouse==='W1'?response('200',{task:{taskNo:'TASK-FIXTURE',warehouseCode:'W1'}}):response('B0001'); if(route==='sync-tasks')return response('200',{records:[{taskNo:'TASK-FIXTURE',warehouseCode:warehouse,taskRole:'WAREHOUSE_SYNC'}],total:1}); if(route==='sync-runs')return response('200',{records:[{taskNo:'TASK-FIXTURE'}],total:1}); return response('200',{context,records:[],total:0}); }; return {requests,fetchImpl}; } test('explicit TEST execution and independent warehouse are required',()=>{ assert.throws(()=>parseArguments(['--environment','prod']),/TEST/); assert.throws(()=>parseArguments(['--environment','TEST','--execute']),/SCOPE/); assert.throws(()=>parseArguments(['--environment','TEST','--warehouse','W1','--other-warehouse','W1']),/DIFFER/); assert.throws(()=>parseArguments(['--environment','TEST','--execute','--execute']),/DUPLICATE/); assert.equal(parseArguments(['--environment','TEST']).execute,false); assert.throws(()=>validateEnvironment({...env,CHONGCHONG_ENV:'DEV'}),/TEST/); assert.throws(()=>validateEnvironment({...env,CHONGCHONG_ADMIN_API_BASE_URL:'https://user:secret@test.example.invalid/api'}),/GATEWAY/); assert.throws(()=>validateEnvironment({...env,CHONGCHONG_ADMIN_API_BASE_URL:'https://test.example.invalid/api?token=secret'}),/GATEWAY/); }); test('plan makes no network requests and never reads env files',async()=>{ const p=await runAcceptance({execute:false},{env:{},fetchImpl:()=>{throw Error('network');}}); assert.equal(p.mode,'PLAN');assert.equal(p.fixtureWrites,false);assert.equal(p.thirdPartyCalls,false); }); test('real protocol coverage passes without printing or saving sensitive payloads',async()=>{ const f=fixture(),snapshots=[];const result=await runAcceptance(options,{env,fetchImpl:f.fetchImpl,save:r=>snapshots.push(JSON.stringify(r))}); assert.equal(result.outcome,'PASS',JSON.stringify(result)); for(const id of ['scope.same-sku-other-owner','context.cross-warehouse','sync.off-controlled-rejection','sync.off-no-task-created']) assert.equal(result.cases.find(c=>c.id===id)?.status,'PASS',id); const serialized=snapshots.join(''); for(const forbidden of ['password-secret','token-secret','refresh-secret','owner-secret','sku-secret','test.example.invalid','sensitive-message'])assert.ok(!serialized.includes(forbidden),forbidden); const commands=f.requests.filter(r=>r.method==='POST'&&!new URL(r.url).pathname.startsWith('/api/auth/')); assert.equal(commands.length,5);assert.ok(commands.every(r=>new URL(r.url).pathname.endsWith('/sync-tasks')&&r.body.action==='INVENTORY')); assert.equal(f.requests.filter(r=>new URL(r.url).pathname.endsWith('/auth/logout')).length,4); }); test('OFF preflight blocks every command when mode is not OFF',async()=>{ const f=fixture({mode:'VALIDATION'});const result=await runAcceptance(options,{env,fetchImpl:f.fetchImpl}); assert.equal(result.outcome,'FAIL');assert.ok(!f.requests.some(r=>r.method==='POST'&&new URL(r.url).pathname.endsWith('/sync-tasks'))); }); test('without opt-in no sync POST occurs; missing permission identity stays blocked',async()=>{ const f=fixture();const result=await runAcceptance({...options,probeOff:false},{env:{...env,SELFOP_READONLY_PASSWORD:''},fetchImpl:f.fetchImpl}); assert.equal(result.outcome,'BLOCKED');assert.ok(!f.requests.some(r=>r.method==='POST'&&new URL(r.url).pathname.endsWith('/sync-tasks'))); }); test('a changed OFF preflight stops before all sync POST requests',async()=>{ const f=fixture({changeMode:true});const result=await runAcceptance(options,{env,fetchImpl:f.fetchImpl}); assert.equal(result.outcome,'FAIL');assert.ok(!f.requests.some(r=>r.method==='POST'&&new URL(r.url).pathname.endsWith('/sync-tasks'))); assert.equal(result.cases.find(c=>c.id==='run.blocker').reason,'OFF_CHANGED_STOPPED'); }); test('internal errors never pass as controlled OFF rejection; unexpected acceptance aborts',async()=>{ assert.equal(businessRejected({http:200,body:{code:'S0500'}}),false); assert.equal(businessRejected({http:503,body:{code:'B0001'}}),false); assert.equal(offRejected({http:200,body:{code:'B0001',message:'SELFOP_WAREHOUSE_UNCONFIGURED'}}),false); for(const config of [{offCode:'S0500'},{offMessage:'SELFOP_WAREHOUSE_UNCONFIGURED'},{acceptCommand:true}]){ const f=fixture(config);const result=await runAcceptance(options,{env,fetchImpl:f.fetchImpl}); assert.equal(result.outcome,'FAIL');assert.equal(result.cases.find(c=>c.id==='sync.off-controlled-rejection').status,'FAIL'); } }); test('evidence whitelist retains diagnosis and drops arbitrary body content',()=>{ assert.deepEqual(evidence({http:200,body:{code:'B0001',requestId:'request-2',traceId:'trace-2',password:'secret',data:{accessToken:'secret'}}}), {http:200,code:'B0001',requestId:'request-2',traceId:'trace-2'}); assert.equal(evidence({http:500,body:{code:'secret with spaces'}}).code,null); assert.throws(()=>pin({salesRunId:0,inventoryRunId:0}),/CONTEXT/); assert.equal(pin({salesRunId:0,inventoryRunId:0,queryAsOf:'2026-10-12T00:00:00Z'}).salesRunId,0); }); function syntheticFixture(){ const notes={synthetic:true,fixtureId:'SYNTHETIC-SELFOP-20261012',sourceAccount:'lingxing-primary',hashes:{A:'hash-A',B:'hash-B'}, currentVersions:{A:{salesRunId:'202',inventoryRunId:'203'},B:{salesRunId:'206',inventoryRunId:'207'}},oldSalesRunId:'201',assertions:[ {endpoint:'owners',expected:{total:2,customerCodes:['SYNTH-OWNER-A','SYNTH-OWNER-B']}}, {endpoint:'sku-sales-summary',expected:{total:2,records:{'SYNTH-OWNER-A':{outboundQuantity:30,observedQuantity:30,dataStatus:'COMPLETE',completeDayCount:2,partialDayCount:0,unknownDayCount:0}, 'SYNTH-OWNER-B':{outboundQuantity:10,observedQuantity:10,dataStatus:'COMPLETE'}}}}, {endpoint:'sku-daily-sales',expected:{points:[{businessDate:'D-2',outboundQuantity:10,dataStatus:'COMPLETE'},{businessDate:'D-1',outboundQuantity:20,dataStatus:'COMPLETE'}],summaryOutboundQuantity:30}}, {endpoint:'sku-sales-summary',params:{rangePreset:'TODAY'},expected:{'SYNTH-OWNER-A':{outboundQuantity:null,observedQuantity:5,dataStatus:'PARTIAL'},'SYNTH-OWNER-B':{outboundQuantity:null,observedQuantity:2,dataStatus:'PARTIAL'}}}, {endpoint:'sku-sales-summary',params:{salesRunId:'201'},expected:{outboundQuantity:3,observedQuantity:3,dataStatus:'COMPLETE'}}, {endpoint:'inventory-coverage',expected:{total:5,sharedByOwner:{'SYNTH-OWNER-A':{physicalQuantity:60,availableQuantity:60,outboundQuantity30d:30,inventoryCoverageDays:60}, 'SYNTH-OWNER-B':{physicalQuantity:20,availableQuantity:20,outboundQuantity30d:10,inventoryCoverageDays:60}},zero:{sku:'SYNTH-ZERO'},unknown:{sku:'SYNTH-UNKNOWN'},new:{sku:'SYNTH-NEW'}}}, {endpoint:'hot-skus',expected:{total:2,order:['SYNTH-OWNER-A','SYNTH-OWNER-B'],sku:'SYNTH-SHARED-SKU',outboundQuantities:[30,10]}}, {endpoint:'slow-skus',expected:{total:2,order:['SYNTH-OWNER-B','SYNTH-OWNER-A'],sku:'SYNTH-SHARED-SKU',outboundQuantities:[10,30]}}, {endpoint:'sku-sales-summary',params:{warehouseCode:'SELFOP-TEST-B'},expected:{total:1,customerCode:'SYNTH-OWNER-A',outboundQuantity:999}}, {endpoint:'sync-overview',expected:{A:{sampleCount:2,sampleDates:['D-3','D-1'],accumulationStartedOn:'D-3'},B:{sampleCount:0,accumulationStartedOn:null}}}, ]}; const context={...notes.currentVersions.A,salesScopeHash:'hash-A',inventoryScopeHash:'hash-A',queryAsOf:'2026-10-12T04:00:00Z',anchorDate:'2026-10-12'}; const cases=syntheticCases(notes,context),payloads=new Map(); const row=(customerCode,sku,fields={})=>({sourceAccount:notes.sourceAccount,warehouseCode:'SELFOP-TEST-A',customerCode,sku,...fields}); for(const scenario of cases){ const id=scenario.id.substring(10),data={context:{...context},records:[],total:0}; if(id==='owners'){data.records=['SYNTH-OWNER-A','SYNTH-OWNER-B'].map(customerCode=>({customerCode,customerName:null}));data.total=2;} if(id==='date-range-and-owner-isolation'){data.records=Object.entries(notes.assertions[1].expected.records).map(([code,fields])=>row(code,'SYNTH-SHARED-SKU',fields));data.total=2;} if(id==='daily-exact-axis'){data.summary={customerCode:'SYNTH-OWNER-A',sku:'SYNTH-SHARED-SKU',outboundQuantity:30};data.points=notes.assertions[2].expected.points.map((p,i)=>({...p,businessDate:fixtureDate(context.anchorDate,i-2)}));} if(id==='today-partial'){data.records=Object.entries(notes.assertions[3].expected).map(([code,fields])=>row(code,'SYNTH-SHARED-SKU',fields));data.total=2;} if(id==='old-version-fixed'){data.context.salesRunId='201';data.records=[row('SYNTH-OWNER-A','SYNTH-SHARED-SKU',notes.assertions[4].expected)];data.total=1;} if(id==='inventory-zero-unknown-and-age'){ data.records=Object.entries(notes.assertions[5].expected.sharedByOwner).map(([code,fields])=>row(code,'SYNTH-SHARED-SKU',fields)); data.records.push(row('SYNTH-OWNER-A','SYNTH-ZERO',{physicalQuantity:0,availableQuantity:0}), row('SYNTH-OWNER-A','SYNTH-UNKNOWN',{physicalQuantity:null,availableQuantity:null,inventoryCoverageDays:null,quantityStatuses:{physicalQuantity:'UNKNOWN',availableQuantity:'UNKNOWN'}}), row('SYNTH-OWNER-A','SYNTH-NEW',{observationEligible:false,inventoryCoverageDays:null}));data.total=5; } if(id==='hot-skus-eligibility-order'||id==='slow-skus-eligibility-order'){ const expected=notes.assertions[id.startsWith('hot')?6:7].expected; data.records=expected.order.map((code,i)=>row(code,expected.sku,{outboundQuantity:expected.outboundQuantities[i]}));data.total=2; } if(id==='warehouse-b-positive'){ data.context={...context,...notes.currentVersions.B,salesScopeHash:'hash-B',inventoryScopeHash:'hash-B'}; data.records=[{...row('SYNTH-OWNER-A','SYNTH-SHARED-SKU',{outboundQuantity:999}),warehouseCode:'SELFOP-TEST-B'}];data.total=1; } if(id==='zero-sales-versus-unknown')data.points=[-2,-1].map(offset=>({businessDate:fixtureDate(context.anchorDate,offset),dataStatus:'COMPLETE',outboundQuantity:'0.000000',observedQuantity:0})); if(id==='pre-existence-is-unknown')data.points=[{businessDate:'2026-10-10',dataStatus:'UNKNOWN',outboundQuantity:null,observedQuantity:null}, {businessDate:'2026-10-11',dataStatus:'COMPLETE',outboundQuantity:0}]; if(id.startsWith('daily-sample-gaps-')){ const letter=id.at(-1),expected=notes.assertions[9].expected[letter],present=new Set((expected.sampleDates??[]).map(p=>fixtureDate(context.anchorDate,Number(p.slice(1))))); data.collectionMode='OFF';data.warehouses=[{warehouseCode:'SELFOP-TEST-'+letter,dataFamily:'INVENTORY',executionEnabled:false,publicationEnabled:false, inventoryDailySamples:{windowFrom:'2026-09-12',windowUntil:'2026-10-12',expectedDays:30,sampleCount:expected.sampleCount, accumulationStartedOn:expected.accumulationStartedOn===null?null:'2026-10-09',missingDates:Array.from({length:30},(_,i)=>fixtureDate(context.anchorDate,i-30)).filter(p=>!present.has(p))}}]; } payloads.set(scenario.id,data); } return {notes,context,cases,payloads}; } test('reviewed synthetic fixture covers all thirteen business checks with bound old/current version pairs',()=>{ const f=syntheticFixture();assert.equal(f.cases.length,13); validateSyntheticNotes(f.notes,{account:'lingxing-primary',warehouse:'SELFOP-TEST-A',otherWarehouse:'SELFOP-TEST-B'}); assert.throws(()=>validateSyntheticNotes({...f.notes,synthetic:false},options),/SYNTHETIC/); for(const c of f.cases)assert.equal(c.verify(f.payloads.get(c.id)),true,c.id); const old=f.cases.find(c=>c.id==='synthetic.old-version-fixed'); assert.equal(old.params.salesRunId,'201');assert.equal(old.params.inventoryRunId,'203');assert.equal(old.params.queryAsOf,f.context.queryAsOf); assert.ok(f.cases.every(c=>c.route!=='sync-tasks'&&!c.route.includes('publish'))); assert.equal(fixtureDate('2026-03-01',-1),'2026-02-28'); }); test('synthetic checks reject mixed owners/warehouses, silent current-version fallback, zero-filling and ineligible Top rows',()=>{ const f=syntheticFixture(); const reject=(id,mutate)=>{const c=f.cases.find(c=>c.id==='synthetic.'+id),data=structuredClone(f.payloads.get(c.id));mutate(data);assert.equal(c.verify(data),false,id);}; reject('date-range-and-owner-isolation',d=>{d.records[0].observedQuantity+=999;}); reject('date-range-and-owner-isolation',d=>{d.records[1].customerCode='SYNTH-OWNER-A';}); reject('warehouse-b-positive',d=>{d.records[0].warehouseCode='SELFOP-TEST-A';}); reject('old-version-fixed',d=>{d.context.salesRunId='202';}); reject('inventory-zero-unknown-and-age',d=>{d.records[3].availableQuantity=0;}); reject('pre-existence-is-unknown',d=>{d.points[0].observedQuantity=0;}); reject('daily-exact-axis',d=>{d.points[1].businessDate='2026-10-12';}); reject('hot-skus-eligibility-order',d=>{d.records[0].sku='SYNTH-NEW';}); reject('slow-skus-eligibility-order',d=>{d.records.reverse();}); reject('daily-sample-gaps-A',d=>{d.warehouses[0].inventoryDailySamples.missingDates.push('2026-10-11');}); reject('daily-sample-gaps-B',d=>{d.warehouses[0].inventoryDailySamples.sampleCount=1;}); }); test('synthetic report explicitly marks provider evidence and elapsed expiration as unverified without adding a wait blocker',async()=>{ const f=syntheticFixture();const result=await runAcceptance({...options,account:'lingxing-primary',warehouse:'SELFOP-TEST-A',otherWarehouse:'SELFOP-TEST-B'}, {env:{CHONGCHONG_ENV:'TEST',CHONGCHONG_ADMIN_API_BASE_URL:env.CHONGCHONG_ADMIN_API_BASE_URL},syntheticNotes:f.notes, fetchImpl:async()=>({status:401,headers:new Headers(),json:async()=>({code:'A0401'})})}); assert.equal(result.synthetic,true);assert.equal(result.evidenceType,'SYNTHETIC_QUERY_FIXTURE_NOT_PROVIDER_EVIDENCE'); assert.ok(result.uncovered.some(item=>item.includes('30 elapsed minutes'))); assert.ok(!result.cases.some(c=>c.id==='context.expired')); assert.equal(parseArguments(['--environment','TEST','--synthetic-fixture','notes.json']).syntheticFixture,'notes.json'); }); test('optional nullable fields survive NON_NULL wire serialization while zero-filling stays rejected',()=>{ const f=syntheticFixture(); const omitNulls=value=>Array.isArray(value)?value.map(omitNulls):value&&typeof value==='object'? Object.fromEntries(Object.entries(value).filter(([,v])=>v!==null).map(([k,v])=>[k,omitNulls(v)])):value; for(const c of f.cases)assert.equal(c.verify(omitNulls(f.payloads.get(c.id))),true,c.id); for(const id of ['synthetic.today-partial','synthetic.pre-existence-is-unknown','synthetic.inventory-zero-unknown-and-age']){ const c=f.cases.find(c=>c.id===id),data=omitNulls(f.payloads.get(id)); if(id.endsWith('today-partial'))data.records[0].outboundQuantity=0; else if(id.endsWith('pre-existence-is-unknown'))data.points[0].observedQuantity=0; else data.records[3].availableQuantity=0; assert.equal(c.verify(data),false,id); } });