| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647 |
- const test=require('node:test');
- const assert=require('node:assert/strict');
- const fs=require('node:fs');
- const path=require('node:path');
- const vm=require('node:vm');
- const source=fs.readFileSync(path.resolve('work/database-enrichment-20261110/collect.cjs'),'utf8');
- async function simulate(httpStatus,size){
- const directory=path.resolve('work/test-collector'),files=new Map();let calls=0;
- const products=Array.from({length:size},(_,i)=>({productId:'jd:'+i,itemId:String(i),platform:'jd',missingReviews:true}));
- files.set(path.join(directory,'product-queue.json'),JSON.stringify(products));
- files.set(path.join(directory,'social-gaps.json'),'[]');
- const fakeFs={readFileSync:p=>{if(!files.has(p))throw Error('UNEXPECTED_FILE_READ');return files.get(p);},
- writeFileSync:(p,b)=>files.set(p,b),existsSync:p=>files.has(p),mkdirSync(){},
- copyFileSync:(a,b)=>files.set(b,files.get(a)),renameSync:(a,b)=>{files.set(b,files.get(a));files.delete(a);}};
- const fromVoc=id=>{
- if(id.includes('catalog'))return {searchVocApis:async()=>({}),getVocApiDoc:async()=>({status:'ok',data:{endpoint:{method:'GET',channel:'ecommerce',params:[]}}})};
- if(id.includes('credentials'))return {readCredentialContext:()=>({newApiToken:'synthetic-test-token'})};
- const call=async()=>{calls++;throw Object.assign(Error('SIMULATED_GATEWAY_RESPONSE'),{httpStatus,kind:'upstream'});};
- return {callSocialGateway:call,callEcommerceGateway:call};
- };
- const fakeProcess={argv:['node','collect.cjs','--all'],exitCode:0};
- const sandbox={__dirname:directory,Buffer,AbortSignal,Date,Promise,process:fakeProcess,
- console:{log(){},error(){}},fetch:()=>{throw Error('NETWORK_NOT_ALLOWED_IN_TEST');},
- setTimeout:fn=>{fn();return 0;},
- require:id=>id==='node:fs'?fakeFs:id==='node:module'?{createRequire:()=>fromVoc}:require(id)};
- sandbox.global=sandbox;
- await vm.runInNewContext(source,sandbox);
- return {calls,result:JSON.parse(files.get(path.join(directory,'all-collection-result.json'))),exitCode:fakeProcess.exitCode};
- }
- test('terminal gateway failures stop the queue without claiming source deletion',async()=>{
- for(const status of [401,402,403]){
- const actual=await simulate(status,5000);
- assert.ok(actual.calls<=6,'Only the active workers may complete');
- assert.equal(actual.result.stopReason.code,'UPSTREAM_HTTP_'+status);
- assert.equal(actual.result.stopReason.sourceRemovalConfirmed,false);
- assert.ok(actual.result.remainingJobs>4990);
- assert.equal(actual.exitCode,2);
- }
- });
- test('a transient upstream failure does not mark all remaining links unavailable',async()=>{
- const actual=await simulate(503,8);
- assert.equal(actual.calls,8);
- assert.equal(actual.result.stopReason,null);
- assert.equal(actual.result.failed,8);
- });
|