test-one-by-one.mjs•5.47 kB
import { spawn } from 'child_process';
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
console.log('Running individual tests to find memory leak...\n');
const tests = [
'should discover TypeScript projects in monorepo',
'should skip hidden directories and node_modules',
'should return undefined for files outside any project',
'should initialize with auto-discovery',
'should initialize without auto-discovery',
'should add a new project configuration',
'should return empty diagnostics when not initialized',
'should filter diagnostics by severity',
'should return empty completions when not initialized',
'should return undefined when not initialized',
'should return empty references when not initialized',
'should return empty changes when not initialized'
];
async function monitorMemory(proc) {
return new Promise((resolve) => {
const memProcess = spawn('ps', ['-o', 'pid,rss,vsz', '-p', proc.pid]);
let output = '';
memProcess.stdout.on('data', (data) => {
output += data.toString();
});
memProcess.on('close', () => {
const lines = output.trim().split('\n');
if (lines.length > 1) {
const parts = lines[1].trim().split(/\s+/);
resolve({
pid: parts[0],
rss: (parseInt(parts[1]) / 1024).toFixed(2) + ' MB',
vsz: (parseInt(parts[2]) / 1024).toFixed(2) + ' MB'
});
} else {
resolve(null);
}
});
});
}
async function runSingleTest(testName, index) {
console.log(`\n[${index + 1}/${tests.length}] Running: ${testName}`);
const startTime = Date.now();
const proc = spawn('pnpm', [
'test',
'tests/unit/languageServer.test.ts',
'--',
'-t',
testName,
'--run'
], {
env: {
...process.env,
NODE_OPTIONS: '--expose-gc --max-old-space-size=16384'
}
});
let output = '';
proc.stdout.on('data', (data) => output += data.toString());
proc.stderr.on('data', (data) => output += data.toString());
// Monitor memory periodically
const memoryReadings = [];
const monitorInterval = setInterval(async () => {
const mem = await monitorMemory(proc);
if (mem) {
memoryReadings.push({
time: Math.floor((Date.now() - startTime) / 1000),
...mem
});
}
}, 500);
return new Promise((resolve) => {
proc.on('close', (code) => {
clearInterval(monitorInterval);
const duration = Math.floor((Date.now() - startTime) / 1000);
const passed = code === 0;
console.log(` Status: ${passed ? 'PASSED' : 'FAILED'}`);
console.log(` Duration: ${duration}s`);
if (memoryReadings.length > 0) {
console.log(` Memory readings:`);
// Show first, middle and last readings
const readings = [
memoryReadings[0],
memoryReadings[Math.floor(memoryReadings.length / 2)],
memoryReadings[memoryReadings.length - 1]
].filter(Boolean);
readings.forEach(r => {
console.log(` ${r.time}s: RSS=${r.rss}`);
});
}
// Check if test had errors
if (output.includes('FATAL ERROR') || output.includes('heap out of memory')) {
console.log(' ⚠️ OUT OF MEMORY ERROR DETECTED!');
// Save the output for analysis
const errorFile = path.join(__dirname, `memory-error-${index}.log`);
fs.writeFileSync(errorFile, output);
console.log(` Error log saved to: ${errorFile}`);
}
resolve({
test: testName,
passed,
duration,
memoryReadings,
hadOOM: output.includes('heap out of memory')
});
});
});
}
// Run all tests sequentially
async function runAllTests() {
const results = [];
for (let i = 0; i < tests.length; i++) {
const result = await runSingleTest(tests[i], i);
results.push(result);
// If we hit OOM, stop
if (result.hadOOM) {
console.log('\n⚠️ Stopping due to out of memory error');
break;
}
// Small delay between tests
await new Promise(resolve => setTimeout(resolve, 1000));
}
// Summary
console.log('\n=== Test Summary ===');
console.log(`Total tests: ${results.length}`);
console.log(`Passed: ${results.filter(r => r.passed).length}`);
console.log(`Failed: ${results.filter(r => !r.passed).length}`);
console.log(`OOM errors: ${results.filter(r => r.hadOOM).length}`);
const oomTests = results.filter(r => r.hadOOM);
if (oomTests.length > 0) {
console.log('\nTests that ran out of memory:');
oomTests.forEach(t => console.log(` - ${t.test}`));
}
}
runAllTests().catch(console.error);