18 lines
4.8 KiB
JavaScript
18 lines
4.8 KiB
JavaScript
import fs from 'node:fs';import path from 'node:path';import net from 'node:net';import assert from 'node:assert/strict';import {spawn} from 'node:child_process';
|
|
const read=p=>JSON.parse(fs.readFileSync(p,'utf8')),state=read('C:/laragon/data/sgf-tempo/run/modular-regression-current.json'),tag=process.argv[2],native=process.argv[3]==='native';if(state.port!==55439||!/^[a-f0-9]{12}$/.test(tag??''))throw Error('Owned report fixture required');
|
|
const root=path.join(state.root,'private/ledger-'+(native?'native-':'')+tag),out=path.join(root,'ledger-reports-http.json');if(fs.existsSync(out)||!read(path.join(root,'ledger-reports-cases.json')).passed)throw Error('New HTTP proof over checked report fixture required');
|
|
await new Promise((resolve,reject)=>{const s=net.createServer();s.once('error',reject);s.listen(8047,'127.0.0.1',()=>s.close(resolve));});const log=fs.openSync(path.join(root,'ledger-reports-http-server.log'),'a'),server=spawn('C:/laragon/tools/sgf-tempo/php-8.4.27/php.exe',['-S','127.0.0.1:8047',path.resolve(native?'scripts/ledger-cycle-native-http-router.php':'scripts/ledger-http-router.php')],{windowsHide:true,stdio:['ignore',log,log],env:{...process.env,LEDGER_QA_SETTINGS:path.join(root,'settings.json')}});
|
|
let checks=0;const ok=(v,s)=>{checks++;assert(v,s);},jar=new Map();let context='';const get=async(url,extra={})=>{const r=await fetch('http://127.0.0.1:8047'+url,{headers:{Accept:'application/json',Cookie:[...jar].map(([k,v])=>k+'='+v).join('; '),'X-SGF-Context':context,...extra},redirect:'manual',signal:AbortSignal.timeout(15000)});for(const c of r.headers.getSetCookie()){const p=c.split(';')[0],i=p.indexOf('=');jar.set(p.slice(0,i),p.slice(i+1));}const text=await r.text();let data;try{data=JSON.parse(text);}catch{}return{status:r.status,data,text,headers:r.headers};};
|
|
const range='from_on=2026-10-29&to_on=2026-10-29',url='/api/general-ledger/trial-balance?'+range;
|
|
try{
|
|
let ready=false;for(let n=0;n<50&&!ready;n++){try{ready=(await get('/qa/ledger-demo')).status===200;}catch{}if(!ready)await new Promise(r=>setTimeout(r,100));}ok(ready,'Own report server ready');ok([401,302].includes((await get(url)).status),'Unauthenticated report refused');const login=await get('/qa/ledger-enter/read');ok(login.status===200,'Existing QA read identity');context=login.data.context??'';
|
|
let first;for(const size of [25,100]){const r=await get(url+'&per_page='+size,{'X-Ledger-Report-Proof':String(size)});ok(r.status===200&&r.data.rows.length===size&&r.data.pagination.total===122,'Paginated actual report API '+size);ok(r.data.totals.debit_minor===13205&&r.headers.get('cache-control').includes('no-store'),'Whole-filter totals and no-store');if(!first)first=r.data;}
|
|
const observations=[25,100].map(size=>read(path.join(root,'ledger-reports-http-'+size+'.json')));ok(observations.every(v=>v.transaction?.isolation==='repeatable read'&&v.transaction.read_only==='on'&&v.writer_locks===0),'Coherent read-only transactions, zero writer locks in both sizes');ok(observations[0].report_queries===3&&observations[1].report_queries===3,'Three aggregate/page/marker queries independent of account page size');
|
|
const account=first.rows.find(r=>r.code==='QA-CONTRAPARTIDA').account_id;let r=await get('/api/general-ledger/account-ledger?'+range+'&account_id='+account+'&page=2');ok(r.status===200&&r.data.rows[0].balance_minor===6055+Array.from({length:25},(_,i)=>i+11).reduce((a,b)=>a+b,0),'HTTP running balance crosses page boundary');
|
|
r=await get('/general-ledger/trial-balance?'+range);ok(r.status===200&&r.text.includes('/general-ledger/account-ledger?')&&!r.text.includes('method="post"')&&!r.text.includes('<script>'),'Shared report HTML has account drill-down and no commands');r=await get('/general-ledger/account-ledger?'+range+'&account_id='+account+'&page=2');ok(r.status===200&&r.text.includes('Versão da fonte')&&r.text.includes('Proposta #'),'Source/review evidence rendered');
|
|
for(const q of ['',range+'&tenant_id=9','from_on=2026-02-30&to_on=2026-10-29',range+'&per_page=26',range+'&page=100001',range+'&account_id=999999',range+'&account_id%5Bx%5D=1'])ok([403,422].includes((await get('/api/general-ledger/trial-balance?'+q)).status),'Invalid/injected scope or account refused');
|
|
ok((await get('/api/general-ledger/account-ledger?'+range)).status===422,'Account ledger requires explicit account');
|
|
if(!native){const switched=await get('/qa/ledger-enter/read?module=purchasing');context=switched.data.context;ok((await get(url)).status===409,'Report refuses wrong SGF module context');}
|
|
fs.writeFileSync(out,JSON.stringify({passed:true,checks,host:native?'SGC':'SGF',actual_http:true,read_only:true,writer_locks:0,report_queries_per_page:3,page_sizes:[25,100],totals_cover_all_rows:true,source_evidence:true,no_commands:true,observations,visual_review:false},null,2)+'\n');console.log(JSON.stringify({passed:true,checks,native,report_queries:3}));
|
|
}finally{server.kill();fs.closeSync(log);}
|