51 lines
2.8 KiB
JavaScript
51 lines
2.8 KiB
JavaScript
import {test} from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import http from 'node:http';
|
|
import {requestLifetime} from '../server/request-lifetime.mjs';
|
|
import {analyzeSpec} from '../server/ai.mjs';
|
|
import {auditOfferInParts} from '../server/offer-audit-parts.mjs';
|
|
import {requestOfferAssistant} from '../src/services/offerAssistant.js';
|
|
test('premature real HTTP response closure aborts work after the request body is complete', {timeout:3000},async()=>{
|
|
let ready,aborted;
|
|
const received=new Promise(resolve=>ready=resolve), cancelled=new Promise(resolve=>aborted=resolve);
|
|
const server=http.createServer((req,res)=>{
|
|
const lifetime=requestLifetime(req,res);
|
|
lifetime.signal.addEventListener('abort',()=>{lifetime.dispose();aborted();},{once:true});
|
|
req.resume();req.on('end',()=>ready(lifetime));
|
|
});
|
|
await new Promise(resolve=>server.listen(0,'127.0.0.1',resolve));
|
|
const client=http.request({hostname:'127.0.0.1',port:server.address().port,method:'POST'});
|
|
client.on('error',()=>{});client.end('complete request body');
|
|
try {
|
|
const lifetime=await received;assert.equal(lifetime.signal.aborted,false);
|
|
client.destroy();await cancelled;assert.equal(lifetime.signal.aborted,true);
|
|
} finally {client.destroy();await new Promise(resolve=>server.close(resolve));}
|
|
});
|
|
test('caller cancellation aborts provider fetch and never triggers fallback',async()=>{
|
|
const original=globalThis.fetch,old=process.env.GEMINI_API_KEY;
|
|
process.env.GEMINI_API_KEY='synthetic-test-only';let calls=0;
|
|
const c=new AbortController();
|
|
try {
|
|
globalThis.fetch=async(url,{signal})=>new Promise((resolve,reject)=>{
|
|
calls++;signal.addEventListener('abort',()=>reject(new DOMException('Aborted','AbortError')),{once:true});c.abort();
|
|
});
|
|
await assert.rejects(analyzeSpec({text:'Sentetik kaynak',chain:['gemini'],signal:c.signal}),{name:'AbortError'});
|
|
assert.equal(calls,1);
|
|
} finally {globalThis.fetch=original;if(old===undefined)delete process.env.GEMINI_API_KEY;else process.env.GEMINI_API_KEY=old;}
|
|
});
|
|
test('audit cancellation stops remaining batches and is not returned as a partial result',async()=>{
|
|
const c=new AbortController();let calls=0;
|
|
await assert.rejects(auditOfferInParts(['Numune'],'x'.repeat(50000),async()=>{
|
|
calls++;c.abort();throw new DOMException('Aborted','AbortError');
|
|
},{signal:c.signal}),{name:'AbortError'});
|
|
assert.ok(calls<=2);
|
|
});
|
|
test('closing assistant view aborts its pending HTTP fetch',async()=>{
|
|
const c=new AbortController();let aborted=false;
|
|
await assert.rejects(requestOfferAssistant({url:'/api/ai/belge-sor',body:{},readToken:()=>'test',signal:c.signal,
|
|
fetcher:async(url,{signal})=>new Promise((resolve,reject)=>{
|
|
signal.addEventListener('abort',()=>{aborted=true;reject(new DOMException('Aborted','AbortError'));},{once:true});c.abort();
|
|
})}),{name:'AbortError'});
|
|
assert.equal(aborted,true);
|
|
});
|